☰
GSD:别让Agent在脏上下文里写代码,上下文清洗实战
2026/10/2 5:09:54 网站建设 项目流程

GSD:别让 Agent 在脏上下文里写代码

说实话,Agent写代码翻车这件事,我一开始是没有认真对待的。直到我连续三天看着同一个Coding Agent在我自己的项目里反复横跳:一会儿觉得这是个Python项目,一会儿又开始改package.json;刚跟它确认过用户需求是“导出报表”,它转头就在代码里写了一个导出PDF的逻辑。我当时的第一反应是“模型不行”,第二反应是“Prompt没写好”,直到我把Agent启动时携带的上下文全部导出来翻了一遍,才意识到问题根本不是模型,而是它在进入工作状态之前,就已经泡在了一团浆糊里。

这个项目,我给它起名叫GSD——最直白的理解就是“Get Stuff Done”,但实际上它是“帮Agent把代码写好”这件事本身的一场底层自省。GSD要解决的核心问题,不是让Agent变聪明,而是别再让它在脏上下文里写代码。脏上下文是什么?就是Agent每次调用时看到的那些系统提示、历史记录、检索资料、工具回写日志拼接而成的那一大堆文本。它们看似无害,实际上决定了Agent的所有后续行为。这个内容适合所有正在用AI辅助写代码的人看,尤其是那些已经发现“Agent偶尔能用、但经常不可控”的人,以及正在给自己搭建Agent工作流的开发者。本文我会把GSD的核心设计思路、上下文污染的几个主要来源、我做的一次完整清洗实操,还有排查过程中踩过的坑,全部摊开来讲。

1. 脏上下文到底“脏”在哪:先理解Agent眼里看到的到底是什么

1.1 Agent每一次写代码之前,都被迫“读”了一遍垃圾

很多人在调Agent时,以为它只是根据你最新的那条指令去写代码,其实不是。Agent在真正生成代码之前,它的模型上下文里已经被打包了一堆东西:系统提示词、任务目标、历史对话摘要、工具返回结果、目录结构,甚至上一次会话遗留下来的总结。这些东西合起来,就是Agent的“工作台面”。如果这个台面上堆满了过期的需求、重叠的指令和互相打架的资料,Agent写得越认真,错得越离谱。

我用GSD做性能对比的时候,有一个特别典型的案例:同一个代码生成任务,在干净上下文里的通过率接近八成;一旦把旧任务的工作日志、三条定向检索摘要、还有一长串工具调用历史都塞进去,通过率直接跌破两成。而且最神奇的是,Agent自己并不觉得有问题,它会很自信地把错误方案写出来,甚至还会在注释里写“根据上下文中的要求”。它对自己看到的垃圾没有任何判断力,这就是脏上下文的危险之处。

1.2 三种最常见的“脏形态”:冗余、冲突、过期

我把脏上下文归纳成三种形态,每一种的成因和处理方式都不一样。

第一种是冗余。最典型的就是把整个历史对话从头到尾都塞进上下文,或者系统提示里同时保留了好几套互相对齐但已经不需要的旧版规则。冗余的坏处不只是浪费Token,而是它会把模型对任务目标的注意力给稀释掉。理论上模型有“长程注意力”能力,但它在真正长上下文里还是会漏,而且漏得很有规律:越靠中间的指令越容易被忽略。

第二种是冲突。比如知识库里检索出来的三份文档,一份说方案A,一份说方案B,还有一份改了需求要说方案C。Agent拿到这些彼此矛盾的资料之后,最可能的处理方式不是停下来问你,而是自己“平均”出一个四不像的方案。这种问题在有RAG增强的Agent里特别常见。

第三种是过期。上一轮任务的目标、中间产物、临时方案,如果是同一套上下文机制被带进了本轮任务,过期信息就会像旧地图一样,明明标的是一条已经修好的路,Agent却以为那是施工中的路。过期信息最麻烦,因为它不会报错,它只会让Agent非常确定地走向错误方向。

1.3 为什么Agent自己察觉不到脏?

