46-mandatory-planning-and-task-decomposition.md 37.2 KB

46 · Planning 应作为每个任务的默认前置步骤,覆盖三类信息来源

状态: 📝 设计中——四个关键决策已拍板。Phase 0 已完成(2026-09-01 真实回归验证):链路能收敛、44 号文档修复确认生效,发现的独立缺陷已拆到 47 号文档 并修复。Phase 1 代码已实现(2026-09-02,见「Phase 1 实现记录」):新 agent subtask-planning + enqueueTaskRun 挂钩(收窄为显式 opt-in)+ 复用 R-9.3 任务级共享索引对接下游,单测覆盖,但还没做真实端到端回归(且过程中出过一次真实 CLI 子进程泄漏事故,已修复并加了测试环境防护,见该节)。Phase 2 已实现(收窄版,2026-09-02,见「Phase 2 实现记录」):经验检索(新查询能力,扫已雇 agent 的 dream 沉淀)+ 按需 deep research(图外调用 org-hunt,默认关闭),单测覆盖,同样还没做真实端到端回归。"历史同类 goal 检索"这条来源本轮明确收窄未做。Phase 3-5 涉及核心调度引擎范式级改动(任务池认领)+ 全新子任务级预算模型,风险量级不同,本轮不做,另起设计讨论 日期: 2026-09-01 触发场景: 用户复盘 43 号文档(goal 分解粒度)时,追问"为什么本地和线上所有公司的任务看板都没有子任务分解"。核实后发现:不是巧合或配置遗漏,acceptance_mode='itemized' 在当前系统里从未被真正触发并落库过一次——追问引出了比 43 号文档更大的架构缺口:43 号文档只解决"验收要不要拆细",而用户认为规划(把一件事拆成第一步/第二步/第三步)本身应该是每个任务默认必经的前置步骤,不是一个可选的、可以被判"不需要"的例外。 格式对齐 27-requirement.md/43-task-decomposition-granularity.md:原话照搬 + 结构化复述,现状调研另起一节。


原始需求(用户原话,一字不改)

所以,拆解任务计划这件事情是默认要做的。也就是说,我们做任何一个任务,其实都要有一个 planning(规划)的过程。

Planning 过程就是明确这个事情怎么做:第一步干什么,第二步干什么,第三步干什么。这个是一定要规划出来的。而这种规划来源于以下三个地方:

  1. 模型本身有规划能力。
  2. 来源于我们的知识库、经验库、memory 或 history。
  3. 来源于我们去做线上的 Deep Research。去研究怎么更好地实现这个过程,别人是怎么做的,线上有什么 know-how、有什么方法论,怎么做这件事情才是更优解。

比如说,我们怎么做一个视频:视频要不要生成分镜、生成脚本、修改编剧台词?最后怎么视频合成、怎么验证?这些方法论是需要有一个 planning 过程的,这个过程一定是要有的。所以,我们之前没有做任务分解,但并不代表这个事情在现实生活中不存在。既然我们之前的架构上有这个问题,那我们就必须要改变它。

也就是说,我们做任何一个 ORG graphy 或者是 work graphy 的时候,就应该先有 planning 的过程:

  1. 分解任务;
  2. 所有的 agents 围绕这个任务看板来工作,一层一层地接子任务;
  3. 子任务做完之后,再去做主任务的 validate。

人的工作是这样的,那多 Agent 的协同工作也应该是这样的。


结构化复述

拆成三条独立主张:

  1. 规划是默认前置步骤,不是可选判断——任何一个任务(goal / org graph / work graph 层面)在真正执行前,都必须先产出一份"第一步干什么、第二步干什么"的分解结果。当前架构里"要不要拆"是一次可以判"不需要"的例外判断,这一点本身就是缺陷。
  2. 规划的信息来源要显式覆盖三类:① 模型自身推理能力,② 内部知识库/经验库/memory/history,③ 外部 deep research(别人怎么做、行业 know-how、方法论)。三者不是互斥,是应该都被用上的三个输入源。
  3. 执行模型要围绕"任务看板"重新组织:分解出的子任务应该是 agent 们认领、逐层完成的对象;子任务做完之后再做主任务的 validate(先子后主,不是先给主任务判总分)。

现状调研(本次会话核实,基于 43/44 号文档 + 本次代码交叉核对)

结论:当前架构在这三条主张上都有真实的、具体的缺口,不是风格问题。逐条列证据:

1. 规划目前是"要不要拆"的保守判断,默认是不拆

system/agents/task-planning/agent.md Step 2bis(决定 acceptance_mode 的地方)原文态度:

