news 2026/9/24 21:42:58

GitLab + Arbess + OSS:构建可追溯的 Java 制品流水线

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
GitLab + Arbess + OSS:构建可追溯的 Java 制品流水线

1. 为什么要用 Arbess 把 GitLab 和 OSS 串起来

1.1 从“构建靠人盯”到“流水线自动跑”的转变

先交代背景。我们团队内部有大量 Java 服务,代码都放在自建的 GitLab 上,但很长一段时间里,构建、打包、传服务器这些环节都靠开发自己手动执行。开发在本地跑mvn package,再把 JAR 用 scp 传到服务器,遇到多模块项目经常漏传依赖包,构建机器上残留的历史包一多,连哪次提交打出来的都不知道。后来我们引入了 GitLab Runner 做 CI,虽然能解决一部分自动构建的问题,但管理多个 Runner、维护.gitlab-ci.yml里的复杂规则、跨项目复用流水线成本都很高。

真正让我下决心切换的,是团队开始要求“所有制品必须进统一制品库”。GitLab 自带的 Package Registry 可以存,但要接入现有的发布审批流程别扭,而且运维想按目录、按版本、按分支精细控制保存周期,Package Registry 的可见性模型不够灵活。这个时候我们开始试 Arbess。

Arbess 可以简单理解成一个偏向“流程编排”的 DevOps 平台,它和 GitLab 的集成非常直接:你可以拉取 GitLab 仓库、读取提交事件、触发构建任务;也能在同一个平台里把构建、测试、上传制品甚至后续的部署动作串成一条可视化流程。我这边把最终目标定为:GitLab 代码提交后自动触发 Arbess 流水线,流水线里完成 Java 项目构建,再把 JAR 制品上传到阿里云 OSS 做统一归档。这样做的好处是,后续部署系统直接从 OSS 下载指定版本即可,彻底摆脱了“从某台构建机目录里翻包”的原始状态。

1.2 对比 GitLab CI、Jenkins 之后为什么留了 Arbess

我当时把三个方案放在一起比过:原生 GitLab CI、公司已经在用的 Jenkins、还有 Arbess。这里贴一张我评估时用的对比,能直观看出为什么最后留下 Arbess。

对比项GitLab CIJenkinsArbess
流水线定义方式YAML,写起来灵活但规则一多容易失控页面配置 + 脚本,自由度高,但插件维护成本高可视化节点编排,也支持脚本节点,门槛最低
跨项目复用需要模板继承与 include,配置思维偏代码靠共享库,初期搭建成本高节点模板可以直接复用,适合多项目推广
与 GitLab 交互原生,不需要额外打通通过 GitLab Plugin 配置,偶尔出现 token/权限问题内置 GitLab 集成,Webhook 和 API 配置都比较直观
制品上传 OSS要自己写 runner shell 脚本,且对非 GitLab 仓库不友好脚本自由度最高,但也最容易写得乱可以把上传封装成独立节点,后续其他项目直接拖
学习成本中高

强调一下,我并不是说 GitLab CI 或 Jenkins 不行,而是我们团队需要一个“让运维能画流程、开发能点按钮”的平台。Arbess 的这种流程编排方式,对非 CI 专职人员比较友好。另外一点很关键:Arbess 的节点执行日志可以集中看到,构建失败时不需要登录 GitLab 去翻 Runner 日志,省了很多沟通成本。

1.3 这条链路解决的核心问题:制品可追溯

很多团队对“构建成功”的理解就是看到日志里出现BUILD SUCCESS。但放到运维视角,这远远不够。上传到 OSS 之后,每个 JAR 都带上了分支名、提交号、构建序号,我们在任意时刻都能回答三个问题:

  • 这个制品是哪个分支、哪次 commit 构建出来的?
  • 对应的源码在哪里可以看?
  • 如果这个制品有问题,当时用的是哪个 JDK、哪个 Maven 版本、哪份配置文件?

这就是“制品可追溯性”。把 GitLab 的提交信息作为变量的来源,在 Arbess 里传递给构建和上传节点,OSS 的对象命名里直接体现这些信息。后面一旦线上出了诡异问题,我不需要再去问开发“你什么时候传的包”,直接看 OSS 里对象的最后修改时间和元数据就能定位。