这个问题值得展开说。模型在做生成时,本质上是基于全部上下文信息做概率预测。它没有“主动校验”这个步骤,不会问自己:“这段历史和当前任务到底有没有关系?”所以即便是GPT级别的主流模型,也不会主动识别出上下文中的垃圾。它们更像一个超高速的阅读者,读到什么就理解到什么,理解了就顺着往下写。如果读到的信息是错的,AI最多只是输出不连贯,但在逻辑表面上它往往会显得极其自洽。

这也是GSD项目最核心的认知:与其改模型,不如改模型看到的东西。上下文干净,模型正确率自然提高;上下文脏,模型再强也拦不住它自己编。很多人把希望寄托在更强的新模型上,但在我做过十几组对比之后发现,模型能力提升带来的收益,远远不如上下文清洗带来的收益。模型你换一个,可能进步10%,但上下文洗干净,稳定度可能提升50%以上。

2. 上下文污染的四个主要来源:把“脏”给拆开看

2.1 会话历史:最大、最难防的一坨

会话历史是所有Agent上下文里最天然存在的部分。不管是ChatGPT还是Claude Code这类工具,当你跟Agent聊了二十轮之后,前面的对话已经被整体编码进了上下文。这里有个很容易忽略的问题:对话里既包含了你的真实需求,也包含了大量试错过程中的中间产物。比如你可能说过“先试试这个方法”,后来自己发现方法不对,改成“还是用另一个方案吧”。但对Agent来讲,最初的“先试试”依然占着一个权重很高的位置。

我的经验是:在代码生成场景里,历史对话携带的“噪音/信号比”会随轮数指数上升。第1轮到第5轮,上下文里基本都是有效信息;第5轮往后,修正、反悔、补充说明和无关闲聊的比例会迅速增加。GSD的做法很粗暴:把任何超过十轮的会话都打上“怀疑”标记,进新任务时要么重开话题,要么强制生成结构化的任务摘要,而不是直接把原文全带过去。

2.2 检索结果:来源多不等于信息好

带RAG检索的Agent是最容易把自己搞乱的。知识库检索出来的东西,在质量上是参差不齐的:有些是官方文档,有些是内网同事笔记,有些是已经被废弃的API文档。当这些互相矛盾的内容同时出现在上下文里时,Agent就进入了我们常说的“检索打架”状态。

我做过一个小实验:把同一个问题分别用一份高质量文档和三份低质量文档喂给Agent,结果模型明显倾向于生成包含所有文档观点的大杂烩。它不会主动做来源可信度排名。所以在GSD的流程里,检索结果在进入上下文之前,必须经过一道“归并”工序:相同主题、相同结论的内容先合并;过期或冲突的内容要么标记优先级,要么直接排除。检索这一步,质量永远比数量重要。

2.3 工具返回:日志和报错记录并不是给模型看的东西

这个问题在函数调用型Agent里尤其严重。很多工具返回值都是面向人类开发者的:大量的DEBUG日志、堆栈信息、JSON字段,甚至还有控制台彩色编码标记。这些东西如果被原样塞进上下文,模型会误以为这些是必须遵循的代码风格或业务逻辑。

我自己踩过的最蠢的一个坑:一个Python编码Agent在完成任务后,把一次正常执行时打印的WARNING信息当成了“用户要求解决的问题”,开始主动修复一个不存在的Bug。为什么?因为WARNING信息在上下文里紧挨着用户指令,模型分不清哪部分是工具噪音、哪部分是核心目标。后来GSD在工具返回层做了一道净化,把工具日志中的运行时信息默认丢弃,只保留下层状态变更和结构化返回值,这个奇怪行为就消失了。

2.4 系统提示词:不是写得越多越好

系统提示词是很多人最喜欢堆东西的地方。今天加一条“你必须遵守编码规范”,明天加一条“记得重视安全性”,后天再加一段“回答时请考虑部署环境”。大家都在疯狂往系统提示里塞规则,觉得规则越多越安全。但实际情况是,规则堆积到一定数量之后,Agent对每一条的敏感性会显著下降,它不会每条都严格执行,只会抓住那些它认为更重要的内容。