判断错的代价是不对称的:错误地写 "itemized"(验收标准其实互相依赖)会让后续验收拆出没法独立成立的子任务,比漏写、保守选 "holistic" 的代价更高。拿不准就留 "holistic"。

这与"规划是默认动作"直接相反——现在的默认值是"不规划到子任务颗粒度",只有信心足够时才拆。而且这一步只回答"验收要不要拆",从不回答"这件事第一步干什么、第二步干什么"这种通用意义上的 planning。

2. 规划阶段被显式禁止使用知识库/深度调研

system/agents/task-planning/tools.md「你不该用的工具」表格原文:

| 联网搜索、读第三方资料 | 拆分的唯一真相来源是 goal 描述原文。去外面找依据,等于给自己发明需求(违反 agent.md 硬约束 8) |

这条规则本身有合理的历史动机(防止 LLM 脱离用户原话臆造需求),但结果是:用户设想的三条规划来源里,第 2 条(知识库/经验库/memory/history)和第 3 条(deep research)在当前唯一的"goal → task"规划入口上被明文禁止,规划只能来自第 1 条(模型自身能力)。

值得注意:知识库/经验库这条路径不是完全空白——dream 机制(29 号文档)会把各 agent 的运行经验提炼后写回 agent.md/soul.md 的专属区块(本对话前半段刚看过 CEO 的这次刷新)。但这是事后单向沉淀:写给 agent 在被调用时"顺带看到",不是规划阶段主动查询的机制——task-planning 判断"要不要拆、怎么拆"时,完全不会去读任何 agent 的 dream 沉淀经验。

3. 已经存在一套真正做"deep research"的机制,但没有接入日常任务规划

system/agents/org-hunt(+ org-digest/org-evolve)是 41 号文档验证过的一套真实调研机制:用 l1-web-fetch 抓取网页、评估数据源权威性、产出方法论。这正是用户设想里"第 3 条来源"的现成实现,而且经过真实跑通验证(41 号文档"11 轮真跑挖出并修复 5 个独立缺陷")。

但它当前只服务于 FDE 方法论训练场景(org-innovator 评估/训练某个角色的专业能力),只在 deliverable.json 这一种 work-graph-template 骨架里被引用,从未被接入 task-planning 或 org-planner 的常规执行路径。换句话说:deep research 的能力已经造好了,只是没有被接到"用户下一个任务 → 系统怎么规划"这条主路径上。

4. 子任务目前只影响"验收",不影响"执行分工"

43 号文档的落地范围里明确记录了这条设计决策:

子任务要不要独立开发+验收循环 | 先只拆验收,开发仍整体完成——org-coder 一次性写完整个交付物,验收侧改成按子任务(验收条目)逐条判,而不是给总分 | 改动小得多……独立开发循环(每个子任务各起一个 work-graph run)留作后续再评估

用户这次的第 2 条主张——"所有的 agents 围绕这个任务看板来工作,一层一层地接子任务"——正是 43 号文档当时明确放弃、留待后续评估的那部分。现在看,"后续"就是现在。

5. org/work graph 是预先铺好的固定拓扑,不是"任务池、谁有空谁认领"

现有 org graph / work graph 是建图阶段(orggraph-planning/workgraph-planning)一次性规划出的 DAG,节点和边在执行前就已固定,执行时严格按拓扑推进。org-planner 没有任何"创建 task"的工具(43 号文档已核实),子任务是靠服务端在它产出 acceptance.md 之后物化出来的,不是 agent 从一个共享任务池里"认领"的。

用户"agents 围绕任务看板逐层接子任务"这句话,字面上更接近一个动态任务池 + 认领机制,跟"图在建图那一刻就已经画死"的现有模型有结构性差异——这不是一个小改动,需要先确认要不要走这个方向(见下节问题 C)。

6. 即便是现有最小范围的子任务机制,可靠性也还没被坐实

上一轮对话已核实:当前 data/graph.sqlite 里 acceptance_mode='itemized' 的 task 零条,所有公司运行态目录里都搜不到 itemized 字样——43/44 号文档做的那次真实验证用的测试公司数据也已被清理。也就是说,在讨论"要不要扩大规划范围"之前,现有范围内的东西本身还没有一次成功的端到端确认。


设计决策(2026-09-01 定案)

