首页
/ Spec Kit 复杂功能开发实战:用任务范围控制与子代理委派化解上下文窗口耗尽

Spec Kit 复杂功能开发实战:用任务范围控制与子代理委派化解上下文窗口耗尽

2026-09-03 18:52:46作者:苗圣禹Peter

当大型功能顺利走完 /speckit.specify/speckit.plan/speckit.tasks 三个阶段后,退化往往发生在 /speckit.implement 执行中途:随着上下文窗口逐渐填满,代理开始偏离计划、忽略任务甚至产生幻觉。本文基于 Handling Complex Features 展开,讲清楚这一问题的根因——上下文窗口耗尽——以及 Spec Kit 提供的四种递进式解法:按任务数量或阶段限制单次执行范围、指示代理使用子代理(sub-agent)委派任务、两者组合,以及最后的"Spec of Specs"分解策略。读完后你能够根据功能规模和所用代理的能力,选择一套无需任何工具链改动的上下文管理方案,让长实现过程稳定可续跑。

问题背景:为什么实现阶段会退化

Spec Kit 的核心流程是先由规格(spec)驱动生成计划与任务清单,再交给代理执行。前三个命令之所以稳定,是因为每次调用只处理一个相对完整的产物;而 /speckit.implement 需要在一个会话内持有整个功能的上下文。当单次执行试图把整个功能都装进上下文窗口时,模型会随着窗口填满而逐渐退化,典型症状包括:

  • 在长 /speckit.implement 运行中途丢失计划;
  • 忽略 tasks.md 中尚未完成的任务;
  • 出现幻觉,尤其是上下文压缩(context compaction)被触发的前后。

文档给出的结论是:修复方向不是让模型更强,而是控制每次执行的范围,让每一次调用都远远低于上下文限制。所有方案都建立在同一个机制之上——/speckit.implement 命令接受自由格式的用户输入,代理在继续执行前必须考虑这些输入。这意味着不需要任何工具改造,仅靠给命令附加一句话即可改变其执行范围。

机制基础:为什么"续跑"天然可行

从命令模板源码可以印证上述两个前提。

第一,用户输入是强制项。implement 命令模板开头即声明:

## User Input

$ARGUMENTS

You **MUST** consider the user input before proceeding (if not empty).

$ARGUMENTS 占位符会被展开为你在斜杠命令后附加的任意文本,模板明确要求代理在推进前必须考虑它——这就是"限制任务数量""委派给子代理"等指示得以生效的原因。

第二,任务完成状态持久化在文件里,而非会话里。模板第 8 步要求:

IMPORTANT For completed tasks, make sure to mark the task off as [X] in the tasks file.

也就是说,每完成一个任务,代理会把它在 tasks.md 中的 - [ ] 标记为 - [X]。下次再调用 /speckit.implement 时,代理重新读取同一份 tasks.md,自然会跳过已完成项、从未完成项继续。这正是"分批执行可以无状态衔接"的底层保证。

第三,tasks.md 本身自带可切分的结构。从 任务模板任务生成规则 可见,任务被组织为固定阶段:Phase 1 为 Setup(项目初始化),Phase 2 为 Foundational(阻塞性前置),Phase 3+ 为按优先级排列的用户故事(P1/P2/P3),最后为 Polish 收尾阶段;每个任务都有稳定 ID(T001、T002……),并带有 [P] 标记表示"可并行"(不同文件、无依赖)。阶段名、任务 ID 和 [P] 标记,就是后面四种方案中所有范围限定指令的操作对象。

另外,执行前的前置检查脚本也会验证 tasks.md 存在:implement 命令的 frontmatter 声明执行 check-prerequisites.sh --json --require-tasks --include-tasks,对应实现见 check_prerequisites.py,其中 --require-tasks 参数强制要求 tasks.md 已存在,--include-tasks 将其纳入 AVAILABLE_DOCS 列表供代理读取。

方案一:限制单次执行的任务数量

最简单的做法是不让 /speckit.implement 一次跑完所有任务,而是明确指示它提前停止。按任务 ID 范围限定:

/speckit.implement only execute tasks T001-T010, then stop and report progress

或者按阶段限定:

/speckit.implement only execute the Setup phase, then stop

这里的"Setup phase"直接对应 tasks-template.md 中的 "Phase 1: Setup (Shared Infrastructure)",而 T001-T010 则对应模板中示例任务的编号区间。执行结束后:

  • 已完成的任务在 tasks.md 中被标记为 [X]
  • 下一次 /speckit.implement 调用读取同一份文件,从断点继续;
  • 每次运行的上下文占用都被压在一个可控区间内,远离压缩触发点。

