怎么让AI在大型复杂项目中不拉垮

1,809 阅读7分钟

大家好,我卡颂,专注于AI助力程序员转型阅读我的更多思考

在2025年的当下,“Coding Agent(比如CursorWindsurfClineTrae...)可以一键生成Demo项目”这一点已经毋庸置疑。

但在老项目中使用Coding Agent开发(尤其是大型复杂项目)还会遇到不少挑战,比如:

  • 改代码越改越乱

  • 忘记之前的对话

  • 遇到bug陷入反复修改的死循环

本文会分析以上问题出现的原因,并给出一种解决办法。

问题的根源

在2025年的当下,编程能力已不是制约Coding Agent的瓶颈。

问题的根源在于LLM上下文限制造成的信息缺失

举例,假设项目中存在如下UserTS类型报错:


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举例:

  1. 读取User类型定义文件
  • 使用内部工具:read_file

  • 参数:{path: "types/index.ts"}

  • 目的:获取User类型的具体定义,比如:

// types/index.ts
export type xx = {
  name: string;
  age: number;
};
  1. 搜索User类型在项目中的使用
  • 使用内部工具:search_files

  • 参数:{path: "项目目录", regex: "User", file_pattern: "*.ts"}

  • 目的:查找User类型在项目中的使用情况,比如:

// src/components/ChatPage.tsx
import { User } from '@/types';

const ChatPage: React.FC = () => {
  const [user, setUser] = useState<User>({ name: 'John', age: 30 });
  // ...
};
  1. 结合报错信息以及1、2步得到的信息,得出修复方案

  2. 修复类型报错

使用内部工具:replace_in_file

  • 参数:{path: "src/components/ChatPage.tsx", diff: //如下}
<<<<<<< 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系列200k600k12,00030,000
Gemini-2系列1M3M60,000150,000
DeepSeek-V364k192k3,8409,600
Qwen2.5系列128k384k7,68019,200

在应对复杂项目的Coding Agent多轮执行时,随着上述提到的信息不断积累,会迅速占满上下文。

有很多策略能阻止上下文被占满,比如:

  • 简单粗暴的截断之前的信息

  • 总结的信息替代原始信息

但不管怎样,都或多或少会造成信息丢失,进而出现开篇提到的几种问题。

为了应对上下文被信息占满,主流Coding Agent都会限制一次任务中请求的次数,比如CursorCline的限制是20次:

限制一次任务中请求20次

解决办法

解决办法说起来很简单,就两点:

  1. 限制一轮任务产生的信息在上下文窗口范围内

  2. 在多轮任务之间共享信息

我以Cline这款开源Coding Agent举例如何做到上述两点。

对于Cursor这样的闭源商业产品,背后可能内置了类似机制。

如何限制?

如何限制一轮任务产生的信息在上下文窗口范围内呢?

其实只要知道如下两点就能办到:

  1. 当前任务已经占用多少上下文

  2. 完成当前任务总共会占用多少上下文

第一点很好解决 —— 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个文件:

  1. projectbrief.md - 项目基础文档,定义核心需求和目标
  2. productContext.md - 项目存在的原因、解决的问题、工作方式、用户体验目标
  3. activeContext.md - 当前工作重点、最近更改、下一步计划、活跃决策
  4. systemPatterns.md - 系统架构、关键技术决策、设计模式、组件关系
  5. techContext.md - 使用的技术、开发设置、技术约束、依赖关系
  6. progress.md - 已完成内容、待构建内容、当前状态、已知问题

文件之间通过mermaid格式定义了从属关系:

Memory Bank完整工作流

上面提到,Cline包含计划模式执行模式

启用Memory Bank后:

  • 在计划模式中,Cline会在计划前,根据文件从属关系检索memory-bank目录,根据任务类型了解必要的信息

  • 在执行模式中,Cline会根据当前进展更新memory-bank目录下的文件

这样,在执行任何任务前,Coding Agent都有项目的必要信息。

总结

造成当前Coding Agent不能全面在大型复杂项目中使用的核心原因是LLM上下文限制造成的信息缺失

为了解决这个问题,需要:

  1. 在多轮任务之间共享信息

  2. 限制一轮任务产生的信息在上下文窗口范围内

其中,1 可以通过Memory Bank保存信息。

2 可以在Agent执行任务前,利用LLM将复杂大任务拆解为简单小任务。

其中,拆解后的必要信息也会保存在Memory Bank

需要强调的是:

  1. Memory Bank只是一种理念

不一定局限在编程领域。比如,编程学院 一文提到将该理念应用在教学上。

不一定用本地文件存储。比如,memory-bank-mcp通过MCP方式调用Memory Bank

  1. 不止是Cline在使用

Cline是开源项目,我们可以很方便分析他的执行逻辑。

更多闭源Coding Agent也会使用类似实现,只不过他们没有对外暴露。