问题 决定 直接后果
A:规划打通到哪一层 新增独立的"深度规划"阶段,插在 task-planning(goal→task,保持极简不变)和现有 org-planner 之间 task-planning 职责不变(仍是"要不要多条 task"的粗粒度判断,3 轮内、不碰磁盘)。新阶段专门承接"这件事第一步/第二步/第三步怎么做"+ deep research + 查经验库,产出结构化的分解结果,取代现有"org-planner 收尾后才物化子任务"的时序——分解结果要在执行开始前就产出,而不是brd/prd/sdd写完后才回头拆
B:Deep Research 触发时机 规划环节自行判断——先查经验库/memory/dream 沉淀,查不到或置信度低时才触发调研(复用 org-hunt/org-digest) 新阶段需要两类工具权限:① 读 agent 的 soul.md/agent.md dream 区块 + 跨公司经验(目前没有现成的"查经验库"检索接口,需要新建);② 有条件触发 org-hunt(目前只能被 workgraph-planning 挑进固定模板,需要开放为"新阶段可按需插入")
C:执行模型 引入任务池 + 认领机制,替代当前"建图时固定 DAG、严格拓扑推进"的执行方式 这是四条里改动面最大的一条:graph-engine.js 当前是纯拓扑驱动(readDefGraph 一次性给出全部节点和边),需要新增"子任务作为可认领工作项"的调度层——agent(或调度器代 agent)从共享任务看板拉取匹配自己角色、状态为"可认领"的子任务,而不是等图上游节点产出后按边推给固定下游
D:验证时机 子任务拥有独立的开发+验证生命周期(这次和 A/C 一起做,不再分阶段) 每个子任务对应一次独立的开发→验证循环(而不是 43 号文档现状的"整体开发、分子验证"),意味着每个被认领的子任务大概率各自触发一次工作流实例(起类似 work-graph run 的调用),成本和并发编排复杂度显著上升,需要有预算/并发槽位控制(可复用 27-P3C 已实现的队列/并行槽位机制)

四条决策合起来的完整流程:

goal 创建
  │
  ▼ task-planning(不变,粗粒度)
  产出 1..N 条 task(draft)
  │
  ▼ 人工"全部下达"(不变)
  │
  ▼ 【新】深度规划阶段
  1. 查经验库/memory/dream 沉淀,看有没有可复用的方法论
  2. 置信度不够 → 触发 org-hunt/org-digest 做 deep research
  3. 结合"模型自身规划能力 + 查到的经验/调研结果",产出结构化分解
     ("这件事第一步做什么、第二步做什么…",形态类似 43 号文档的 acceptance.md
      但发生在执行前而不是收尾后,且不仅是验收条目,是完整的步骤清单)
  4. 把分解结果物化成任务看板上的一批"可认领子任务"(不是固定图节点)
  │
  ▼ 【新】任务池认领执行
  各角色 agent(org-coder / org-validator / …)按自己的角色,从共享看板拉取
  下一条匹配、状态为"可认领"的子任务 → 独立开发 → 独立验证 → 回写子任务终态
  │
  ▼ 汇总收敛
  全部子任务 completed → 父 task success;任一子任务 failed → 父 task fail
  (沿用 43 号文档已实现的父子终态汇总规则,未变)

已知的高风险点(老实写,别假装这是小改动)

  • 任务池认领是对现有图执行引擎(graph-engine.js)的范式级改动,不是加字段/加钩子能做到的。现有引擎的核心心智模型是"边决定谁在什么时候跑",任务池模型的心智模型是"角色决定谁能跑什么,时机由认领动作决定"——两者要并存(company 结构层的 org graph 显然还是要保留固定角色拓扑,不可能把 CEO/CTO 汇报关系也做成认领制),需要先明确任务池模型的作用域边界:只用于"深度规划产出的子任务"这一层,还是要往上影响到 work-graph 本身怎么跑。这个边界目前还没有定案,是 Phase 1 设计阶段必须先钉死的第一件事。
  • 43/44 号文档已经踩过一次"新机制先天有可靠性缺口"的坑(acceptance.md 未必被稳定产出,闸门只查私有目录不查共享区),且现有最小范围的子任务机制(43 号文档)在生产数据里至今零命中。在没有把现有范围坐实之前就叠加更大的改动,风险会累加而不是替换。
  • "每个子任务独立开发+验证循环"直接推高成本——一个 goal 可能因此从"1 次 work-graph run"变成"N 次子任务级 run",需要先有预算模型(每个子任务分到多少预算、超预算怎么办)才能不失控。
  • Deep research 的调用成本和可靠性——org-hunt 目前只在方法论训练场景验证过(41 号文档),没有在"日常任务规划、时间敏感"场景下验证过延迟和成功率。

技术实施计划(架构级阶段划分,未细化到代码行)