2. 开工前的三样准备:GitLab 令牌、Arbess 服务、OSS 权限

2.1 GitLab 侧要准备什么

Arbess 要读取 GitLab 项目、接收推送事件,第一步就是在 GitLab 里创建 Access Token。这里我有过惨痛教训。最开始为了图省事,建了一个read_user权限的 Token,配置到 Arbess 后一直报错,日志里就是那句经典的:

login failed. check api token or gitlab version. log in via git if the version...

一开始以为 GitLab 版本太老,排查了半天。后来用 curl 直接调 GitLab API 才发现,是 Token 的 scope 权限不够。Arbess 拉取项目列表、拿分支信息、检查合并请求状态,最少需要read_apiapi权限;如果还需要它帮你创建 Webhook,那就必须给apiscope。建议直接建一个专用的 Bot 账号,给它Maintainer级别,Token 勾选apiread_repository两项。

另外有个和热词相关的常见问题:“your account is pending approval from your gitlab administrator”。自建 GitLab 如果开启了 LDAP 或新用户审核,新建的 Bot 账号没有通过管理员审批时,Arbess 连接时会一直失败。这个错比较隐蔽,因为页面上不会指向 GitLab 账号状态。遇到这种情况,先进 GitLab Admin Area 把账号激活,再回 Arbess 重连。

Token 创建好之后,建议先用下面这条命令验证,确认不会等到配置完 Arbess 才发现问题:

curl --header "PRIVATE-TOKEN: <your_access_token>" \ "http://gitlab.example.com/api/v4/projects?per_page=1&simple=true"

能正常返回 JSON,就说明 API 通路没问题。

2.2 Arbess 服务本身要注意的配置

Arbess 的部署方式各家不一样,我这里默认你已经有一套可用的 Arbess 服务。在 Arbess 里配置 GitLab 连接时,有三项最容易踩坑:

  • GitLab URL必须填内网其他机器也能访问的地址,不要填localhost127.0.0.1。很多团队部署在容器里,Arbess 服务容器里访问宿主机的 GitLab,应该用宿主机局域网 IP。
  • SSL 验证如果 GitLab 是自签名证书,建议先在测试环境关掉验证,否则会卡在证书信任上。内部使用没有太大风险,但如果是公网环境,还是建议开启并导入证书。
  • API Version与 GitLab 版本的兼容性。Arbess 底层走的是 GitLab REST API v4,如果你的 GitLab 还停留在 11.x 之前的老版本,很多接口路径对不上,登录时的报错会和 Token 错误混在一起,非常误导人。至少升到 13.x 以上再排查其他问题。

还有一点:如果 Arbess 和 GitLab 在同一台机器上,务必确认构建任务的临时工作目录权限。Arbess 运行用户必须对 workspace 目录有读写权限,否则拉取代码时会报“Failed to create workspace”或者权限拒绝。

2.3 OSS 侧:Bucket 规划和最小权限

OSS 这边不能上来就拿主账号 AccessKey 配置到流水线里。我的建议是:

  1. 创建一个独立的 Bucket,例如devops-artifacts,读写权限设为“私有”,不对外公开。
  2. 在 RAM 里创建一个子账号,只授予 OSS 相关权限,不要给 ECS 等资源权限。
  3. 权限策略从最小开始,一般流水线需要oss:PutObjectoss:GetObjectoss:ListObjects,不需要 DeleteObject;清理过期制品可以交给 OSS 生命周期规则,而不是让流水线误删。

以下是一份可以直接用的 RAM 策略示例:

{ "Version": "1", "Statement": [ { "Effect": "Allow", "Action": [ "oss:PutObject", "oss:GetObject", "oss:ListObjects" ], "Resource": [ "acs:oss:*:*:devops-artifacts", "acs:oss:*:*:devops-artifacts/*" ] } ] }

这里“Resource”里既写了 Bucket 本身,也写了 Bucket 下所有对象。如果用了oss:ListObjects,一定要把 Bucket 级别的 ARN 也加进来,否则在控制台或工具里列举对象会失败。

