gemini-cli 自动修 Bug 流水线解析:Bug Fixer Agent 系统提示词设计与源码级实现
在 gemini-cli 仓库的 tools/caretaker-agent 目录下,运行着一条“GitHub Issue → 自动定位 → 自动修复 → 自动评测 → 自动提交 PR”的无人值守流水线(caretaker-agent)。本文以该流水线中 PR 生成器(pr-generator)的第一轮编码智能体系统提示词 bug_fixer_prompt.md 为主体,完整拆解它对“自动修 Bug 的 Coding Agent”的角色约束、输入规范、四阶段工作流与安全边界,并结合 orchestrator.py、agent_runner.py 等源码,说明这份提示词是如何被装载进无头(headless)沙箱、与工具白名单和迭代循环协同工作的。读完后你将掌握:一份面向自动化代码修改场景的系统提示词应该如何设计其“强制动作、输入契约、验证闭环与越权护栏”,以及这类 Agent 在 Cloud Run 环境中运行的完整机制。
提示词在 PR 生成流水线中的位置
pr-generator 由一个 Python 工作流目录驱动,入口是 worker.py:它初始化 Config 并启动 Orchestrator 状态机。状态机按轮次循环:
- 第 1 轮:调用
Coding Agent,系统提示词文件正是bug_fixer_prompt.md(orchestrator.py 第 341-351 行); - 第 2 轮及以后:若评测未通过,则改用 code_revision_prompt.md 读取上一轮反馈
pr_feedback.md进行定向修订; - 每轮代码生成后,由 code_evaluator_prompt.md 定义的 Evaluator Agent 输出
verdict.json判定APPROVED或NEEDS_REVISION。
也就是说,bug_fixer_prompt.md 是这条“生成—评测—修订”迭代环的起点提示词,它面对的输入是上游 triage 阶段产出的“可执行缺陷规格”(workable_spec),产出则是对目标仓库的真实文件修改。
角色定义:以测试驱动和防回归为目标的自主工程师
提示词开篇的 Role 一节给出的定位是:
You are an expert autonomous software engineer specializing in bug resolution, test-driven development, and regression prevention.
即“专长于缺陷解决、测试驱动开发(TDD)与回归防护的专家级自主软件工程师”。任务目标被明确限定为三步:接收 bug 规格 → 在本地仓库应用修复 → 实现完备测试并验证。值得注意的是角色措辞中反复出现 autonomous(自主)——这意味着 Agent 运行在无人值守环境中,不可能停下来向人提问。这一前提正是后面“CRITICAL EXECUTION RULES”中“不得只看不改”“不得请求许可”等硬性规则的由来。
三条关键执行规则:对抗 LLM 的“只读惰性”
提示词中最具工程价值的是 CRITICAL EXECUTION RULES 一节,它针对 LLM Agent 常见的三类失败模式设置了强约束:
- 强制文件编辑(MANDATORY FILE EDITS):必须使用文件编辑工具(
replace_file_content、multi_replace_file_content或write_file)修改workable_spec.implementation_plan.files_to_modify中列出的文件,并向workable_spec.testing_strategy.test_file添加新的测试断言; - 禁止“看完即止”(DO NOT STOP AFTER VIEWING OR BASELINE TESTS):绝不允许在仅读取文件或仅运行未修改的基线测试后就结束会话,必须在本地工作区产生具体文件修改;
- 立即应用编辑(APPLY EDITS IMMEDIATELY):打开并查看目标文件后,应立即用编辑工具应用修复与测试断言,随后用
run_command验证。
这三条规则与运行环境的源码实现形成了精确呼应。agent_runner.py 第 38-65 行 定义了无头沙箱的工具白名单与自动批准钩子:
# Permitted tool allowlist for headless sandbox operations
ALLOWED_SANDBOX_TOOLS = {
# Reading tools
"view_file",
"read_file",
# File writing & editing tools
"replace_file_content",
"multi_replace_file_content",
"write_file",
"write_to_file",
# Command execution
"run_command",
}
if hooks is not None:
@hooks.pre_tool_call_decide
def auto_approve_all_tools(context, tool_call) -> str:
"""Only auto-approves safe, allowlisted tools in headless mode."""
if tool_call.name in ALLOWED_SANDBOX_TOOLS:
return "PROCEED"
return "REJECT"
从源码结构看,提示词中点名的 replace_file_content、multi_replace_file_content、write_file、run_command 恰好都落在白名单内:白名单内工具被 pre_tool_call_decide 钩子自动放行(无人点击“允许”),名单外工具一律 REJECT。这解释了为什么提示词需要反复强调“必须用编辑工具落盘”——因为无头环境里不存在人工确认,Agent 若只停留在“阅读 + 思考”层面,会话就会被白白消耗掉。
输入规范:workable_spec 字段契约
提示词规定 Agent 会收到一个包含 workable_spec 的 JSON 载荷,需要提取的关键字段如下:
| 字段路径 | 含义 | 提示词中的用途 |
|---|---|---|
workable_spec.implementation_plan.files_to_modify |
目标文件清单 | 限定必须修改的文件范围 |
workable_spec.implementation_plan.steps |
详细修复步骤说明 | 修复实施的逐步指令 |
workable_spec.testing_strategy.framework |
测试框架(如 Vitest、Jest、Pytest) | 决定新测试用什么框架编写 |
workable_spec.testing_strategy.test_file |
测试应添加/更新的测试文件 | 测试断言的落点 |
workable_spec.testing_strategy.verification_steps |
需要验证的具体断言/场景 | 测试用例的设计依据 |
这份规格并非凭空传给 Agent。在 orchestrator.py 第 215-221 行,Orchestrator 会把校验通过的 Firestore 文档原样落盘为 PR 工作区根目录下的 firestore_doc.json——这正是提示词 Phase 1 要求解析的文件。规格中的另一个顶层字段 issue_id(orchestrator.py 第 159 行)与 github_metadata(owner/repo/issue_number)则用于后续的锁校验、分支命名与 PR 创建。
工作流详解:四个阶段如何落地
Phase 1:摄入与验证(Ingestion & Validation)
- 解析 JSON 输入(即
firestore_doc.json),从workable_spec中提取全部相关细节; - 验证本地环境:确认自己位于目标仓库根目录;确认
files_to_modify列出的文件存在;检查test_file是否存在,若不存在则计划创建它。
对应的环境准备由 Orchestrator 在 Agent 启动前完成(orchestrator.py 第 102-143 行):克隆或同步 origin/main、设置 bot 的 git 身份、把 firestore_doc.json/pr_feedback.md/changes.diff 等管线产物写入 .git/info/exclude 以免污染 git status,再 git checkout -B ssr-agent-<issue_num> origin/main 切出特性分支,并以 NODE_OPTIONS="--max-old-space-size=4096" npm ci --no-audit --no-fund --maxsockets 3 安装依赖(orchestrator.py 第 200-213 行)。所以提示词里“确认位于仓库根目录”这条,实际上由外层 AgentRunner 的工作目录切换保证:run_agent 通过 working_directory 上下文管理器 将进程 CWD 切到 repo_path,并用全局 asyncio.Lock 串行化,因为 os.chdir 是进程级操作。
Phase 2:实施(MANDATORY FILE EDITS)
- 应用代码修改:使用
replace_file_content或write_file,严格依照steps修改files_to_modify中的文件;不重构无关代码,保持改动最小化并聚焦于该 bug; - 实现测试:打开(或创建)
test_file,添加与verification_steps对齐的新测试用例,确保使用指定framework,测试需整洁、可读,必要时对外部依赖做 mock。
这里“最小化改动”原则与外层状态机形成闭环:_prepare_iteration_commit(orchestrator.py 第 372-397 行 实际位于 orchestrator.py)对每轮工作区做 git add . && git reset --soft origin/main 后生成 diff;若第 1 轮没有任何改动,会直接抛 OrchestrationError("Failed to generate any code changes in the first iteration.") 终止本次任务。换言之,“只看不改”不仅浪费一次迭代,还会让整次 Job 失败。
Phase 3:验证与校验(Verification & Validation)
提示词对验证阶段的命令选择做了非常具体的规定:
- 只跑目标测试:只运行
test_file中的测试来验证修复; - 明确禁项:不要运行
npm run preflight; - 推荐命令形式(以 Vitest 为例):
npx vitest run <path/to/test_file>npm test -w <workspace> -- <path/to/test_file>
- 零失败要求:目标测试文件内所有用例必须全部通过;
- 失败迭代:若失败,分析错误输出 → 用文件编辑工具修正实现或测试 → 重跑目标测试 → 循环直至干净通过。
只跑目标测试而非全量套件,是受计算资源约束的工程决策:整个 Job 容器限额为 2 CPU / 8Gi 内存、超时 3600 秒(见 job.yaml)。确定性回归检查则由 Orchestrator 在评测通过后另行执行——_run_regression_checks(orchestrator.py 第 530-574 行)在评测沙箱中执行 npm run clean、npm ci,并对 test:ci 类失败通过 PreflightFilter 的白名单规则判断是否可豁免。
Phase 4:报告(Reporting)
- 概述所做修改并列出被修改的文件;
- 列出运行的测试及其通过/失败状态;
- 确认未检测到回归。
这一节对应的是 Agent 会话结束时的文本输出,最终会被 AgentRunner.run_agent 收集进 full_output(按 step_index 排序拼接 content 与 thoughts,见 agent_runner.py 第 234-247 行),供上层日志追溯。
约束与安全边界
提示词末尾的 Constraints & Safety 三条规则,划定了 Coding Agent 的行为边界:
- 不得运行
git commit、git push或任何修改远程仓库的命令,改动只留在工作目录; - 不得修改
files_to_modify与test_file之外的文件,除非有明确理由(例如测试框架所需的包配置更新); - 新代码必须匹配现有代码库的风格与模式。
这些约束与白名单机制互为表里:即便 Agent 试图 git push,run_command 虽在白名单内可以执行,但外层 Orchestrator 才是真正掌握 git 远程操作的一方——它使用内存中的 http.extraHeader 认证头推送分支并调用 GitHubClient 创建 PR(orchestrator.py 第 647-691 行)。把“改代码”与“推代码”分离给两个信任层级,是该流水线安全设计的核心:Agent 永远只是工作区的编辑者,而非发布者。
提示词的装载与执行机制
从源码看,这份 Markdown 提示词的运行链路如下:
Orchestrator.__init__将script_dir指向 agent_prompts 目录(orchestrator.py 第 75-82 行);- 第 1 轮调用时传入
system_prompt_file="bug_fixer_prompt.md",AgentRunner._load_prompt_file读取文件内容作为system_instructions,并做路径穿越防护(agent_runner.py 第 99-121 行);若文件缺失则回退到默认指令并记 warning; LocalAgentConfig(vertex=True, project=..., location=..., model=..., system_instructions=..., workspaces=[repo_path])组装本地 Agent 配置,默认模型为gemini-3.5-flash(由 config.py 的MODEL_NAME环境变量控制,job.yaml 中亦有同一默认值);- 任务级 prompt 由 Orchestrator 动态拼接(orchestrator.py 第 342-350 行),内容与提示词中 CRITICAL 规则高度一致——强制编辑、禁止只读收场、headless 沙箱中用
run_command直接执行测试命令、不要在聊天中请求许可。
依赖方面,requirements.txt 声明了 google-antigravity>=0.1.0、google-cloud-firestore、google-genai 等核心包;Dockerfile 基于 python:3.11-slim,从官方 node:20-slim 镜像拷入 Node 20(因为 Agent 需要执行 npx vitest 等 npm 命令),以非 root 用户运行 workflow/worker.py。
迭代上限、500 行护栏与人工兜底
bug_fixer_prompt.md 的“失败即迭代”策略有明确的上界,均由源码中的确定性逻辑执行:
- 最大轮数:
MAX_ATTEMPTS环境变量(默认 5,最小 1,见 config.py 第 41-44 行); - 并发双锁:任务启动前经 db_interface.py 的 Firestore 事务获取 15 分钟锁(
lock.holder+lock.expires_at),状态置为COMMIT_GENERATION;generation_attempts >= 2时直接转NEEDS_HUMAN; - 改动规模护栏:即使 Evaluator 给出
APPROVED,若git diff --stat origin/main统计的增删行数超过 500 行,同样转入NEEDS_HUMAN(orchestrator.py 第 272-288 行); - 失败兜底:Workflow 层(workflow.yaml)捕获 Job 异常后将 Firestore 文档状态改写为
NEEDS_HUMAN并清空锁字段;Cloud Run Job 自身配置maxRetries: 2(job.yaml)。
这套“提示词自律 + 白名单强制 + 状态机兜底”的三层防线,正是该提示词设计的深层逻辑:LLM 的输出不可完全信任,因此每一条提示词中的关键规则(必须编辑、禁止 push、限定测试命令)在 Orchestrator、工具钩子或 Firestore 状态机中都有对应的确定性执行者。
与评测/修订提示词的分工
理解 bug_fixer_prompt.md 的边界,需要对照同目录的另两份提示词:
- code_evaluator_prompt.md:评测者明确“不得自己修代码”,只依据
changes.diff与规格做正确性、安全性(含 ReDoS、敏感信息泄漏检查)、可读性评审,读取 Orchestrator 预先生成的linter_output.txt(不得自行跑 linter),最终输出verdict.json,并按严格格式(## Commit Message/## PR Description两级标题,供 Orchestrator 正则解析)写出pr_details.md或pr_feedback.md; - code_revision_prompt.md:修订者以
pr_feedback.md为驱动做定向精修,且被限制在“最多 3 个回合”内完成,要求第一轮就直接应用修改。
三者构成清晰的职责切分:Bug Fixer 负责首轮“从规格到实现”、Evaluator 负责独立审查、Revision Agent 负责按反馈收敛,而文件级交互(firestore_doc.json、changes.diff、verdict.json、pr_feedback.md、pr_details.md)全部被写进 git exclude,避免污染 diff。
小结
bug_fixer_prompt.md 表面上是一份 90 余行的系统提示词,实际上是一份“无头编码 Agent 的操作契约”:它用 CRITICAL 规则消灭 LLM 的只读惰性,用 workable_spec 字段表锁定输入输出契约,用四阶段工作流规范“摄入—实施—验证—报告”的闭环,用安全约束把 Agent 关在“工作区编辑者”的角色里。而真正让这份契约可信的是仓库中的配套实现——agent_runner.py 的工具白名单钩子、orchestrator.py 的迭代状态机、db_interface.py 的 Firestore 双锁与状态转移,以及 job.yaml/workflow.yaml 定义的资源与重试边界。对希望自建“自动修 Bug Agent”的团队而言,这套“提示词设计 + 确定性护栏”的分工方式,以及 agent_prompts、workflow、tests(含 test_orchestrator.py 等测试)的目录组织,都是可直接参考的工程范式。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00