建议顺序:Phase 0(先坐实现有范围)→ Phase 1(深度规划阶段骨架)→ Phase 2(经验库检索 + deep research 接入)→ Phase 3(任务池认领)→ Phase 4(子任务独立开发验证循环)→ Phase 5(看板 UI)。理由:每一阶段都在前一阶段的地基上加一层能力,且允许在任何一个阶段暂停评估效果/成本,不是一次性大爆炸式改造。

Phase 0 · 坐实现有范围(前置条件,不是本文档新增范围)

在叠加新机制前,先补一次 43/44 号文档遗留的端到端确认跑——用真实公司走一遍现有 acceptance_mode='itemized' 全链路,确认它能稳定收敛。当前生产数据零命中,不能假设地基是稳的。

Phase 1 · 深度规划阶段骨架

  • 新增独立 agent(暂定 deep-planning,命名需过 27 号命名规范),接在 task-planning 产出 task、人工下达之后,org 图真正执行之前。
  • 先只做"模型自身规划能力"这一路(用户三条来源里的第 1 条):产出结构化步骤分解,格式参考 org-planner 现有 acceptance.md 表格惯例,但覆盖"怎么做"而不仅是"怎么验收"。
  • 暂不接经验库/deep research,暂不接任务池——先验证"分解结果能不能被下游正确消费"这一步。
  • 明确任务池模型的作用域边界(上面"高风险点"第一条),写成本文档的补充小节,动 Phase 3 之前必须先定案。

Phase 2 · 经验库检索 + Deep Research 接入

  • 新建一个"查经验库"的检索能力——扫描相关 agent 的 dream 沉淀区块 + 历史同类 goal 的执行记录,给深度规划阶段用。这是全新能力,当前没有任何 agent 具备"主动查别的 agent 经验"的工具。
  • 打通深度规划阶段按需触发 org-hunt/org-digest 的路径(当前它们只能被 workgraph-planning 挑进固定模板,需要开放"按需调用"的口子)。
  • 验收:给一个"经验库有答案"的任务和一个"经验库没答案、需要调研"的任务各跑一次,确认分支判断正确、调研产出确实被规划阶段消费。

Phase 3 · 任务池认领机制

  • 范围先限定在"深度规划产出的子任务"这一层(不动 company 结构层的 org graph 固定拓扑)。
  • 新增"可认领子任务"的状态位与认领接口;调度器或各角色 agent 心跳时拉取匹配自己角色的可认领项。
  • 需要复用/扩展 27-P3C 已实现的队列与并行槽位机制,避免重新发明并发控制。

Phase 4 · 子任务独立开发+验证循环

  • 每条被认领的子任务触发独立的开发→验证生命周期(复用 work-graph run 的既有机制,而不是新发明一套)。
  • 预算模型:子任务预算怎么从父 task 预算里切分、超支怎么处理,需要单独设计(可能复用现有 wallclock/token 预算机制的分配逻辑)。
  • 父子终态汇总规则沿用 43 号文档已实现的逻辑(全 success 才 success)。

Phase 5 · 看板 UI

  • 任务看板要能展示"可认领池"状态(谁在等认领、谁已认领在跑),不只是现有的父子树形/表格展示。

Phase 0 实现记录(2026-09-01,真实回归已完成)

用真实(非 mock)测试公司 p0verify0901 走完一次完整的 goal→task→org 执行链路。测试公司数据未清理,留作证据(data/companies/p0verify0901/)。

结论:链路能收敛,44 号文档的修复确认生效,但发现一个新的、独立的真实缺口——acceptance_mode='itemized' 在当前 org-planner 子图形状下永远物化不出子任务,不是概率问题,是结构性打不通。这解释了 46 号文档「现状调研」第 6 条记录的"生产库零命中"现象:不是运气差,是这条路径已经失效。

验证结果

检查项 结果
task-planning 真实判定 itemized(未诱导、未重试,T-mtis98aq-8c7f)
goal-benchmark/planner-validator 是否真正跑完(44 号文档修复验证) ✅ 两者都 success,不再被误判 skip;contract.json 声明 produces.acceptance 指向共享 artifacts/ 绝对路径,闸门正确识别
acceptance.md 是否产出 ❌ 全程未产出,四个 org-planner 节点私有目录搜遍为空
子任务是否物化(parent_task_id 指向该 task) ❌ 0 条
coder-validator 是否逐条上报子任务结果 ❌ 未调用,走的是整体 holistic 判定(SUBTASKS_INCOMPLETE 闸门因为子任务本来就是 0 条而天然放行)
父 task 终态 completed(按 holistic 规则收敛,不是 43 号文档设计的"全子任务 completed 才 success"规则——因为没有子任务可供该规则生效)
回退/报错 零回退(backward_count 全程 0),零 fail_reason,全程 18 分 55 秒

