
1. 从一堆报错说起为什么现在聊 AI Agent 正当时如果你最近在折腾大模型相关的东西大概率见过这几个让人头大的报错context is too large and auto-compaction could not recover、this models maximum context length is 1048576 tokens、provider rejected the request schema or tool payload。这些报错背后其实指向同一件事——你正在从调个 API 问个问题的阶段跨进让模型自己干活的阶段也就是 AI Agent。我接触 Agent 这个概念不算早真正上手做第一个能跑通闭环的 Agent 大概是去年的事。当时踩的坑现在回头看特别典型以为 Agent 就是LLM 几个函数调用结果发现光是让模型稳定地选对工具、传对参数、处理失败重试就够折腾好几天。后来慢慢摸清了 Context 管理、Tools 设计、容错控制这几块的门道才算真正入门。这篇手册想做的事情很明确把 AI Agent 从概念到落地这条路上那些真正卡人的地方讲清楚。不是那种Agent LLM Memory Tools Planning念一遍公式就完事的科普而是把每个模块为什么这么设计、实际写代码时会遇到什么、怎么绕开常见的坑一条条摊开来说。适合两类人看一类是刚听说 Agent 想搞清楚它到底和普通 LLM 调用有什么区别的另一类是自己动手搭过但总在某个环节翻车的。前者能建立完整的认知框架后者能直接抄走一些实战经验。关键词里出现的Context、Tools、LLM、Agent这几个词基本就是这篇的主线。我会按先搞懂 Agent 到底特殊在哪 → Context 怎么管 → Tools 怎么设计 → 容错怎么做 → 完整搭一个能跑的这个顺序往下走中间穿插大量我实际踩过的坑和验证过的做法。2. Agent 和普通 LLM 调用的分水岭到底在哪2.1 一次调用 vs 一个循环本质区别很多人第一次接触 Agent 会困惑我直接调 LLM API 也能让它回答问题为什么还要搞个 Agent这个困惑的根源在于没分清单次推理和闭环决策的区别。普通 LLM 调用是这样的你给一段 prompt模型返回一段文本结束。整个过程是一问一答模型没有机会根据自己输出的结果去调整下一步动作。而 Agent 的核心是循环模型输出一个动作比如调用某个工具系统执行这个动作拿到结果把结果再喂回给模型模型基于新信息决定下一步——这个循环会一直持续到任务完成或者触发终止条件。用生活化的类比普通 LLM 调用像是你问一个博学的人一个问题他凭记忆回答你Agent 像是你雇了一个助理他可以查资料、打电话、发邮件做完一步看结果再决定下一步直到把事办成。区别不在于谁更聪明而在于能不能根据环境反馈调整行为。这个区别直接决定了工程上的复杂度差异。单次调用你只需要关心 prompt 写得好不好Agent 你要关心的是循环什么时候停、上下文会不会爆、工具调用失败了怎么办、模型选错工具怎么纠正。这些就是后面几节要展开的内容。2.2 ReAct 范式目前最主流的 Agent 骨架聊 Agent 架构绕不开 ReActReasoning Acting。它的核心思想是让模型在每一步都先想一下Reasoning再决定做什么Acting然后把动作结果作为观察Observation纳入下一轮思考。这个范式之所以成为主流是因为它把思考和行动显式地分开了模型在推理链里能自己纠正方向。一个典型的 ReAct 循环长这样Thought: 我需要先查一下这个城市的天气 Action: get_weather Action Input: {city: 杭州} Observation: 杭州今天多云18-25度 Thought: 拿到天气了现在可以给出穿衣建议 Action: finish Action Input: {answer: 杭州今天多云18-25度建议穿薄外套}实际工程里不一定严格用 Thought/Action/Observation 这种文本格式很多框架用 function calling 的原生结构化输出替代了文本解析但**推理-行动-观察这个循环的本质没变**。理解这一点很重要因为后面所有的 Context 管理、工具设计、容错都是围绕这个循环展开的。2.3 主流架构的几种变体ReAct 是基础款实际项目里会根据任务特点做变体。我整理了几种常见的架构类型核心特点适用场景主要代价ReAct推理与行动交替通用任务、需要多步工具调用循环轮次多token 消耗大Plan-and-Execute先规划完整步骤再执行步骤明确的长任务规划错了整条链都废Reflexion执行后自我反思再重试需要迭代优化的任务反思质量依赖模型能力Multi-Agent多个 Agent 分工协作复杂任务拆解通信开销大调试困难新手我的建议是先把 ReAct 吃透别一上来就搞 Multi-Agent。我见过太多人任务还没跑通就开始设计规划 Agent 执行 Agent 审核 Agent的三层架构结果连单个 Agent 的工具调用都调不稳。ReAct 跑顺了再根据实际瓶颈决定要不要上更复杂的架构。3. Context 管理Agent 最容易翻车的地方3.1 Context 为什么会爆一个具体的账context is too large这个报错是 Agent 开发里出现频率最高的之一。要理解它为什么容易发生得先算一笔账。假设你的 Agent 系统提示词 2000 token工具定义 1500 token用户任务描述 500 token。这是初始的 4000 token。然后每轮循环模型输出假设 300 token工具返回结果假设 800 token那么每轮净增约 1100 token。跑 20 轮就是 22000 token加上初始的接近 26000 token。看起来还好但问题在于工具返回结果往往远超预期。你让 Agent 去读一个网页返回的正文可能就 5000 token让它查数据库返回的 JSON 可能上万 token。几轮下来context 轻松突破模型的窗口上限。像 1048576 token 这种超大窗口的模型还好但大多数常用模型的窗口在 8K 到 128K 之间很容易撞墙。3.2 三种 Context 压缩策略的实际取舍Context 管理本质上是在保留信息和控制长度之间做权衡。我实际用过的主要有三种策略第一种是滑动窗口只保留最近 N 轮对话。实现最简单但问题是早期的重要信息比如用户最初的需求、已经确认过的关键参数会被丢掉导致 Agent 失忆。第二种是摘要压缩把历史对话用 LLM 总结成一段简短摘要。这个能保留语义但摘要本身有信息损失而且每次压缩都要额外调一次 LLM增加延迟和成本。第三种是结构化记忆把关键信息抽取成结构化字段存起来比如任务目标、已完成步骤、待办事项需要时再注入 context。这个最可控但需要针对任务设计抽取逻辑。我实际项目里的做法是混合使用系统提示词和工具定义永远保留这是 Agent 的本能最近 3-5 轮完整保留保证短期连贯性更早的历史做摘要压缩同时把任务关键状态单独存成结构化字段。这样既不会爆 context也不会让 Agent 忘掉核心目标。提示压缩触发阈值不要设成模型窗口的 100%建议设在 70%-80%。因为压缩本身需要调用 LLM这次调用也要占 context留出余量才不会在压缩时又爆一次。3.3 一个容易忽略的坑工具返回结果的裁剪前面提到工具返回结果往往是 context 膨胀的主因。我的经验是在工具层面就做裁剪而不是等 context 快满了再处理。具体做法每个工具在返回结果前先判断结果大小。如果是网页正文只返回前 N 个字符加一个内容过长已截断的标记如果是列表数据只返回前 K 条加总数如果是 JSON只保留关键字段。这样从源头控制住单次返回的体积比事后压缩高效得多。我踩过的一个具体坑早期做网页抓取工具时直接把整个 HTML 转文本返回一个页面动辄几万 token。后来改成只提取正文、限制长度context 增长速度直接降了一个数量级。这个改动看起来简单但对 Agent 能跑多少轮的影响是决定性的。4. Tools 设计Agent 能力的天花板4.1 工具不是越多越好能力边界的取舍新手容易犯的一个错误是拼命给 Agent 加工具觉得工具越多能力越强。实际情况恰恰相反工具太多会导致模型选择困难调用准确率下降。我做过一个对比测试同一个任务给 Agent 配 5 个工具时调用准确率大概 90% 以上配到 20 个工具时掉到 70% 左右。原因不难理解工具描述本身占 context工具越多描述越长模型要在更多选项里做判断出错概率自然上升。所以工具设计的第一原则是按需配置。一个 Agent 只配它完成当前任务真正需要的工具不要搞一个万能工具箱塞给所有 Agent。如果确实需要很多能力考虑拆成多个专职 Agent每个 Agent 配少量工具。4.2 工具描述怎么写给模型看的说明书工具描述的质量直接决定调用准确率。我见过很多工具描述写得像给人类看的 API 文档什么该接口用于查询用户信息支持多种查询条件这种描述对模型来说信息量太低。好的工具描述应该包含三样东西这个工具做什么、什么时候该用、参数怎么填。举个例子对比差的描述查询天气好的描述查询指定城市的实时天气和未来预报。 当用户询问天气、温度、是否需要带伞、穿衣建议时使用此工具。 参数 city 必须是城市中文名如杭州不要传省份名或英文名。第二种描述明确告诉模型使用场景和参数约束调用准确率会明显提升。参数描述里最好给出正例和反例模型对不要传什么的敏感度比要传什么更高。4.3 工具返回格式结构化还是自然语言工具返回给模型的结果用结构化 JSON 还是自然语言这个也有讲究。结构化 JSON 的优点是信息密度高、字段清晰模型解析准确。缺点是如果字段太多模型容易抓错重点。自然语言的优点是模型理解起来自然缺点是信息密度低、占 token 多。我的实践是混合核心结果用结构化字段附加说明用自然语言。比如查询天气返回{ city: 杭州, temperature: 18-25°C, condition: 多云, summary: 今天多云气温适中适合外出建议穿薄外套 }结构化字段保证模型能准确提取数据summary 字段用自然语言给出结论模型可以直接引用。这样既准确又省 token。4.4 工具调用失败的处理别让一次失败毁掉整个任务工具调用失败是常态网络超时、参数错误、服务不可用都会发生。关键是怎么处理。最差的做法是失败就直接报错终止。稍微好一点的是重试但无脑重试可能陷入死循环。我的做法是分级处理参数错误把错误信息返回给模型让它修正参数重试通常一次就能改对网络超时自动重试 2-3 次间隔递增服务不可用返回明确的失败信息让模型决定是换工具还是告知用户连续失败设置最大重试次数超过就终止并返回已完成的部分这里有个细节错误信息要写给模型看不是写给人看。不要返回Error 500而是返回天气服务暂时不可用请稍后重试或告知用户无法查询。模型拿到这种信息才知道下一步该干嘛。5. 容错与可靠性让 Agent 从能跑到敢用5.1 幻觉工具调用模型编造不存在的工具这是 Agent 开发里一个很隐蔽的坑模型有时候会调用一个你根本没定义的工具。比如你只给了get_weather和search_web模型却输出了get_weather_forecast。这种情况在模型对工具理解不深或者任务描述模糊时特别容易发生。处理方式是在工具调用层做白名单校验模型输出的工具名如果不在已注册列表里不要直接执行而是返回一个错误信息给模型告诉它工具 X 不存在可用工具是 A、B、C。模型收到这个反馈通常会纠正。我实测下来加了这层校验之后幻觉工具调用导致的失败基本能消除。代价是偶尔多一轮循环但比任务直接崩掉划算得多。5.2 死循环检测Agent 卡住不动的识别与打断Agent 陷入死循环是另一个常见问题。表现是反复调用同一个工具、反复输出相似的思考、或者一直在两个状态之间来回跳。检测死循环有几个信号可以监控相同工具连续调用次数超过阈值、连续多轮的工具调用参数高度相似、循环轮次超过预设上限。任何一个触发就打断返回当前状态让模型重新规划或者直接终止。我一般会设一个硬性的最大轮次限制比如 15 轮超过就强制终止。这个限制不是偷懒而是防止极端情况下无限消耗 token。实际任务很少需要超过 15 轮如果经常撞到这个上限说明任务拆解或者工具设计有问题该回头优化而不是放宽限制。5.3 输出格式校验结构化输出的稳定性如果 Agent 需要输出结构化结果比如 JSON格式错误是高频问题。模型可能少个括号、多个逗号、字段名拼错。处理方式有两层第一层是在 prompt 里明确格式要求并给示例第二层是在解析时做校验解析失败就把错误信息返回给模型让它重新输出。第二层是关键因为再好的 prompt 也不能保证 100% 格式正确。对于格式要求严格的场景可以用模型的原生结构化输出能力比如 function calling 的 schema 约束从生成层面保证格式。但要注意不是所有模型都支持而且 schema 太复杂时模型也可能出错所以解析层的校验还是不能省。6. 从零搭一个能跑的 Agent完整流程6.1 环境准备与模型选型动手之前先明确技术选型。模型方面如果任务需要复杂的工具调用和推理选工具调用能力强的模型如果只是简单的信息提取和格式化小模型也够用。我的建议是先用能力强的模型跑通流程再考虑降本换成小模型反过来做会浪费很多时间在调试模型能力不足上。框架方面如果只是想理解原理建议先不用框架手写一遍。用原生 API 加一个简单的循环把 ReAct 的流程跑通你会对 Context 怎么组装、工具怎么调用、结果怎么回传有非常直观的理解。跑通之后再上框架才知道框架帮你做了什么、哪些地方需要定制。6.2 最小可用 Agent 的代码骨架下面是一个极简的 Agent 循环骨架用伪代码表示核心逻辑def run_agent(task, tools, max_turns15): messages [ {role: system, content: SYSTEM_PROMPT}, {role: user, content: task} ] for turn in range(max_turns): # 1. 调用模型 response call_llm(messages, toolstools) # 2. 检查是否要调用工具 if response.tool_calls: for tool_call in response.tool_calls: # 3. 白名单校验 if tool_call.name not in tools: result f工具 {tool_call.name} 不存在 else: # 4. 执行工具带异常处理 try: result execute_tool(tool_call) except Exception as e: result f工具执行失败{e} # 5. 结果回传 messages.append(response.message) messages.append({ role: tool, content: str(result)[:MAX_TOOL_RESULT_LEN] }) else: # 6. 没有工具调用任务完成 return response.content # 7. Context 压缩检查 if count_tokens(messages) COMPRESS_THRESHOLD: messages compress_context(messages) return 任务未在限定轮次内完成这个骨架包含了前面讲的所有关键点白名单校验、异常处理、结果裁剪、Context 压缩、轮次限制。实际项目里每个部分都会更复杂但核心逻辑就是这个循环。6.3 调试 Agent 的实用技巧调试 Agent 比调试普通程序麻烦因为它的行为有随机性。我总结了几个实用的调试方法第一把每一轮的完整输入输出打日志。包括发给模型的 messages、模型的原始输出、工具调用的参数和结果。出问题时回看日志能快速定位是哪一轮出的错。第二固定随机性。调试时把 temperature 设成 0让模型输出尽量确定。这样同一个输入能复现问题不然每次跑结果都不一样根本没法调。第三单步执行。写一个调试模式每轮循环暂停人工确认模型的决定是否合理再继续。这个在排查模型为什么选错工具这类问题时特别有用。第四构造最小复现用例。Agent 出问题时把出问题的那一轮的完整 context 单独拿出来写个脚本直接喂给模型看它怎么反应。这样能排除循环逻辑的干扰聚焦在模型决策本身。7. 几个我踩过的真实坑和对应的解法7.1 工具描述里的隐藏歧义有一次我做了两个工具search_news和search_web描述分别写的是搜索新闻和搜索网页。结果模型经常在该用 search_news 的时候调了 search_web。问题出在描述太模糊模型分不清边界。后来我把描述改成search_news用于查询特定主题的最新新闻资讯返回带时间戳的新闻列表search_web用于查询通用信息、百科知识、非时效性内容。改完之后调用准确率明显提升。这个坑的教训是工具描述要明确边界告诉模型什么时候不该用这个工具比只说什么时候该用更重要。7.2 Context 压缩把关键信息压没了早期我用纯摘要压缩结果发现 Agent 跑着跑着把用户最初的核心需求忘了。比如用户说帮我找三篇关于 X 的文章并总结压缩几轮之后 Agent 只记得总结文章忘了三篇这个数量约束。解法是把任务约束单独抽出来不参与压缩每轮都注入。具体做法是在系统提示词之外维护一个任务状态字段包含原始目标、关键约束、已完成步骤这个字段永远完整保留。摘要压缩只处理对话历史不碰任务状态。7.3 模型在工具返回错误后反复重试同一个错误有一次工具因为参数格式问题一直失败模型每次都返回同样的错误参数重试陷入死循环。原因是错误信息写得太笼统模型不知道该怎么改。后来我在错误信息里加上了具体的修正建议比如参数 date 格式错误应为 YYYY-MM-DD你传入的是 2024/01/01。模型拿到这种信息一次就改对了。这个经验是错误信息要可操作告诉模型怎么改而不只是告诉它错了。7.4 多工具并行调用的顺序问题有些模型支持一次返回多个工具调用理论上可以并行执行提高效率。但实际用下来发现如果工具之间有依赖关系比如第二个工具需要第一个的结果并行执行会出错。我的处理是默认串行执行只有明确无依赖的工具才并行。判断依赖关系比较麻烦保守起见串行更稳。如果确实需要并行优化可以在工具定义里加一个依赖声明字段让模型知道哪些工具可以一起调。8. 关于 Agent 学习路线的一点个人建议如果你刚开始学 Agent我的建议是别一上来就啃框架文档。框架抽象了很多细节你照着文档能跑起来一个 demo但出了问题完全不知道从哪查。更好的路径是先手写一个最简单的 ReAct 循环只配一两个工具把模型输出工具调用 → 执行 → 结果回传 → 模型继续这个流程跑通。然后逐步加东西加 Context 压缩、加错误处理、加死循环检测、加多个工具。每加一个都实际跑一下观察行为变化。这个过程走完你对 Agent 的理解会比看十篇教程都扎实。再往后就是针对具体场景做优化。不同任务的瓶颈不一样有的卡在工具调用准确率有的卡在 Context 长度有的卡在推理轮次太多。没有通用解法只能具体问题具体分析。但只要你把前面这些基础打牢了遇到问题知道往哪个方向查剩下的就是时间和经验的事了。我自己到现在也不敢说把 Agent 玩透了这个领域变化太快新的模型能力、新的框架、新的范式层出不穷。但底层那套东西——Context 怎么管、工具怎么设计、失败怎么处理——这些是不太会变的。把这些搞明白上面不管出什么新东西你都能快速上手。