把 AI 编程能力放进 CI,本质是把一次外部网络调用、一份非确定性输出和一把凭据,塞进原本确定性的构建流程。所以配置的重点通常不是「怎么调通接口」,而是三件事:凭据不落盘、上下文被限制在 diff 范围内、AI 步骤失败不阻塞主构建。
一、凭据:只注入,不落盘
用 CI 平台自带的 Secret / 受保护变量机制,在 job 运行时以环境变量注入,仓库里的配置文件只写变量名,不写值。这条看似基础,实际最容易破功的地方在细节:
- 不要为了调试 echo 出密钥,也不要把它写进日志、注释、错误信息或生成的产物里。
- 平台侧一般提供日志脱敏,但脱敏通常是精确字符串匹配:密钥被拼接、切片、编码之后就可能绕过规则。因此不要把密钥当作模板参数二次加工。
- 权限最小化:能用只读、限定项目、可随时撤销的短期令牌,就不要用账号级长期令牌,并设置过期时间。
- 关注触发来源。由 fork 或外部贡献者触发的流水线,Secret 通常不可用。这类事件的正确行为是「跳过 AI 步骤并说明原因」,而不是让步骤报错。
- 自托管 runner 上,环境变量对同机其他任务可能可见。敏感调用应使用专用 runner 或临时凭据。
二、上下文:让 AI 只看到该看的东西
把整个仓库塞给模型,既贵又不准。可行的做法是先算清楚「本次变更到底是什么」:
- 明确基线。用目标分支与当前分支的共同祖先做对比,而不是直接比较两个分支的最新提交,否则会把目标分支上的无关改动一并带进上下文。
- 只取变更文件和变更 hunk,再补少量必要上下文,例如被改函数的签名、文件顶部的 import 区。
- 设置硬性上限:文件数、总字符或 token 数、单文件大小。超限时按优先级截断,并在输出里显式标注「本次分析不完整」,避免模型在残缺上下文里给出看似自信的错误结论。
- 大 diff 分批处理,每批独立分析后再汇总,批次之间不共享无关上下文,减少相互干扰。
- 补单元测试时,只针对变更函数生成,且默认不直接合入:以草稿或建议形式产出,由人确认后再提交。
三、超时、降级与并发
AI 步骤是外部依赖,必须当作不可靠组件来设计。
- 单独设超时。给 AI 步骤设置自己的超时时间,而不是靠整个 job 的超时兜底——后者会让一次卡死拖垮整条流水线。
- 失败不阻塞。把 AI 步骤设为允许失败,或放进独立 job,使主构建与测试不依赖它的结果。
- 输出作为建议而非门禁。审查意见、变更摘要以评论或报告形式产出,不直接 fail 流水线。若确实需要门禁,只对高置信度的规则类检查设卡。
- 重试要有上限与退避,并区分错误类型:超时、限流、5xx 可以重试;鉴权失败、参数错误重试没有意义,应立即降级并给出可读原因。
- 并发控制。同一分支的连续推送用并发组取消旧任务,避免多份 AI 调用同时压向 API;对限流做客户端排队或降速。变更摘要这类不阻塞构建的任务可以异步化。
四、可观测性
每次调用至少记录:输入规模、是否发生截断、耗时、是否降级、最终状态。这些字段能帮你区分「模型判断力问题」和「配置把上下文截坏了」。同时,不要把完整 diff 和凭据一起写进日志。
优先级
这三件事有明确顺序:先保证凭据不泄漏,再保证上下文可控,最后才是让它跑得更快。顺序反了,通常会在某次外部贡献者提交或一次大重构里暴露出来。
(说明:以上为通用工程实践整理,未引用任何特定产品或官方文档;具体平台的 Secret 机制、超时与允许失败语义请以对应版本的官方文档为准。)