根因

org-planner 名义上(agent.md/tools.md 文档)要交 brd.md/prd.md/sdd.md/acceptance.md 四份产物,但它是 nodeKind='subgraph',真正执行靠 workgraph-planning 现场规划的子图。这次真实规划出的子图是 org-planner-prd → org-planner-sdd → org-planner-benchmark → org-planner-validator(没有 brd-planning,也没有任何节点职责是写 acceptance.md)——org-planner-benchmark 产出的是 goal-benchmark.json(R-19-B 契约的 benchmark 段,44 号文档那套新机制),跟"子任务物化"依赖的 acceptance.md 是两套不同产物,已经对不上。graph-engine.js 里 maybeMaterializeItemizedSubtasks(约 2372-2417 行)扫不到 acceptance.md 时会静默降级为 holistic(设计上是"软失败不拖垮硬产出",出发点合理),但代价是这条路径悄无声息地形同虚设,没人会发现。

org-planner/agent.md、org-planner/tools.md 里"四份产物含 acceptance.md"的文档描述本身可能已经过时,没跟上 goal-benchmark.json/R-19-B 契约这套后来的机制。

遗留决策:这个新发现的 bug 怎么处理

已拆分成独立文档处理,已修复:见 47 号文档(acceptance.md 缺失时物化逻辑改读 goal-benchmark.json 的 dimensions[],2026-09-02,单测 5 条全过)。47 号文档末尾也记了一条需要 Phase 1 设计时想清楚的遗留点:这条兜底修的是旧的(43 号文档设计的)物化机制,Phase 1 打算把分解提前到执行开始之前,旧机制届时可能降级为安全网而不是主路径——不影响当下必要性,但 Phase 1 设计阶段要显式决定要不要保留它。


Phase 1 详细设计(2026-09-02,设计已细化,未实现)

命名

按 27-naming-conventions.md §二「规划类 agent —— {产出物}-planning」的既有惯例(brd-planning/prd-planning/sdd-planning 都按自己产出什么命名),新 agent 命名为 subtask-planning——它的产出物就是 subtask-goal(该规范 §一 作用域表里已经预留了这一级:"子任务的目标(一个 task-goal 分解出多个)"),命名轴完全对上,不用新造概念。

与 task-planning 的关系:task-planning 把 company-goal 拆成多条 task(= task-goal);subtask-planning 把一条 task-goal 拆成多条 subtask-goal——同一条命名轴上相邻的两级,职责边界清楚。

触发点:enqueueTaskRun(不改 task-scheduler 的排队逻辑)

server/routes/company.js:1099 enqueueTaskRun() 是 dispatch 时真正创建 org run 并把 task 标记 queued 的地方,紧接着会调用 writeTaskGoalArtifact() 写下这条 task 的验收边界产物。这是最合适的钩子位置——原因:

  • 不碰 task-scheduler.js:该文件的排队/占坑逻辑充满精细的并发不变式(本次设计阶段读代码时看到的注释密度就是证据),新增一道"等 subtask-planning 跑完才能出队"的阻塞闸门风险很高,且违反 33/44/47 号文档反复验证过的教训——软数据不能当硬闸门。
  • 异步、不阻塞:subtask-planning 在 enqueueTaskRun 内用 setImmediate 触发(照抄 runGoalSplit 现成的异步模式),跟 org run 的排队/起跑并行,不等它。多数情况下 subtask-planning 只是一次单轮 LLM 调用,会比 org run 真正排到执行位、org-planner 开始跑之前完成;即使没赶上,也只是这一轮 org-planner 拿不到分解方案参考,不是失败。

产出物:写共享 artifacts/ 区,不是私有目录

吸取 44/47 号文档的教训——产物必须落在下游查得到的地方,且格式要对已经证实稳定工作的机制友好。写入 runRootDir(run)/artifacts/subtask-plan.json,形状复用 47 号文档刚验证过的 goal-benchmark.json 风格(结构化、非 Markdown 表格,避免重蹈 acceptance.md 那种"文档说要写、实际没人写"的覆辙):

{
  "steps": [
    { "seq": 1, "title": "...", "why": "...", "depends_on_hint": null },
    { "seq": 2, "title": "...", "why": "...", "depends_on_hint": [1] }
  ],
  "reasoning_source": "model_only"
}

reasoning_source 字段是为 Phase 2 预留的("model_only" / "memory" / "deep_research"),Phase 1 恒为 "model_only"。

