异构双审门禁(HDR Gate)
产出一份可交给陌生 agent 独立执行的开发文档,而不是自己把代码写完。
核心逻辑:文档的验收测试,是另一个 agent 的执行过程。作者和审稿人都会靠先验脑补,只有一无所知的人不会。
六条铁律
- 先判定,再动手。 不判定复杂度就直接开写,是本 skill 最常见的误用。
- 歧义不阻塞判定。 需求说不清"哪个平台"不等于不能判定——判定只看需求规模。先按显式假设判定,把假设一次性抛给用户确认,不许先问、等回答、再判定。
- 双审必须背对背。 Agent2 和 Agent3 各自独立评审,不共享上下文、不看到对方结论。串行评审会被锚定,等于只审了一遍。
- 合并去重与分级分离。 归并是体力活(flash 做),定级是判断(主持做)。两者混在一起,弱模型会错并、漏并。归并也必须由独立会话执行;若主持兼任(省一次调用),必须在
trace.md标MERGED-BY-HOST并在交付时声明——归并丢的是「漏并」,而漏并只有另一个视角才捞得回来。 - 冷读者不许问,作者不许答。 试跑期间一旦口头补答,补的是对话不是文档,这次试跑就废了。它记下的清单才是要改的东西。
- 交付文档即终止。 本 skill 结束时不动一行代码。实施由用户手动开新会话完成。
第 -1 步 · 澄清预算(歧义不阻塞)
用户交给你一个说不清的需求,是常态,不是异常。
"我之前那个项目里的那个 agent"——这种话在你听来是歧义,在用户听来是"我已经说清楚了,你怎么这都不懂"。你要做的不是把理解成本推回去,而是用假设承担不确定性。
三条硬规则
| # | 规则 | 为什么 |
|---|---|---|
| 1 | 澄清不是前置门禁 | 复杂度判定只依赖需求规模(改几个文件、动不动契约),不依赖细节。A 平台还是 B 平台,判定结论往往一样 |
| 2 | 最多 1 轮、最多 4 问 | 一次 AskUserQuestion 就是一轮。出现第 2 轮澄清,说明第 1 轮设计失败 |
| 3 | 每问必须自带默认值 | 没有默认值的问题 = 把决策成本转嫁给用户。格式:问题(默认:A,理由:…) |
什么值得问
| 值得阻塞 | 不值得阻塞(写成假设,继续走) | |---|---| | 答案会改变方案类型或成本量级(包一层薄壳 vs 建一套新服务) | 参数细节(字段名、端口号、超时值) | | 涉及不可逆决策(删数据、换存储引擎) | 可被后续评审推翻的实现选择(模块放哪个目录) | | 只有用户知道的信息(用哪个平台、哪套凭据) | 仓库里能查到的事实(现有接口怎么鉴权)——那该去读代码,不是问人 |
第三条最容易犯规:问用户"你们的登录接口怎么鉴权的",答案就在代码里。先去仓库找,找不到才问。
假设账本
没确认的全部编号写下来,别只在心里记:
A1 · 平台 = 当前这个应用里创建的 agent 依据:需求写"这个平台",且当前工作区只有这一处符合
A2 · 调用方 = 外部 MCP 客户端 依据:需求写"给其他 agent 调用"
A3 · 现有 agent = 提示词 + 工具配置,无独立 HTTP 入口 依据:仓库内未见部署单元
- 存
.hdr-gate/<需求名>/assumptions.md - 写进文档 §0.1,标注"已确认 / 待确认"
- 假设不是免责声明,是给审稿人的靶子:阶段 2 的 Agent2 必须专门审"这些假设是否成立"。A1 错了整份文档作废,所以每条假设都要写清依据和"若不成立的影响"
第 0 步 · 复杂度判定(必做,不可跳)
读完需求后,先判定是否值得上门禁,然后把理由讲给用户听,由用户决定。
判定标准(命中任一即倾向启用)
| # | 标准 | 怎么判断 | |---|---|---| | 1 | 跨 3 个以上文件 | 从需求描述能看出改动面 | | 2 | 涉及架构或数据模型决策 | 要新建表/改字段/改接口契约/引入新模块 | | 3 | 需引入新依赖 | 新库、新服务、新外部 API | | 4 | 影响现有功能 | 有破坏面、需要向后兼容 | | 5 | 用户明确要求 | 说了"写开发文档""出方案""给别人做" |
不命中任何一条 → 直接告诉用户"这个不用上门禁",然后正常做。 不要为了用 skill 而用 skill。
向用户描述的话术
用这个结构,简短直接:
这个需求我判断【值得 / 不值得】上异构双审门禁。
命中的标准:① … ② …
影响面预估:约 N 个文件,涉及 <表/接口/模块>
走门禁的代价:约 13 次模型调用、4 个模型、预计 <时长>
不走的风险:<具体风险,比如"改错字段没人兜住,上线后才发现">
建议:<走 / 不走 / 走简化版(砍掉冷读试跑)>
判定后必须让用户选,不要自行开工。但只有一次交互机会,把三样东西塞进同一个 AskUserQuestion(≤4 问):
| 问题 | 内容 | |---|---| | Q1 门禁 | 「我判定值得上门禁(命中①③⑤)。走完整 / 走简化版 / 直接做」 | | Q2–Q4 关键歧义 | 每个问题 2–4 个选项,第一个选项标「推荐」,等于你的默认假设 |
用户全点默认 → 一次交互同时拿到判定许可和假设确认。
需求本来就清楚(无歧义):只发 Q1,不要为了凑数硬造问题。
绝对不要先发一条"我需要你确认三件事"、等用户答完再发判定——那是两轮打断,也是用户抱怨"没法直接用"的直接来源。
第 1 步 · 项目分析 + 初稿
你扮演 Agent1(Qwen3.8-max 档),也可以 spawn 一个 subagent 承担。
- 读项目结构、关键模块、既有约定、可复用件
- 按
dev-doc-template.md骨架写 v0.1 - 存到
.hdr-gate/<需求名>/v0.1.md
硬门禁:缺「任务卡(T1…Tn)」或「验收断言(可执行命令)」任一章节 → 自己打回重写,不许进评审。
第 2 步 · 背对背双审(并行)
用 Agent 工具同时起两个 subagent,互相不传对方的存在:
| 角色 | 模型 | 审什么 | |---|---|---| | Agent2 | GLM-5.3 | 能不能落地 + 信息完备性(文档没告诉我什么)+ 假设是否成立(§0.1 逐条打假) | | Agent3 | DeepSeek 4.1 | 做出来会不会错(边界/异常/并发/兼容/破坏面/验收可测性) |
两个 prompt 都必须包含:
- 只给它文档路径 + 仓库路径,不给本对话任何上下文
- 明确"不得假设文档未写明的信息,凡是需要假设的地方都要列为问题"
- 明确"§0.1 的每条假设,请到仓库里验证;能证伪的直接列 P0"
- 输出格式:
[编号] 位置 | 问题 | P0/P1/P2 | 建议改法 | 依据
产出分别存 review-glm.md、review-ds.md。
降级协议(必须显式,不许静默)
默认不是降级,默认是报告。 先判定自己处在哪一级:
| 级别 | 条件 | 盲区 | 能不能叫「双审」 |
|---|---|---|---|
| full | 两个审稿人跨模型族(qwen vs glm vs deepseek) | 基本不重合 | ✅ 可以 |
| session | 同族不同会话,或同模型换会话 | 重合,只隔离了记忆 | ⚠️ 只能叫「多会话复核」 |
| single | 一个会话审两遍 | 完全重合 | ❌ 等于没审 |
降到 session / single 时,三件事一件都不能少:
- 先试能不能不降。 本平台 Agent 工具支持
model参数(default/lite/reasoning/ 具体模型 id)。至少把审稿人压到lite、作者用default,制造尺寸差——同族不同尺寸比同族同模型强一档。别还没试就说「模型不可指定」。 - 写降级记录
.hdr-gate/<名>/degraded.md:降级到哪一级、原因、试过什么、丢了什么。原因要具体到「缺哪个环境变量」,不要写「环境不支持」。 - 交付时第一句声明强度,并说清「补 key 重跑要多少次调用」。
绝对禁止:把 session 级产物说成「已过双审」;frontmatter 不写 review_mode 就交付。
第 3 步 · 合并去重(Agent4)+ 分级(主持)
两段,不可合并:
第一段 — Agent4(flash 档)机械归并:按根因合并两份清单,统一编号,输出候选分类(共识/疑似分歧),不给定级。
第二段 — 你(主持)复核:纠正错并、捞回漏并、定 P0/P1/P2、确认分歧项成立。
产出 merged.md + trace.md(溯源表):
GLM-01 → P0-01 → 合并(与 DS-03 同根因)
DS-07 → 独立 → 保留为分歧项
溯源表不是可选项。弱模型归并时丢信息,是两个强模型评审投入被浪费的主要方式。
第 4 步 · 一次性修复(Agent1)
拿合并后的完整清单一次改完 → v0.2。逐条回应:
[P0-01] 已改(§5 T2 补了表结构)
[P1-03] 不改(理由:与项目现有 X 约定冲突,已写入§9已知限制)
禁止:静默忽略;只改措辞不改方案。
第 5 步 · 分歧裁定
只处理分歧项。裁定顺序:
- 能靠代码/文档/事实验证的 → 听事实
- 无法验证的 → 听保守一方
- 纯成本权衡 → 听作者,但必须写进「已评估的替代方案」
- P0 级仍谈不拢 → 交给用户裁决,不自行放行
第 6 步 · 复审双签 → v0.3
Agent2、Agent3 各自独立复审 v0.2(此轮可见裁定记录,可只核对"自己提的 P0 是否关闭"以省成本)。
放行条件全部满足:
- 所有 P0 已关闭
- 所有 P1 有明确处置(已修 / 转待办并写入「已知限制」)
- P2 已登记
- 双方各自签「可交接」/「不可交接 + 阻塞理由」
返工上限 2 轮,第 3 轮强制交用户裁决。通过后产出 v0.3(双签通过版)。
第 7 步 · 冷读试跑(最关键,不许省)
找一个完全陌生的执行者,只给 v0.3 文档 + 仓库,不给任何背景。
用 Agent 工具起一个全新上下文的 subagent。三条硬条件:
- 全新会话,无本对话任何上下文
- 未参与第 2/6 步的评审(GLM、DS 已被污染,禁用)
- 异族于 Agent1 —— 默认用
glm-5.2(zhipu 族,作者是 qwen 族);同族时必须选小尺寸
为什么试跑要用"笨"模型:小模型不脑补,倾向严格按字面执行。文档有歧义它会直接卡住——这正是你要的信号。max 太聪明,会用先验把洞填平。
prompt 必须包含这三条指令:
- 你是第一次接触这个项目,只有这份文档和代码仓库
- 不要问任何人,把所有疑问写进清单
- 严格按文档字面执行,不要用常识补全任何未写明的内容
让它做三件事:
- 复述:用 5 行以内说出它理解的目标与改动范围
- 报缺口:列出「我要动手但文档没告诉我」的全部信息
- 试跑:实际执行 T1–T2
产出 cold-read.md,每条:[缺口编号] 卡在哪个任务 | 我需要什么信息 | 文档当前怎么写 | 我的猜测与风险
判定与分流
| 缺口性质 | 判定 | 去向 | |---|---|---| | 路径 / 命令 / 数据结构 / 接口契约 / 配置项 / 枚举值 / 错误码 缺失 | 不合格(>0 条即不合格) | → 第 8 步 | | 暴露方案缺陷(照做会错、缺依赖、改不动) | 不合格 | → 回第 4 步改方案,重走第 6、7 步 | | 设计偏好类 | 可接受 | 要求文档补一句「此处自行决策,无需询问」 |
试跑期间绝对不许口头补答。它问"user.py 在哪",你回了"src/models/user.py"——这句话就该写进文档,而不是说给它听。
第 8 步 · 补齐定稿 → v1.0 交付
Agent1 按缺口逐条补齐。
硬门禁:只允许增加信息,不允许改变方案。 若补齐时发现必须改方案 → 立即停止,回第 4 步。改方案绕过双签,等于让未经评审的内容混进定稿。
补齐原则:
- 能内嵌就内嵌(把代码片段、字段表、命令直接写进文档),不能内嵌才给路径
- 凡是"接手方一定会问"的问题,答案前置写进去,别等它问
交付物
| 产出 | 路径 | 说明 |
|---|---|---|
| 开发文档 | <工作区根目录>/<需求名>.md | 唯一交付物,用户手动交给新会话执行 |
| 中间产物 | .hdr-gate/<需求名>/ | v0.1–v0.3、双份清单、溯源表、冷读缺口、裁定记录 |
<需求名>.md 用中文短名,如 用户登录态改造.md、订单导出功能.md。
交付时告诉用户四句话,第一句必须是评审强度:
- 这次的实际强度:
review_mode是哪一级、审稿人真用了什么模型(跨族 / 同族多会话 / 单会话)、Agent4 归并是真跑了还是主持兼任、假设有几条被真正核实过。这一句不许省,也不许含糊。 - 文档路径,以及它基于哪个 commit
- 还有哪些 P2 未修、哪些 P1 转成了待办(在文档 §9)
- 下一步:开一个新会话,把这份文档交给它执行;不要让写文档的这个会话自己执行(作者会脑补,文档的洞永远暴露不出来)
若强度低于 full,追加一句:补什么条件能重跑到 full、大约多少次调用。
交付后停止。不要顺手开始写代码。
成本与模型配置
| 配置 | 调用次数 | 场景 | |---|---|---| | 最小(一次通过) | 9 次 | 中等复杂 | | 典型(1 轮返工) | 13 次 | 常规复杂需求 | | 上限(2 轮返工) | ≈17 次 | 跨模块重构 |
| 角色 | 模型(默认走阿里百炼 Token Plan) | 模型族 | 备注 |
|---|---|---|---|
| Agent1 作者 | qwen3.8-max | qwen | 分析与长文档写作 |
| Agent2 可行性审 | glm-5.3 | zhipu | 必须异族于 Agent1 |
| Agent3 正确性审 | deepseek-v4-pro | deepseek | 必须异族于 Agent1 |
| Agent4 合并去重 | qwen3.8-flash | qwen | 只归并,不定级 |
| 冷读试跑者 | glm-5.2 | zhipu | 异族于 Agent1、未参与评审 |
| 主持 | 你自己 | — | 分级、裁定、版本管理 |
异质性看「模型族」,不看「通道」。 Token Plan 一个通道里同时有 Qwen / GLM / DeepSeek 三家模型,provider 相同但族不同,盲区照样不重合。真正无效的是同族同模型——那只是换了会话,脑补习惯一模一样。hdr.py doctor 会按族判定并给出提示。
另外注意:三家挤在一个通道意味着单点故障,通道挂了双审同时失败。介意就给 agent1 配 fallback。
平台不支持指定具体模型时:用 lite 近似 flash、default/reasoning 近似 max,并靠会话隔离 + 职责写死保证独立性。
常见误用(自查表)
| 症状 | 问题 |
|---|---|
| 没做第 0 步判定就开写 | 轻量需求被上了重流程 |
| 先发澄清、等回答、再判定 | 两轮打断。判定不依赖细节,应先判定再合并提问 |
| 一次问超过 4 个问题,或选项没有默认值 | 把决策成本转嫁给用户;用户会答一半就烦了 |
| 问用户"你们接口怎么鉴权的" | 仓库里查得到的事实不该问人,先读代码 |
| 假设只记在脑子里 | 阶段 2 无法打假,错假设一路带到定稿 |
| 两个审稿人看到对方清单 | 锚定,双审退化成一个审 |
| 同族两个会话,却说"已过双审" | 只拿到会话隔离,没拿到盲区错开。必须降级标注为 session |
| 说"平台不能指定模型",但没试过 model 参数 | Agent 工具支持 default/lite/reasoning,至少能拉尺寸差。先试再说 |
| doctor 报缺密钥,看一眼就往下走 | 配置再漂亮也跑不起来。退出码 2 就是"不许继续" |
| 归并由主持兼任,交付时不说 | 漏并只有独立视角能捞回来,兼任必须声明 MERGED-BY-HOST |
| 让 GLM/DS 当冷读者 | 它们已读过文档,是假装陌生 |
| 冷读时回答了它的提问 | 补的是对话不是文档,试跑作废 |
| 文档缺可执行验收断言 | 接手方必然卡住,等于没写 |
| 定稿后自己动手写代码 | 作者的脑补会让文档缺陷永远暴露不出来 |
配套工具:优先用脚本驱动,别手工搬运
tools/ 下有一套零依赖实现,把上面的阶段变成了可执行命令。有这个目录就用它,比手工 spawn 更快也不容易漏步骤。
若已挂载 MCP(hdr-gate 服务)
| 工具 | 用途 |
|---|---|
| hdr_ask_parallel | 双审就用它:一次并行问 agent2 + agent3,两者互不可见 |
| hdr_ask | 单次按角色提问,可传 repo 自动附带文件树 |
| hdr_list_roles | 查模型绑定 + 异质性体检(同厂会标 ❌) |
若用命令行
python3 tools/hdr.py doctor # 先自检
python3 tools/hdr.py init --name X --repo /path --req "…"
python3 tools/hdr.py draft --name X # 阶段1
python3 tools/hdr.py review --name X # 阶段2(自动并行)
python3 tools/hdr.py merge --name X # 阶段3
python3 tools/hdr.py fix --name X # 阶段4
# 阶段5 人工裁定 → 写进 .hdr-gate/X/resolution.md
python3 tools/hdr.py sign --name X # 阶段6(解析 SIGNOFF)
python3 tools/hdr.py coldread --name X # 阶段7
python3 tools/hdr.py finalize --name X # 阶段8 → 交付
python3 tools/hdr.py status --name X
没有工具时
退回手工流程:用 Agent 工具 spawn 独立 subagent,把角色职责和输出格式写进 prompt(格式见 tools/prompts.py),产物落盘到 .hdr-gate/<需求名>/。
最关键的一点不变:两个审稿人的会话必须互不相通,冷读者必须是全新上下文。
完整规范见 sop-full.md,文档骨架见 dev-doc-template.md,工具用法见 tools/README.md。
Scan to join WeChat group