# 跨 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 平级存放。内容方法论(不含代码): 1. 节点边界怎么划:一个节点 = 一次独立的、有明确输入输出契约的 Work Node 执行(一次 `claude -p` 调用)。任务小到一次调用就能完成时不需要拆图(呼应需求文档第 6 节约束)。 2. `edge_type` 怎么选:`zero_token`(纯聚合/规约,不需要 Agent 推理,比如"把三份判断投票汇总")vs `needs_judgment`(下游需要真正读懂上游内容才能继续,比如"PRD 依赖 BRD 的实际内容")。 3. 如何识别可并行的候选点:如实列出每对节点之间是否存在真实数据流动——没有数据流动就不要加 `depends_on`,G 会自动把它们并发调度。 4. 每个节点必须自带 `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-graph` Skill 的方法论,把 `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`(mock `claude` 子进程返回一个"给三个独立模块各自补单元测试"的真实场景响应)。 - 证明该 `graph_manifest` 经 `topological_layers()` 分层后,三个节点确实落在同一层(跟 G 的实现直接挂钩,不是空谈)。 - 证明 `generic_node_prompt_builder` 生成的 `build_prompt` 能驱动 `run_graph()` 端到端跑完(mock `execute_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 场景"给三个独立模块各自补一个单元测试",用于验证机制可用性,不接入真实生产路径。