与 org-planner 的衔接点:软注入,不建硬依赖

org-planner 现在读的输入里已经有一套"P1 虚拟引用"注入模式(company-context.md,prompt-builder 直接拼进提示词,见 27-P1 文档)。subtask-plan.json 走同一种模式:prompt-builder 组装 org-planner 任务提示词时,检查这条 task 对应 run 的共享 artifacts/subtask-plan.json 是否存在,存在就拼进提示词一段"已有的分解参考(来自 subtask-planning,仅供参考,不是必须遵守的清单)",不存在就跟现在完全一样,什么都不加。不改 org-planner 的硬约束、不要求它必须使用这份参考——Phase 1 的验收标准只是"分解结果能被下游正确读到",不是"下游行为因此改变"(那是 Phase 1 完成后才评估的效果问题,不是这一步的实现范围)。

工具权限

比照 task-planning 的极简先例(该 agent 现在"大概率一个工具都不需要用"):v1 只给读权限(bash/read_file,无 str_replace),能读的输入是任务描述 + 公司 org graph 摘要(跟 task-planning 拿到的是同一批,首轮消息里给)。明确不给:创建/修改 task 的 API、创建/下达 run 的 API、招聘/改 org graph 的 API(原因与 task-planning 工具箱里那张"不该用的工具"表完全一致——落库是服务端的活,agent 只交结构化产出)。联网调研(Phase 2 才接)本阶段也不给。

Phase 3 前必须先定案的边界(呼应「已知的高风险点」第一条)

任务池认领机制的作用域明确限定为:subtask-planning 产出的 subtask-plan.json 里的 steps[],物化成 tasks 表里 parent_task_id 指向该 task、可被认领的行。不影响:

  • company 级 org graph(ceo/cto/org-planner/org-coder 这套角色拓扑,27-P2 已实现,继续保持人工固定/慢变/可审计);
  • workgraph-planning 现场规划出的 org node 内部 work graph(brd-planning → prd-planning → sdd-planning → ... 这类,继续保持固定 DAG)。

任务池只是在"task"和"当前这套固定的 org/work graph 执行"之间新插了一层——这层里的东西(subtask)才能被认领,图本身怎么跑不变。这条边界写在这里,是为了 Phase 3 设计时不用重新讨论一遍。

Phase 1 验收标准(后续真实回归要检查的)

  1. dispatch 一条 task 后,subtask-planning 是否被异步触发、是否产出了 subtask-plan.json?
  2. org-planner 的任务提示词里是否真的拼进了这段参考(不是"写了注入逻辑但没生效")?
  3. subtask-planning 没跑完/失败时,org-planner 这一轮是否完全不受影响(确认软注入的降级路径成立)?

Phase 1 实现记录(2026-09-02,代码已实现,未做真实端到端回归)

落地清单

内容 位置
新 agent 本体 subtask-planning system/agents/subtask-planning/{config.json,agent.md,identity.md,soul.md,tools.md},config.type='meta-planning'(复用 task-planning 同款分类,不进 org graph)
规划服务(含 CLI 调用 + 宽松解析归一化) server/services/subtask-planning.js——单轮调用、无重试、单条不合法数据丢弃不作废整批(与 task-planning 的严格写入前校验刻意不同,见 agent.md「你的产出是建议,不是指令」)
触发点 enqueueTaskRun(server/routes/company.js)新增 withSubtaskPlanning 参数,默认 false,只在两处显式传 true:/goals/:goalId/dispatch(批量下达)、/tasks/:taskId/enqueue(单条下达)。POST /:companyId/tasks(quick task,外部 agent 自主派发)与 /rerun 保持默认不触发——理由见下「设计比原计划收窄的一处」
产物 runRootDir(run)/artifacts/subtask-plan.json(共享区,47 号文档同款教训:不写节点私有目录)
与下游的衔接 登记进 graph_files(kind='subtask_plan'),纳入 graph-engine.TASK_SHARED_KINDS——复用 R-9.3 任务级共享机制自动出现在该 task 下任意节点的「上游输入」提示词段落,没有另写 prompt-builder 注入逻辑(比原设计「衔接点」一节设想的软注入方案更省事,见下)
测试 subtask-planning.test.js(12 条,纯函数解析/归一化)+ subtask-planning-materialize.test.js(4 条,共享区落地 + describeInputs 真的能读到)。全量单测 1558 passed,唯二失败与本次改动无关(改动前即存在)