按"任务 ID 范围"切分适合任务粒度均匀的功能;按"阶段"切分更符合 tasks-template.md 中描述的依赖结构——Setup 无依赖可立即开始,Foundational 阻塞所有用户故事,用户故事阶段之间可以并行或按优先级顺序推进。先跑完一个阶段再验证,正好利用模板中每个阶段的 Checkpoint 设计。

方案二:指示代理使用子代理委派

如果你的编码代理支持子代理(例如 GitHub Copilot CLI 或 VS Code 的 GitHub Copilot 扩展),可以把单个任务的执行委派出去:

/speckit.implement delegate each parallel [P] task to a sub-agent

原理是:每个子代理获得的是一个聚焦的上下文——一个任务加上相关的计划摘录,而不是完整的功能上下文。这样主会话的上下文几乎不增长,压缩(compaction)永远不会在主会话触发。[P] 恰好是 tasks-template.md 定义的并行标记(不同文件、无依赖),天然适合并行委派;而 implement 命令模板 本身也要求"parallel tasks [P] can run together",两者在语义上完全对齐。

方案三:组合范围限定与委派

对于非常大的功能,把前两个手段叠加使用:

/speckit.implement execute only the Core phase, delegate [P] tasks to sub-agents

这样主会话只处理一个阶段的骨架与串行任务,阶段内的可并行任务 [P] 再分发给子代理。范围限定压低主会话的上下文压力,委派进一步压低单个任务在会话中的驻留时间,两者互为补充。

方案四:把功能分解为更小的规格(Spec of Specs)

单个阶段本身就已经压垮上下文时,前三招都不够用,此时应把功能拆分为若干可独立规格的子功能。每个子功能拥有自己的 spec.mdplan.mdtasks.md,各自走一遍完整的 specify/plan/tasks/implement 循环。

这就是 "spec of specs" 方法:先做一次分解路径(roadmap pass),把巨型功能拆成若干自包含的小规格;每个子规格小到足以在上下文窗口内完成整个循环。由于它引入了额外的规格维护开销,文档明确建议只保留给其他方法都处理不了的功能

完整操作流程(如何执行 roadmap 路径、roadmap 工件的结构、子规格如何双向链接回 roadmap、以及一个计费门户的完整示例)见 Spec of Specs。其中有几个要点值得注意:

  • roadmap 是刻意保持"浅"的:只命名和排序子功能,不做设计,设计留到各子功能的 /speckit.specify 中进行;
  • roadmap 是一个普通 Markdown 文件(功能级 epic 放 specs/<epic-slug>/roadmap.md,更大的横切 epic 可放顶层 ROADMAP.md),每行带稳定 ID、意图、范围边界、依赖与状态;
  • 子规格的 spec.md 开头一行回链 roadmap 条目(如 **Input**: Parent roadmap: specs/<epic>/roadmap.md → entry R3),roadmap 表格的 Sub-spec 列反向指向子规格目录,双向纯文本链接让追溯无需任何工具;
  • 若要并行构建互不依赖的子功能,可以使用独立的 git worktree,让每次运行都有隔离的 active-feature 状态;
  • 若某个子功能仍然过大,可以递归地给它再做一层 roadmap——只在上下文问题实际要求时才深入。

四种方案如何选择

文档给出的选择矩阵:

方案 适用场景
限制为 N 个任务或一个阶段 任何代理;最简单;不需要子代理支持
子代理委派 支持子代理的代理;最大化并行度
范围限定 + 委派组合 支持子代理的代理上的大型功能;兼顾两者
分解为更小的规格 单个阶段仍然过大、无法在一次运行内处理时

文档的建议顺序是:大多数情况下,限制每次运行的任务范围就是最简单的修复;当你的代理支持子代理且你希望并行时,再上委派;只有当一个阶段本身大到一次运行装不下时,才做规格分解。

这套阶梯与 Spec Kit 的整体设计理念一致:规格驱动开发强调多步精炼而非一次性生成(见 What is Spec-Driven Development),而复杂功能处理的本质,就是把"一次生成"进一步细化为"多次有边界、可断点续跑的小步生成"——边界来自 tasks.md 的 ID/阶段/[P] 结构,续跑来自文件化的 [X] 标记,扩展性则来自规格本身的分解。

小结

  • /speckit.implement 退化的根因是上下文窗口耗尽,修复手段是把每次执行范围压进上下文限制内;
  • 范围指示能生效,是因为 implement 命令模板 强制代理先考虑用户输入,且 check-prerequisites 脚本 保证执行前 tasks.md 就绪;
  • 断点续跑能生效,是因为任务完成状态以 [X] 形式持久化在 tasks.md 中,任务结构(阶段、ID、[P] 标记)由 tasks 模板 标准化;
  • 按"限制任务数 → 子代理委派 → 组合 → Spec of Specs 分解"逐级升级,优先选最轻的方案,把规格分解留给单阶段仍然过大的极端情况。
登录后查看全文
热门项目推荐
相关项目推荐