CI 与 GitHub Action
三种办法把发布门槛放进你们的流水线。门槛通过时退出码都是 0,没通过是 1,判不了(没设规则、运行没跑完、读不到门槛)是 2;出错是 3。门槛通过、但有只提示的低危问题时仍是 0,另外打一行警告(reviewctl eval --launch 在 GitHub Actions 上把它打成一条 warning 注记)。
| 你们用什么测 | CI 里跑 | 在 PR 上评论 |
|---|---|---|
SDK(*.eval.ts、eval_*.py) | preworld eval | SDK 的 Action |
| 项目在平台上的测试(沙盒、测试机、对话 AI) | reviewctl eval --launch,或调 API | reviewctl 的 Action 加 launch: true,或平台自己的 GitHub 检查 |
| 仓库里的测试集对着对话 AI | reviewctl eval --set … --target … | reviewctl 的 Action |
两个 Action 在平台仓库的 integrations/ 下;uses: 里写哪个仓库和版本,发邮件到 admin@nice2.io 索取。令牌放进 CI 的密钥,从不写在工作流文件里。
SDK 的 Action
integrations/github-action-sdk 运行 preworld eval,把 Markdown 摘要写进任务摘要、评论到 PR 上(一条评论,每次 push 更新),门槛没过时让检查失败。它等平台评分器打完分再读门槛(最多 PREWORLD_GATE_WAIT 分钟,默认 10)。SDK 用的是你们从平台下载、和代码一起提交的那个文件(从平台装 SDK):npm ci 或 pip install 从它装。
on: pull_request
permissions: { contents: read, pull-requests: write }
jobs:
eval:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 22 }
- run: npm ci
- uses: <owner>/<repo>/integrations/github-action-sdk@<ref>
with:
paths: evals
api-key: ${{ secrets.PREWORLD_API_KEY }} # 有上传权限的项目令牌
project: prj_你的项目编号| 输入 | 默认 | 意思 |
|---|---|---|
api-key | (必填) | 项目令牌 |
project | (必填) | 项目编号 |
paths | . | 文件或目录,空格隔开 |
runtime | node | node 或 python(改为装 Python 和你们的项目,不装 Node) |
command | npx --no-install preworld eval / python -m preworld eval | 换一条命令 |
base-url | SDK 的默认 | 平台地址 |
environment | ci | 实验的环境标签 |
working-directory | . | 在哪里跑 |
fail-on-gate | true | 门槛没过或读不到时让检查失败 |
disable-comment | false | 不在 PR 上评论 |
language | en | 评论用 en 还是 zh |
github-token | ${{ github.token }} | 评论要 pull-requests: write |
输出:exit-code、result(--json 的文件)和 summary(Markdown 文件)。
评论里每个 Eval 一段:实验的链接、行数、次数和任务出错数,然后是一张表「评分器 · 平均 · 对基线的变化 · 改善 · 回归」(还在平台上打分的写待评分),再是发布门槛和每条规则。从 fork 来的 PR,或者令牌只读时,只给一条警告,不评论。
reviewctl 的 Action
integrations/github-action 先构建 reviewctl,再按两种方式之一运行。
发起项目的测试,等发布门槛
on: [pull_request, push]
permissions: { contents: read, pull-requests: write }
jobs:
gate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: <owner>/<repo>/integrations/github-action@<ref>
with:
launch: true
api-url: https://<平台地址>
project: prj_你的项目编号
token: ${{ secrets.PREWORLD_PROJECT_TOKEN }} # 项目的 API 令牌 pj_…(自动化 → API 令牌)
# commit: auto # 默认:PR 的 head,否则推送的提交;none 不带提交
# image: ghcr.io/acme/agent@sha256:… # 自带镜像的项目
# scope: all # all、functional、security、failed
# wait-minutes: 60它在平台上发起项目全部已确认的测试(连仓库的项目按那个提交在沙盒里跑,自带镜像的按它的镜像,测试机项目在测试机上),等这一轮变成的实验的发布门槛,把门槛的表格写进任务摘要和 PR,按门槛退出。同一个任务重跑时带同样的幂等键,等的还是同一轮。
仓库里的测试集
- uses: <owner>/<repo>/integrations/github-action@<ref>
with:
set: ai/support-faq.yaml # 测试集
target: ai/target.yaml # 被测对话 AI 的连接文件
min-pass-rate: 90%
env:
SUPPORT_BOT_KEY: ${{ secrets.SUPPORT_BOT_KEY }} # target.yaml 里 key_env 写的变量名
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} # 有 AI 判定的标准时才需要(评审模型用 JUDGE_MODEL 指定)测试集在 PR 的检出目录里跑,所以改了的系统提示词或题目在部署之前就能测到。带上 api-url、project 和 token(CLI 令牌 rt_…)时,默认分支上的 push 推送到平台存档,PR 和存档里最近的一次比。
| 输入 | 默认 | 意思 |
|---|---|---|
launch | false | true:在平台上发起,等门槛 |
set、target | 测试集和连接文件(不和 launch 一起用) | |
commit | auto | launch:要测的提交(auto、提交号或 none) |
image | launch:要测的镜像 | |
scope | all | launch:all、functional、security 或 failed |
wait-minutes | 60 | launch:等门槛最多几分钟 |
repeat | 每个测试跑几遍 | |
gate、min-pass-rate | 测试集的通过标准文件,或最低通过率 | |
baseline | auto | 测试集和谁比 |
push | auto | 把测试集的运行推送到存档 |
fail-on-threshold | true | 门槛没过或没判出时让检查失败 |
disable-comment | false | 不评论 |
api-url、token、project | 平台、令牌、项目 | |
working-directory | . | 在哪里跑 |
artifact-name | reviewctl-results | 上传的产物名 |
github-token | ${{ github.token }} | 评论用 |
输出:exit-code、verdict(launch 时是 success、failure 或 neutral)、experiment-id、experiment-url、run-id、report-url 和 summary。
reviewctl eval --launch
在任何 CI 里都能这样发起:
export REVIEWCTL_API_URL=https://<平台地址>
export REVIEWCTL_TOKEN=pj_你的令牌 # 项目的 API 令牌
reviewctl eval --launch --project prj_你的项目编号 --commit "$GIT_SHA" --wait 60 -o summary.md| 参数 | 意思 |
|---|---|
--project prj_… | 必填 |
--commit <40 位提交号> | 连仓库的项目:要测的提交 |
--image <镜像> | 自带镜像的项目:要测的镜像 |
--scope all|functional|security|failed | 测哪些 |
--repeats <n> | 每个跑几遍 |
--wait <分钟> | 等门槛最多几分钟(默认 60) |
--idempotency-key <键> | 8 到 128 个字符:重试时等的是同一轮 |
--title <文字>、-o <文件.md|文件.json>、--json | 摘要的标题、写到哪里、JSON 打到标准输出 |
它打印门槛的表格:每个评分器的平均、对基线的变化、改善和回归的行数,再是每条规则的 ✓ / ✗ 和实得值,以及要先处理的问题。从不写 Agent 的原话、攻击内容或密钥。测试集的用法见命令行。
用自己的脚本等门槛
用 POST /v1/projects/<编号>/jobs(项目令牌)发起,答复里有 experiment_id 和 gate_url。然后长轮询门槛直到定下来,按它的结论退出:
GATE=$(curl -fsS -X POST "https://<平台地址>/v1/projects/$PROJECT/jobs" \
-H "Authorization: Bearer $PREWORLD_PROJECT_TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: gh-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT" -d "{\"commit\":\"$GITHUB_SHA\"}" | jq -r .gate_url)
for i in $(seq 60); do
G=$(curl -fsS -H "Authorization: Bearer $PREWORLD_PROJECT_TOKEN" "$GATE?wait=60")
[ "$(echo "$G" | jq -r .final)" = true ] && break
done
case $(echo "$G" | jq -r 'if .final then .conclusion else "neutral" end') in success) exit 0;; failure) exit 1;; *) exit 2;; esacconclusion 在门槛通过且运行跑完时是 success,没通过是 failure,没设规则、或没跑完也没有确定没过的是 neutral。回答的字段见 v2 接口。发起的字段见从 CI 发起。
平台自己的 GitHub 检查
连了 GitHub 仓库的项目可以让平台自己测每次 push 和 PR,把门槛作为 GitHub 检查挂在提交上,不用写工作流:见自动化。平台也在 PR 上评论时,把 Action 的 disable-comment 设成 true,免得两条评论。