与原设计的两处出入

  1. 触发点从"enqueueTaskRun 内部无条件触发"收窄成"调用方显式 opt-in"。原设计(本文档上一版)打算让 enqueueTaskRun 无条件触发,动手时撞上 goal-task-acceptance.test.js 的「验收 22」——它守着一条真实存在的产品保证:POST /:companyId/tasks(外部 agent curl 自主派发的快速任务,例子就是"把周报发出去"这种行政指令)必须零 LLM 调用,这是给 agent 间快速委派留的零成本通道。subtask-planning 无差别触发会直接击穿这条保证。改法:enqueueTaskRun 新增 withSubtaskPlanning 参数,默认 false,只在"goal 批量下达"和"单条 task 显式下达"这两个真正对应"人/系统郑重下达一条任务"的语义上打开。

  2. 与 org-planner 的衔接从"prompt-builder 软注入"改成"复用 R-19.3 任务级共享索引"。原设计打算专门给 org-planner 写一段"检查 subtask-plan.json 存在就拼进提示词"的注入逻辑。动手核实 graph-engine.describeInputs 的实现后发现:这个函数在 subgraph 节点上直接跳过(org-planner 本身是 subgraph),真正的消费者应该是它展开出的子图里那些 agent_call 节点(org-planner-prd/org-planner-sdd/…)——而这些节点已经有一套现成机制(TASK_SHARED_KINDS,任务级共享产物索引,acceptance/contract 已经在用)自动把"这个 task 下的共享产物"塞进任意节点的提示词,不受拓扑相邻性限制。把 subtask_plan 加进这个白名单,比另写一段注入逻辑更省代码、更少一个新的失败模式,而且覆盖面更广(org-coder 阶段的节点也能看到,不只 org-planner)。

⚠️ 一次真实的安全事故(写实话,别再犯)

第一版实现(enqueueTaskRun 内部无条件触发,未做任何测试环境防护)在跑 npx vitest run server/tests/unit 时,真实开出了 44 个 claude CLI 子进程挂在后台(ps aux 现场抓到,手动 kill 清理干净,未产生数据损坏,但存在真实 API 调用成本)。根因:task-planning/workgraph-planning 那套"默认走真实实现,测试要显式注入桩才安全"的设计前提,建立在"只有专门测规划逻辑的测试才会碰到这条触发路径"之上;subtask-planning 的触发点(enqueueTaskRun)被全仓库大量跟规划毫不相关的单测(测排队、测预算、测状态流转)顺带路过,这些测试从没想过要为一个新加的旁支功能注入桩。

修法:subtask-planning.js 的 planSubtasks() 新增一道防护——process.env.VITEST(vitest 对所有测试进程自动置位,通用判据不是我们发明的)为真、且没有人显式调用过 setPlanSubtasks() 注入时,直接跳过真实调用,返回空结果(等价于 47 号文档反复用到的软失败路径)。这是 subtask-planning.js 独有的防护,task-planning.js 没有、也不需要——它的触发面窄得多,从未出现过这个问题。加完防护后,全量测试(1558 条,含 integration/devloop)跑三遍,ps aux 确认零残留子进程。

遗留:还没做真实端到端回归

设计文档「Phase 1 验收标准」一节列的三条(① dispatch 后 subtask-planning 真的被触发并产出 artifact;② org-planner 展开的子图节点提示词里真的能读到这段参考;③ subtask-planning 没跑完时 org-planner 完全不受影响)——①③ 已经被集成测试间接覆盖(用注入桩验证了机制本身是对的),②的"提示词真的拼上了共享索引这一段"也已经用集成测试直接验证(describeInputs 真实读到 subtask_plan 并列进提示词)。没做的是:用真实公司、真实 goal、真实 Claude CLI 走一遍全链路,确认 subtask-planning 在真实调用下真的产出有意义的分解(不是机制通不通,是内容有没有用)——考虑到刚踩过的真实 CLI 子进程事故,这次真跑验证需要更谨慎地控制范围(单个任务、有人盯着、跑完立刻检查有没有残留进程),不建议顺手跑,值得单独作为一步来做。


Phase 2 实现记录(2026-09-02,收窄版,代码已实现,未做真实端到端回归)

用户原话要求"把 Phase 2-5 一次性做完"。动手前先做了一轮代码调研,发现文档字面描述掩盖了真实工作量落差:dream(29-DREAM)只单向写回经验,没有任何可查询索引;"R-19.3 共享索引"是笔误(实指 TASK_SHARED_KINDS/R-9.3,跟经验库无关);org-hunt 只能作为图节点被 workgraph-planning 动态选中,没有图外可调用入口;Phase 3(任务池认领)是"改动面最大的一条",要给纯拓扑驱动的 graph-engine.js 并行引入认领制调度层;Phase 4 需要全新的子任务级 run + 预算模型;Phase 5 在 3/4 落地前没有真实"可认领池"状态可展示。跟用户对齐后,这一轮只做 Phase 2(收窄版),Phase 3-5 涉及核心调度引擎范式级改动 + 全新预算模型,风险量级不同,另起设计讨论。

