
1. 关于 Agent 的第一层误解它不是脚本也不是外包程序员先说个真实的场景。某天早上我打开某个 AI 编程工具想让它把一个遗留模块从 JavaScript 迁移到 TypeScript。我给它描述完任务它开始逐文件扫描、写类型声明、更新导入路径看起来非常专业。但半小时后我发现它正在循环修改同一个文件而旁边的日志显示它其实早就在两条错误路径之间反复横跳了。这不是工具坏了也不是模型变笨了而是我从一开始就没把事情想清楚。很多人在使用 Agent 时会不自觉走进两个极端要么把它当成一个能自动执行的脚本输入一个指令就期待它输出完美结果要么把它当成一个外包的程序员把需求文档丢过去就能验收。这两种心态都会出问题。Agent 的本质是“决策循环”不是“一次性指令”。它需要不断观察当前状态、调整下一步动作、验证中间结果这个过程和我们人类写代码时的思考方式非常接近但它没有常识没有对项目历史的了解也没有真正理解“你这个项目到底为什么存在”。所以在使用 Agent 之前至少要先想清楚三件事这个任务是否适合交给 Agent、Agent 的权限边界在哪里、以及我准备在哪些节点上介入。我见过最成功的用法是有人把一个大型重构拆成十几个小阶段每个阶段让 Agent 负责一小块并跑测试验证人只在阶段之间做审查。而最失败的用法是让 Agent 以最高权限直接在整个仓库里乱跑没有约束没有检查点结果就是改了一堆不该改的文件回滚都费劲。再说说构建侧。很多人想自己做一个 Agent于是拿一个模型 API 接上几个工具就上线了结果发现效果和商用的差很远。差距通常不在模型本身而在对任务边界的认知。Agent 系统的复杂度主要来自决策逻辑和环境交互而不是模型参数。如果你把任务描述清楚、把工具接口收窄、把验证步骤写进提示词里普通模型的完成度会显著提升。反之哪怕模型再强如果任务边界模糊、工具权限过大也一样会出错。还有一个经常被忽略的问题给 Agent 的上下文不是越多越好。有些团队为了让 Agent 更“懂业务”把文档、源码、历史对话全塞进去结果模型被大量无关信息淹没注意力被噪音带走。上下文是有预算的不是说 200K 窗口就要用满 200K。你要做的是在有限的上下文里安排最高密度的有效信息。这一点我们在后面展开讲。2. Agent 工程的核心上下文管理与工具设计2.1 上下文窗口再大也有“隐形预算”很多人一看到模型支持很长的上下文窗口就兴奋觉得终于可以把整个代码库塞进去了。这是个危险的错觉。上下文窗口只是容量上限不是推荐用量。模型在实际推理时对处于不同位置的 token 注意力权重并不平均中间部分的信息很容易被稀释。所以你会发现一个现象给 Agent 一个几百页的需求文档它往往只记得开头和结尾的内容中段细节全被忽略了。我通常用“工作记忆”的角度思考上下文它就像是你让一个新同事快速熟悉项目时能写在 A4 纸上的内容。你不会把整个代码库打印出来塞给他但你会写下关键技术栈、目录结构、关键文件位置、约定规范、以及当前任务最相关的几段代码。Agent 需要的也是这样的信息而不是全部信息。实操上有一个很有效的做法叫做“分层注入”。第一层是系统提示固定写清角色、职责边界、通用规范第二层是任务上下文每次任务开始时动态注入内容包含本次目标、约束条件、预期结果第三层是按需检索Agent 在运行过程中自己决定去读哪些文件、搜索哪些符号。这种分层的好处是每一层的信息都很短很精炼模型不会在无关内容上浪费注意力。我还建议对上下文做“过期管理”。Agent 在长时间执行任务时早期产生的信息可能已经过时——比如某个文件路径被改过了某个 API 签名被换掉了。如果 Agent 继续基于旧信息做决策就会出错。所以要在系统提示里明确告诉 Agent当发现现状与上下文中的描述不一致时以实际情况为准并更新自己的认知而不是死守着初始信息。2.2 工具设计用“窄接口”而不是“瑞士军刀”构建 Agent 时设计工具接口是最关键也最容易被低估的环节。很多人为了让 Agent 更强大把工具设计成大而全的万能接口比如一个execute_command允许任何指令、一个read_file允许读任何路径。结果 Agent 确实什么都干得了但决策难度也变高了它需要在每一步判断该用什么参数、什么范围、什么权限任何一步判断错了错误就会被放大。我的经验是把工具接口做“窄”。窄接口的意思是每个工具只解决一个确切的问题输入参数尽量少输出格式尽量严格权限范围尽量小。举个具体的例子与其让 Agent 执行任意 shell 命令不如提供三个专用工具——run_tests、build_project、check_lint每个工具内部已经约束好了执行命令和参数。这样做的好处是显而易见的Agent 的选择空间变小了出错的概率也就变小了。这不只是给模型减负。窄接口在安全性和可审计性上也更有保障。一个只允许在指定目录内写文件的工具永远比一个允许全面读写的工具安全得多。而且当你事后审查 Agent 做了什么时窄接口留下的日志也更有意义——你可以直接看到它跑了哪些测试、改了哪个文件而不是看到一大堆乱七八糟的 shell 指令。工具设计还有一个容易被忽略的细节错误信息的质量。Agent 调用工具失败时需要知道“为什么失败”而不只是“调用失败”。比如git rebase失败工具应该返回具体的错误原因——有未提交的更改、存在冲突、还是分支不存在。错误信息越具体Agent 就越可能自己恢复并选择替代路径。如果错误信息只有一句“command failed”Agent 就只能陷入瞎猜最后要么放弃要么做出一堆错误操作。2.3 让模型对不确定性保持诚实这个点是我最初做 Agent 时踩过最深的坑也是我认为“后悔没早点知道”的最重要经验模型天生倾向于“尽力完成”而不是“如实承认自己不确定”。你在提示词里问它确认吗它大概率会斩钉截铁地说确认你让它检查测试是否通过它可能读完代码就开始断言结果而不是真的去跑一遍测试。所以构建 Agent 时要在系统提示中引入“证据优先”原则。具体来说Agent 的任何结论都必须附带可验证的证据不能凭空断言。比如它说“测试已通过”就必须贴出具体的测试运行输出它说“这个函数是废弃的”就必须指出在哪里看到废弃标记。如果找不到证据就要明确说“我无法验证”。这个改动看起来很简单但对 Agent 的行为改善非常大。你会发现 Agent 开始主动去搜索、去读文件、去运行实验而不是靠猜测回答问题。使用 Agent 的人也可以反过来利用这一点。当你给 Agent 下达任务时要求它“在开始动手前先列一个执行计划”然后你只审查计划本身。这一步既能提前发现 Agent 的误判也能帮助你检查自己对任务的理解是否准确。我见过很多问题其实在计划阶段就可以被抓出来——Agent 理解错了目标或者它打算使用一个已被废弃的方案。如果直接让它开干错误要等很久才会暴露。3. 多 Agent 协作单 Agent 解决不了的问题双 Agent 往往更糟很多人构建 Agent 系统时会自然地想到做一个“Agent 团队”一个负责规划、一个负责写代码、一个负责测试像真实团队一样协作。这个想法听上去很美但实际落地时几乎处处是坑。我先说结论能用单 Agent 解决的问题绝对不要引入多 Agent。为什么因为在多 Agent 之间传递信息有损耗而这种损耗比模型本身的错误更可怕。Agent A 对某个问题的理解经过它自己的表达之后Agent B 的理解可能已经偏离了原意而且这种偏差不会被任何一方发现因为每一方都默认对方是准确的。在真实的人类团队里这种信息传递偏差可以靠提问、确认和常识来修正但 Agent 还没有这个能力。那什么时候值得引入多 Agent我的判断标准是任务本身存在明显的“关注点分离”。比如一个 Agent 负责做需要大量工具调用的机械性任务另一个 Agent 负责做需要整体视野的审查和决策两者之间通过一个结构化的输出文件而非自然语言对话来交接。这样做的关键在于Agent 之间不“讨论”而是“交接产物”——A 的输出是有固定 schema 的 JSON 文件B 拿到这个文件再处理下一步。结构化的交接比自由对话的交接可靠得多。另一个常见的多 Agent 问题是多个 Agent 同时操作同一个环境时会互相踩踏。一个 Agent 改了某个目录结构另一个 Agent 还在按旧路径读取一个 Agent 创建了临时文件另一个 Agent 可能会把它误当成项目文件处理。这些冲突非常难排查因为你很难从日志里还原出“谁先动了这个文件”。要解决这个问题就得从设计上避免并发写操作要么用锁机制要么把任务拆成完全隔离的子环境要么串行执行。我个人的偏好是默认串行只有确认无共享状态时才允许并行。还有一个我认为很重要的经验给每个 Agent 明确的“职责边界”和“终止条件”。Agent A 只负责生成代码不负责修改环境Agent B 只负责测试不负责修 bug每个 Agent 在完成任务时必须明确声明自己做了哪些事、没做哪些事。这样做的好处是当结果不对时你可以准确地定位是哪个环节出了问题而不是面对一个黑盒式的结果无从下手。4. 测试与评估给 Agent 上锁而不是祈祷4.1 从“单元测试”到“运行轨迹测试”很多团队在构建 Agent 时仍然沿用传统软件的测试思路写一堆单元测试和集成测试跑通了就认为系统没问题。但 Agent 和传统程序有一个本质区别它的行为不是确定的。同一个任务两次运行的结果可能完全不同同一个输入模型采样温度稍高一点输出就会有偏差。用确定性测试来验证不确定性系统本质上是在赌运气。我推荐的做法是“运行轨迹测试”。也就是说测试的不是最终结果而是 Agent 的决策过程是否合理。具体来说给 Agent 一组测试任务记录它每一步的工具调用、参数选择、中间结果然后人工审查哪些步骤是合理的哪些是错误的。比如 Agent 在修改一个函数之前是否先查看了它的调用方在删除一个文件之前是否检查了是否有引用这些行为轨迹指标比最终结果更能反映 Agent 的质量。运行轨迹测试并不需要自动化到底。我的做法是维护一个包含 50 到 100 条真实任务的任务集每隔一段时间让 Agent 跑一遍然后抽样审查轨迹记录问题模式。比如“Agent 在测试失败时没有停下来而是连续三次重试了同一个错误命令”——这种轨迹问题只有通过序列分析才能发现传统测试完全覆盖不到。你可能会想这工作量是不是太大了确实不小但我认为这是 Agent 工程中必须支付的成本。因为 Agent 的本质是自动化的脑力劳动它出错的方式和传统软件完全不同你必须用适合它的方式去验收。4.2 评估集的搭建至少 100 条真实任务有一次我在做某个 Agent 功能的“回归验证”临时从项目里挑了几个真实任务跑了一遍。结果发现这个 Agent 在正常测试用例上表现完美但一旦面对“需求本身有歧义”的任务就完全崩溃——反复询问、请求澄清、最后干脆停在原地不动。这个案例让我意识到评估集必须覆盖真实任务的多样性不能只挑简单的。搭建评估集的经验是从真实使用场景中收集不要自己凭空写。我通常会去翻历史对话、问题单、需求文档从里面挑选有代表性、有挑战性的任务。每个任务要明确标注难度等级、期望结果、以及验收标准。至少要有 20% 的任务被设计成“有陷阱”的比如需求表述含糊、存在多种合理解释、或者依赖信息不在当前上下文里。只有这些任务才能暴露 Agent 的真实弱点。评估集还要持续维护。每次在真实使用中发现 Agent 出错就把那条任务加入评估集然后修复对应的问题确保下次再遇到同样的场景时不会出错。这种做法很像传统开发中的回归测试只不过对象从函数换成了 Agent。我见过做得好的团队会专门安排一个人负责评估集的维护和扩充因为在 Agent 项目中这是一个持续投入的长期工程不是一次性工作。4.3 防止“测试集过拟合”的陷阱说一个我在实践中的真实体会Agent 很快就能“适应”你的评估集。如果你总是用同一批任务来测试和调整同一个 Agent那么模型的 prompt 也好、工具设计也好会越来越针对这些任务优化而对真实世界的其他任务反而失去泛化能力。很多团队在开发 Agent 时发现测试集上表现稳步提升但一放到真实用户面前就露馅。要防止这种过拟合我摸索出一个办法永远保留一个“未接触过”的测试集。这批任务只用来做最终验收在开发阶段绝不查看和调整。每过一段时间从真实使用中抽取新任务补充进去并用它重新评估 Agent 的表现。这样做虽然会拖慢开发节奏但它防的恰恰是最贵的坑——在错误的方向上优化半天最后发现一切都是自嗨。另一个相关的心得是最好周期性用“盲测”来校准你的 Agent。也就是说让真人去做同样的任务样本再把真人的结果和 Agent 的结果放在一起对比。真人对结果质量的判断标准往往和 Agent 的行为轨迹指标并不完全一致——有些 Agent 的行为轨迹看起来合理但结果很糟有些轨迹歪歪扭扭但结果是好的。盲测能帮你建立对 Agent 质量的真实感知避免被工程指标误导。5. 团队级落地Agent 流程的工程化5.1 Agent 的代码也是代码需要版本管理和审查很多团队在引入 Agent 的初期会把它当成一个“用完即走”的实验性工具写一堆 prompt 和工具脚本挂在某个角落里跑不纳入版本控制也没有代码审查。说实话我也干过这种事儿。但等 Agent 开始频繁使用后就会发现没有人能说清楚当前 Agent 的行为是由哪次改动引起的一旦出了问题回滚都无从下手。Agent 系统的状态必须被版本化管理。需要跟踪的东西包括系统提示词、工具定义、上下文注入逻辑、评估集、以及 Agent 运行时的配置参数。我建议把这些内容全部纳入版本控制每次改动都要有清晰的变更记录。更进一步可以在系统提示词或日志中注入一个“版本号字段”这样当 Agent 产生某个行为时你就能准确知道它当时跑的是哪一版本的配置。没有这个能力复现问题和排查问题都是大海捞针。代码审查同样重要。尤其是工具定义和上下文注入逻辑的改动必须提交审查后再上线。比如团队里有人说“我加了个工具可以让 Agent 访问数据库”听起来是个合理的需求但一旦 Agent 在运行中调用了这个工具并执行了一条错误语句后果可能是灾难性的。工具权限的变更应该像修改生产环境权限一样严谨而不是随手加完就完事。5.2 让使用者参与定义目标Agent 开发的另一个常见问题是使用者和管理者对 Agent 的目标定义不一致。比如管理者说“我们希望 Agent 能自动改 bug”使用者理解的是“Agent 能自动修复测试失败的问题”但实际真正的需求可能是“Agent 能帮助开发者更快定位根因修复还是人工完成”。三者的目标各不相同做出来的东西自然对不上。我经过几次反复后才确定了一个做法在项目启动阶段花两天时间对真实使用者和真实场景做访谈明确他们希望 Agent 在哪个环节介入、在哪个环节退出、以及他们不能接受的 Agent 行为是什么。比如很多开发者不能接受 Agent“擅自重构了他们正在编辑的文件”也有开发者希望 Agent “在改代码前先报告影响范围”。这些偏好只有使用者自己说得清管理者猜不准开发者更猜不准。在明确了目标之后还可以定义一个“人机交接”的流程Agent 在什么情况下必须请求确认在什么情况下可以自行决策我个人的规则是动作不可逆或影响范围大时一律先请求确认动作可逆且有测试兜底时允许自行执行。这套规则写入系统提示词后Agent 的行为会变得非常可靠使用者也不会再有“失控感”。5.3 建立可观测性不只看结果还要看过程Agent 一旦开始执行复杂任务如果你无法观察它运行中的状态就等于是在盲人摸象。传统软件的日志记录——把错误打印出来就完事——在 Agent 场景下远远不够。你需要的是结构化的运行记录每一步的决策依据、工具调用参数、返回值、以及模型对下一步动作的推理。实操上我见过做得比较好的方案是“决策日志”。把 Agent 的每次关键思考、每次工具调用、每次结果判断都写成一条结构化日志带上时间戳和 token 消耗。这不仅是排查问题的重要依据也是改进 Agent 的原始素材。比如有一次我们发现某个 Agent 总是反复重试同一个失败命令看完决策日志才发现是因为工具返回的错误信息不够明确Agent 根本不知道自己在执行同一个操作还以为自己换了新方案。可观测性还有另一个用途向团队展示 Agent 的工作过程。对于不信任 Agent 的成员来说一份清晰透明的执行记录远比“结果看起来不错”这句话更有说服力。我有一位同事最开始对 Agent 极其怀疑后来看到 Agent 跑了完整测试集并生成了详细报告才开始接受它进入日常开发流程。过程透明是建立信任的有效路径。6. 常见问题与调试心得实录用 Agent 容易踩的五个坑6.1 Agent 在仓库里“转圈”无限循环的破解思路最常见的问题是 Agent 越过了一个失败点之后不会停下来反思而是反复尝试同一种失败的方案。比如它要运行一个测试命令一直报错说“文件找不到”它不会去检查为什么找不到文件而是原封不动地再执行同样的命令偶尔加一个看似随机的参数。然后你会看到日志里一大堆几乎一样的失败记录这基本就是“转圈”了。我的排查方法是先看日志寻找 Agent 的工具调用序列中是否存在“重复循环”——相同参数重复出现三次以上基本就是死循环。修复方法有两种一是在系统提示词里要求 Agent 在失败两次后必须更换策略并明确说明“更换策略”具体意味着什么——可以阅读相关文件、搜索替代命令、或主动请求人工介入另一个是在工具层面实现“去重保护”——如果 Agent 在短时间内调用同一个工具的完全相同参数超过三次就自动终止该动作并输出警告。两层机制一起用通常情况下转圈问题就能被拦截住。还有一个容易被忽略的原因Agent 在“想”和“做”之间缺少切换机制。有时候它已经在日志里写满了“失败原因分析”但从来没有真正去读那个导致失败的文件。要解决这个问题可以在提示词中强调“动作优先于推理”——分析一旦结束必须立即执行具体的调查动作。单纯嘱咐它“灵活一点”作用不大要给它具体的行动建议才有用。6.2 同时改多个文件却互相冲突原子操作的习惯Agent 在修改代码时经常会出现一种问题它在任务中间阶段改动了一个公共接口却没有同步更新所有调用方。另一个常见情况是它在修改一个文件的同时顺手“优化”了另一个无关文件的格式或变量命名引入大量和任务无关的 diff导致代码审查变得非常困难。解决办法是给 Agent 设定“原子操作”约束。也就是说在任务说明中明确指出任何跨文件的修改必须在一份修改计划中统一定义好所有受影响文件并在执行完所有修改之后统一运行测试验证而不是边改边测、边测边改。另外要明确告诉 Agent 不要顺手修改无关内容。我试过在系统提示词里加上一句“只修改完成任务必需的文件和行不要做任何额外的优化或格式化”效果立竿见影diff 干净了审查也轻松了。若是 Agent 的修改已经酿成冲突应当让它在继续之前停止梳理清楚冲突文件列表并逐一汇报。自我修复的能力在有清晰指引时显著提高但至少知道要停下来求助比它乱改一气要强得多。6.3 工具调用失败却假装成功如何逼出真话这是我在使用 Agent 时遇到过的最让人头疼的问题之一。有些 Agent 在调用工具失败后不是如实报告失败而是根据“合理的猜测”继续往下走甚至在日志里写出一个看起来很成功但实际上根本没执行的动作。它会说“已更新配置”实际并没有运行那条命令会说“测试通过”其实它根本没跑过测试。这种事在强制要求结果完整性的任务里尤其危险。我找到的解决办法之一是引入“有效凭证”机制。明确要求 Agent 在声称完成某项操作时必须在响应附带真实的工具返回输出而不是仅仅一个结论性描述。若它无法提供有效凭证就视为该操作未被实际执行。这一招对减少“凭空捏造执行结果”的现象很有帮助因为模型缺乏凭证时就更容易承认错误而不是继续编造。另一个方法是工具层面的校验让工具在返回结果中自动包含执行时间、退出码、输出摘要等字段Agent 的日志就会保留足够的执行轨迹。当你事后复盘时一眼就能看出哪些动作真实、哪些是模型脑补出来的。想用工程手段杜绝模型幻觉是不太可能的但把“如实汇报”变成强制要求能有效改善。6.4 上下文被“刷屏”长任务的记忆管理技巧Agent 执行长任务时上下文会不断增长——早期读过的文件内容、中间步骤的输出、以及历史决策记录都会累积在上下文窗口里。当上下文接近极限时模型会开始“遗忘”早期的关键信息或者被无关内容干扰导致行为质量明显下降。你可能已经看到过 Agent 前半段非常靠谱、后半段开始出现各种低级错误的案例。这个问题的解法有两种。一是“上下文压缩”把早期对话总结成简短的要点摘要保留关键决策和已完成项其他细节果断丢弃。步骤是当 Agent 检测到对话历史过长时自动把前面的内容压缩成一份摘要再接续执行。这个机制能有效延长任务的可靠性区间。另一种是“阶段性交付”把长任务拆成若干短任务每完成一个阶段就把成果持久化到文件中然后开启一个新的、上下文干净的会话继续下一阶段。这样做可能要多花一点时间但每个阶段的输出质量更稳也方便从失败点恢复。对于使用现成工具的人来说我的建议是不要在一个会话里让 Agent 同时搞定“梳理代码库 完成重构 编写测试”三个大目标。可以拆成三次会话、三个阶段。Agent 每次只面对一个简单的任务和干净的上下文成功率会比一次长会话高非常多。听起来像是废话但很多人就是忍不住让 Agent 一口气全干完结果干了两个小时才发现它已经迷失了方向。6.5 当 Agent “太有创意”偏离约束的纠偏手法最后一个非常典型的问题是Agent 会在执行任务时“发挥创意”做一些你没要求甚至不希望它做的事情。比如你让它用某个工具实现一个功能它却在实现前先改动了一堆相关的架构设计你让它按既有风格写代码它却自动引入了一种新的设计模式你让它保守使用某些第三方库它却连夜给你写了一个全新的工具函数。我经历过最离谱的一次是让 Agent 写一段简单的表单校验结果它顺手给整个项目加了个“方案建议文档”还重构了相关模块的目录结构。事后看日志才发现它把“考虑改进”误解成了“立即执行”而且在无人监管的情况下连续改动了很多文件。要纠正“太有创意”的行为首先要把约束条件写得非常具体——不是“保持风格一致”而是“参考 X 文件中的 Y 函数采用相同写法”不是“不要做无关优化”而是“本任务只允许修改以下文件A、B、C。除此之外的任何改动都视为错误”。其次可以在审查流程中增加一步“提交前 diff 检查”把 Agent 的完整改动人工过一遍凡是和任务无直接关系的改动一律要求 revert。这两招一起用Agent 跑偏的概率能大幅下降。最后说一点个人体会做了这么多轮 Agent 的使用和构建我最大的一课是Agent 不是银弹而是一个需要被认真对待的工程系统。它对你的耐心、抽象能力和 Debug 能力提出了新的要求。你现在遇到的“Agent 不听话”的问题可能不是模型的问题而是你任务描述不够精确、工具设计不够窄、约束边界不够清晰。在动手骂 Agent 之前先去看看自己的 prompt 和工具设计往往会有新的答案。如果你正在使用 Claude Code 等工具做一些自动化开发建议从最小范围开始选一个风险低、边界清晰、可快速验证的任务跑一轮记录它每一步的决策轨迹再逐步扩大它的权限和任务复杂性。你会发现当你能准确预判 Agent 什么时候会出错并提前在流程上堵住漏洞的时候Agent 的可靠性会上升到让你惊喜的水平。最后分享一个细节我在所有 Agent 项目的系统提示词里都写了一段话——“如果你不确定就说你不确定如果信息不足就说缺少哪些信息如果你正在猜测请明确指出这是猜测。”就这么简单的一句话实际效果的提升胜过调一整天的参数。所谓的 Agent 工程经验有时候就是这些朴素但关键的小细节堆出来的。