我在GSD里做了一个值得参考的尝试:把系统提示词拆成“省流版”和“详细版”两级。省流版只有五到八条核心规则,按重要程度排序放在最前面;详细版则外置成一个文件,只在Agent主动查询时才进入上下文。对比下来,这个方法在很大程度上解决了规则太多导致的“规则稀释”。

3. GSD怎么做:一套给Agent做“上下文体检”的完整流程

3.1 第一步:把Agent看到的全部上下文导出并盘点

我建议开发Agent工作流的人,都至少做一次彻底的上下文盘点。方法是给Agent加一个环境变量,像这样:

export GSD_DUMP_CONTEXT=1

然后跑两三轮正常的任务,把每一轮启动时的上下文原始内容都dump下来。注意这里不是让你看转化后的模型输入,而是看最底层的拼接结果——系统提示、会话历史、工具返回等所有东西按顺序排列之后,才是Agent真正看到的内容。

导出之后,拿一个文本分析工具做基础统计:有哪些Token被反复提及?哪些冲突词汇出现频次很高?哪些段落和当前任务完全不相关?这一步的目的是“看见”,为后续清洗提供依据。我见过不少团队做了这个动作之后才意识到,自己以为很干净的Agent,实际上下文中有接近一半都是在重复上一次的任务内容。

3.2 第二步:给上下文分“区”,从源头切脏

真正可落地的上下文管理,不能靠模型自觉,而是靠结构隔离。我的做法是把Agent的上下文分为四个独立区域:

第一区是“系统前缀区”,只放当前任务的最终目标、核心约束、交付格式。第二区是“实时工作区”,放当前会话内新出现的信息,包括最新指令、工具返回、用户反馈。第三区是“历史摘要区”,只放对历史过程的压缩摘要,原始日志必须清走。第四区是“外部引用区”,放RAG检索到的文档,但这个区在进入上下文之前必须经过格式净化和冲突消解。

这四个区在物理上要是独立的,不然又会被模型当成一整锅粥。你可以用一个简单的JSON结构来标记分区:

{ "prefix": "...", "workspace": "...", "summary": "...", "references": [...] }

然后在把上下文交给模型之前,做一次拼接,并在每个分区起始处强制加一个“分区标记符”。这种处理看起来笨,但效果立竿见影。分区能很大程度防止不同来源的信息交叉污染。

3.3 第三步:编写清洗规则,建立“白名单”和“黑名单”

清洗规则是GSD的核心资产。我整理出来的规则很简单,但每条都来自实际踩坑:

黑名单规则包括:所有DEBUG/INFO级别的日志;所有历史任务的中间产物;所有工具调用的原始参数头;所有超过一个月且未被用户重新确认的业务规则;所有来自低优先级知识库的冲突文档。

白名单规则包括:用户最近一次明确表达的最终目标;经过结构化后的工具返回值;当前任务的文件变更清单;由高优先级文档生成的归并摘要。

清洗规则最好是配置化的,不要硬编码在代码里。不要一上来就写Python类来处理,我是用一个YAML或JSON文件管理规则,Agent的每次上下文构建都会先去读取规则文件。配成这样:

filters: - type: drop_prefix pattern: "DEBUG|INFO" - type: drop_expired ttl: 30d - type: merge_duplicate field: "topic"

这样做的好处是你可以随时调整规则,而不需要重新发布整个Agent框架。而且当团队成员对“什么该进上下文”有争议时,配置化可以把争议从代码评审变成配置文件评审,效率高很多。

3.4 第四步:在Agent运行中动态“扫尘”,不只是一次性清理

一次性清洗是不够的。Agent在对话过程中还会持续产生新信息,这些新信息如果不加约束,又会重新制造一个新的脏上下文。所以GSD里我加了一个“动态卫生检查器”,每次Agent调用工具之后、进入下一轮生成之前,都会自动执行一次短暂的上下文扫描。