关于 Endpoint,提醒一个容易忽略的点:阿里云 OSS 的 Endpoint 分成公网和内网。如果 Arbess 构建节点部署在阿里云 ECS 上,而且 ECS 与 OSS Bucket 在同一个地域,应该用内网 Endpoint(比如杭州是oss-cn-hangzhou-internal.aliyuncs.com),速度快且不产生下行流量费。但如果你把流水线搭建在公司自家机房,那就只能用公网 Endpoint。千万别为了“看着统一”把内网 Endpoint 写在本地构建环境里,那样会一直连不上。

3. Java 构建任务在 Arbess 里的落地步骤

3.1 构建参数先想清楚,别把乱写脚本当“灵活”

很多人在 Arbess 里创建构建节点时,图省事直接写一行:

mvn clean package

看起来没问题,但放到多模块 Java 项目上就会埋雷。比如你的仓库里有parentcommonservice-aservice-b多个模块,而这次 MR 只改了service-a,全量构建所有模块不仅浪费时间,还可能因为某些模块代码不规范导致整体失败。我的建议是在构建节点的脚本里用如下方式:

mvn clean package -pl service-a -am -DskipTests=false

解释一下参数的含义:

  • -pl service-a表示只构建service-a模块;
  • -am表示“也构建依赖到的模块”,比如common,但不会构建无关模块;
  • -DskipTests=false表示测试照跑,除非有特殊原因否则不要跳过。

还有一个实际问题就是 Maven 仓库下载慢。国内环境建议在settings.xml里配置阿里云 Maven 镜像。在构建节点脚本里可以直接指定:

mvn clean package -pl service-a -am \ -s /opt/maven/conf/settings-aliyun.xml

我在settings-aliyun.xml里配置了mirrorOfcentralmaven.aliyun.com镜像仓库。这样即使不专门做二次缓存,构建速度也比默认中央仓库快很多。

3.2 在 Arbess 里编排节点:每个节点只干一件事

Arbess 的流程编排是节点制的,我习惯把 Java 项目构建拆成几个独立节点,而不是把所有命令堆在一个节点里。

推荐的最小节点顺序是:

  1. Git 拉取节点:指定 GitLab 仓库地址、分支、以及要用的凭证。
  2. Maven 构建节点:执行编译、单测、打包。
  3. 信息提取节点:从构建产物和 GitLab 提交记录中提取版本号、提交号、分支名。
  4. OSS 上传节点:把 JAR 按照约定路径传到 OSS。
  5. 通知节点:构建完成后发钉钉或企业微信消息,里面带上制品路径和下载链接。

每个节点之间可以通过变量传递数据。比如 Git 节点拉取代码后会暴露GIT_COMMITGIT_BRANCH这样的变量,上传节点读取这些变量来拼 OSS 对象名。不要在一个节点里既编译又把上传路径写死,后面换分支策略或加版本规则时,你会很想回去重做。

如果你需要在构建节点里先看一次 Maven 全量依赖树,可以用:

mvn dependency:tree -pl service-a -am

确认依赖范围没有意外后,再执行完整构建。这一条在从老 Jenkins 迁移项目时特别有用,能快速看出某个模块是不是偷偷依赖了别的模块的 SNAPSHOT 版本。

3.3 制品命名:把可追溯性落实到文件名

构建成功后的 JAR 默认名字一般是service-a-1.0.0-SNAPSHOT.jar,这种命名在本地开发没问题,但统一归档到 OSS 时,遇到不同分支打出同一个版本号,后上传的会覆盖先上传的。我的处理方式是重命名 JAR,把分支和短提交号拼进去。可以在 Maven 构建之后、上传之前加一个 Shell 节点:

APP_NAME="service-a" VERSION="1.0.0" BRANCH="${GIT_BRANCH##*/}" # 去掉 refs/heads/ 前缀 COMMIT="${GIT_COMMIT:0:8}" BUILD_NUM="${BUILD_NUMBER:-unknown}" JAR_FILE="target/${APP_NAME}-${VERSION}.jar" # 防止同一个 JAR 被重复构建时旧文件残留 ls -l "${JAR_FILE}" OSS_KEY="releases/${APP_NAME}/${BRANCH}/${COMMIT}-${BUILD_NUM}/${APP_NAME}-${VERSION}-${BUILD_NUM}.jar" echo "OSS_KEY=${OSS_KEY}" > build.properties

为什么要把OSS_KEY写成变量写入临时文件而不是硬编码到下一个节点?因为后续如果要在上传节点之外做审计,我们需要一个统一的元数据来源。从build.properties里读取,能保证上传脚本、通知消息里引用的路径完全一致,不用维护两套。

