封面图
背景:IDE 简史
IDE 是开发者的工作环境。它将编辑器、编译器、调试器以及各类开发工具整合到一个统一的空间中。
在 IDE 出现之前的远古时期,开发环境是由一个个零散的工具组成。编辑、编译、链接、调试分别发生在不同程序中,开发者需要自己完成拼接。
这一局面在 Turbo Pascal(1983) 出现后发生了改变。Turbo Pascal 将编辑器、编译器和链接器整合为一个整体,面向 Pascal 语言提供端到端的开发体验。通过减少工具切换,显著提升了开发效率。
随后是 Microsoft Visual Studio(1997)。Visual Studio 引入了更完整的调试体系和项目系统,其核心模块 IntelliSense 可以基于语义提供代码补全和提示。这标志着 IDE 开始理解代码结构。
进入 21 世纪,IntelliJ IDEA(2001) 将“代码理解”推进到新的层级。通过全项目索引、精确的重构能力以及跨文件的导航,IDEA 将理解的范围从“当前文件”扩展到了“整个代码库”。
Visual Studio Code(2015) 则选择了不同的方向。VS Code 保持轻核心,将语言理解通过插件机制和LSP协议外包给外部插件。这一步将代码理解能力从 IDE 中解耦了出来,IDE 开始成为一个聚合上下文的平台。
在这一分化路径上,出现了两种截然不同的演进方向。
一条路线以 Cursor(2023) 为代表。Cursor 将语言模型深度嵌入 IDE 的各个环节,从代码生成、重构到调试,IDE 本身开始参与上下文组织,并主导与模型的交互。
另一条路线则以 Zed(2023) 为代表。Zed 保持编辑器的克制定位,将“思考”通过ACP协议外包给外部智能体,将智能体从 IDE 中解耦了出来。
在这种架构下,像 Claude Code(2024) 这样的代码智能体开始脱离 IDE 本体运行,独立承担代码理解、规划与执行的职责,而 IDE 退回到“观察、编辑与呈现”的角色。
今天的代码智能体正是在这一历史背景下出现的。代码智能体的价值,最终取决于它是否能在可控可重复的流程中工作,这也引来了一个新的问题 —— 如何为代码智能体设计一套可工程化的工作流程?
上下文管理
在一场对话中,智能体会维持一个上下文窗口,并且在每次推理时会把该窗口输入到模型中。窗口的长度是有限的,并且会随时间滑动 – 新的输入不断进入,旧的内容会被挤出窗口之外(但在实践中例如系统指示及 MCP 工具的关键上下文会被保护)。模型不会看到窗口外的内容,只基于当前窗口进行生成:
窗口由多种信息共同构成:
- 系统指示,用于定义全局行为与约束
- 用户输入,描述当前任务目标
- 工具调用,工具调用请求以及返回结果,一般为结构化数据
- 智能体输出,对用户任务的答复
在不微调模型的前提下,上下文窗口是模型进行推理的唯一输入来源,直接决定输出的质量。因此,需要有一套明确的管理方法确保模型在一个正确、完整、长度受控且信噪比足够高的上下文窗口下运行。
无管理
这里有一种朴素的做法:自由提问,并祈祷自己在反复询问中接近目标。在这个过程中,上下文完全依赖对话历史线形积累,并且按照笔者本人的经验,对话会在以下几个时刻崩溃:
- 对话长度失控,应用开始卡顿,上下文濒临溢出
- 对话内容失控,智能体反复道歉的同时不断给出离谱答复
失控发生时,一个补救的做法是:丢弃当前会话,重开一个新会话并在最初的提示词里加入更多的约束和指引,希望这一次能回到正轨。这种方法并没有真正解决上下文管理的问题,它只是通过反复重置上下文来掩盖上下文本身缺乏约束的事实。这种方法只适合短任务,对于复杂任务很容易使得对话走向失控。
上下文压缩
一个对上述方法的改进措施是进行上下文压缩:当上下文变得臃肿时,暂停当前对话并让智能体做一个总结:
把当前的对话总结成文档
progress.md,明确最终目标、当前采用的方案、已经完成的步骤以及正在解决的问题。
随后,在新的会话开始时输入:
阅读
progress.md。
这种方式对上下文进行了提炼,丢弃了大量临时、过程性的信息,包括:
- 多轮代码的修改与回滚
- 工具返回的大段 JSON 数据
- 各种日志
这些信息只在当下是必要的,但不需要长期存在于上下文中。最终的目标是把上下文提炼出稳定、可复用的结构化产物。不过,这种方式仍然是一种事后修正:只有在上下文变得臃肿之后,才通过总结来收拾残局。
子智能体委托
子智能体委托提供了另一种更为前置的管理策略。其核心思想是一些辅助性任务,例如文件搜索、代码理解,中间产生的细节信息并没有必要长期留存在窗口中,后续的推理也只是需要这些任务的最终结果。智能体接受到此类任务时,分裂出一个有独立上下文窗口的子智能体并把任务委托给它,子智能体完成任务后把最终结果返回到主智能体的上下文:
对种做法将这些任务的推理过程从主窗口中剥离了出来,提升了主窗口的信噪比的同时控制了总长度。
阶段化
通过阶段化工作流程,明确划分每个阶段的职责边界、输入与输出,将复杂任务拆解为 调研—规划—实现 三类基础阶段,并在阶段切换处引入人工审查,以避免决策混杂和上下文失控:
这一流程利用了上下文压缩进行阶段间的过渡。高噪声、探索性的工作被隔离在单独的上下文中,并通过子智能体委托完成。
调研
这一阶段的目标是搜集并确认事实,以建立对问题的准确理解,并输出一份调研报告。这一阶段通常涉及大量代码文件的查找、阅读与路径梳理。下文给出一份调研报告模版:
1 | # 调研报告:<调研主题> |
规划
这一阶段的目标是把之前的理解转化成可执行的操作序列,最终输出一份技术方案。下文给出一份技术方案模版:
1 | # <功能 / 缺陷> 实现规划报告 |
实现
这一阶段的目标是严格执行已确认的技术方案,按照既定计划逐步落地,并在每个步骤完成后进行对应的验证。
人工审查
每个阶段都会产出对应的文档或代码,这些产出都需要经过人工审查。审查的重点会随着阶段前移而提高:越靠前的环节,其结论和决策对后续影响越大,因此审查也应越严格。
换言之,应当重文档、轻代码——前期通过对调研报告和技术方案的严格审查,尽可能消除方向性错误;一旦进入实现阶段,代码改动本身反而更偏向执行与验证,其审查成本也相对可控。
代码库优化
在引入代码智能体之后,代码库中的文档不再只有一个受众。因此,需要对代码库文档结构做有意识的拆分。
README.md
README.md 的定位是面向人类的入口文档,其目标是帮助开发者快速理解项目,常见的章节包括:
- 项目简介
- 快速上手指南
- 基本使用方式
- 贡献指南
AGENTS.md
与 README.md 相对应,AGENTS.md 的定位是面向代码智能体的入口文档,其目标是提供精确的上下文,常见的章节包括:
- 架构介绍,列举关键模块与模块之间的职责边界
- 构建与测试命令,明确指出标准构建方式、测试入口以及常见组合命令
- 代码风格与约定,包括命名规范、目录约定、是否允许自动格式化等
- 测试流程,哪些测试必须通过
- 安全与限制,禁止修改的目录、敏感文件、外部依赖使用限制等
大部分代码智能体会约定性地读取 AGENTS.md,而不是让用户显示说明。虽然 README.md 通常也会被读取,但只有 AGENTS.md 被视为必须遵守的规则。