落地清单

内容 位置
经验检索(新模块) server/services/experience-lookup.js——queryExperience({companyId, task}):查这家公司已雇佣 agent 的 memory/experience.md(dream 沉淀),关键词重叠打分(中文用双字滑窗近似分词,不引依赖)。命中为零是真实信号("查不到"),不是异常
按需 Deep Research(新模块) server/services/deep-research.js——triggerDeepResearch({companyId, task, topic}):图外直接 AgentManager.callAgent('org-hunt', ...),轻量提示词,不套用 org-hunt 训练场景的三件套契约。默认关闭(ENABLE_DEEP_RESEARCH 环境变量,不为 '1' 直接返回 null,连注入的假实现都不调用)
subtask-planning.js 两段式改造 defaultPlanSubtasks:先查经验库拼进提示词 → 调一次 agent,agent 自评 confidence → 经验为空或 confidence:"low" 就触发调研 → 有结果就带着调研结果再调一次取代第一轮。reasoning_source(model_only/memory/deep_research)由服务端根据实际发生的分支算出,不是 agent 自报的。新增更细粒度注入点 setSubtaskAgentCaller(仿 dream-service.setDreamAgentCaller),能测到这段编排逻辑本身,不只是测"落盘"那一层
subtask-plan.json 增补字段 reasoning_source/experience_refs/research_used,纯增量、向后兼容旧的注入桩(缺失时兜底 model_only/[]/false)
system/agents/subtask-planning/agent.md 输出契约加 confidence 字段(硬约束 9),补充"你可能会看到两种提示词"一节
测试 experience-lookup.test.js(6 条)、deep-research.test.js(6 条,含"关闭开关时哪怕注入了假实现也不调用"这条最重要的安全阀)、subtask-planning.test.js 扩展(extractConfidence + buildSubtaskPlanningPrompt 的经验/调研小节,7 条新增)、subtask-planning-materialize.test.js 扩展(新增字段落盘 2 条 + defaultPlanSubtasks 三条分支编排 4 条)。全量单测 1177 条,1175 passed,唯二失败(.env.example 覆盖 + 测试 id 稳定性)与本次改动无关、改动前即存在。测试全程 ps aux 确认零残留 CLI 子进程

与原设计的出入

  1. "历史同类 goal 执行记录"这条来源本轮不做——只做 agent 经验区块检索。原设计的用户原话把"经验库/memory/dream 沉淀"和"历史同类 goal 检索"并列成一条来源,但后者需要语义检索基础设施(当前没有),贸然上关键词匹配对"同类"这种判断噪音会很大。这是范围收窄,不是遗忘,留给以后需要时再评估怎么做语义检索。
  2. Deep research 复用 org-hunt,但用轻量提示词,不套用它的训练场景三件套契约(knowhow_raw.md/crawl_config.json/seed_data.json ≥50 条)。原因:那套契约是为 FDE 训练场景校准的,直接套用在"人在等一条 task 入队"这种时间敏感场景会不可控地慢。org-hunt 本身的图节点契约、deliverable.json 模板都没动。
  3. Deep research 触发默认关闭(ENABLE_DEEP_RESEARCH 环境变量)。org-hunt 的延迟/成功率在"日常任务规划、时间敏感"场景下从未验证过,且 Phase 1 已经因为一个新触发点疏于隔离出过真事故。这跟 Phase 1 withSubtaskPlanning 默认 false 是同一个谨慎级别——机制已实现且单测覆盖,但真实调用需要用户手动开关、挑单个任务验证。

遗留:还没做真实端到端回归

跟 Phase 1 一样,机制通不通已经用注入桩验证(三条 reasoning_source 分支、经验命中/未命中、调研开/关/成功/失败都有独立测试覆盖)。没做的是:真实开一次 ENABLE_DEEP_RESEARCH=1,挑一个真实任务,确认①经验检索真的能从生产环境的 dream 沉淀里查到有用内容(目前多数本体 dream 还没攒够料,可能长期查不到,这是预期状态不是 bug);②org-hunt 用轻量提示词跑起来的真实延迟、真实调研质量;③两轮调用叠加后的真实 token/时间成本。不在本轮自动测试范围内,需要用户后续单独决定何时验证。