基于 Issue 与 PR 合成「Golden Workable Spec」:Gemini CLI caretaker-agent 分诊评测的黄金基准生成方法论
导读:本文围绕
tools/caretaker-agent评测体系中的一份核心 System Prompt 规格 —— generate_golden_spec.md 展开。它定义了一种从真实 GitHub Issue + 关联 PR diff 合成 高保真、公平(fair)的 Golden Workable Spec JSON 的两阶段推理流程,是自动分诊机器人(triage worker)评测基准中「真值/黄金答案」的生成依据。读完本文,你将掌握这套方法的公平性剪枝规则、Workable Spec 合成的七条硬性约束、输出 JSON 结构,以及它如何被 Python 编排器加载、schema 校验并接入评测跑批全链路。
一、文档定位:它不是写给人类看的 README,而是一份「模型系统提示词」
这份文件名为 Golden Workable Spec Generator System Instructions,从字面与用途上都很特殊——它是一份面向 LLM Agent 的系统指令规格,由评测链路中负责生成黄金基准的合成器(spec synthesizer)直接加载并作为 system instruction 使用。
从仓库结构看,tools/caretaker-agent/evals/triage/ 下包含一整套针对「Gemini CLI Issue 分诊 Worker」的评测套件:
- helpers/generate_golden_spec.md:本次关联文档,即系统指令本体;
- helpers/generate_golden_spec.py:加载上述 md 并调用 Antigravity SDK(
google.antigravity)执行推理的 Python 模块; - tools/generate_golden_issue.py:产出「Golden Issue」JSON 数据集文件的 CLI 入口;
- cloudrun/triage-worker/utils/validator.py:对生成结果做结构化 schema 强校验;
- runner.py 与 judge.md:分别负责基准跑批与「LLM 裁判」打分。
其中 generate_golden_spec.py 第 29 行将本 md 定义为 PROMPT_FILE,并在第 49-54 行将其整体读入作为系统指令;随后用 LocalAgentConfig(system_instructions=system_instruction, ...) 构造 Agent 上下文。因此,本文件的实际读者是运行在评测流水线中的合成器 Agent,它的最终交付物是一份可直接落盘为基准真值的 JSON 对象,外加一份公平性说明 golden_spec_rationale。
二、两阶段强制推理流程(REQUIRED REASONING WORKFLOW)
文档要求合成器在输出最终 JSON 之前,必须严格执行两阶段推理,这是保证黄金基准「100% 公平、高精度」的前提。
阶段一:PR 文件与修复点分析(PR File & Fix Analysis)
先通读 PR 标题(title)、PR 正文(body)与代码 diff,识别本次 PR diff 中改动的每一个文件,以及每个文件内部的具体改动(改了什么逻辑、新增了什么常量、调整了哪条正则等)。这一阶段的目标是建立「改动清单」,为下一阶段的甄别提供素材。
阶段二:公平性剪枝通道(Fairness Pruning Pass,基准公平性的关键)
阶段二要求对 PR diff 中修改的每一个文件,逐一回到原始 Issue 描述进行交叉比对,并对每个文件回答两个问题:
- 「这个文件是解决用户在 Issue 文本中报告的症状所严格必需(strictly required)的吗?」
- 「还是说,这是 PR 作者顺手夹带的次要重构(secondary refactoring)、未被报告的扩展功能(un-reported feature extension),或内部架构清理(internal architecture cleanup)?」
由此导出文档中的严格剪枝规则(STRICT PRUNING RULE):
必须把所有「次要重构类文件」从
files_to_modify中剪掉;只保留直接负责解决所报告 Bug 的主目标源码文件。
这条规则在工程语义上非常关键:人类提交的 PR 往往混入了与 Issue 无关的额外改动,而评测基准的目标是检验分诊 Agent 能否像「理想的、最小化的修理工」一样定位病灶。如果基准把夹带文件也当作答案的一部分,就会诱导 Agent 输出过度扩散、不可落地的修改清单,降低基准的诊断精度与可执行性。
三、Workable Spec 合成的五条硬性规则
在推理完成之后,合成器需要依据以下规则把结论组织进 JSON。这五条共同定义了「什么是高质量、无手挥(no hand-waving)的可执行规格」。
1. 黄金规格理由(golden_spec_rationale)只谈「被剪掉的文件」,不谈显而易见的规则
理由文本必须严格聚焦于:哪些源文件被从 files_to_modify 中剪除了、以及为什么。例如:若 PR diff 中夹带了次要重构、未报告的功能扩展或内部架构清理,就要逐一写出被剪文件名并解释为何出于基准公平性将其排除;若没有任何源文件被剪除,则应明确陈述:
"No source files were pruned; all PR modifications directly address the reported issue."
同时文档特别要求不要复述显而易见的规则(例如「测试文件被排除在 files_to_modify 之外」这类常识),理由只应聚焦于非显而易见的剪枝决策。换言之,golden_spec_rationale 的价值在于解释「那些看起来像源码、实际上属于范围外的东西」,而非照抄排除清单。
2. 只允许源码文件(Source Files Only)
workable_spec 内的 files_to_modify 必须且只能包含主源码文件,严格排除:
- 测试文件(如
*.test.ts); - 锁文件(
package-lock.json、yarn.lock、pnpm-lock.yaml); - 文档类 Markdown;
- 版本号 bump 文件。
测试文件唯一的归宿是 testing_strategy.test_file 字段。这条规则与 generate_golden_spec.py 第 65-78 行的 diff 预处理逻辑相互呼应——该模块在把 diff 拼进 prompt 前,会逐行丢弃命中 package-lock.json / yarn.lock / pnpm-lock.yaml 的 diff --git 文件块,从源头减少噪声输入。
3. 测试文件落地(Test File Grounding)
- 若 PR diff 修改或新建了自动化测试文件,则将
testing_strategy.test_file设置为该精确路径; - 若 PR diff 没有触碰任何自动化测试文件,则
testing_strategy.test_file必须严格写为"N/A"。
4. 具体命名(Concrete Names,如适用)
summary.root_cause 与 implementation_plan.steps 必须引用修复所涉及的具体函数名、正则表达式、常量或数据结构。文档明确禁止“约等于手挥”的写法,如 "update the code as needed"、"fix the logic"、"adjust accordingly" —— 每一步都必须给出明确、无歧义的技术指引。
5. 禁止手挥(No Hand-Waving)
与第 4 条一体两面:含糊、泛化、无法被代码生成器直接执行的表述都属于不合格内容。Workable Spec 的最终消费者(分诊修复 Agent / 评测器)依赖步骤清单去评估“能否照做”,因此文字越具体,基准越可靠。
四、输出 JSON 模板与字段语义
合成器的最终响应必须是严格匹配下列结构的裸 JSON 对象,且不得包裹在 Markdown 代码块中(该约束本身是写给 Agent 的行为要求):
{
"golden_spec_rationale": "Focus strictly on what source files were PRUNED and why (or state 'No source files were pruned; all PR modifications directly address the reported issue').",
"workable_spec": {
"issue_id": "{owner}/{repo}#{issue_number}",
"summary": {
"problem": "Concise statement of reported problem strictly matching the issue description.",
"root_cause": "Analysis of root cause referencing specific functions/regexes modified in the PR diff if applicable.",
"context": "Additional technical context from issue and PR."
},
"implementation_plan": {
"files_to_modify": ["path/to/primary_source_file.ts"],
"steps": [
"Ordered step-by-step instructions strictly required to implement the fix for reported issue."
]
},
"testing_strategy": {
"test_file": "path/to/test_file.test.ts",
"expected_behavior": "Description of expected behavior after fix.",
"verification_steps": [
"Specific test assertions to add/modify or manual CLI verification steps."
],
"framework": "Testing framework used (e.g. Vitest or 'N/A' if no automated test file is present)."
}
}
}
对模板逐字段拆解:
golden_spec_rationale:字符串,承载第三节第 1 条的剪枝说明。workable_spec.issue_id:采用{owner}/{repo}#{issue_number}格式,作为黄金条目的唯一身份标识。summary.problem:对报告问题的精炼陈述,必须严格贴合 Issue 原文,不得改写题意。summary.root_cause:根因分析,若适用则引用 PR diff 中修改的具体函数/正则。summary.context:来自 Issue 与 PR 的额外技术上下文。implementation_plan.files_to_modify:仅主源码文件的路径数组(见规则 2)。implementation_plan.steps:严格围绕报告 Issue 的有序修复步骤(见规则 4、5)。testing_strategy:测试文件路径(或"N/A")、修复后期望行为、需新增/修改的具体断言或手工 CLI 验证步骤、测试框架名(如 Vitest)。
模板末尾还要求:不得包含 spam 评估、effort 标签等元数据,输出须完全聚焦于「代码生成与测试」的指令本身。文档的这一限制与其说是在约束格式,不如说是在约束合成器不要夹带判断噪音,让基准真值保持纯净。
五、源码侧的落地:schema 强校验与黄金条目落盘
5.1 结构化校验器如何兜底
模板产出后,generate_golden_spec.py 第 108-118 行会调用 validator.py 的 validate_triage_result 做硬校验,校验失败即抛错,不会进入数据集。从校验器源码可见其规则粒度:
triage_metadata.quality必须是["SPAM", "EMPTY", "NEEDS_INFO", "FEATURE", "OK"]之一;- 当
quality == "OK"时,effort_estimate必须为SMALL / MEDIUM / LARGE之一,且必须携带workable_spec; workable_spec.issue_id必须匹配正则^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+#[0-9]+$(校验器第 76-84 行);summary(problem/root_cause/context均为 str)、implementation_plan(files_to_modify/steps均为字符串列表)、testing_strategy(四个字段类型逐一断言)三段结构缺一不可。
也就是说,前文模板中所有“看起来像约定”的字段,在这里都变成了强类型、强结构断言——生成器即使收到格式漂移的模型输出也会在入口处被拦截。例如 _parse_llm_json(第 32-46 行)会先剥掉 Markdown 围栏、用 json.loads(strict=False) 解析,失败时再通过正则兜底反转义非法字符,最后仍要求顶层是 dict 对象。
5.2 生成器的运行环境与输入装配
generate_golden_spec 函数(第 57-123 行)展示了整条链路的运行时细节:
- 它需要
owner / repo / issue_number / issue_data / pr_data五元输入,其中issue_data、pr_data由 GitHub API 层预先抓取(见generate_golden_issue.py第 28-34 行); - prompt 由 Issue 标题/正文、PR 标题/正文以及过滤后的 diff(去掉三类锁文件块)拼装而成;
- 合成器 Agent 使用
policies = [deny("*")],即以「拒绝一切工具调用」的安全策略运行,因为该任务纯粹是「读文本 → 写 JSON」的推理型任务,不需要触碰文件系统或网络; - Agent 的 API Key 来自环境变量
GEMINI_API_KEY。
5.3 如何产出黄金 Issue 数据集
从 tools/generate_golden_issue.py 看,generate_golden_issue 是数据集工厂的编排器,其 CLI 用法为:
python3 -m evals.triage.tools.generate_golden_issue --issue <number> [--pr <number>]
它把合成的 workable_spec 与 golden_spec_rationale 连同 issue_title、issue_body、target_version、expected_quality(默认在关联了 PR 时为 "OK")、expected_effort(从 effort/small|medium|large 这类 label 解析)写入 dataset/golden-issues/gemini_cli_{issue_number}.json。其中默认 owner/repo 为 google-gemini/gemini-cli(第 80-81 行),若带 --pr 则触发本文件描述的整条 Golden Spec 合成流程,否则只生成不含预期规格的 Issue 记录。
5.4 黄金规格如何回流进评测闭环
黄金条目最终被 runner.py 的基准跑批消费:runner 用 Git worktree 为每个 Issue 建立隔离 checkout(add_worktree/remove_worktree),对真实 triage orchestrator 执行一次完整分诊,再调用 judge.py 的 evaluate_categorization 做 quality/effort 精确匹配,并用 judge_workable_spec 把「分诊 Agent 预测的 spec」与「本文档产出的 golden spec」交给 LLM-as-a-Judge 按 judge.md 的四维 0-2 评分量表(target_files_score、root_cause_and_summary_score、implementation_plan_score、testing_strategy_score)外加 human_pr_match 综合判定。值得注意的是,judge.md 内含一条与本文档剪枝思想同源的公平性规则:不允许因为候选 spec 遗漏了超出报告 Issue 范围的额外重构而扣分。
六、实战操作:手工复现一次黄金规格合成
作为评测维护者,可以按如下方式在本地复现这条流水线(仓库为只读状态,仅演示运行/查看方式,不修改任何仓库文件):
- 准备环境:在
tools/caretaker-agent下安装 requirements.txt 所列依赖,并确保.env中存在GEMINI_API_KEY; - 确认 generate_golden_spec.md 与
generate_golden_spec.py同目录(脚本第 29 行硬依赖该相对路径); - 执行
python3 -m evals.triage.tools.generate_golden_issue --issue 28052 --pr 28500(示例参数)抓取 Issue/PR 数据并触发合成; - 到
dataset/golden-issues/下检查生成的gemini_cli_{issue_number}.json:若golden_spec_rationale为空且expected_workable_spec为空对象,说明调用时未提供--pr;若脚本抛ValueError,通常意味着模型输出未通过 validator.py 的 schema 校验。
想验证生成器本身的行为,也可以直接阅读 generate_golden_spec.py 的单元级路径:第 32-46 行是「剥围栏 + 容错解析」的容错兜底,第 65-78 行是「锁文件 diff 预过滤」,第 95-123 行是 Agent 执行与校验封装——这三段几乎一一对应本文第四节、第三节与第五节讲述的约束。
七、小结:这份 System Prompt 为什么值得作为方法论文档阅读
generate_golden_spec.md 表面上是「写给模型的话」,本质上却是一份可审计的基准构建协议:它把「公平」从口号翻译成可执行的剪枝规则,把「高质量」翻译成源码-only 白名单、具体命名、禁手挥和测试文件落地规则,把「可验证」翻译成严格 JSON schema 与 N/A 兜底语义。再叠加 generate_golden_spec.py 的输入净化、validator.py 的结构校验、runner.py + judge.md 的回环打分,整条链路构成了一个「由人类 PR 提炼真值 → 用真值校准分诊 Agent」的自洽基准体系。
若你要在类似的开源 Agent 项目中搭建「Issue 分诊评测基准」,本文件连同其所在目录的 Python 编排代码(见 helpers 与 cloudrun/triage-worker)提供了可直接借鉴的三样东西:一份把公平性显式化的提示词规格、一套强 schema 校验器、以及一个 worktree 隔离的并行跑批与裁判框架。
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