跨 Org Agent 的动态 Work Graph 设计能力——详细设计(SDD)
日期: 2026-08-06
性质: 详细设计,对应需求文档 docs/done/dynamic-work-graph-design-skill-requirements.md(条目 E,已确认)。回答该需求文档第 8 节的开放问题。
依赖:条目 G(docs/work-graph-parallel-execution-design.md)已实现——topological_layers()/run_graph() 已经在生产代码里。
状态: 设计草案,待评审后实施。
1. G 已经回答了 FR-2(并行分组字段格式)
需求文档 FR-2 留空的"哪些节点属于同一个可并行分组"字段格式,G 的实际实现给出了确定答案:不需要新字段。topological_layers() 完全靠 depends_on/edges 结构本身推导独立性——没有相互依赖的节点自动落入同一层,run_graph() 自动并发执行同层节点。Planning Skill 的方法论职责因此简化为:"如实表达真正的依赖关系,不要为了图好看而人为加上并不存在的 depends_on"(14 步版对照笔记"边是数据契约"这条原则的直接应用),不需要额外发明一个"parallel_group"标记。
2. 新 Skill:design-dynamic-work-graph
skills/design-dynamic-work-graph/SKILL.md,与 planning-requirement-expansion、code-task-development 等现有 Skill 平级存放。内容方法论(不含代码):
- 节点边界怎么划:一个节点 = 一次独立的、有明确输入输出契约的 Work Node 执行(一次
claude -p调用)。任务小到一次调用就能完成时不需要拆图(呼应需求文档第 6 节约束)。 edge_type怎么选:zero_token(纯聚合/规约,不需要 Agent 推理,比如"把三份判断投票汇总")vsneeds_judgment(下游需要真正读懂上游内容才能继续,比如"PRD 依赖 BRD 的实际内容")。- 如何识别可并行的候选点:如实列出每对节点之间是否存在真实数据流动——没有数据流动就不要加
depends_on,G 会自动把它们并发调度。 - 每个节点必须自带
task_prompt(该节点执行时使用的完整提示词,自包含,不依赖调用方另外拼接)——这是 Coder/Validator 场景与 Planner 场景的关键区别:Planner 的四个节点类型固定(brd/prd/sdd/benchmark...),下游代码用一个查表_DOC_PROMPTS[artifact_type]就能拿到提示词;Coder/Validator 的子任务没有固定的小词表,必须由 Claude 自己在规划阶段把每个节点的提示词写出来。
3. work_graph_plan.py 改造(FR-3)
不改动 Planner 现有路径:_PROMPT_TEMPLATE(brd/prd/sdd/benchmark 固定链)与 _normalize_graph_manifest 的 canonical-chain 强制逻辑完全保留,org_node == "planner" 时走原有分支,零回归风险。
新增:
_GENERIC_PROMPT_TEMPLATE:当org_node != "planner"时使用,要求 Claude 依据design-dynamic-work-graphSkill 的方法论,把goal_text拆成一个graph_manifest,每个节点除node_id/depends_on外必须包含task_prompt(自包含提示词);输出格式(fenced ``json 块)跟现有约定一致,复用同一套_extract_graph_manifest` 解析逻辑。plan_work_graph()内部按org_node == "planner"二选一模板,函数签名/返回值不变(需求文档非目标 #2)。generic_node_prompt_builder(graph_manifest):新增的公开辅助函数,返回一个build_prompt(node, outputs)闭包,直接读取node["task_prompt"](run_graph()的build_prompt约定不变,仍然是"给定 node + 已完成 outputs,返回这次调用的提示词")——之所以放在work_graph_plan.py而不是e2e_pipeline.py,是因为它跟生成侧的字段约定(task_prompt这个 key 名)强耦合,两者应该在同一个模块里维护,避免字段改名时两处不同步。
_normalize_graph_manifest 不需要改动——canonical-chain 强制分支本来就有 all(t in by_artifact_type for t in _CANONICAL_DOC_CHAIN) 前置判断,Coder/Validator 的动态图没有 brd/prd/sdd/benchmark 节点,天然不触发,其余的 id→node_id/depends_on 兜底逻辑对新路径同样适用,不需要区分。
4. Skill 接入 Coder/Validator
src/agent_profile.py::FRONTMATTER["coder"]["skills"]/["validator"]["skills"] 各自追加 "design-dynamic-work-graph"。.claude/agents/{coder,validator}.md 是从这里渲染出来的(render_agent_definition),不需要手改部署产物。
5. 验证范围(对应需求文档验收标准,按非目标 #1 收窄)
需求文档 FR-5/验收标准 1 优先级是"应该",且非目标 #1 明确"不要求第一版就覆盖 Coder/Validator 的全部真实工作场景,只需要证明机制本身走得通"。本轮实现范围:
- 证明
plan_work_graph(conn, "coder", ...)能生成一个正确带task_prompt、互不依赖节点的graph_manifest(mockclaude子进程返回一个"给三个独立模块各自补单元测试"的真实场景响应)。 - 证明该
graph_manifest经topological_layers()分层后,三个节点确实落在同一层(跟 G 的实现直接挂钩,不是空谈)。 - 证明
generic_node_prompt_builder生成的build_prompt能驱动run_graph()端到端跑完(mockexecute_work_graph)。 - 不改动
e2e_pipeline.py::implement_code()的现有单节点生产路径——那是更大的、需要独立评估的改动(如何决定"这个 Coder 任务复杂到该规划成图"本身就是一个开放问题,需求文档风险第 3 条已经点出),留给后续任务。
6. 回答需求文档第 8 节开放问题
- 新 Skill 命名:
design-dynamic-work-graph,目录skills/design-dynamic-work-graph/。 _PROMPT_TEMPLATE改造方式:按org_node二选一模板(Planner 固定链 vs 通用动态规划),不是让 Claude 完全自由决定 Planner 要生成哪些节点——Planner 那条链是"架构常量",如_normalize_graph_manifest自己的注释所说,不应该变成每次都不同。- FR-2 并行分组字段格式:不需要,G 靠
depends_on/edges结构自动推导(见第 1 节)。 - Coder/Validator 第一个接入场景:mock 场景"给三个独立模块各自补一个单元测试",用于验证机制可用性,不接入真实生产路径。