这个扫描器做三件事:第一,检查是否存在需要过期淘汰的历史消息;第二,检查工具返回中是否有超过预设大小的原始日志,有就截断或剔除;第三,检查当前上下文总量是否超过设定阈值,一旦超过,就触发一次强制摘要过程,把早先的对话内容压缩成几百字的结构化摘要,替换掉原始长文。

我特意把扫描器设计成“每次激活时间限制在几百毫秒以内”,不能成为性能瓶颈。它更像是一个定时清垃圾的保洁员,而不是一个复杂的数据处理引擎。实测下来,动态扫尘在长会话场景里的收益非常明显,Agent错误的次数大幅下降。

4. 工具选型和场景适配:不是所有Agent都要同一套清洗方案

4.1 编码Agent和问答Agent,清洗策略完全不同

我在GSD实践过程中发现一个容易被忽视的事实:编码类Agent和问答/分析类Agent,它们对上下文质量的敏感点完全不同。

编码类Agent最怕的是“历史记忆混乱”。因为代码任务的每一个步骤都强依赖前一步的状态,如果Agent记混了变量名或者搞错了项目结构,后面的代码几乎全部作废。所以编码Agent的清洗重点是工作区隔离和历史摘要。

问答类Agent最怕的是“检索内容冲突”。因为它的主要任务是综合信息并给结论,如果参考文档互相矛盾,它既可能夹带私货,也可能左右摇摆。对这种Agent,清洗重点放在来源优先级和冲突标识上,尽量把互斥信息提前标记清楚,或者在进入上下文前就定好“以文档A为准”。

4.2 长会话场景:别让上下文总长度把你拖垮

很多人在设计Agent时会担心上下文窗口不够用。但我观察到,大部分项目真正的问题不是“窗口太小”,而是“窗口里装的东西很多都是垃圾”。与其想着换一个超长窗口模型,不如先解决垃圾囤积问题。

我在GSD里做了一个很糙但有效的指标:有效上下文密度。计算方法是“当前任务真正需要的信息量 / 总Token数”。把这个密度调高,比什么优化都管用。用数学语言描述就是:

有效上下文密度 = 核心任务相关Token数 / 总Token数

理想情况下,这个密度应该维持在0.5以上,低于这个值就要触发强制摘要。这里的“核心任务相关Token数”不需要精确计算,粗略估计就行,因为它的作用是提供一个触发阈值,而不是做精准测量。

4.3 轻量级方案:不依赖重型框架,也能做上下文卫生

有人一听“上下文管理”,就觉得要上LangChain、LlamaIndex这些重型框架。其实不需要。GSD的核心理念是轻量级、可以在已有的任意Agent框架外面套一层。哪怕你只是在Cursor、Codex这类工具外面写一层临时脚本,也可以实现。

以Codex CLI类工具为例,你可以写一个简单的包装脚本:

#!/bin/bash # gsd-wrapped.sh: 轻量级包装器 export CODEX_CONTEXT_FILE=/tmp/gsd_context.json python3 gsd_preprocess.py --input "$1" --output /tmp/gsd_clean.md codex --context /tmp/gsd_clean.md

这样你就能在进入Agent之前,先把输入上下文过一遍GSD清洗脚本。这原本是不需要改动Agent底层实现的。我个人觉得,先跑通这种轻量方案,比一头扎进复杂框架更靠谱,因为你先建立了对上下文的感知,才谈得上优化。

5. 实操实录:一场“脏上下文vs干净上下文”的对照实验

5.1 实验设计:同一任务,两种输入环境

为了验证GSD的方案是否有效,我做了一个比较简单的对照实验。实验对象是同一款开源编码Agent,任务是用Python写一个支持重试机制的HTTP请求封装函数。要求模块化设计,并包含简单单元测试。

对照组直接把Agent拉起来就跑,不做任何上下文清洗。实验组则先经过GSD的预处理流程:将系统提示简洁化、历史记录压缩为摘要、工具返回信息过滤掉日志。两边使用同样的模型版本、同样的温度参数和同样的生成轮次上限。

5.2 结果对比:差距比我预想的还要大

