50 · 竞争候选 + 对抗批评 + 综合——新图骨架详细设计草稿
状态: 📝 设计草稿,不代表已拍板。这是 49 号文档 §二"提案 A"的展开——49 号只给了三节点拓扑草图,本文档补上骨架 JSON 形状、命名、critic/synthesis 分工、预算风险的具体数字。49 号文档已明确:没有真实场景验证价值前不建议立项写代码,本文档只是 把"如果要做,该怎么做"想清楚,供下一步决定要不要排期时参考,不是开工指令。 日期: 2026-09-04 前置阅读: 49 号文档 §二(提案动机与 场景边界)、27-P4(并行执行引擎,本设计的地基)、 27-naming-conventions.md(命名规则)
一、跟现有骨架的本质区别(复述 49 号 §2.1,作为设计前提)
executor-fanout.json 是分解型 fan-out:split 把任务拆成互不重叠的子任务分给不同分支,merge
做的是拼接(把互补的子产物合并成一个整体)。竞争候选是同型 fan-out:N 个分支做的是同一件事,
下游节点要做的是评判 + 择一/融合,不是拼接。两者拓扑相似、语义完全不同——这是本设计最容易踩错的
地方,写骨架 JSON 时必须在 whenToUse/dataContractNotes 里把这条区别说透,否则 workgraph-planning
选型时会混淆(现有 executor.json vs deliverable.json 就发生过一次真实混淆事故,见 §三.2 引用)。
二、骨架 JSON 形状草稿
沿用 system/work-graph-templates/README.md:129-165 定义的字段结构,不发明新字段。
// system/work-graph-templates/candidate-council.json(暂定名,未定案)
{
"id": "candidate-council",
"label": "候选方案竞争评审",
"whenToUse": "验收标准客观可判定,但实现路径不唯一、单次尝试容易收敛到局部最优解的子任务。典型信号词:\
'设计一个策略/方案'、'优化/选型'、'有几种做法都值得试'。跟 executor-fanout 的区别:executor-fanout 是\
把一个任务拆成不重叠的子任务分给不同分支各自完成(分解型);本骨架是让多个分支各自独立给出同一个目标\
的完整方案,再由 critic 评判、synthesis 择优或融合(同型竞争)。不确定任务是该分解还是该竞争时,默认\
选分解型(executor-fanout)——竞争型成本是 N 倍,只在"真的不确定哪条路线更优"时才划算。",
"ownerOrgNode": "{{orgNode}}",
"nodes": [
{ "nodeName": "{{orgNode}}-candidate-a", "systemAgentId": "{{candidateAgent}}" },
{ "nodeName": "{{orgNode}}-candidate-b", "systemAgentId": "{{candidateAgent}}" },
{ "nodeName": "{{orgNode}}-critic-a", "systemAgentId": "candidate-critic" },
{ "nodeName": "{{orgNode}}-critic-b", "systemAgentId": "candidate-critic" },
{ "nodeName": "{{orgNode}}-synthesis", "systemAgentId": "candidate-synthesis" },
{ "nodeName": "{{orgNode}}-validator", "systemAgentId": "{{validatorAgent}}" }
],
"dataContractNotes": "候选分支数按实际任务增减(本文件给 2 路起手式,同 executor-fanout 的先例)。\
每路候选各配一个独立的 critic 节点——critic 只评判、不产出最终方案,也不是候选自己的下游必经步骤,\
是平行的另一个节点。critic 产出的评语(kind=artifact)与候选产出(kind=artifact)都要能被 synthesis \
节点区分来源,建议候选各自产出走 contract kind(分支间不冲突,同 executor-fanout 对 split 节点的处理),\
critic 评语走 artifact kind。千万不要把 critic 和 synthesis 合并成一个节点——qa-judge 早期版本就是\
"既提修改意见又下终态判决"合一设计,导致过一次真实的无限循环事故(20 次调用/31 分钟才熔断,见\
deliverable.json 的反模式记录),这条教训必须在本骨架延续。",
"edges": [
{ "from": "{{orgNode}}-candidate-a", "to": "{{orgNode}}-critic-a", "condition": "success", "produces": ["contract"] },
{ "from": "{{orgNode}}-candidate-b", "to": "{{orgNode}}-critic-b", "condition": "success", "produces": ["contract"] },
{ "from": "{{orgNode}}-critic-a", "to": "{{orgNode}}-synthesis", "condition": "success", "produces": ["artifact"] },
{ "from": "{{orgNode}}-critic-b", "to": "{{orgNode}}-synthesis", "condition": "success", "produces": ["artifact"] },
{ "from": "{{orgNode}}-synthesis", "to": "{{orgNode}}-validator", "condition": "success", "produces": ["artifact"] },
{ "from": "{{orgNode}}-candidate-a", "to": "{{orgNode}}-candidate-a", "condition": "fail", "edgeKind": "backward" },
{ "from": "{{orgNode}}-candidate-b", "to": "{{orgNode}}-candidate-b", "condition": "fail", "edgeKind": "backward" },
{ "from": "{{orgNode}}-synthesis", "to": "{{orgNode}}-candidate-a", "condition": "fail", "edgeKind": "backward" }
]
}
⚠️ 以上是未经 validateGraph/work-graph-skeletons.test.js 实测的草稿,backward 边、fail 兜底边
的具体挂法(尤其 synthesis 失败该退回哪个候选,还是退回两个候选的公共上游)需要按 workgraph-planning/
agent.md 约束三(每个非入口节点至少一条不带 failReason 的兜底边)与约束五(backward 边判定)逐条
过一遍才能定案,本文档只给方向,不做最终结构校验。
关键设计决策:critic 和 synthesis 必须是两个不同节点
这不是本文档凭空要求,是仓库里已有真实事故记录——system/agents/qa-judge/ 是仓库唯一一个"既提
修改意见又下终态判决"的合一设计先例,system/work-graph-templates/deliverable.json 的
dataContractNotes(第 6 行)明确记录了一次真实故障:org-hunt 套 executor.json 后误选中
qa-judge,critic/judge 合一导致无限重复确认,最终判 infra_flake,烧了 20 次调用 / 31 分钟才
被熔断拦下。同一份文档同时留了正面先例:validator-triager(只归因不判定)与 benchmark-validator
(只打分不算总分,算术交给不跑 LLM 的 goal-contract.js)——这两个都是"评价类角色拆分"的既有范式,
新的 critic/synthesis 分工应该照这个模式设计:critic 只给评语和分数,不下终态;synthesis 只做择优/
融合决策,不重新评分。
三、命名(按 27-naming-conventions.md §3.1/§3.2)
| 层 | 名称 | 依据 |
|---|---|---|
| Work Graph 节点 | {父org节点全名}-candidate-a/-candidate-b、-critic-a/-critic-b、-synthesis |
§3.1:Work Graph 节点带父节点全名前缀 |
| System Agent 本体(candidate) | 不新增,复用宿主领域已有的实现类 agent(比如 org-coder 场景下就是 org-coder 本体本身,跑两次、走两个不同 session scope,见 27-P4 §4.2 的多实例隔离机制) |
候选不是新角色,是同一个实现角色跑两次不同方案,不需要新本体 |
| System Agent 本体(critic) | candidate-critic(不带前缀) |
§3.2:本体不带前缀,避免同一本体因前缀被迫复制成多份 |
| System Agent 本体(synthesis) | candidate-synthesis(不带前缀) |
同上 |
候选节点为什么不需要新本体:候选做的是"用不同方法解决同一个问题",这本质上是同一个实现角色
(比如 org-coder)被调用两次、每次给不同的方法论提示("方案 A 用递归实现,方案 B 用迭代实现"这类
差异化指令可以放在节点的任务描述里,不需要两个不同的本体)。这与 27-P4 §4.2 已经落地的"同一 system
agent 的多实例隔离"(session-pool.js 的 scope 参数)正好对上——两路候选各自拿到独立 session,
互不污染上下文,机制已经具备,不需要新代码。
避坑:system/work-graph-templates/README.md:210-212 列出的 6 个命名冲突 id(agent-creator/
digester/evolver/evolver-youtube-crawler/innovator-* 系列)不能用;critic/synthesis 这两个
职能词目前在 27-NAMING 速查表里没有先例,需要在正式立项时补进 §七 速查表,避免未来又冒出"judge"/
"reviewer"这类近义词造成混淆(triager vs validator 已经因为语义邻近踩过一次坑,见 27-NAMING §3.5)。
四、workgraph-planning 选型判据(新增,未定案)
参照 planner.json 五节点裁剪判据表(workgraph-planning/agent.md:181-233)的成功模式——那张表训练
前只给"你被允许裁剪"这句空泛授权时打分 34/100,训练出具体的信号+阈值判据表后才到 100/100。新骨架的
选型判据必须避免重蹈"同义反复式空泛授权"的覆辙,至少要在两处补齐:
- 骨架自身的
whenToUse字段(已在 §二草稿里写了初版,需要经过同款训练/评审流程收敛,不能只 凭这份草稿直接上生产)。 workgraph-planning/agent.md新增一条硬规则,给出"要不要开竞争候选、开几路"的具体信号词和 阈值——候选参考信号:- S1:验收标准是否已经客观可判定(有明确的正确性/性能基准,不是主观描述)——
否则不该开竞争, 应该先把验收标准搞清楚,这是另一个问题。 - S2:该子任务此前是否已经因为"方案有问题需要打回重做"触发过 backward 边——如果是,说明单次尝试 成功率确实低,竞争候选可能划算;如果从未撞过,不该凭空开竞争(这条呼应 49 号 §2.4 的开放 问题 4:"目前没有实证需求")。
- S3:候选数 N——没有代码层硬顶(见 §五),判据必须给出建议范围(比如 2-3 路),避免 LLM 现场 漫无边际地开出过多分支。
- S1:验收标准是否已经客观可判定(有明确的正确性/性能基准,不是主观描述)——
这条判据表本身要不要现在写、写成什么样,属于"立项时才需要拍板"的内容,本文档只指出"必须有"和 "不能是空泛授权"这两条硬要求,不代本节写最终版本。
五、预算与并发风险(量化数字,来自 2026-09-04 代码核实)
advanceBatch的并发上限取run.max_concurrency,缺省DEFAULT_MAX_CONCURRENCY = 5(server/services/work-graph-db.js:62)。checkBudget(server/services/graph-engine.js:3029-3044)只在取出候选之后、真正 claim 之前 查一次,判定的是"当前已花是否达到上限",不是"这一批 claim 之后会不会超支"。也就是说,如果预算 只剩 3 次调用余量,但这一轮一次性取出了 5 个 ready 候选(默认并发上限),5 个都会被 claim 并真正 跑起来——实际消耗可能超出预算上限,超出幅度最多是maxConcurrency - 1(默认最多多花 4 次调用), 下一轮checkBudget才会拦下后续批次。- 对竞争候选设计的直接影响:如果一次性并行展开 N 路候选(N ≤ 5 会被一次性全部 claim),预算消耗是
N 倍(候选节点 + 各自的 critic 节点,粗算一次三节点竞争至少是 6 个 agent 调用:2 候选 + 2 critic +
1 synthesis + 后续 validator),且这个倍数消耗不会被预算闸门提前拦住。立项时如果要控制这个
风险,需要考虑给竞争型子图单独设一个更保守的
max_concurrency,或者在workgraph-planning的 选型判据里对候选数 N 直接设建议上限(见 §四 S3)。
六、明确不做(本文档范围外)
- 不实现具体的
candidate-critic/candidate-synthesisagent 人设(agent.md/tools.md)——那是 立项后的工作,本文档只给分工原则(critic/synthesis 分离)。 - 不修改
work-graph-templates/README.md或27-naming-conventions.md补录新职能词——留给立项时做。 - 不实现 §四的选型判据表——只给了判据应该覆盖的信号维度,具体阈值/文案需要走跟
planner.json五节点 判据表同款的训练/评审流程才能定案,不能直接照抄草稿上生产。 - 不解决"候选数 N 没有代码层硬顶"这件事本身——如果立项,这可能是最先要补的安全阀,但本文档只指出 风险,不给实现。
七、与既有文档的关系
- 49-antigravity-inspired-parallel-verification-proposal: 本文档是它 §二 提案 A 的展开,结论一致——没有真实场景前不建议立项。
- 27-P4:本设计完全建立在它已完成的并行执行能力(
advanceBatch/ 多实例 session 隔离)之上,不需要 27-P4 补任何代码。 system/work-graph-templates/deliverable.json:critic/synthesis 分离的设计依据直接来自它记录的qa-judge真实反模式事故,本文档延续同一条教训。system/agents/validator-triager/、system/agents/benchmark-validator/:评价类角色"归因/打分/ 算术判定三者分离"的既有范式,是设计 critic/synthesis 分工时的直接参照。