单元测试全绿,回答却变烂了:用退出码给 AI 代理设一道合并门禁

AI Summary (BLUF)
本文介绍如何使用Google Agents CLI v1.13.0为AI代理设置自动化评估门禁,通过阈值判断代理回复质量,并集成到GitHub Actions中,确保只有通过评估的代理版本才能合并到主分支。
核心洞察
这篇文章最有意思的点是:单元测试能保证 agent 的代码跑得通,却保证不了它答得对。改一行指令,测试全绿,回答却可能烂掉。Agents CLI代理命令行界面,Google推出的用于开发、调试和部署代理的命令行工具,支持加载Skills。 在 v1.13.0 里把评估门槛做成了一个退出码,CI 直接读这个码就能决定放行还是拦截,省掉了插件和解析器。三五个用例的小门槛当然不够看,但方向是对的。
单元测试只能验证 agent 的代码能跑,改一行指令就可能让回答变差,而测试照样通过。
去年我们在 Kaggle AI Agents Intensive 与 Google 合作的《Prototype to Production》白皮书第五天内容里讲过这件事。白皮书说,任何 agent 版本在交付用户之前都必须通过自动化评估。Agents CLI 是 Google Cloud 上用来构建、评估和部署 agent 的命令行工具,它在 v1.13.0 里把这条规则中“合并前”的那部分变成了一个设置项。这篇文章里,我先把它加到一个新项目,再加到项目的 CI(每次拉取请求时运行的持续集成检查)里。
图 1:评估通过退出码决定拉取请求检查的成败,CI 读的就是这个码。
核心结论
Agents CLI 在 v1.13.0 版本中,
eval run和eval grade命令会在结尾输出RESULT: PASS或RESULT: FAIL,并通过退出码(0 表示通过,1 表示失败)让 CI 系统直接判断是否拦截合并请求,无需额外插件或解析器。评估阈值可通过评估配置中的
thresholds:映射设置,也可在单次运行时用--fail-under METRIC=SCORE指定;未达阈值或用例报错时均退出码 1,确保坏掉的评估不会意外通过。实测中,将 agent 指令从正常版本改为“Answer in one word. Never call tools.”后,脚手架自带的占位单元测试仍然全部通过,但评估关卡将平均分从 5.00 拉低到 3.00(pass_rate 从 1.0000 降至 0.3333),退出码变为 1,成功拦截了这次改动。
将阈值写入仓库内的
tests/eval/eval_config.yaml后,eval run无需额外参数即可执行关卡检查;配合agents-cli scaffold enhance --cicd-runner github_actions生成的 GitHub ActionsGitHub提供的持续集成和持续交付平台,允许自动化构建、测试和部署流程。 工作流,可将评估作为集成测试之后的步骤接入 CI。由于 agent 回答每次运行会波动(坏掉的 agent 对天气问题一次得 3.00、另一次得 2.67),设置阈值时应留有余量;三个用例的门槛虽小,但白皮书建议将每次生产故障转化为新的评估用例,逐步扩充数据集。
为什么 agent 需要一道不一样的关卡
agent 每次收到请求都要自己决定做什么,所以你得拿一组已知用例来给它的回复和工具调用(它执行的函数,比如查天气)打分。评估就是在提示词数据集上跑一遍 agent,给每条回复评分。
白皮书讲了两种把评估当关卡用的方式。你可以手动在开拉取请求之前跑一遍,也可以接进流水线,让失败的评估自动拦住改动。Agents CLI 用同一条命令 agents-cli eval run 覆盖了这两种方式。
v1.13.0 改了什么
根据发布说明,eval run 和 eval grade 现在结尾会输出一行 RESULT: PASS 或 RESULT: FAIL,上面列出没达标的指标和用例。阈值是你对某个指标能接受的最低平均分。你可以在评估配置里用 thresholds: 映射设置,也可以单次运行时用 --fail-under METRIC=SCORE 指定,没达到阈值就退出码 1。任何用例报错的运行也退出 1,所以坏掉的评估不会稀里糊涂地通过。
每个程序结束时都有退出码,0 表示成功,其他值表示失败。GitHub Actions 这类 CI 系统把非零退出码当作失败步骤,所以阈值能直接让构建失败,不需要插件或解析器。
从已有的评估开始
你需要一个启用了 Vertex AI API 的 Google Cloud 项目,以及通过 gcloud auth application-default login 拿到的本地凭据,或者一个 Gemini API 密钥。setup 会安装 agents-cli 命令和给编码 agent 用的技能,create 会把你的项目写进 .env。新项目自带一个评估:
uvx google-agents-cli setup
agents-cli create gate-agent -y
cd gate-agent && agents-cli install
uvx 不用先安装就能运行 Python 工具,所以 uvx google-agents-cli 和 agents-cli 是同一个 CLI。-y 跳过提示直接取默认值,install 拉取项目依赖。
tests/eval/datasets/basic-dataset.json 里的数据集有三个用例:一句问候、一个天气问题,还有“法国的首都是哪里?”,最后这个带参考答案供评判模型比对。指标 custom_response_quality 是 LLM 当裁判,意思是让第二个大语言模型读每条回复,按 1 分(差)到 5 分(优)打分。
agent 和裁判都通过 .env 里的 Google Cloud 项目调用 Gemini,或者按文件注释里说的,把 .env 切到 GEMINI_API_KEY 也行。评估配置里还带了一个阈值,默认注释掉,等你知道自己的标准再打开。
定好标准,跑一遍
我把标准定在 5 分里的 4 分:
$ agents-cli eval run --fail-under custom_response_quality=4
...
custom_response_quality:
num_cases_total: 3
num_cases_valid: 3
num_cases_error: 0
mean_score: 5.0000
stdev_score: 0.0000
pass_rate: 1.0000
...
RESULT: PASS (custom_response_quality 5.00 >= 4.00)
$ echo $?
0
eval run 串了两步,eval generate 在每个用例上跑 agent,eval grade 给回复打分。pass_rate 是单条得分至少 4 的用例占比。退出码只看平均分。
故意把它弄坏
然后我把指令缩成一行:
- instruction="You are a helpful AI assistant designed to provide accurate and useful information.",
+ instruction="Answer in one word. Never call tools.",
脚手架自带的占位单元测试照样通过,关卡却让这次运行失败了:
$ agents-cli eval run --fail-under custom_response_quality=4
...
custom_response_quality:
num_cases_total: 3
...
mean_score: 3.0000
...
pass_rate: 0.3333
...
Failures:
custom_response_quality: below threshold 4: case 0 (2.00), ...
Next: open ... to read the failing cases, ...
RESULT: FAIL (custom_response_quality 3.00 < 4.00)
$ echo $?
1
完整的 Failures: 行列出了用例 0 和用例 1,也就是问候和天气问题,都是 2.00 分。裁判都给了 2 分,因为对问候回“Anything”太含糊,对天气回“Foggy”跳过了天气工具。“Paris”仍然匹配参考答案,保住了 5 分,所以 pass_rate 是 0.3333。Next: 那行指向 HTML 报告,里面有每个用例的回复和得分。它还建议用 agents-cli eval compare 对比两次运行,这样构建失败的人知道该往哪看。
接进 CI
要在 CI 里用,把标准挪进仓库,取消 tests/eval/eval_config.yaml 里那段注释:
thresholds:
custom_response_quality: 4 # the judge scores 1-5
现在 eval run 不用带参数了。标准就放在仓库里,和提示词、数据集挨着,白皮书也建议把这两样跟代码一起做版本管理。把原始指令改回来,CI 要做的这次调用就通过了:
$ uvx google-agents-cli eval run
...
RESULT: PASS (custom_response_quality 5.00 >= 4.00)
$ echo $?
0
把关卡加进 GitHub Actions
在项目里运行 agents-cli scaffold enhance --cicd-runner github_actions 来加 CI。生成的 .github/workflows/pr_checks.yaml 已经会认证到 Google Cloud,并在改动 app/、tests/、deployment/ 或 uv.lock 的拉取请求上跑单元和集成测试。把关卡作为集成测试之后的一步加进去。你的 .env 不会进仓库,所以这一步自己设置那三个变量,告诉 Gemini 客户端用你全球区域的 Google Cloud 项目。
CICD_PROJECT_ID 是你在 GitHub 里设的仓库变量,指向 CI 运行的项目:
- name: Eval gate
env:
GOOGLE_GENAI_USE_ENTERPRISE: 'true'
GOOGLE_CLOUD_PROJECT: ${{ vars.CICD_PROJECT_ID }}
GOOGLE_CLOUD_LOCATION: global
run: uvx google-agents-cli eval run
在白皮书的流水线里,这是合并前阶段,也就是改动进入主分支之前跑的检查。预发布和生产在后面。
要拦住失败的拉取请求不让合并,把 PR Checks 工作流的 test 作业在分支保护规则里标成必需状态检查。这个工作流只在那些路径有改动时才跑,而 GitHub 会让跳过它的拉取请求上的必需检查一直挂起,所以把 test 设成必需时,记得删掉 pr_checks.yaml 里的 paths: 块。
定标准要留点余量,因为 agent 的回答每次运行都会变。坏掉的 agent 对天气问题一次回“Foggy”,另一次回“Unknown”,所以一次跑出 3.00,另一次 2.67。正常的 agent 三次运行都是 5.00。
要点
我们从脚手架自带的评估出发,给它定了标准,然后把标准挪进配置和 CI 步骤。三个用例的门槛很小,所以白皮书说的“把每次生产故障变成一个新评估用例”就是下一步,你往 basic-dataset.json 里加的每个用例都会改变平均分,后续改动就按这个新平均分来评。
想在自己的 agent 上试,装好 CLI,带上标准跑你的评估,用你自己指标的名字和它量程上的分数:
uvx google-agents-cli setup
agents-cli eval run --fail-under custom_response_quality=4
v1.13.0 发布说明和 Agents CLI 文档详细讲了评估命令,代码在 Agents CLI 仓库里。《Prototype to Production》白皮书覆盖了流水线剩下的部分,从预发布到生产。
常见问题(FAQ)
Agents CLI v1.13.0 的评估门禁在CI/CD流水线中设置的自动化检查,只有代理通过评估(达到阈值)才允许合并代码。是怎么判断通过还是失败的?
eval run 和 eval grade 结束时会输出 RESULT: PASS 或 FAIL,并列出未达标的指标和用例。阈值可在评估配置里用 thresholds 设置,也可单次用 --fail-under 指定;未达阈值或有用例报错都返回退出码 1。
为什么单元测试通过还不够,还要给 agent 加评估关卡?
单元测试只能保证 agent 的代码跑得通,却保证不了它答得对。改一行指令后测试可能全绿,但回复质量会明显变差。评估关卡用已知用例给回复打分,能拦住这类测试发现不了的退化。
怎么把 Agents CLI 的评估门禁接进 GitHub Actions?
运行 agents-cli scaffold enhance --cicd-runner github_actions 生成工作流,在集成测试后加一步 Eval gate,设置 GOOGLE_GENAI_USE_ENTERPRISE、GOOGLE_CLOUD_PROJECT 和 GOOGLE_CLOUD_LOCATION,执行 uvx google-agents-cli eval run,失败即拦截合并。
版权与免责声明:本文仅用于信息分享与交流,不构成任何形式的法律、投资、医疗或其他专业建议,也不构成对任何结果的承诺或保证。
文中提及的商标、品牌、Logo、产品名称及相关图片/素材,其权利归各自合法权利人所有。本站内容可能基于公开资料整理,亦可能使用 AI 辅助生成或润色;我们尽力确保准确与合规,但不保证完整性、时效性与适用性,请读者自行甄别并以官方信息为准。
若本文内容或素材涉嫌侵权、隐私不当或存在错误,请相关权利人/当事人联系本站,我们将及时核实并采取删除、修正或下架等处理措施。也请勿在评论或联系信息中提交身份证号、手机号、住址等个人敏感信息。




