复杂任务怎么做的任务拆分?为什么要拆分?效果如何提升?
任务拆分(Task Decomposition)是把一个说不清、做不完的大目标,变成若干个边界清晰、可独立验证的小步骤。 它不是为了"看起来更有条理",而是同时解决四个硬约束:上下文容量、错误定位、并行加速、失败恢复。
1. 结论:拆分是为了"把不可验证变成可验证"
一个任务能拆好,标准只有一个:每个子任务都有明确的完成判据。 "研究一下竞品"不是子任务,"抓取 A 产品定价页并输出 5 个价格档位"才是。判据清晰,才能自动判定成败、才能重试、才能并行。
2. 机制:三种拆分方式
① 按阶段(Stage)—— 串行,适合流程型任务
调研 ──▶ 提纲 ──▶ 撰写 ──▶ 校对 ──▶ 交付
② 按数据(Data)—— 并行,适合批处理任务
┌─ 文档 1 ─┐
输入集合 ──┼─ 文档 2 ─┼─▶ 归并 ──▶ 结果
└─ 文档 3 ─┘
③ 按目标(Goal)—— 依赖图(DAG),适合工程型任务
[读需求] ──▶ [设计接口] ──┬──▶ [实现 handler] ──┐
└──▶ [写单测] ────────┴──▶ [联调]
真实任务通常是混合的:先按目标拆成 DAG,每个节点内部再按数据并行。
3. 拆分粒度:四条判据
| 判据 | 合格 | 不合格 |
|---|---|---|
| 可验证 | 有断言、有 schema、有明确产出物 | "尽量做好" |
| 单职责 | 一个子任务只改变一件事 | 同时改代码和写文档 |
| 上下文自足 | 给定输入即可独立完成 | 必须看完整对话才能开工 |
| 规模适中 | 1~3 次模型调用能完成 | 需要 20 步 |
粒度太粗会跑偏,太细会丢上下文且成本暴涨。实践中按"一次能可靠完成"来切,宁可 5~8 步,不要 30 步。
4. 代码:让模型输出可执行的计划
计划必须是结构化的,否则无法调度、无法重试、无法并行。
PLAN_SCHEMA = """输出 JSON:
{"steps":[{"id":"s1","goal":"...","depends_on":[],"acceptance":"可判定的完成条件",
"tool":"可选工具名","output_key":"产物键名"}]}
最多 8 步;无依赖的步骤会被并行执行。"""
def make_plan(task: str, llm) -> dict:
raw = llm(f"{PLAN_SCHEMA}\n任务:{task}")
plan = json.loads(raw)
assert len(plan["steps"]) <= 8, "步骤过多,容易失控"
return plan
def execute(plan: dict, run_step) -> dict:
done, failed = {}, set()
pending = list(plan["steps"])
while pending:
ready = [s for s in pending if all(d in done for d in s["depends_on"])]
if not ready: # 依赖成环或前置失败
raise RuntimeError(f"无法推进,剩余:{[s['id'] for s in pending]}")
results = parallel_map(run_step, ready) # 无依赖步骤并行
for step, res in zip(ready, results):
if not res["ok"]:
failed.add(step["id"])
pending.remove(step) # 失败单独处理,不阻塞其他分支
continue
done[step["output_key"]] = res["value"]
pending.remove(step)
return {"outputs": done, "failed": sorted(failed)}
acceptance 字段是整个设计的心脏:调度器可以拿它去跑断言,而不只是相信模型的"我完成了"。
5. 拆分带来的效果提升来自哪
| 提升点 | 机制 | 量化口径 |
|---|---|---|
| 准确率 | 每步上下文只含必要信息,干扰少 | 端到端任务成功率 |
| 可恢复 | 失败只重跑单步,不用从头再来 | 平均重试成本 |
| 延迟 | 无依赖步骤并行 | 端到端 P95 耗时 |
| 可调试 | trace 精确到步骤 | 平均定位时长 |
| 成本 | 小模型跑简单步骤 | 每任务 token 成本 |
注意成本并非单调下降:拆得太细,每步都要重复带系统提示,总 token 反而上升。所以拆分后要做一次"步骤合并"复盘。
6. 常见追问
问:怎么决定拆多细? 用"失败重试的代价"反推:单步失败重跑很贵,就拆细一点;单步本身很便宜,就合并。另一个实用信号是上下文占比——单步所需上下文超过窗口 30%,就该继续拆。
问:子任务之间怎么保证一致? 用契约(Contract):上游产出结构化的产物(JSON/文件),下游只读产物不读对话;接口型任务先定 schema 再各自实现,最后由一次集成校验兜底。
问:计划中途发现错了怎么办? 重规划(Replan):保留已完成的产物,把"已完成 + 失败原因 + 剩余目标"重新喂给规划器,只重排剩余步骤。不要全量重来。
问:拆分的效果怎么证明? 固定评测集,对比拆分前后的成功率、平均步数、token 成本三项。只报成功率不报成本,容易得出"拆得越细越好"的错误结论。
小结
任务拆分把"一个大而模糊的目标"变成"一组小而可验证的步骤",收益来自上下文收敛、错误隔离、并行和断点恢复。判断拆得好不好,看每个子任务有没有明确完成判据;控制成本的关键,是在拆分后再做一轮步骤合并与预算核算。