AI Agent 写代码为什么容易失控?核心不是 Prompt,而是上下文工程
生产级 AI Agent 写代码真正难的地方,不是怎么写一句更聪明的提示词,而是怎么管理它每一步看到的信息、能调用的工具、必须遵守的边界、以及做完以后怎么验证。
很多人第一次用 Coding Agent,都会经历一个很微妙的阶段。
一开始很惊艳。你丢给它一个需求,它会读文件、找依赖、改代码、跑测试,甚至自己修复报错。看起来像一个不知疲倦的初级程序员。
但多用几次以后,问题就来了。
它会把一个很小的 bug 修成一组重构;会为了让测试通过,顺手改掉测试本身;会读错项目里的旧实现;会把日志里的一行异常当成根因;更麻烦的是,它有时不是马上错,而是第一步小错,第二步补错,第三步把错误合理化。
很多人把这归因于一句话:Prompt 没写好。
这个判断不算错,但太浅。
生产级 AI Agent 写代码真正难的地方,不是怎么写一句更聪明的提示词,而是怎么管理它每一步看到的信息、能调用的工具、必须遵守的边界、以及做完以后怎么验证。
这件事现在有一个更准确的名字:上下文工程,Context Engineering。
Agent 和脚本的根本区别
脚本是确定性的。
你写一个脚本扫描目录、改文件、执行测试,它的控制逻辑在代码里。哪一步读文件,哪一步写文件,哪一步退出,都是人提前写死的。
Agent 不一样。
Agent 的控制逻辑有一部分交给了模型。它不是简单执行一段固定流程,而是在每一轮根据当前上下文决定下一步做什么。
一个最小的 Coding Agent,大概可以抽象成这样:
while task_not_done:
context = build_context(goal, repo, memory, tool_results)
action = model.decide(context)
result = tools.execute(action)
context.append(result)
verify_or_continue()
这个循环看起来简单,但危险也在这里。
因为 Agent 每一次决策,都依赖当时的上下文。如果上下文里混进了旧日志、无关文件、过期设计、错误假设,模型就会基于这些材料做出下一步判断。工具执行后的结果又会被塞回上下文,成为下一轮判断依据。
所以 Agent 的错误不是一次性错误,而是循环系统里的状态污染。
这也是为什么 Agent 比普通脚本更难管。
脚本最多是你写错了逻辑。Agent 是它会自己生成下一步逻辑,而且每一步逻辑都被上一轮观察影响。
写脚本时,我们主要关心代码有没有 bug。设计 Agent 时,我们还要关心:它看到了什么、没看到什么、误解了什么、被什么工具输出带偏了。
Prompt 只是启动参数,Context 才是运行时
很多人以为 Prompt 是 Agent 的大脑。
更准确地说,Prompt 只是大脑收到的一部分输入。
在真实的 Coding Agent 里,模型每一轮看到的内容远不止用户那句话。它通常还会看到系统指令、项目规则、目录结构、最近打开过的文件、搜索结果、命令输出、测试失败日志、历史对话、工具定义、长期记忆、当前 diff。
这些东西加起来,才是 Agent 的运行时状态。
这就解释了一个常见现象:同一句 Prompt,在不同项目里效果完全不同。
不是模型性格变了,而是上下文变了。
如果一个仓库有清晰的 README、明确的测试入口、稳定的模块边界、规范的错误日志,Agent 会表现得像一个靠谱同事。
如果一个仓库里到处是历史包袱、重复实现、过期文档、没有测试、命名混乱,Agent 很容易像一个刚入职又不敢问人的新人:它会努力推理,但推理材料本身就是脏的。
这也是为什么“给 AI 多塞点资料”不一定能提升效果。
上下文窗口不是无限工作台,它更像模型的注意力预算。你塞进去的每一段内容,都会和其他内容竞争注意力。高信号材料会帮它判断,低信号材料会稀释判断。
一个成熟的 Agent 系统,不应该把整个仓库一股脑丢给模型,而应该回答三个问题:
第一,本轮任务必须知道哪些事实?
第二,哪些材料只是可能有用,应该通过工具按需检索?
第三,哪些历史信息已经过期,继续保留只会制造噪声?
这就是上下文工程和提示词工程的差别。
提示词工程关心“怎么说”。上下文工程关心“让模型在什么时候看到什么”。
为什么 Agent 会越改越乱
Agent 写代码越改越乱,通常不是因为它不会写代码,而是因为循环系统缺少刹车。
一个典型失控链路是这样的。
第一步,Agent 读到不完整上下文。
比如你让它修一个接口超时问题,它只读到了 controller 和 service,没有读到网关超时配置,也没有读到调用方重试逻辑。于是它把问题判断成 service 内部性能问题。
第二步,它生成一个局部合理、全局错误的计划。
它可能会加缓存、改线程池、改 SQL,甚至重构方法。但真正问题可能只是网关配置和客户端超时不一致。
第三步,工具权限过宽。
如果 Agent 可以随意改文件、删文件、运行命令,它就会用“完成任务”的视角行动。模型不会天然知道哪些文件是业务核心,哪些脚本不能碰,哪些测试不能为了通过而修改。
第四步,观察结果被误读。
它跑了一部分测试,看到通过,就以为问题解决了。但局部测试通过不代表行为正确。更糟的是,测试失败时,它可能不是回到根因,而是继续修补刚刚引入的新错误。
第五步,错误被写回上下文。
一旦 Agent 把“我已经确认这是缓存问题”这样的错误判断带进下一轮,后面的每一步都会围绕这个假设展开。它会越来越自洽,也越来越偏。
这就是为什么你会看到一种很熟悉的翻车方式:Agent 很努力,日志很多,diff 很大,解释也很完整,但方向错了。
技术上看,这不是“AI 不认真”,而是闭环控制系统缺少独立验证。
如果生成计划的是它,执行工具的是它,解释结果的是它,判断完成的还是它,那整个系统其实只有一个脑子。这个脑子一旦进入错误轨道,很难自己跳出来。
工具边界比 Prompt 更重要
很多团队在接入 Agent 时,第一反应是写一大段系统提示:
不要乱改代码。
不要删除文件。
不要修改测试。
先理解项目再动手。
这些要求有用,但不够。
因为提示词是软约束,工具权限才是硬边界。
如果你不希望 Agent 删除数据库,就不要给它直接执行危险 SQL 的能力。如果你不希望它改生产配置,就不要把生产配置写权限暴露给它。如果你不希望它大范围重构,就把写操作限制在明确文件集合里。
一个技术判断很简单:凡是你不敢让一个实习生直接做的动作,也不应该直接开放给 Agent。
真正的 Agent 工具设计,应该按风险分级。
只读工具风险最低,比如搜索文件、读取文件、查看 git diff、查询日志。
可逆写工具风险中等,比如在工作区生成 patch、修改临时分支、创建草稿文件。
不可逆或高影响工具风险最高,比如删除文件、执行数据库变更、发布、改权限、触发生产任务。
低风险工具可以自动执行。中风险工具要有 diff 和验证。高风险工具必须有人确认,或者根本不暴露给通用 Agent。
MCP 这类协议的价值也在这里。它不只是“让模型连更多工具”,更重要的是把资源、提示模板、工具能力用统一接口暴露出来。接口统一以后,团队才有机会做权限、审计、灰度和隔离。
但要注意,工具越多不等于 Agent 越强。
工具集合臃肿以后,模型会面临选择困难。两个工具功能重叠、参数含义模糊、返回结果很长,都会增加误用概率。一个人类工程师都分不清该用哪个工具,Agent 通常不会表现得更稳定。
所以生产级 Agent 的工具设计,应该追求三个标准:
工具职责单一。
参数含义明确。
返回结果短而有信息量。
不要让工具返回几千行日志,然后期待模型自己抓重点。更好的做法是让工具先结构化:错误摘要、关键堆栈、失败测试、相关文件、建议下一步。
Agent 不怕工具少,怕工具乱。
记忆不是聊天记录,而是状态压缩
很多人一听 Agent 记忆,就想到“它能记住我说过的话”。
对 Coding Agent 来说,这个理解太消费级了。
生产级 Agent 的记忆,不是完整聊天记录,而是可复用、可检索、可更新的工程事实。
比如:
这个项目的测试入口是什么。
某个模块为什么不能直接改。
上一次排查已经排除了哪些方向。
一次迁移任务当前完成到哪一步。
哪个设计决策已经被团队确认。
这些信息如果每次都靠模型从历史对话里捞,不稳定,也浪费上下文。更好的方式是让 Agent 在长任务中维护结构化笔记。
你可以把它理解成 Agent 版本的工作日志:
任务目标:修复订单导出超时
已确认事实:
- 超时主要发生在导出超过 5 万条记录时
- Controller 层没有分页流式输出
- 网关超时为 60s,客户端重试 2 次
已排除方向:
- 不是数据库连接池耗尽
- 不是权限校验接口阻塞
下一步:
- 检查导出链路是否支持异步任务
- 补充大数据量导出测试
这种记忆的价值,不是“模型更像人”,而是把长任务拆成可延续的工程状态。
长任务一定会遇到上下文窗口限制。即使窗口越来越大,也不能指望把所有历史都塞进去。更可控的方式是压缩。
压缩不是简单总结,而是保留对后续决策有影响的信息,丢掉已经不需要的原始输出。
比如一次测试失败的完整日志可能有 2000 行,但下一轮真正需要的只有:
失败用例名。
异常类型。
关键堆栈。
疑似相关文件。
是否由本轮改动引入。
这就是上下文工程里的一个核心动作:把原始观察变成决策材料。
生产级 Agent 必须有 Verifier
如果只能给 Coding Agent 加一个模块,我会优先加 Verifier。
原因很直接:生成器不能同时充当最终裁判。
Verifier 的职责不是继续写代码,而是判断当前结果是否满足验收条件。它可以是自动化测试、静态检查、类型检查、安全扫描、规则校验,也可以是另一个更窄职责的模型。
关键是它必须独立于生成链路。
比如 Agent 修改接口后,Verifier 不能只问一句“你觉得修好了吗”。它应该检查:
相关测试是否运行。
失败测试是否和本次改动相关。
公开接口是否发生破坏性变化。
配置文件是否被意外修改。
新增代码是否绕过权限、日志、事务、幂等。
diff 是否超出任务范围。
这一步越工程化,Agent 越稳定。
很多 Agent 翻车的本质,不是没有写出正确代码,而是没有判断“什么时候该停”。
没有停止条件的 Agent,会把每一次失败都当成继续修改的理由。跑测试失败,继续改;改完又失败,再继续改;最后它可能已经偏离原任务很远。
生产级系统必须设置硬停止条件:
最多迭代几轮。
最多修改多少文件。
最多扩大多少 diff。
遇到哪些文件必须暂停。
测试连续失败几次必须交还给人。
这些限制听起来会降低 Agent 自主性,但恰恰是让它可用的前提。
自主性不是没有边界。没有边界的自主性,在工程系统里通常叫事故源。
一个能落地的 Coding Agent 分层
如果把生产级 Coding Agent 拆开,我建议至少分成七层。
第一层是任务入口。
它要把用户需求转成明确任务,不明确就追问。比如“优化一下代码”不是好任务,“把订单导出超过 5 万条时的接口超时问题定位并给出最小修复方案”才是好任务。
第二层是 Router。
它判断任务类型。是解释代码、生成测试、修 bug、小重构、跨模块迁移,还是只需要查资料。不同任务应该进入不同流程。不是所有任务都需要 Agent 模式,小任务用一次模型调用甚至更稳。
第三层是 Planner。
它先输出计划,不直接写代码。计划里要包含读取哪些文件、验证什么假设、预计改哪些位置、什么情况需要暂停。
第四层是 Context Manager。
它负责把项目规则、相关文件、历史决策、工具结果组织成高信号上下文。这里最忌讳“全量塞入”。正确做法是先少量核心上下文,再通过搜索、文件读取、测试结果逐步展开。
第五层是 Tool Policy。
它决定当前阶段允许哪些工具。探索阶段只读;实现阶段允许受限写;验证阶段允许测试和检查;发布或数据库变更必须人工确认。
第六层是 Verifier。
它不写业务代码,只做验收。它可以跑测试,也可以检查 diff 是否越界。它的输出应该是结构化的:通过、失败、阻塞、需要人工判断。
第七层是 Rollback 和 Audit。
所有高影响动作都要能追踪。改了哪些文件,为什么改,哪一轮改,验证结果是什么,失败时如何回退。这些东西不是“企业流程”,而是 Agent 时代的基本安全设施。
把这七层放在一起,你会发现:模型只是其中一个组件。
真正的 Agent 系统,是模型、上下文、工具、权限、验证和审计共同组成的工程系统。
程序员应该怎么改变用法
如果你只是个人用 Cursor、Claude Code、Codex 或其他 AI 编程工具,也不需要一下子搭完整平台。
但你可以立刻改掉几个习惯。
第一,不要上来就让它改代码。
先让它读项目、列假设、给计划。你要看的不是它写得快不快,而是它理解得对不对。
第二,把任务切小。
“重构用户系统”这种任务很适合翻车。“把登录失败的错误码从字符串改成枚举,并补充对应测试”就稳定很多。
第三,明确禁止范围。
比如告诉它:不要改数据库脚本,不要改公共 API,不要修改测试期望,不要碰支付模块。更好的做法是在工具或工作流层面限制,而不是只写在 Prompt 里。
第四,要求它先给 diff 摘要。
你不要只看最终代码,要看它改了哪些文件、每个文件为什么改、有没有超出任务范围。
第五,用测试结果约束它,而不是用感觉约束它。
让它跑具体测试,让它解释失败原因,让它说明哪些失败和本次修改相关。没有测试的项目,Agent 的价值会下降很多,因为它缺少环境反馈。
第六,长任务要让它维护笔记。
尤其是迁移、排障、跨模块改造,不要把所有历史都留在聊天里。让它维护一个任务笔记,记录已确认事实、已排除方向、待办项、风险点。
第七,发现它开始大面积改动时,停下来。
大 diff 不是能力强的表现。很多时候,大 diff 只是 Agent 失去边界感的信号。
最后说一句实话
AI 编程工具正在从补全代码,走向自己读仓库、自己做计划、自己调用工具、自己验证结果。
这个方向不会停。
但越是走向 Agent,越不能只讨论“哪个模型更强”。模型能力当然重要,但在真实工程里,决定可用性的往往是更朴素的东西:
上下文是否干净。
工具是否清晰。
权限是否收敛。
验证是否独立。
失败是否能回滚。
日志是否能追踪。
很多人用 AI 写代码越用越累,不是因为 AI 没价值,而是他们把 Agent 当成一个更聪明的输入框。
Agent 不是输入框。
它更像一个会行动的工程参与者。
你不能只给它一句话,然后期待它天然懂项目边界、业务风险、团队规范和生产事故代价。
真正成熟的 AI 编程工作流,不是让 Agent 替你做所有决定,而是把它放进一个设计良好的工程系统里:让它在该探索时探索,在该执行时执行,在该停下时停下,在该交还给人时交还给人。
未来程序员的竞争力,也不会只是“会不会写 Prompt”。
更重要的是,你能不能把一个不稳定但强大的模型,组织成一个可控、可验证、可交付的工程流程。
这才是 AI Agent 写代码真正的门槛。
更多推荐

所有评论(0)