对照组的表现是灾难级的。Agent在函数定义里莫名引入了两个与本任务无关的依赖,还注释了一行“根据上下文分析,这个模块可能还需要支持异步”——没人让它做异步。更离谱的是,它写的单元测试里有三个断言是基于一个根本不存在的配置项。很明显,它从脏上下文的旧代码片段中“学到”了一些不存在的约定。

实验组的表现非常干净。输出代码完全符合任务描述,没有多余依赖,测试用例也全部基于真实存在的函数接口。唯一的小问题是它在重试逻辑里默认采用了指数退避,但没把这个策略写成可配置参数,属于灵活度不够,不算错误。

5.3 这个实验说明了什么?

说明一个很简单但有分量的道理:Agent写不出好代码,很多时候不是它能力不行,而是它看到的世界太烂。你给模型一坨脏数据,它回你一堆“脏逻辑”;你给它干净边界,它就能稳定发挥。这不是猜测,这是我做了多次同类的不同任务试验之后看到的稳定规律。很多时候我们抱怨AI写代码不靠谱,但真正该优化的是我们喂给它的数据线。

6. 常见问题与排查技巧:现实中踩过的坑,和建议的修法

6.1 清洗过头了,上下文太“薄”导致Agent失忆

有人看完我的方案后容易走极端,把所有历史记录都删掉,结果Agent进入“失忆”状态,连续对话逻辑全断。这是真实存在的副作用。

我的解法是给历史压缩设定一个底线:核心决策点必须保留。比如用户明确否决过的方案、已经确定的技术选型、命名约定,这些绝对不能从上下文里删除。你可以写一个决策点列表,在清洗时凡是命中决策点的内容一律保留,其余才走摘要流程。

6.2 工具返回值被误删,导致Agent拿不到关键字段

工具返回净化这一层,容易误伤。最开始我设定的是把超过一定大小的返回直接截断,结果一不小心把一些重要的数据字段也给截掉了。后来我把规则改成“按字段重要性保留”,先对工具返回做字段名校验,保留业务字段,丢弃日志类和状态码类的冗余信息。

建议所有做工具返回清洗的人,都先花半天时间把项目中所有工具的真实返回结构梳理一遍,做一个“字段优先级映射表”。这个表格看起来费事,但能避免很多莫名其妙的线上问题。

6.3 动态扫尘在超大上下文时延迟变高

动态扫尘的机制虽然轻量,但在上下文真的非常大的情况下,每次扫尘的时间也还是会累积。我的经验是给扫尘设一个触发频率上限,比如最多每三轮对话扫一次,不要每次工具调用后都扫。垃圾清理可以晚一点,但不能因为清理垃圾把正常流程拖垮。

6.4 常见问题速查表

现象可能原因建议处置
Agent反复确认已确认过的需求历史摘要缺失决策点补回决策点保留规则
Agent采用了过期的API用法检索文档未做优先级排序对知识库来源打权重标记
Agent写了很多无关依赖历史代码片段混入工作区对工具返回做字段级过滤
生成结果越来越长但质量下降上下文冗余密度过高触发强制摘要,压缩历史
多轮后规则遵守度明显下降系统提示词规则过多拆分为省流版和详细版两级

7. 让GSD方案持续生效:把它变成你的开发习惯

最后说点实际的。GSD不是一次性项目,它是一种持续性的开发习惯。光做一次上下文清洗没有用,因为Agent每天的输入都在变,知识库在更新,项目的代码结构也在演进。你如果不在Agent工作流里建立起一套常态化的上下文治理机制,过两周它又会重新脏起来。

我个人的做法是给每个Agent项目建一个“上下文卫生清单”,每周五下午花半小时检查一遍:本周新增了哪些工具?哪些历史记录已经过期?系统提示词有没有被不合适地膨胀?这个例行检查看起来不起眼,但它帮我挡住了很多原本会浪费一整天才发现的诡异Agent问题。上下文管理这个东西,你说它是技术也行,说它是习惯也行,但比起换个更强的新模型,它对写代码这件事的帮助其实更实在——至少在GSD这个项目上,我是实打实地体会到了这一点。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询