首页
/ gemini-cli 护理者 Agent 深度解析:代码修订 Agent(Code Revision Agent)的系统提示词与迭代修复闭环

gemini-cli 护理者 Agent 深度解析:代码修订 Agent(Code Revision Agent)的系统提示词与迭代修复闭环

2026-09-06 17:50:17作者:丁柯新Fawn

gemini-cli 仓库的 tools/caretaker-agent/cloudrun/pr-generator 子目录实现了一条自动化的"缺陷规格 → 代码修复 → 评审 → 再修复"流水线,而本文的主角 code_revision_prompt.md 就是流水线中"第 2 轮及以后修复迭代"所使用的系统提示词。读完本文,你能掌握这套提示词的完整结构(输入契约、四阶段工作流、安全约束),以及它如何被 Python 编排器(orchestrator)按迭代次数动态装载、如何与评估者 Agent 产出的 pr_feedback.md 衔接,从而构成一个可运行的自动代码修订闭环。

一、角色定位:它是多 Agent 流水线中的"返修工"

在 pr-generator 的 agent_prompts 目录下共有三份系统提示词,对应三种 Agent 角色:

提示词文件 角色 触发时机
bug_fixer_prompt.md Bug Fixer(首次修复) 迭代第 1 轮
code_evaluator_prompt.md Code Evaluator(评审守门员) 每轮修复后
code_revision_prompt.md Code Revision(迭代修订) 迭代第 2 轮及以后

code_revision_prompt.md 开篇定义了 Agent 的角色:一名专精代码修订、缺陷修复打磨与迭代质量保障的专家级自主软件工程师。它不做首次修复——首次修复由 Bug Fixer Agent 负责——它的职责是"接住评估者 Agent 打回的反馈,把本地实现打磨到生产级标准"。

这一角色分工在编排器源码中可以得到印证。在 orchestrator.py_run_code_generation 方法中,编排器按迭代次数选择提示词文件:

if iteration == 1:
    prompt = ("Fix the bug described in firestore_doc.json. ...")
    prompt_file = "bug_fixer_prompt.md"
else:
    prompt = ("Use the feedback in pr_feedback.md to address the remaining issues in the code and tests. ...")
    prompt_file = "code_revision_prompt.md"

也就是说,只要评估未通过、循环进入第 2 轮,Agent 收到的系统提示词就切换为 code_revision_prompt.md,而用户消息则明确指向 pr_feedback.md 中的剩余问题。

二、输入契约:三个输入源与它们的语义