如果你用 Spring Boot 项目,构建产物通常是target/*.jar,但里面会有.jar.original这种文件,上传前最好用find精确匹配:

find target -maxdepth 1 -name "*.jar" ! -name "*.original"

避免把 Maven 插件生成的临时文件一起传上去。

4. JAR 如何安全可靠地进 OSS

4.1 上传方式选型:脚本优先,SSH 不参与

OSS 上传有几种常见姿势:阿里云 CLI、ossutil、各种 SDK。在 Arbess 的节点里,我推荐ossutil命令行工具,理由有三点。

  1. 它只有一个二进制文件,不依赖 Java 环境,构建节点只要能用 Shell 就行。
  2. 它原生支持断点续传、分片上传、并发控制,传大 JAR 包很稳。
  3. 配置简单,可以通过环境变量或--access-key-id--access-key-secret参数传凭证,无需在机器上留下明文配置文件。

安装非常直接:

curl -L -o /usr/local/bin/ossutil \ "https://gosspublic.alicdn.com/ossutil/ossutil-v1.7.19-linux-amd64.zip" 2>/dev/null # 这里是简化示意,实际可以解压后放置

如果构建节点已经装了python,也可以选择阿里云 OSS Python SDK,但维护成本会高一层,而且如果只有上传这一个诉求,脚本方式更轻。

方式适合场景缺点
ossutil流水线内单文件/批量上传额外安装一个二进制
阿里云 CLI同时操作多种阿里云资源依赖较大,配置偏重
Java SDK需要在代码里做复杂逻辑每次上传都要写不少代码
OSS Browser人工传包不适合自动化

4.2 编写一个可复用的上传脚本

以下是我放在 Arbess OSS 上传节点里的脚本精简版。它的核心工作是:读取上一个节点生成的变量文件,检查 JAR 存在,调用 ossutil 上传,并输出对象的外链地址。

#!/usr/bin/env bash set -euo pipefail source ./build.properties OSS_BUCKET="devops-artifacts" OSS_ENDPOINT="oss-cn-hangzhou.aliyuncs.com" # 根据实际区域修改 # 推荐通过 RAM 子账号的 AccessKey 环境变量传入 OSS_AK_ID="${OSS_ACCESS_KEY_ID}" OSS_AK_SECRET="${OSS_ACCESS_KEY_SECRET}" LOCAL_JAR=$(find target -maxdepth 1 -name "*.jar" ! -name "*.original" | head -n 1) if [[ -z "${LOCAL_JAR}" ]]; then echo "[ERROR] 未找到可上传的 JAR 包,构建产物可能未生成" exit 1 fi echo "[INFO] 待上传文件:${LOCAL_JAR}" echo "[INFO] OSS 目标路径:${OSS_KEY}" ossutil cp "${LOCAL_JAR}" \ "oss://${OSS_BUCKET}/${OSS_KEY}" \ --access-key-id "${OSS_AK_ID}" \ --access-key-secret "${OSS_AK_SECRET}" \ --endpoint "${OSS_ENDPOINT}" \ --content-type "application/java-archive" \ --force echo "[INFO] 上传完成"

脚本里每个细节都可以展开说一说。

  • set -euo pipefail:保证任何一步失败都会让节点直接失败,而不是“看似跑完但制品没传上去”。
  • --force:覆盖同名对象,配合我们的唯一命名规则,这个覆盖几乎不会误伤旧制品。
  • --content-type:不设置的话,ossutil 可能会根据 JAR 的二进制内容识别成application/octet-stream。虽然不影响下载,但后面如果接阿里云 CDN 或做 Head 请求时,Content-Type 不对会带来小麻烦。

4.3 我用过的几种上传失败的典型场景

第一类,Endpoint 和 Bucket 区域不匹配。报错类似NoSuchBucket或者InvalidAccessKeyId。以前我在北京区域的 ECS 上配了杭州区域的公网 Endpoint,明明代码逻辑没错,但就是传不上去。排查步骤很简单:在 ECS 上用curl访问一次 OSS 域名看通不通,再检查 Endpoint 属于哪个区域。

第二类,AccessKey 权限问题。报错AccessDenied时,优先检查 RAM 策略里的 Resource 是否包含 Bucket 本身和/*对象。我见过有人只授权了devops-artifacts/*,结果ossutil ls这个 Bucket 能列出来,真正cp对象时却拒绝,因为PutObject对单个对象的权限确实有了,但某些版本的 SDK 或工具会先要求 List 权限。把策略改成我上面那个 JSON 示例就好。

第三类,上传路径中包含特殊字符。如果GIT_BRANCH带上了feature/xxx这种斜杠,OSS 对象名里会出现子目录,这没问题;但如果你直接在 JAR 文件名里放中文或空格,上传后 URL 访问时会遇到编码问题。我的习惯是:所有路径统一使用小写英文、数字、斜杠和中划线,分支名中的/保留作为目录层级,但分支名里的其他非法字符要主动替换成-

4.4 生命周期清理:制品不是传上去就一劳永逸

制品库最怕无限膨胀。如果不做清理,一次构建 500 MB 的胖 JAR,全团队一天触发 20 次流水线,一个月就是 300 GB。OSS 的存储费用虽然不贵,但真没必要留那么多“垃圾”。建议在 OSS 控制台给 Bucket 配置生命周期规则:

  • releases/*/master/*保留 180 天;
  • releases/*/develop/*保留 60 天;
  • releases/*/feature/*保留 30 天。
  • snapshots/目录直接 7 天过期。

具体天数按团队需求来,重点是不要所有目录一刀切。如果不小心把生产稳定版本也设成 30 天清理,某天回滚时就会发现找不到旧包,非常尴尬。

5. 从“构建成功”到“制品可用”:验证、排错与日常维护

5.1 端到端验证怎么做得快又准

流水线配置完,第一件事不是直接改代码触发,而是先在 Arbess 里手动跑一次。我一般按这个顺序验证:

  1. Git 节点测试:看能否按指定分支拉取到最新代码。
  2. 构建节点测试:确认 Maven 能正常编译,环境变量GIT_COMMITGIT_BRANCH是否在日志里正确打印。
  3. 上传节点测试:上传完去 OSS 控制台刷新一下,看对象名是否符合预期。
  4. 下载验证:用ossutil cp下载回来,比对哈希值。这一步最容易被省略,但非常重要。
ossutil cp "oss://${OSS_BUCKET}/${OSS_KEY}" ./test.jar \ --access-key-id "${OSS_AK_ID}" \ --access-key-secret "${OSS_AK_SECRET}" \ --endpoint "${OSS_ENDPOINT}" md5sum ./test.jar # 与构建产物 md5 对比 md5sum "${LOCAL_JAR}"

哈希一致,才能确认上传过程没有损坏文件。之后再从 GitLab 侧手动触发一次 Webhook,验证 MR 或 push 事件能不能自动拉起流程。

5.2 日常维护中最容易出现的问题清单

我整理了一份自己团队遇到过的报错对照表,供你排查时参考。

现象大概率原因处理方式
Arbess 连接 GitLab 后登录失败,报 check api token or gitlab versionToken scope 不足或 GitLab API 版本过低给 Token 加apiscope;升级 GitLab 至 13+
账号提示 pending approval from administratorGitLab 启动了用户审批用管理员账号激活该用户
Maven 构建卡在依赖下载中央仓库网络不稳定配置阿里云 Maven 镜像
JAR 上传后 OSS 里大小是 0 字节脚本中JAR_FILE路径指向了空文件在脚本里加文件存在且非空判断
上传报 InvalidAccessKeyIdAccessKey 写错或 RAM 子账号被禁用在目标机器用ossutil config交互验证
其他机器无法访问 OSS 内网 Endpoint构建节点不在同一区域/VPC改用公网 Endpoint 或打通内网

值得注意的是,第一类报错我到现在还会在同事新搭环境时看到。很多教程只教你填 Token,不提醒 scope。只要日志中出现login failed. check api token or gitlab version,不要第一时间怀疑版本,先用 curl 手动调 GitLab API 验证 Token 能力和网络连通性,这一步能省下至少半小时。

5.3 这个链路还能往哪里扩展

当最基础的“GitLab 触发 → Arbess 构建 → OSS 归档”跑通之后,我强烈建议做下面几件事,把链路价值放大:

  • 增加代码质量节点:在 Maven 构建节点后面接一个 SonarQube 扫描节点,扫描失败则流程中断,让问题代码没有机会进入制品库。
  • 增加人工审批节点:生产分支的构建上传,不是上传完就结束,而是先进“待发布”状态,由相关负责人在 Arbess 里点击确认后才允许后续部署系统从 OSS 拉取该制品。
  • 增加镜像或部署节点:如果 Java 服务最终要跑在 Kubernetes,上传 JAR 之后还可以接一步“构建 Docker 镜像”,把镜像推到私有镜像仓库,形成从源码到环境的完整闭环。
  • OSS 版本管理:如果团队需要保留每次构建的历史不可变快照,可以开启 Bucket 版本控制。但建议谨慎使用,它会让存储量翻倍,配合生命周期规则一起用才合理。

还有一个我个人体会很深的小经验:每次调整流水线前,先在 Arbess 里手动跑一次空构建,验证基础环境没有变化。我吃过一次亏,因为构建节点所在机器被运维重装过,JDK 从 11 换成了 17,但我们流水线脚本里还写着source /etc/profile去加载老路径,结果构建一直失败。后来我们在构建节点脚本开头统一打印 Java 和 Maven 版本,一旦环境变更,日志里立刻能看出来,不必去翻系统变更记录。

java -version mvn -version echo "JAVA_HOME=${JAVA_HOME:-}" echo "MAVEN_HOME=${MAVEN_HOME:-}"

把这几行加到构建脚本最顶部,排查环境问题会轻松很多。集成 Arbess、GitLab 和 OSS 这条链路,本身并不复杂,真正花时间的往往是这些容易忽略的细节。把基础打好,后续无论是接质量门禁、推送镜像还是做更复杂的发布流程,都会顺手很多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/24 21:42:49

Agent Skills实战指南:从函数调用到技能库的设计与实现

"Agent Skills"这一两年在AI工程圈里是实打实的热词&#xff0c;尤其是做LLM应用的朋友&#xff0c;几乎每个技术群里都有人问&#xff1a;Agent到底怎么落地&#xff1f;Skills和Tools到底有什么区别&#xff1f;为什么别人家的Agent能自动拆解任务、自己家的却整天…

作者头像 李华
网站建设 2026/9/24 21:40:40

U2Net轻量化实战:分组卷积压缩至86M,边缘端SOD部署指南

简介&#xff1a;本资源是一套面向计算机视觉初学者与进阶研究者的非特定类别图像分割实践项目&#xff0c;聚焦显著性目标检测&#xff08;SOD&#xff09;在通用图像分割中的落地应用&#xff0c;特别适配轻量化部署需求。项目基于U2Net模型展开深度优化实验&#xff0c;完整…

作者头像 李华
网站建设 2026/9/24 21:40:40

中文NER实战:BERT+BiLSTM+CRF源码解析与课程设计指南

简介&#xff1a;基于BERTBiLSTMCRF实现中文命名实体识别的Python源码&#xff0c;面向需要完成课程设计或期末大作业的高校学生&#xff0c;也适合正在学习自然语言处理与序列标注的开发者。项目覆盖数据预处理、模型训练到指标评估的完整流程&#xff0c;下载解压即可运行&am…

作者头像 李华
网站建设 2026/9/24 21:40:33

His标签蛋白纯化全流程解析:从菌体破碎到凝胶层析

蛋白纯化是生物实验室的高频操作&#xff0c;但不同来源、不同性质的蛋白&#xff0c;纯化策略差异很大&#xff0c;翻车概率也不小。这篇就以一个His标签蛋白纯化项目为例&#xff0c;把从菌体破碎到凝胶层析的完整路线、每个环节的设计逻辑、常见坑位都拆开讲清楚&#xff0c…

作者头像 李华
网站建设 2026/9/24 21:40:30

从回归到排序:构建与人类偏好对齐的AI人脸吸引力模型

最近在Hacker News上逛的时候&#xff0c;看到一个「Show HN」项目&#xff1a;AI Facial Attractiveness Model Aligned with Human Preferences&#xff0c;通俗说就是做一个“用人类偏好对齐出来的AI人脸吸引力模型”。这个方向我过去大半年一直在折腾&#xff0c;从第一批d…

作者头像 李华