实战:在 CI/CD 中以非交互模式运行 Agent
系列入口:如何使用 Agent。M9 第 6 篇。
一、非交互和你平时用法的本质区别
平时用 Agent,你能随时纠偏、补充、否决;但在 CI/CD 里,它运行在无人值守的环境中:没有追问、没有图形界面、跑完即走。 这带来三个必须解决的问题:输入要一次性说清、成败要能被机器判定(退出码/结构化产出)、环境要干净可复现。
因此,放进流水线的任务应是边界清晰、结果可客观验证的那类;模糊、需要大量业务判断或不可逆操作的,不适合无人值守。原则是:先在本地把非交互命令调通、能稳定重复,再接进 CI。

二、第一步:限定任务,输入写明确
非交互模式下没有"我再解释一下"的机会,所以任务描述必须自包含:要做什么、范围限定在哪些路径、不许做什么、完成标准是什么。 常见适合的任务包括:生成/更新某些样板代码、按固定规则做检查或格式化、补文档、跑代码审查并输出结构化意见、执行预先定义好的重构。
把这些要求写进一份随仓库版本化的说明或命令(可复用自定义斜杠命令),让 CI 用 -p(print/headless)一类参数传入。避免开放式指令如"看看有什么可以改进的"——无人盯守时,它可能产生不可预期的大范围改动。
三、第二步:环境、凭证与工作区隔离
CI 环境要为它准备好运行条件:固定的运行时版本、依赖、工作目录,并通过 CI 的 Secret 机制注入所需凭证(API key 等),绝不要把密钥写进仓库或命令日志。
要特别处理它的改动范围:通常在一个干净检出的分支/工作区里运行,若它会修改代码(如生成文件),应明确这些改动是要提交、还是仅用于校验。对有副作用的操作(推送、发布、写外部系统),默认关闭或单独放人工审批阶段——无人值守的 Agent 默认只做只读或可丢弃的改动最安全。
四、第三步:用退出码和结构化产出判定成败
流水线靠机器判断,因此要约定清晰的判定信号。
主要看退出码:成功为 0、非 0 即失败,让 CI 据此中止或继续。若任务是产出意见或结果(如代码审查),让它输出结构化格式(JSON 等),再由后续脚本解析:有无阻断性问题、数量、位置,从而决定流水线状态,而不是让一段自由文本去靠关键词匹配(极易误判)。
务必处理超时和重试:给非交互执行设明确的时间上限,防止挂死占用 Runner;对网络类瞬时故障可有限重试,但对"结果不正确"不应靠重试碰运气。产出与关键日志要保存为 CI artifact,便于失败时排查。
五、第四步:成本、频率与安全
非交互 Agent 每次运行都可能产生模型调用费用,所以要控制触发频率和范围:只在相关文件变更、特定事件或合并前运行,而不是每个无关提交都全量跑。可用路径过滤、并发取消等 CI 特性省成本。
安全上坚持最小权限:CI 所用 token/凭证只授予该任务所需的最小范围,限制可写目标;对外部连接沿用只读账号。把"Agent 自动提交的内容"也纳入评审——即便它能直接改代码,合并到主干前仍应有测试门禁和必要的人工确认,避免自动化产出绕过质量关。
六、典型落地阶段
| 阶段 | 适合自动做 | 保留人工 |
|---|---|---|
| 提交/PR | 风格检查、生成意见、风险提示 | 是否处理意见 |
| 构建 | 更新生成文件、校验一致性 | 接受生成产物 |
| 合并前 | 跑评测/回归集 | 跌破基线后的取舍 |
| 发布 | 生成变更日志草稿 | 发布审批、生产写入 |
七、一个可参考的流水线编排
把前述原则落成具体阶段,更便于照做。一个典型的 PR 流水线可以这样编排。
检出与环境准备:固定版本、安装依赖、恢复缓存,保证可复现;只读分析阶段:以非交互模式让 Agent 做风险扫描、生成结构化审查意见(JSON),由脚本解析——有阻断项则给 PR 打失败、并把意见作为评论回写,但不直接改代码;一致性校验阶段:若仓库含生成代码,让 Agent 在隔离工作区重新生成,再用 git diff 判断提交的产物是否过期,不一致即失败;测试门禁阶段:运行单元/集成测试与评测回归集,跌破基线则阻断。
发布阶段(独立、需人工):Agent 可起草变更日志,但实际部署、生产写操作必须人工审批后才执行。整条链路要为 Agent 步骤设独立的超时和重试、把关键产出存为 artifact,并通过路径过滤让它只在相关文件变更时运行。这样的编排把 Agent 放在"加速信息处理"的位置,每一个有后果的决定仍由确定性门禁或人把关,自动化和安全各得其所。
八、常见问题
Q:非交互输出不稳定、时好时坏怎么办? 优先把任务收敛到确定性强、可客观判定的范围;用结构化输出和明确验收脚本降低随机性影响;必要时多次运行取一致结论,但要认识到开放性任务本就不适合无人值守。
Q:怎么防止它在 CI 里乱改一大堆文件? 在指令中限定路径与禁止项,使用干净工作区,并对实际 diff 做检查(如限制允许变更的文件清单),越界即失败。
Q:凭证会泄露到日志吗? 用 CI 的 Secret 存储并避免打印;选择会自动掩码密钥的运行方式,最小化 token 权限,降低泄露危害。
Q:失败了没人看怎么办? 配置告警/状态检查把失败通知到责任人,保存日志与产出;宁可让流水线显式失败,也不要静默忽略 Agent 的错误。
八、失败排查与流水线的可观测性
非交互 Agent 在流水线里失败时,没有人能当场追问,因此可观测性决定了排查是几分钟还是几小时。
保存足够现场:把 Agent 的完整输出、结构化结果、相关 diff 和截图(GUI 场景)存为 artifact,失败时不必重新跑就能看到当时状态。明确失败分类:让脚本区分是环境/凭证问题、超时、还是产出确实不合格,日志清晰标注,避免对着一句模糊的非零退出码猜测。加通知和归属:失败主动通知责任人或回写 PR,并带上关键摘要,而不是等人发现红灯。
保留可本地复现的入口:同一条非交互命令应能在本地用相似环境跑,便于开发调试,而不是只能反复推提交试错。再配合幂等设计——重跑流水线不会因为上次的残留状态而行为异常。目标是让无人值守 Agent 的每一次失败都"现场完整、原因清晰、可本地复现",自动化才真正可维护,出问题也不会演变成黑箱。
九、控制非交互 Agent 的成本
无人值守意味着 Agent 会随流水线反复运行,成本若不管控会悄悄膨胀,值得专门设计。
按变更触发:用路径过滤、事件类型限制,让它只在相关代码或 PR、合并前运行,无关提交不触发。并发取消与缓存:同一分支新推送时取消旧运行、复用环境缓存,减少浪费。分层调用模型:简单判定用便宜模型或本地规则,只在必要时动用昂贵模型,和置信度路由思路一致。
设用量可见性:把每月调用与花费纳入报表、设预算上限和异常告警(详见后续成本治理篇)。优先只读分析:不需要修改代码的检查类任务比重构类便宜得多,应作为流水线主力。这样在享受自动化的同时把投入控制在可预期范围,让非交互 Agent 的边际成本始终低于它省下的人力,这套实践才经济成立。
十、凭证与 Secret 的处理
非交互 Agent 常需访问模型、代码或外部系统,凭证一旦处理不当,风险比本地使用高得多。
一律走 CI Secret:密钥不入库、不写进命令行、利用平台的自动掩码,避免泄露到日志。最小权限、按需颁发:给流水线的 token 只覆盖该任务所需,分开读写凭证,用完即失效或定期轮转。审计其使用:异常的凭证调用应可被发现。这样即使日志外泄或 Runner 被滥用,损害也被限制在最小。
十一、让结果可机器判定
无人盯守时,自由文本无法可靠决定流水线成败,需要明确的信号设计。
退出码是第一信号:0 通过、非 0 阻断,约定清晰。结构化输出用于复杂判定:让 Agent 产出 JSON,由脚本解析阻断项数量与位置,避免用关键词匹配自由文本。结合确定性门禁:测试、diff、lint 等客观检查优先于模型意见。把判定规则固化下来,流水线才不会因输出措辞变化而时好时坏,自动化结论也才可信赖。
十二、超时、重试与幂等
无人值守时,挂死和重复执行是两类典型故障,需要在设计阶段就处理。
给每个 Agent 步骤设明确超时,防止 Runner 被无限占用;重试只针对网络等瞬时错误且次数有限,结果不正确不应靠重试碰运气;保证幂等——重跑不会因上次残留而产生重复提交或脏数据,可在隔离工作区、每轮重置。这三点让非交互 Agent 在不可靠的真实环境里仍表现确定,流水线也不会因为一次抖动而卡死或留下难查的副作用。
Q:Agent 步骤拖慢了整个流水线怎么办? 把它后置为不阻塞合并的异步检查、或只在相关路径变更时触发,并用更快的小模型处理常规项;不要让一个昂贵步骤卡住所有提交,否则团队会想办法禁用它。
十三、检查清单
- 任务边界清晰、输入自包含,已在本地以非交互方式调通。
- 凭证经 Secret 注入,工作区干净、改动范围受限。
- 以退出码与结构化产出判定成败,设了超时与有限重试。
- 触发频率与路径受控,成本可接受,日志已留存。
- 写操作/发布默认人工审批,自动产出仍过测试与评审门禁。
总结
在 CI/CD 里跑 Agent,关键是把交互式的灵活换成非交互的确定性:任务要自包含、限定路径和禁止项,凭证用 Secret 注入、在干净工作区运行,用退出码和结构化 JSON 让机器可靠判定成败并设置超时与重试;同时按文件变更控制触发频率和成本、坚持最小权限、把写操作和发布留给人工审批,自动改动也必须通过测试与评审;先在本地稳定复现再接流水线,才能让无人值守的 Agent 成为可靠的自动化环节,而不是一个不可控的变数。