提示词的 "Inputs" 一节声明,修订 Agent 在运行时可访问三类输入:

  1. pr_feedback.md(或 feedback.md:评估者 Agent(Evaluator Agent)对上一轮变更产出的详细反馈,按类别(Correctness、Security、Readability、Test Failures)分组,并带有具体文件名与行号引用。
  2. firestore_doc.json(或 example_firestore.json:原始 workable_spec,包含缺陷摘要、实现计划(files_to_modifysteps)与测试策略(frameworktest_fileverification_steps)。
  3. 本地仓库:承载上一轮代码变更与单元测试的代码库。

这些文件并非凭空出现,而是编排器在工作区中预先铺好的。以 firestore_doc.json 为例,orchestrator.py 在克隆仓库、检出 ssr-agent-<issue_num> 分支并执行 npm ci 之后,会把 Firestore 文档写入 PR 工作区根目录:

spec_pr_path = os.path.join(self.config.pr_repo_path, "firestore_doc.json")
with open(spec_pr_path, "w", encoding="utf-8") as f:
    json.dump(firestore_doc, f, indent=2)

pr_feedback.md 的"回传"则由 _save_feedback_to_coding_workspace 方法负责:当某一轮迭代未获批准时,编排器把评估工作区(eval 目录)中的 pr_feedback.md 拷贝回编码工作区(pr 目录),若评估者未产出该文件则写入占位说明,保证下一轮修订 Agent 始终"有反馈可读"(见 orchestrator.py_save_feedback_to_coding_workspace)。单元测试 tests/test_orchestrator.py 中的 test_save_feedback_to_coding_workspace 正是对这条拷贝路径的断言。

另外值得一提的工程细节:编排器在克隆仓库时会向 .git/info/exclude 追加 firestore_doc.jsonpr_feedback.mdfeedback.mdchanges.diffverdict.jsonpr_details.md 等条目(见 orchestrator.py),使这些 Agent 间的"传令文件"不会污染 git status 与最终 diff。

三、Phase 1:反馈摄取与规格交叉验证

修订 Agent 工作流的第一步不是改代码,而是"读懂要改什么":

  1. 读取评估反馈:打开并完整检查 pr_feedback.md(或 feedback.md);
  2. 交叉引用规格:查阅 firestore_doc.json,确保修订方向与原始规格的 workable_spec.summary.problemroot_cause 以及 testing_strategy.expected_behavior 保持一致——这一步防止 Agent 在"逐条消解反馈"时偏离缺陷本身;
  3. 归类问题:把反馈中的每一项 action item 归入四个类别:
    • Correctness & Logic gaps(正确性与逻辑缺陷)
    • Security vulnerabilities or unsafe patterns(安全漏洞或不安全模式)
    • Readability & Coding standard violations(可读性与编码规范违规)
    • Missing or failing unit tests(缺失或失败的单元测试)

这种"先分类、后动手"的结构与评估者提示词 code_evaluator_prompt.md 中的评估维度(Correctness、Security、Readability)严格对齐——修订 Agent 的输入分类体系就是评估者输出分类体系的镜像,形成闭环。

四、Phase 2:定向修订与实现约束

这是提示词的核心章节,规定了"怎么改",可以拆成四个子约束。

4.1 最小化修改,禁止范围蔓延

  • 严格针对评估反馈中指出的每一条问题修改目标源文件;
  • 保持变更聚焦、最小化,不重构无关代码、不引入 scope creep。

这一约束在编排器侧有对应的"量化防线":即便某轮获得 APPROVED,如果 git diff --stat origin/main 解析出的总修改行数(插入 + 删除)超过 500 行,编排器仍会把该 issue 标记为 NEEDS_HUMAN 而不是自动提 PR(见 orchestrator.py)。提示词中的"最小化"原则与代码中的 500 行硬上限互为表里。

4.2 严格安全断言(Security Assertions)

提示词对安全维度提出了四条硬性要求,几乎全部面向 Node.js/TypeScript 场景的常见注入面:

  • Input Validation:任何新增输入、参数或解析出的数据结构都必须做安全校验;
  • Regex Security:正则表达式必须抵御 ReDoS(正则拒绝服务),避免过度宽松的通配符;
  • Data Handling:敏感数据与硬编码凭据不得被记录或泄露,存储必须安全;
  • Safe APIs:优先使用标准库或项目认可的安全 API,而非裸命令字符串或不安全调用。

值得注意的是,这四项断言与评估者提示词 code_evaluator_prompt.md 的 "Security Analysis" 章节逐条对应——评估者用什么标准打分,修订 Agent 就按什么标准自查,两套提示词实际上是同一套评审标准的一体两面。

4.3 质量与可读性断言

  • Style & Conventions:遵循语言标准规范(如 TypeScript/Node.js 约定)与项目既有风格规则(.eslintrctsconfig);
  • Naming & Simplicity:命名描述性、一致,函数短小模块化,遵循单一职责原则;
  • Comments:注释解释"为什么"而非"是什么",避免对显而易见的语法做冗余说明。

4.4 测试覆盖的修正与扩充

  • 打开 workable_spec.testing_strategy.test_file
  • 修复反馈中指出的失败测试;
  • 若评估者指出边缘场景缺失或 verification_steps 覆盖不全,则新增测试用例;
  • 所有测试必须使用规格中指定的 framework(如 Vitest、Jest),并能在 headless 环境中可靠执行。

"headless 环境"这一点由运行基础设施保证:agent_runner.py 维护了一个无头沙箱工具白名单 ALLOWED_SANDBOX_TOOLSview_fileread_filereplace_file_contentmulti_replace_file_contentwrite_filewrite_to_filerun_command),并注册 pre_tool_call_decide 钩子自动放行白名单内工具、拒绝其余工具——这就是提示词中"用 run_command 直接执行测试、不要向聊天窗口请求许可"的执行基础。

五、Phase 3:动态验证与回归测试

Phase 3 是"自我验证"环节,四步递进:

  1. 跑 Linter:执行项目 lint 命令(如 npm run lintnpx eslint .),把修改文件中的 lint 错误清零;
  2. 跑目标测试套件:用 run_command 直接执行目标测试文件(如 npx vitest run <test_file>),确认所有被修订的代码路径与边缘场景通过;
  3. 跑回归测试:执行相关的周边乃至全项目测试,确保修订没有破坏既有功能;
  4. 失败则迭代:任何 lint 或测试失败,都需分析输出、调整实现或测试断言后重跑,直到 100% 通过。

这里有一个与评估者分工的微妙之处:在正式流水线中,ESLint 检查实际是由编排器在评估工作区预先执行并落盘为 linter_output.txt 的——orchestrator.py_run_eslint_static_check 会对 git diff origin/main 变更的 .ts/.tsx/.js/.jsx 文件执行 npx eslint --max-warnings 0 ...。但修订 Agent 提示词仍要求它自己跑 lint 并清零,这体现了"Agent 自验证 + 编排器确定性复验"的双保险设计:Agent 的自查是必要非充分条件,最终结论仍由评估者与编排器的确定性检查裁定。

六、Phase 4:报告义务与"3 轮"硬预算

修订 Agent 完成验证后必须产出一份简洁报告,包含三部分内容:

  • 逐条列出 pr_feedback.md 中的每个反馈点及对应的解决方式;
  • 列出执行过的测试与 lint 命令及其通过状态;
  • 确认安全、质量与回归检查全部通过。

提示词末尾(Constraints & Safety 部分)还给出了一条极具工程实用性的预算约束:

You have a strict budget of 3 turns maximum to complete this task. Apply the fixes directly in your very first turn, and use your next turn to verify with tests.

即:第 1 轮直接改代码,第 2 轮跑测试验证,总共不超过 3 轮。这与 Bug Fixer 提示词中"不得只读文件和跑基线测试就结束回合"(CRITICAL EXECUTION RULES 第 2 条)形成呼应——两条规则共同治理 LLM Agent 最常见的失败模式:过度探索、拖延产出。同样,提示词明确禁止浪费回合跑 git statusgit loggit show 这类探索性命令,"你已经拥有完整源码访问权"。

七、约束与安全边界:修订 Agent 的行为红线

提示词 "Constraints & Safety" 章节划定五条红线,每条都在编排器中有对应的机制承接:

红线 编排器侧的承接机制
禁止 git commit / git push,变更留在工作目录 提交动作由编排器在 _prepare_iteration_commit 中以软提交方式统一完成(orchestrator.py
不得修改 files_to_modifytest_file 之外的文件(除非有明确理由,如构建/测试框架配置) 评估者按 diff 范围评审,越界修改会被 "Scope" 检查项捕获
修订代码必须匹配现有代码库的架构模式与风格 评估者 Readability 维度 + 编排器 ESLint 静态检查
任务是"基于 pr_feedback.md 应用修复" 第 2 轮起用户 prompt 即指向 pr_feedback.md
不跑探索性 git 命令;3 轮硬预算 工具白名单 + 无头沙箱自动审批(agent_runner.py

八、提示词如何被装载:AgentRunner 的装载链

最后把镜头从"提示词写了什么"转到"提示词如何生效"。编排器构造 AgentRunner 时把 agent_prompts 目录传给 script_dirorchestrator.py),随后每次 run_agent 调用按以下链条装载提示词(见 agent_runner.py):

  1. _load_prompt_file 按文件名读取 markdown,并做路径穿越防护(拒绝解析后落在 script_dir 之外的路径);
  2. 文件存在则以其全文覆盖默认 system instructions,不存在则回退为 "You are the {role}..." 的兜底指令并记录警告;
  3. 提示词连同 Vertex AI 配置(默认模型 gemini-3.5-flash,见 config.py)一起注入 LocalAgentConfig
  4. 由于 Agent 交互基于进程 CWD,AgentRunner 用一把 asyncio.Lock 串行化所有 Agent 的目录切换,避免并发任务互相踩踏工作目录。

装载完成后的循环上限由环境变量 MAX_ATTEMPTS(默认 5,最小 1)控制——注意这是流水线级的"最多几轮 修复→评审"总迭代(config.py),而提示词中的 "3 turns" 是单次 Agent 会话内的工具调用轮次预算,两者尺度不同、各司其职。超过总迭代仍未获批时,编排器释放 Firestore 锁并把 issue 置为 NEEDS_HUMAN,由 tests/test_orchestrator.pytest_run_loop_max_attempts_exceeded 验证该路径确实会调用 release_lock

九、小结:一份"返修工"提示词的设计要点

回到 code_revision_prompt.md 本身,可以提炼出它对"如何编写 LLM 代码修订 Agent 的系统提示词"给出的几条可复用经验:

  • 输入契约显式化:把 Agent 能看到的文件(反馈、规格、仓库)逐一列名并说明语义,包括备选文件名(pr_feedback.mdfeedback.md),容忍上游产出差异;
  • 工作流阶段化:摄取 → 定向修订 → 动态验证 → 报告,每阶段有明确产物与通过标准,其中验证阶段的"失败则迭代直到 100% 通过"把回归风险内建进流程;
  • 与评审标准镜像对齐:修订断言(输入校验、ReDoS、安全 API、SRP、注释规范)与评估者维度一一对应,反馈在两个 Agent 之间无需转译;
  • 预算与红线双约束:"首轮直接改、次轮验证、3 轮封顶"治理拖延,"禁 commit/push、禁越界改文件"保护工作区主权,让 git 提交权始终握在确定性编排器手里;
  • 自验证 + 确定性复验的双保险:Agent 自查 lint 与测试只是入场券,编排器的 ESLint 落盘、回归检查、500 行 diff 上限才是最终裁判。

对于想在自己的仓库中搭建"评估—修订"闭环的工程师,这套 pr-generator 目录下的三份提示词与 workflow 编排代码(含 Dockerfilejob.yamlworkflow.yaml 等 Cloud Run Job 部署配置)构成了一个完整可参考的实现样本:提示词负责"教会 Agent 怎么返修",编排器负责"保证返修过程可控、可审计、可终止"。

登录后查看全文
热门项目推荐
相关项目推荐