大家好,我卡颂,专注于AI助力程序员转型 (阅读我的更多思考)
在2025年的当下,"Coding Agent
(比如Cursor
、Windsurf
、Cline
、Trae
...)可以一键生成Demo
项目"这一点已经毋庸置疑。
但在老项目中使用Coding Agent
开发(尤其是大型复杂项目)还会遇到不少挑战,比如:
-
改代码越改越乱
-
忘记之前的对话
-
遇到bug陷入反复修改的死循环
本文会分析以上问题出现的原因,并给出一种解决办法。
问题的根源
在2025年的当下,编程能力 已不是制约Coding Agent
的瓶颈。
问题的根源在于LLM上下文限制造成的信息缺失。
举例,假设项目中存在如下User
TS类型报错:
ts
Type '{ name: string; }' is not assignable to type 'User'.
Property 'age' is missing in type '{ name: string; }' but required in type 'User'.
我们希望Coding Agent
在理解:
-
User
类型的设计初衷 -
对项目产生的影响
后,再修复其类型报错(而不是粗暴的仅修复报错)。
为了完成任务,Coding Agent
会调用多种内部工具,产生多个执行步骤。
以Cline
举例:
- 读取
User
类型定义文件
-
使用内部工具:
read_file
-
参数:
{path: "types/index.ts"}
-
目的:获取
User
类型的具体定义,比如:
ts
// types/index.ts
export type xx = {
name: string;
age: number;
};
- 搜索
User
类型在项目中的使用
-
使用内部工具:
search_files
-
参数:
{path: "项目目录", regex: "User", file_pattern: "*.ts"}
-
目的:查找
User
类型在项目中的使用情况,比如:
ts
// src/components/ChatPage.tsx
import { User } from '@/types';
const ChatPage: React.FC = () => {
const [user, setUser] = useState<User>({ name: 'John', age: 30 });
// ...
};
-
结合报错信息以及1、2步得到的信息,得出修复方案
-
修复类型报错
使用内部工具:replace_in_file
- 参数:
{path: "src/components/ChatPage.tsx", diff: //如下}
ts
<<<<<<< SEARCH
const [user, setUser] = useState<User>({ name: 'John' });
=======
const [user, setUser] = useState<User>({ name: 'John', age: 18 });
>>>>>>> REPLACE
在执行上述步骤过程中,会产生大量信息,比如:
-
项目背景信息
-
完整执行步骤
-
执行具体步骤产生的新信息(比如
User
的定义、使用User
的代码、报错信息...) -
Agent
内部信息(比如内部工具的定义)
上述信息会共同存在于Coding Agent
背后使用的LLM
上下文中。
当前,主流LLM
的上下文长度及对应极限字符数、代码行数如表:
模型 | Token 上限 | 对应字符数 | 紧凑代码行数 | 复杂代码行数 |
---|---|---|---|---|
Claude系列 | 200k | 600k | 12,000 | 30,000 |
Gemini-2系列 | 1M | 3M | 60,000 | 150,000 |
DeepSeek-V3 | 64k | 192k | 3,840 | 9,600 |
Qwen2.5系列 | 128k | 384k | 7,680 | 19,200 |
在应对复杂项目的Coding Agent
多轮执行时,随着上述提到的信息不断积累,会迅速占满上下文。
有很多策略能阻止上下文被占满,比如:
-
简单粗暴的截断之前的信息
-
用总结的信息替代原始信息
但不管怎样,都或多或少会造成信息丢失,进而出现开篇提到的几种问题。
为了应对上下文被信息占满 ,主流Coding Agent
都会限制一次任务中请求的次数,比如Cursor
、Cline
的限制是20次:
解决办法
解决办法说起来很简单,就两点:
-
限制一轮任务产生的信息在上下文窗口范围内
-
在多轮任务之间共享信息
我以Cline
这款开源Coding Agent
举例如何做到上述两点。
对于Cursor
这样的闭源商业产品,背后可能内置了类似机制。
如何限制?
如何限制一轮任务产生的信息在上下文窗口范围内呢?
其实只要知道如下两点就能办到:
-
当前任务已经占用多少上下文
-
完成当前任务总共会占用多少上下文
第一点很好解决 ------ Cline
会为每个任务显示Token消耗量 、上下文窗口占用量。
比如下图,执行任务初始化服务端,增加prisma、postgresql 用中文回答我,已经消耗2.2m token,占用 63.4k上下文。
距离上下文极限 1m 还早,可以放心继续执行任务。
对于第二点,Cline
提供了两种工作模式:
-
计划模式:针对用户提问,生成完整执行计划
-
执行模式 :根据计划模式产出的计划,按步骤执行
比如下图是Cline
针对上述初始化服务端任务列的计划:
熟练的工程师可以评估这份计划的执行难度。
如果计划过于复杂,可以让Cline
继续拆解子任务,直到你评估当前任务能在上下文窗口范围内完成。
如何共享信息?
如果每个子任务都对应新的上下文窗口,后面的任务如何知道之前的信息呢?
比如,当我们评估下图步骤2需要进一步拆解为红、绿框中的子任务:
当红框子任务完成后,开启新对话窗口,如何知道:
-
当前已经完成什么?
-
接下来要做什么(绿框任务)?
这个问题再发散点 ------ 在大型复杂项目中,Coding Agent
不同任务之间如何共享必要的信息?
这里要介绍Memory Bank。
这是Cline
团队提出的概念,帮助LLM在不同任务之间共享项目信息。
简单来说,这是一套用于Coding Agent
的提示词,定义了附加在Coding Agent核心逻辑上的外挂逻辑,提示词包括两部分内容:
-
存储的目录结构
-
完整工作流
Memory Bank存储目录结构
Memory Bank
会在项目目录下创建memory-bank
目录,包含6个文件:
- projectbrief.md - 项目基础文档,定义核心需求和目标
- productContext.md - 项目存在的原因、解决的问题、工作方式、用户体验目标
- activeContext.md - 当前工作重点、最近更改、下一步计划、活跃决策
- systemPatterns.md - 系统架构、关键技术决策、设计模式、组件关系
- techContext.md - 使用的技术、开发设置、技术约束、依赖关系
- progress.md - 已完成内容、待构建内容、当前状态、已知问题
文件之间通过mermaid
格式定义了从属关系:
Memory Bank完整工作流
上面提到,Cline
包含计划模式 和执行模式。
启用Memory Bank
后:
-
在计划模式中,
Cline
会在计划前,根据文件从属关系检索memory-bank
目录,根据任务类型了解必要的信息 -
在执行模式中,
Cline
会根据当前进展更新memory-bank
目录下的文件
这样,在执行任何任务前,Coding Agent
都有项目的必要信息。
总结
造成当前Coding Agent
不能全面在大型复杂项目中使用的核心原因是LLM上下文限制造成的信息缺失。
为了解决这个问题,需要:
-
在多轮任务之间共享信息
-
限制一轮任务产生的信息在上下文窗口范围内
其中,1 可以通过Memory Bank
保存信息。
2 可以在Agent
执行任务前,利用LLM
将复杂大任务拆解为简单小任务。
其中,拆解后的必要信息也会保存在Memory Bank
。
需要强调的是:
Memory Bank
只是一种理念
不一定局限在编程领域。比如,编程学院 一文提到将该理念应用在教学上。
不一定用本地文件存储。比如,memory-bank-mcp通过MCP
方式调用Memory Bank
。
- 不止是
Cline
在使用
Cline
是开源项目,我们可以很方便分析他的执行逻辑。
更多闭源Coding Agent
也会使用类似实现,只不过他们没有对外暴露。