GSD 是一个用于通过 AI 编程智能体完成大型、多会话项目的系统。它不是用来做玩具演示的。也不是用来“给我建个落地页”的。它是为真正的项目而生的——那种包含许多文件、多个子系统需要相互通信、且规模大到没有任何一个智能体能在单个上下文窗口内完成的项目。
它所解决的问题描述起来很简单,但在实践中却极其残酷:智能体会随着时间的推移失去连贯性。它们会忘记三个任务前构建了什么。它们生成的某些文件虽然存在,但根本跑不起来。它们在每一轮对话中都要燃烧 token 重新阅读项目结构。它们在被中断后无法自行恢复,除非人类重新解释一切。而当某些东西崩坏时,也没有干净利落的方法可以回滚。
GSD 2.0 解决了所有这些问题。以下是它的工作原理。
层级结构:里程碑(Milestones)、切片(Slices)、任务(Tasks)
所有的东西都被分解为三个层级:
里程碑(Milestones) 是可交付的版本——即你正在构建的那个大目标。
切片(Slices) 是可以独立演示的垂直能力。不是“实现数据库层”(水平的),而是“用户可以注册并登录”(垂直的)。每个切片都有一个演示句式:“完成这个后,用户可以 ___。”如果你不能用人类可观察到的事物来填补这个空白,那说明这个切片的范围界定错了。
任务(Tasks) 是与上下文窗口大小匹配的工作单元。一个任务正好适合一个智能体跑完一次会话(session)。如果放不下,那就是两个任务。这是一条铁律,因为打破它正是智能体开始失去连贯性的源头——它们工作了太长时间,以至于早期的决策被压缩没了,上下文中污染了数十次旧的工具调用,模型的推理能力也随之下降。
这种层级结构不仅仅是为了组织。每一层都有特定的产物、特定的验证标准和特定的压缩机制,从而在不撑爆上下文的前提下,让下游的工作始终能获取到必要的信息。
边界映射:在实现之前先进行接口级思考
这可能是影响最深远的一项规划功能。
在规划一个里程碑时,每个切片都要声明它生产(produces)了什么,以及它从上游切片消费(consumes)了什么。不是含糊其辞的——而是具体的。包括函数、类型、接口、端点(endpoints),并附带名称。
S01 → S02
Produces(生产):
- types.ts → User, Session, AuthToken (interfaces)
- auth.ts → generateToken(), verifyToken(), refreshToken() Consumes(消费): 无 (叶子节点)
S02 → S03
Produces(生产):
api/auth/login.ts → POST handler
middleware.ts → authMiddleware() Consumes from S01(从 S01 消费):
auth.ts → generateToken(), verifyToken()
这就迫使智能体在编写实现代码之前先思考接口。当切片 3 正在被规划时,它不需要去猜测切片 1 构建了什么——边界映射准确地说明了有哪些东西可用,并且规划步骤会验证上游切片是否真的生产了映射中所声明的内容。
再也不会出现“切片 3 需要一个切片 1 从未导出过的函数”的情况了。再也不会对“什么已存在”抱有无声的假设了。契约是明确的,并且会被检查。
LLM 与确定性逻辑的剥离
这是核心的架构原则,也是该系统在 token 上保持高效与可靠的主要原因。
规则是:如果你能写一个 if-else 语句来保证它每次都被正确处理,那它就必须是确定性(deterministic)代码——而不是 LLM 推理。模型花在机械操作上的每一个 token 都是浪费的 token,并会引入故障模式。
确定性代码处理什么:
- 所有 git 操作(分支、检查点、提交、压缩合并、回滚)
- 所有状态转换(下一个任务、完成任务、完成切片、推进)
- 文件解析和格式化(读取和写入所有 markdown 产物)
- 目录脚手架(创建带有正确 frontmatter 的文件夹和文件)
- 状态推导(从磁盘上的文件重建当前位置)
- 上下文组装(加载摘要、预算 token、丢弃旧上下文)
- 静态验证(检查文件是否存在、导出是否存在、导入是否连接、存根是否被检测到)
LLM 处理什么:
- 将范围分解为切片(架构判断)
- 将切片分解为任务(范围判断)
- 编写必须具备的功能(理解哪些可观察的结果才是重要的)
- 与用户讨论灰色地带(解读意图)
- 在研究期间侦察代码库(判断相关性)
- 诊断验证失败的原因(溯因推理)
- 编写摘要(压缩发生了什么以及为什么重要)
- 真正地编写代码
LLM 做的是需要判断力的工作。确定性代码做所有其他的事情。智能体永远不会去构造一条 git 命令。它永远不会去解析 markdown 来弄清楚下一个任务是什么。它永远不会去格式化 frontmatter。它调用一个工具,获得一个结果,然后继续进行创造性的工作。
有两个工具暴露了整个确定性层:gsd_manage(18 个动作,用于状态、git、脚手架、上下文)和 gsd_verify(4 个动作,用于静态验证)。一次工具调用取代了原本需要模型去推理的 5-10 次 bash/read/edit 调用。
上下文修剪:为每个任务提供干净的窗口
这彻底改变了多任务执行的可靠性。
每个任务都会在对话中注入一条不可见的锚点(anchor)消息。在每次调用 LLM 之前,一个上下文钩子会将消息历史记录修剪回当前任务的锚点。
这在实践中意味着:任务 5 看不到任务 1-4 的 40 次工具调用。它看不到之前工作中的失败尝试、中间读取过程以及调试信息。它得到的是一个干净的上下文窗口,其中只包含它的任务计划、相关的上游摘要,别无其他。
如果没有这个机制,你就会遇到上下文腐烂(context rot)——这是多任务智能体工作的隐形杀手。在一个切片进行到任务 3 或 4 时,上下文窗口已经充斥着来自早期任务的陈旧工具输出。模型在四个任务前读取过的文件内容后来已经被重构了。早就被修复的问题的调试追踪记录。不再相关的构建和测试运行产生的数百行终端输出。模型不知道什么是当前的,什么是陈旧的——它们都只是窗口里的 token 而已。于是它开始基于过时的信息做决定。它引用了被重命名的变量。它遵循了被重构代码的模式。它避开了早期尝试过但失败的方法,尽管当时失败的原因现在已经不适用了。随着上下文中信噪比的崩溃,推理质量稳步下降。
这就是为什么大多数智能体系统在序列任务的第 3-4 个左右就会碰壁。并不是模型变笨了——而是上下文被毒化了。每一个新任务都拖着之前所有任务的探索、死胡同和中间状态的“尸体”。
锚点修剪彻底消除了上下文腐烂。每个任务都获得一个干净的窗口。上下文中唯一的东西就是当前的任务计划和精选的上游摘要。没有陈旧的读取,没有旧的工具调用,没有积累的噪音。任务 7 运行时的上下文质量和任务 1 完全一样。
上下文注入:零探索调用
在任务开始之前,系统会预先组装智能体需要的所有东西:
- 任务计划(目标、步骤、必须具备项)
- 依赖切片的压缩摘要
- 里程碑级别的上下文和决策
- 如果是恢复被中断的工作,则提供“从这里继续”的数据
这些都是自动注入的。智能体永远不需要使用 grep 查找项目结构,也不需要 read 状态文件来弄清楚自己在哪里,或者搜索以前的切片中构建了什么。如果它这么做了,那就是上下文组装坏了——那是个 Bug,而不是工作流。
目标是零探索(discovery)调用。智能体花在“我在哪、有什么、决定了什么”上的每一个 token,都是没有花在实际实现上的 token。
分形摘要:可扩展的记忆
当一个任务完成时,智能体会写一份结构化的摘要:构建了什么、做出的关键决策、修改的文件、建立的模式,以及下游工作应该知道什么。
当一个切片完成时,任务摘要会被压缩成切片摘要。当完成的切片足够多时,切片摘要又会被压缩成里程碑摘要。如果需要更多细节,每个层级都包含向下钻取(drill-down)的路径。
在规划切片 6 时,你不需要加载来自切片 1-5 的 15 份独立任务摘要。你只需要加载一份里程碑摘要——大概 200 行——其中包含核心信息:构建了什么、有哪些可用、该遵循什么模式、锁定了哪些决策。
注入上下文的摘要的 token 预算上限约为 2500 token。如果依赖链太大,最老和最不相关的摘要会被优先丢弃。里程碑级别的摘要优先级高于切片级别,切片级别优先级高于任务级别。
一条关键规则:永远不要对摘要进行再摘要(never summarize summaries)。每个摘要层级都是从下一层级加上实际代码状态重新生成的。切片摘要来源于任务摘要,而不是来源于先前切片摘要的压缩版本。这防止了当你不断压缩已经被压缩过的文本时所产生的复合信息丢失。
验证:以目标为导向,而非以任务为导向
“所有步骤已完成”不叫验证。检查实际结果才是。
每个任务都定义了“必须具备项(must-haves)”——这不是步骤的待办清单,而是可观察的标准:
真相(Truths) 是必须为真的行为:“用户可以使用电子邮件和密码注册。”“登录返回 JWT token。”“CLI 将结果输出到 stdout。”这些要求智能体实际运行命令、检查浏览器行为或读取输出以进行确认。
产物(Artifacts) 是必须存在且有真实实现的文件:src/lib/auth.ts —— JWT 助手,至少 30 行,导出 generateToken 和 verifyToken。不是“auth.ts 存在”,而是“auth.ts 存在,有足够实质的内容,并且确实导出了它应该导出的函数。”
关键链接(Key links) 是产物之间的连线:login/route.ts 从 auth.ts 导入 generateToken。middleware.ts 导入 verifyToken。这捕获了最常见的智能体故障模式——独立存在但实际上并没有相互连接的文件。
静态验证确定性地检查所有这些:文件是否存在、行数、导出检测、导入连线以及存根(stub)检测。存根检测器扫描 TODO 注释、FIXME 标记、return null、return {}、console.log 占位符、硬编码的空响应。一个返回空对象的 8 行代码文件是无法通过验证的。
除了静态检查,还有一个分为 4 层的验证阶梯:
- 静态验证——文件存在,导出存在,连线已连接,没有存根
- 命令验证——测试通过,构建成功,lint 干净
- 行为验证——浏览器流程有效,API 响应正确
- 人工验证——只有在智能体真的无法自行验证时,用户才会进行检查
每个任务都会选择它能达到的最高层级。智能体不会要求人类去检查它可以用 curl 命令验证的东西。
讨论阶段:行动前的对齐
这是系统中被严重低估的功能之一,也是为什么 GSD 能够在很大程度上放手运行而不会构建出错误东西的原因。
大多数 AI 编程智能体的核心问题是:你说“给我做个登录”,它们立马开始写代码。它们在头 5 分钟内做出了 30 个决定——session 存储还是 JWT,要不要邮件验证,OAuth 还是纯密码,重定向行为,错误信息格式——而你直到看着最终结果,纳闷它为什么和你想的不一样时,才会知道它们做出了哪些选择。
GSD 将讨论(Discuss)作为一个头等重要的阶段。在规划开始之前,智能体会阅读需求范围,识别出灰色地带——即存在多种合理方法,且你的偏好确实很重要的地方——并就这些问题采访你。不是泛泛而谈。它会生成针对具体决策的特定问题,并提供结构化的选项:“Session 处理:(a) 带有刷新轮换的 JWT,(b) 使用 Redis 的服务端 Session,(c) 你来定。”它是一个思考伙伴,而不是一个念核对清单的面试官。
使这种方式奏效的关键行为:
它跟随能量流动。 无论你强调什么,它都会深入挖掘。如果你花时间谈论错误处理体验,它就会提出更深入的相关问题。它不会机械地走完一个预定的列表。
它挑战模糊性。 “把它做简单点”会被怼回来。怎么个简单法?对用户来说简单?实现起来简单?以后扩展简单?智能体不会接受模糊的答案,因为模糊的输入会产生发散的输出。
它让抽象变得具体。 “带我过一遍使用流程。”“它在屏幕上实际看起来是什么样的?”“当它失败时会发生什么?”这些问题迫使在写下一行代码之前就把事情理清楚。
范围护栏防止偏航。 如果你提出了一个属于其他切片的功能,它会把这个想法记录为延后处理,并重新引导:“听起来这是一个新功能——我会把它记下来留到以后做。现在,让我们专注于认证流程。”
它的输出是一个 context.md 文件——一份结构化的记录,包含了每一个决定以及你的推理过程。这个文件会被注入到所有下游工作中:规划、执行、验证等等。当智能体在实现切片 2 的任务 4 时,它的上下文中仍然有你在讨论阶段做出的决定。它不会重新辩论它们。它也不会因为忘记了你说过的话而悄悄做出不同的选择。这些决定被锁定,并在整个流水线中流转。
这就是之所以能实现放手执行的原因。你在一个 10 分钟的对话中前置了对齐工作,随后的每个任务都会自动继承这些决定。而另一种选择——在智能体实现到一半时打断它以纠正航向——在 token 和时间成本上都要昂贵得多。
研究阶段:三思而后行
这也是可选的。在规划一个切片之前,智能体可以侦察代码库和相关的库文档。
它的输出是一个 research.md,包含两个防止最昂贵错误的章节:
不要手搓(Don't Hand-Roll) 指出了那些看起来简单但已经有现有解决方案的问题。“不要自己写 JWT 验证——用 jose。”
常见陷阱(Common Pitfalls) 记录了会出什么错、为什么、如何避免,以及危险信号。这取决于库文档、代码库模式和已知的故障模式。
这项研究会被注入到规划阶段,因此任务分解和必须具备项都考虑了现实世界的限制,而不是理想化的假设。
Git 策略:每个切片一个分支并使用 Squash Merge
每个切片都有自己的 git 分支。在该分支上,每个任务开始前都会有一个检查点(checkpoint)提交,验证通过后会有一次正式的提交。当切片完成时,该分支会作为一个干净的提交被 squash merge(压缩合并)到 main 分支。
Main 分支读起来就像一个更新日志:
- feat(M001/S06): verification + summarization + UAT
- feat(M001/S05): task execution + context pruning
- feat(M001/S04): milestone and slice planning commands
- feat(M001/S03): extension scaffold and command routing
- feat(M001/S02): state machine + deterministic operations
- feat(M001/S01): types + file I/O + git operations
每个切片一个提交。可以独立回退。该分支也会被保留下来以提供每个任务级别的历史记录——git log、git bisect、git blame 都可以针对这些细粒度的提交进行工作。
回滚非常直接:
- 糟糕的任务 → 在分支上
git reset到检查点 - 糟糕的切片 → 还原 main 分支上那个单独的 squash 提交
- 合并后 UAT 失败 → 修复任务放在一个
-fix分支上,然后 squash merge 为fix(M001/S01): what was fixed
用户永远不需要运行 git 命令。智能体通过确定性的工具调用处理所有的分支、提交、合并和归档。
从这里继续:在中断中存活
上下文窗口会结束。会话会超时。用户会按下 Ctrl+C。系统能处理所有这些情况。
如果一个任务被中断了——不管是因为压缩(compaction)、会话结束还是手动停止——系统都会写一个 continue(继续)文件,记录:
- 已经完成了什么
- 还有什么没做
- 在任务期间做出的决定(这样下一个会话就不会重新辩论它们)
- “氛围(vibe)”——什么是棘手的,需要注意什么
- 恢复时要做的第一件确切的事情
一个新的会话会读取这个文件,加载任务计划,将两者注入上下文,然后从它中断的地方准确地继续下去。这个 continue 文件在恢复时会被消耗掉——它是短暂的,而不是永久记录。
这与 Pi(Claude Code)的压缩事件挂钩,因此如果运行时自动压缩对话,continue 文件会在压缩发生之前自动写入。不会丢失任何工作。
UAT:自动生成“信任但要验证”的文档
对于任何使用 AI 编程智能体的人来说,都有一个令人困扰的问题:当智能体说“完成了”时,你到底怎么知道它是真的完成了?
你可以读代码。你可以检查文件存不存在。但对大多数人来说,真正的问题是:它真的按照我要求的那样工作了吗?我能不能去用一下,看看它承诺的功能到底有没有?
GSD 会自动生成这个。每次一个切片完成时,系统都会生成一份用户验收测试(UAT)脚本——一份人类可读的文档,确切地告诉你如何验证已构建的内容。这不是事后才想起来的补充。也不是你需要主动要求它才会提供的东西。它被内置到了完成流程中。完成一个切片,获得一个测试脚本。
这些不是实现细节。不是“验证 generateToken 返回一个有效的 JWT”——自动化验证已经检查过那个了。UAT 关乎的是作为人类的你所能观察到的东西:
测试:注册流程
操作:
- 打开 http://localhost:3000/signup
- 在邮箱字段输入 "test@example.com"
- 在密码字段输入 "password123"
- 点击 "Sign Up"(注册)
期望结果:
- 页面重定向到 http://localhost:3000/dashboard
- 标题显示 "Welcome, test@example.com"
- 刷新页面会让你保持登录状态
每一步都是一个可以复制粘贴的命令或特定的 UI 动作。每个期望结果都准确描述了你应该看到什么——不是“它应该工作”,而是具体的文本、具体的 URL、具体的行为。你永远不需要去疑惑“命令是什么?”、“我该去哪个页面?”或者“成功看起来是什么样子?”
测试源自该切片的演示句式和必须具备项,并与任务摘要中实际构建的内容进行了交叉验证。它们是连接“智能体说它完成了”和“我能亲眼看到它完成了”之间的桥梁。
而且关键的是,UAT 是非阻塞(non-blocking)的。智能体写好测试脚本,然后立即进入下一个切片。你可以在方便的任何时候进行测试——在切片之间、在里程碑结束时,任何适合你工作流的时候都行。如果你发现了问题,你告诉智能体,它会创建修复任务。无需等待。没有繁文缛节。就只是一份文档放在那里,你想什么时候去验证都可以。
在项目中的任何特定节点,你都会拥有一份针对每一个已完成切片的 UAT 文件。这是一份自动生成的书面记录,上面写着“这是构建好的东西,这是证明它的方法”。这不仅对建立信任有用——对项目上手、演示,以及在三个星期后回想这玩意儿到底是干嘛的,都非常有用。
为什么它有效
根本的洞察是,导致 AI 编程智能体不可靠的大部分原因,并不是模型本身生成的代码——而是围绕在它周围的所有事情。状态管理、上下文污染、失去连续性、git 操作中的机械错误、检查过程而不是结果的验证,以及因为复合压缩而丢失信息的摘要。
GSD 2.0 使所有这些都变成了确定性的。模型编写代码并做出判断。其他所有事情——状态转换、文件管理、git 操作、上下文组装、静态验证——都由 TypeScript 处理,要么正确运行,要么抛出明确的错误。
其结果是,这样一个智能体:
- 为每一个任务获取全新、相关的上下文窗口
- 永远不会将 token 浪费在机械操作上
- 产出可验证的结果,而不仅仅是完成的清单
- 透明地在中断和会话边界中存活下来
- 自动维护一个干净、可回滚的 git 历史
- 通过压缩来扩展其记忆,而不是重新读取一切
所有这些都由磁盘上的 markdown 文件支撑。没有数据库。没有外部服务。只有文件和 git。
GSD