
1. 从七个零件到七次抉择AI Agent 到底怎么落地很多人第一次接触 AI Agent 这个词脑子里浮现的是科幻电影里那种能自己思考、自己行动的智能体。但真到了工程落地阶段你会发现它没那么玄乎——本质上就是一个 LLM 加上一套循环机制、工具调用、记忆管理和任务编排的组合体。我过去一年里参与过几个 Agent 项目的搭建从最开始的套壳对话到后来能自主完成多步任务的系统踩过的坑比想象中多得多。这篇文章想做的事情很直接把 Agent 拆成七个核心要素再顺着工程实现的脉络梳理出七个关键决策点让你看完之后能自己动手搭一个能跑起来的 Agent而不是停留在概念层面。先说清楚这篇文章适合谁看。如果你是大模型应用开发者正在琢磨怎么把 LLM 从聊天机器人升级成能干活的东西那这篇就是写给你的。如果你是对 Agent 架构感兴趣的技术管理者想搞清楚团队做 Agent 到底要投入哪些模块也能从这里拿到一个清晰的框架。哪怕你只是刚入门听说过 tool calling、ReAct、memory 这些词但没实际写过我也会尽量用生活化的类比把原理讲透让你知道每一步为什么这么做而不是照抄代码。核心关键词先摆出来AI Agent、LLM、工具调用、循环机制、Agent 架构。这几个词贯穿全文也是理解 Agent 工程实现的钥匙。我不会堆砌术语而是围绕一个 Agent 从零到跑起来需要做哪些决策这条主线展开每个决策点都会给出我的选型理由、实操细节和踩坑记录。2. 七个核心要素Agent 的解剖学在聊决策点之前得先把 Agent 的构成讲清楚。我习惯把它拆成七个要素这七个要素缺一个Agent 就不完整。你可以把它想象成开一家餐厅LLM 是厨师工具是厨房设备记忆是菜谱和库存记录循环机制是出餐流程规划是菜单设计执行是实际炒菜反馈是顾客评价。少了哪个环节餐厅都开不下去。2.1 LLM 作为推理内核选型比调参更重要LLM 是 Agent 的大脑负责理解任务、做决策、生成行动指令。这里第一个要面对的问题就是用哪个模型我的经验是不要一上来就追求最强模型。Agent 的特点是调用频繁一个任务可能触发十几次甚至几十次 LLM 调用token 成本会迅速放大。所以选型时要平衡三件事推理能力、调用成本、响应延迟。对于工具调用密集型的 Agent我通常优先选原生支持 function calling 的模型。原因很简单原生支持意味着模型在训练阶段就见过工具调用的格式输出的结构化程度高解析失败率低。如果用一个不支持 function calling 的模型你得靠 prompt 硬凑 JSON 输出再写一堆正则去解析稳定性差一大截。实测下来原生支持的模型在工具调用成功率上能高出 20% 到 30%。另一个容易被忽略的点是上下文窗口。Agent 在执行多步任务时历史对话、工具返回结果、中间推理过程都会堆进上下文。如果窗口太小跑到一半就得截断历史Agent 会失忆忘记之前做过什么。我一般建议至少 32K 起步复杂任务场景下 128K 更稳妥。但窗口大不代表要全塞满后面讲记忆管理时会细说怎么控制。提示选模型时先做一个小测试——给它三个工具定义让它根据一个多步任务决定先调哪个。如果它能在不额外提示的情况下正确规划顺序说明这个模型的 agentic 能力过关。2.2 工具调用Agent 的手和脚工具调用是 Agent 区别于普通聊天机器人的核心能力。没有工具Agent 只能说有了工具它才能做。工具可以是搜索、计算器、数据库查询、API 调用、文件读写甚至是对另一个 Agent 的调用。工程上工具调用的关键不在于工具本身多复杂而在于工具描述的质量。我见过太多项目工具功能写得没问题但描述含糊导致模型不知道该在什么场景下调用它。工具描述要回答三个问题这个工具做什么、什么时候用、参数怎么填。比如一个天气查询工具描述不能只写查询天气而要写根据城市名称查询当前天气适用于用户询问某地天气状况的场景参数 city 为城市中文名。工具的数量也要控制。我个人的经验是单次暴露给模型的工具不要超过 10 个。工具太多模型选择时会犹豫调用错误率上升。如果确实有很多工具可以做分层先让模型选工具类别再在类别内选具体工具。这就像你去餐厅点菜菜单太长反而不知道吃什么分个前菜、主菜、甜点就好选多了。2.3 记忆管理让 Agent 记住该记的记忆分短期和长期。短期记忆就是当前任务的上下文长期记忆是跨会话的知识积累。很多 Agent 项目只做了短期记忆跑完一个任务就失忆下次遇到类似问题还得从头来。短期记忆的管理核心是上下文压缩。当对话历史超过一定长度不能简单截断而要做摘要。我的做法是保留最近几轮完整对话把更早的历史用 LLM 压缩成一段摘要。这样既保留了关键信息又控制了 token 消耗。摘要的 prompt 要明确要求保留已完成的步骤、当前进度、待办事项这三类信息。长期记忆的实现方式有好几种向量数据库存储、结构化数据库、甚至简单的文件追加。选哪种取决于你的场景。如果是知识问答类 Agent向量数据库配合语义检索是标配如果是任务执行类 Agent结构化存储任务记录更实用。我踩过的一个坑是一开始用向量库存所有历史结果检索时经常召回不相关的旧记录干扰当前任务。后来改成只存成功完成的任务模式检索准确率才上来。2.4 循环机制Agent 的心跳循环机制是 Agent 的运行时骨架。最经典的是ReAct 模式推理Reasoning→ 行动Action→ 观察Observation循环往复直到任务完成。这个循环看起来简单但工程实现时有几个关键决策。第一是循环终止条件。不能无限循环必须设置最大步数。我一般设 10 到 15 步超过就强制终止并返回当前结果。第二是每步的验证。模型输出的行动指令要经过校验才能执行比如参数格式对不对、工具名存不存在。第三是异常处理。工具调用失败时是把错误信息返回给模型让它重试还是直接终止我的做法是返回错误信息并允许重试一次连续失败两次才终止。循环机制的设计直接决定了 Agent 的可靠性。我见过一个项目循环里没有步数限制结果模型陷入死循环一直调用同一个工具烧了一堆 token 才被人工发现。所以任何循环都必须有硬性上限这是铁律。2.5 规划能力先想后做还是边做边想规划能力决定 Agent 是谋定而后动还是走一步看一步。前者叫 plan-and-execute后者叫 ReAct。两种模式各有适用场景。Plan-and-execute 适合步骤明确、依赖关系清晰的任务比如帮我订一张从北京到上海的机票然后预订酒店最后安排接机。Agent 先拆解出完整计划再逐步执行。优点是全局视角好不容易漏步骤缺点是如果中途情况变化计划要重新调整。ReAct 适合探索性任务比如帮我找一下这个 bug 的原因。Agent 边查边想根据每步结果决定下一步。优点是灵活缺点是容易跑偏需要好的引导。我的经验是复杂任务用混合模式先让模型生成一个粗粒度计划执行时每一步再用 ReAct 细化。这样既有全局方向又有局部灵活性。2.6 执行引擎把决策变成动作执行引擎负责把模型的决策翻译成实际动作。这部分工程味最重也最容易被低估。它要处理的事情包括解析模型输出、参数校验、工具调用、超时控制、结果格式化。参数校验是重中之重。模型输出的参数经常有格式问题比如该传数字传了字符串、该传数组传了单个值。执行引擎要能识别并纠正这些常见错误而不是直接把错误抛给工具。我一般会写一层参数适配器对每个工具定义参数类型和转换规则模型输出后先过适配器再执行。超时控制也不能省。外部 API 调用可能卡住如果不设超时整个 Agent 就挂在那里。我给每个工具调用设 30 秒超时超时后返回错误信息让模型决定是否重试。2.7 反馈机制让 Agent 知道自己做得对不对反馈机制是 Agent 自我修正的能力。最简单的反馈是工具返回结果模型根据结果决定下一步。但更高级的反馈包括任务完成度评估、结果质量打分、错误归因。我常用的一个技巧是引入 critic 角色。在 Agent 完成任务后让另一个 LLM 调用或者同一个模型换个 prompt来评估结果是否满足原始需求。如果不满足把评估意见返回给主 Agent 让它修正。这个机制在代码生成类 Agent 上效果特别明显能显著降低看起来完成了但实际有 bug的情况。七个要素讲完你会发现它们不是孤立的而是相互咬合的。LLM 做决策工具执行动作记忆提供上下文循环驱动流程规划指引方向执行保证落地反馈促进修正。理解了这七个要素接下来看七个决策点就顺理成章了。3. 七个决策点工程实现的关键抉择要素是有什么决策点是怎么选。这部分是全文的核心我会把每个决策点的选项、我的选择理由、实操细节和踩坑经验都摊开讲。3.1 决策点一Agent 架构选单体还是多体第一个决策就是架构层面的做一个单体 Agent还是多个 Agent 协作单体 Agent 就是一个 LLM 加一套工具和循环所有任务都由它处理。优点是简单、调试方便、上下文统一。缺点是当任务复杂时prompt 会变得很长模型容易顾此失彼。多 Agent 是把任务拆给多个专职 Agent比如一个负责规划、一个负责执行、一个负责审核。优点是职责清晰、每个 Agent 的 prompt 可以精简。缺点是通信成本高、上下文传递容易丢信息、调试复杂。我的选择是从单体开始遇到瓶颈再拆。很多项目一上来就搞多 Agent 架构结果发现单体就能解决的问题被复杂化了。判断是否需要拆分的标准是单 Agent 的 prompt 是否超过 2000 字、是否经常混淆不同职责、是否在某个子任务上表现不稳定。如果这三个问题出现两个以上才考虑拆分。拆分时我推荐主从模式一个主 Agent 负责规划和调度多个子 Agent 负责具体执行。主 Agent 不直接调工具而是把子任务派给子 Agent。这样主 Agent 的上下文保持干净子 Agent 各自专注。3.2 决策点二工具调用的粒度怎么定工具粒度是个容易被忽视但影响很大的决策。粒度太粗一个工具干太多事模型难以精确控制粒度太细工具数量爆炸模型选择困难。我的原则是一个工具只做一件事但这件事要有实际意义。比如发送邮件是一个合理的工具粒度而连接邮件服务器和填写邮件内容就太细了应该合并。反过来处理用户请求就太粗了应该拆成具体的操作。实操中我会先列出 Agent 需要完成的所有原子操作然后合并同类项。合并的标准是如果两个操作总是连续出现且中间不需要模型决策就合并成一个工具。比如查询订单和格式化订单信息总是连着做就合并成查询并格式化订单。工具命名也有讲究。用动词加名词的格式比如search_weather、send_email、query_database。避免用do_stuff这种含糊的名字。命名清晰模型调用时出错率会降低。3.3 决策点三记忆存哪里、存多久记忆存储的决策涉及三个维度存储介质、存储内容、保留策略。存储介质方面短期记忆放内存就行长期记忆我推荐结构化数据库加向量库的组合。结构化库存任务记录、用户偏好这类精确信息向量库存知识片段、历史对话这类需要语义检索的内容。两者配合检索时先用结构化条件过滤再用向量相似度排序。存储内容要克制。不是什么都要记。我一般只存三类用户明确表达的偏好、成功完成的任务模式、反复出现的错误及解决方案。其他信息用完就丢。存太多会导致检索噪声大反而降低效果。保留策略上短期记忆随会话结束清空长期记忆设过期时间。我一般给长期记忆设 30 天过期定期清理。因为用户偏好和任务模式会变化太旧的记忆可能已经失效。注意存储用户相关数据时要考虑隐私合规敏感信息脱敏后再存这是底线。3.4 决策点四循环控制用固定步数还是动态判断循环控制的核心问题是什么时候停固定步数简单粗暴跑满 N 步就停。动态判断是让模型自己决定任务是否完成。我实际用的是两者结合设一个最大步数作为硬上限同时让模型在每步输出一个是否完成的标志。如果模型认为完成提前退出如果到最大步数还没完成强制退出并返回当前状态。这里有个细节模型判断完成经常过于乐观。它可能觉得给出了答案就算完成但答案其实不对。所以我会加一层验证模型说完成后用一个独立的判断逻辑可以是另一个 LLM 调用也可以是规则校验确认结果是否真的满足需求。验证通过才真正结束。最大步数怎么定我的经验值是任务预期步数的 2 到 3 倍。比如一个任务预计 5 步完成最大步数设 10 到 15。留出重试和纠错的空间又不至于无限循环。3.5 决策点五错误处理是重试还是降级Agent 执行过程中出错是常态。工具调用失败、模型输出格式错误、外部服务超时都会发生。错误处理的决策是重试、降级还是终止我的策略是分级处理。对于瞬时错误网络抖动、服务临时不可用重试一到两次。对于格式错误把错误信息返回给模型让它重新生成。对于逻辑错误比如参数值不合法返回具体原因让模型修正。连续失败三次才终止并返回错误。降级策略也要准备。比如主模型调用失败可以切换到备用模型主工具不可用可以切换到替代工具。降级不是必须的但在生产环境里有降级方案的 Agent 可用性明显更高。一个实用的技巧是错误信息要具体。不要只返回调用失败而要返回参数 city 为空请提供城市名称。模型拿到具体错误修正的成功率会高很多。3.6 决策点六Prompt 怎么组织才能稳定Prompt 工程在 Agent 里比在普通对话里更重要因为 Agent 的 prompt 要同时承载角色定义、工具说明、输出格式要求、约束条件。组织不好模型就会跑偏。我的 prompt 结构是四段式角色与目标、可用工具、输出格式、约束与示例。角色与目标放最前面让模型明确身份工具说明要简洁每个工具一两句话输出格式用 JSON schema 明确约束条件列清楚比如不要编造工具返回结果。Few-shot 示例很关键。我会放两到三个完整的输入-推理-工具调用-输出示例让模型模仿。示例要覆盖典型场景和边界情况。实测下来加了 few-shot 的 Agent输出稳定性提升明显。Prompt 长度要控制。太长的 prompt 会稀释关键信息。我的经验是核心指令控制在 500 字以内工具说明和示例另算。如果 prompt 超过 2000 字考虑拆分 Agent 或精简内容。3.7 决策点七怎么评估 Agent 好不好用最后一个决策点是评估。Agent 不像传统软件输入输出确定测试用例好写。Agent 的输出有随机性评估要设计专门的方案。我的评估分三层单元测试、场景测试、端到端测试。单元测试针对单个工具调用验证参数解析和执行结果场景测试针对典型任务验证 Agent 能否完成端到端测试模拟真实用户验证整体体验。评估指标我关注四个任务完成率、平均步数、工具调用准确率、token 消耗。任务完成率是核心低于 80% 就要优化。平均步数反映效率太高说明 Agent 在绕路。工具调用准确率反映 prompt 和工具描述的质量。token 消耗直接关系成本。评估要持续做。我一般建一个测试集包含 20 到 30 个典型任务每次改动后跑一遍对比指标变化。这样能及时发现回归问题。4. 从零搭一个 Agent实操流程与关键代码理论讲完该动手了。这部分我会用一个具体例子——一个能查询天气、计算、搜索信息的 Agent——把搭建流程走一遍。代码用 Python框架用最朴素的实现不依赖 LangChain 这类重型框架目的是让你看清每一步在做什么。4.1 环境准备与依赖安装先装依赖。核心就两个一个 LLM 客户端一个 HTTP 库。pip install openai requests如果你用的是其他模型服务换成对应的 SDK 就行。我建议先用官方 SDK 跑通再考虑封装。环境变量里配好 API key 和 base url。不要硬编码在代码里这是基本的安全习惯。import os from openai import OpenAI client OpenAI( api_keyos.getenv(LLM_API_KEY), base_urlos.getenv(LLM_BASE_URL) )4.2 定义工具与工具描述工具定义我用一个字典列表每个工具包含名称、描述、参数 schema 和实际执行函数。def get_weather(city: str) - str: # 实际项目里这里调天气 API这里用模拟数据 weather_data { 北京: 晴25度, 上海: 多云28度, 广州: 小雨30度 } return weather_data.get(city, f未找到{city}的天气数据) def calculate(expression: str) - str: try: result eval(expression) return str(result) except Exception as e: return f计算错误{e} tools [ { type: function, function: { name: get_weather, description: 根据城市名称查询当前天气适用于用户询问某地天气的场景, parameters: { type: object, properties: { city: { type: string, description: 城市中文名如北京、上海 } }, required: [city] } } }, { type: function, function: { name: calculate, description: 计算数学表达式适用于需要数值计算的场景, parameters: { type: object, properties: { expression: { type: string, description: 数学表达式如 23*4 } }, required: [expression] } } } ] tool_functions { get_weather: get_weather, calculate: calculate }工具描述我写得比较具体明确说了适用于什么场景。这是为了让模型知道什么时候该调这个工具。4.3 实现循环机制循环机制是 Agent 的心脏。我用一个 while 循环每轮调用模型根据模型输出决定是调工具还是返回结果。import json def run_agent(user_input: str, max_steps: int 10): messages [ {role: system, content: 你是一个能调用工具的助手。根据用户需求决定是否调用工具。如果需要调用工具输出工具调用如果不需要直接回答。}, {role: user, content: user_input} ] for step in range(max_steps): response client.chat.completions.create( modelyour-model-name, messagesmessages, toolstools, tool_choiceauto ) message response.choices[0].message # 如果模型没有调用工具说明它认为可以直接回答 if not message.tool_calls: return message.content # 把模型的工具调用请求加入历史 messages.append(message) # 执行每个工具调用 for tool_call in message.tool_calls: function_name tool_call.function.name function_args json.loads(tool_call.function.arguments) # 执行工具 if function_name in tool_functions: result tool_functions[function_name](**function_args) else: result f未知工具{function_name} # 把工具结果加入历史 messages.append({ role: tool, tool_call_id: tool_call.id, content: str(result) }) return 达到最大步数限制任务未完成这段代码有几个关键点。第一max_steps是硬性上限防止死循环。第二工具执行结果要带上tool_call_id这是模型匹配请求和结果的依据。第三工具执行失败时返回错误信息而不是抛异常让模型有机会修正。4.4 参数校验与错误处理上面的代码是简化版实际项目里参数校验不能省。模型输出的参数可能有各种问题我加一层校验。def validate_and_execute(function_name, function_args): if function_name not in tool_functions: return f错误工具 {function_name} 不存在 # 检查必填参数 tool_def next((t for t in tools if t[function][name] function_name), None) if tool_def: required tool_def[function][parameters].get(required, []) for param in required: if param not in function_args or function_args[param] is None: return f错误缺少必填参数 {param} try: return tool_functions[function_name](**function_args) except Exception as e: return f工具执行错误{str(e)}校验分两步先检查工具是否存在再检查必填参数是否齐全。都通过才执行执行时再包一层异常捕获。这样任何环节出错都返回可读的错误信息模型能据此调整。4.5 记忆与上下文管理当对话变长上下文会膨胀。我加一个简单的压缩逻辑超过一定轮数把早期对话摘要化。def compress_messages(messages, keep_recent6): if len(messages) keep_recent 1: return messages system_msg messages[0] recent messages[-keep_recent:] old messages[1:-keep_recent] # 把旧对话压缩成摘要 summary_prompt 请用一段话总结以下对话的关键信息保留已完成的步骤和当前进度\n for msg in old: summary_prompt f{msg.get(role, unknown)}: {msg.get(content, )}\n summary_response client.chat.completions.create( modelyour-model-name, messages[{role: user, content: summary_prompt}] ) summary summary_response.choices[0].message.content return [system_msg, {role: system, content: f历史摘要{summary}}] recent这个压缩逻辑在每轮循环开始前调用。保留最近 6 条消息更早的压缩成摘要。摘要 prompt 明确要求保留已完成的步骤和当前进度这是 Agent 继续任务最需要的信息。4.6 跑起来看看效果把上面的代码拼起来跑一个测试。if __name__ __main__: result run_agent(北京今天天气怎么样如果温度超过20度帮我算一下25乘以4) print(result)预期执行流程是模型先调get_weather查北京天气拿到晴25度然后判断温度超过 20 度再调calculate算 25*4最后综合结果回答。整个过程大概 3 到 4 步。实测下来这个简单 Agent 在天气加计算的组合任务上成功率很高。但如果任务更复杂比如需要多轮搜索和推理就需要更精细的 prompt 和更多的工具。5. 常见问题与排查技巧实录Agent 开发过程中遇到的问题五花八门我整理了一份速查表覆盖最常见的几类。5.1 模型不调用工具怎么办这是新手最常遇到的问题。模型明明有工具可用却直接回答不调工具。原因通常有三个工具描述不够清晰、prompt 没有引导、模型本身 agentic 能力弱。排查顺序先看工具描述是不是写得太笼统。再看 system prompt有没有明确说需要时调用工具。如果都没问题换个 agentic 能力更强的模型试试。我遇到过一个案例工具描述写的是查询数据模型不知道查什么数据改成根据用户ID查询订单数据后调用率立刻上来了。5.2 工具调用参数错误怎么修参数错误分两类格式错误和值错误。格式错误比如该传数字传了字符串值错误比如传了不存在的城市名。格式错误靠参数适配器解决。我在执行前加一层类型转换按 schema 定义把参数转成正确类型。值错误靠错误信息反馈解决。工具返回城市不存在后模型通常会换个城市重试。如果参数错误频繁发生说明工具描述里的参数说明不够详细。把参数示例写进描述里比如city 参数示例北京、上海能明显降低错误率。5.3 Agent 陷入死循环怎么破死循环的表现是 Agent 反复调用同一个工具或者在不同工具间来回跳。根本原因是模型没有从工具结果中获得有效信息或者任务本身无法完成但模型不放弃。硬性解法是设最大步数这个必须有。软性解法是检测重复调用如果连续两次调用同一个工具且参数相同就中断并返回提示。我还会在 prompt 里加一句如果工具返回结果无法解决问题请直接告知用户给模型一个放弃的出口。5.4 token 消耗过快怎么优化token 消耗主要来自三块system prompt、历史对话、工具返回结果。优化也是从这三块入手。System prompt 精简去掉冗余描述。历史对话用摘要压缩。工具返回结果做截断比如搜索结果只返回前三条长文本只返回摘要。我做过一个优化把工具返回结果从完整 JSON 改成关键字段提取token 消耗降了 40%。5.5 常见问题速查表问题现象可能原因排查方向解决技巧模型不调工具工具描述模糊检查 description 字段补充使用场景和参数示例参数格式错误缺少类型校验检查参数 schema加参数适配器做类型转换死循环无步数限制检查循环终止条件设最大步数加重复调用检测token 消耗高上下文膨胀统计各部分 token 占比压缩历史、截断工具结果任务完成率低prompt 引导不足检查 few-shot 示例补充典型场景示例工具调用失败外部服务问题查看错误日志加重试和降级策略这张表我建议贴在工位上遇到问题先对照排查能省不少时间。5.6 几个独家避坑技巧第一个技巧给工具调用加日志。每次调用记录工具名、参数、返回结果、耗时。出问题时翻日志比猜快得多。第二个技巧用真实用户输入做测试。自己造的测试用例往往太规整真实用户输入有错别字、有歧义、有跳跃。我一般收集 50 条真实输入做回归测试。第三个技巧prompt 改动要版本化。Agent 的 prompt 是核心资产改一次可能影响很大。我用 git 管理 prompt每次改动写清楚原因出问题能回滚。第四个技巧别迷信大模型。有些任务用小模型加好的 prompt效果不比大模型差成本却低很多。我有个项目把模型从最大号换成中号任务完成率只降了 3%成本降了 70%。6. 关于 Agent 工程实现的一些个人体会搭 Agent 这件事我最大的体会是工程细节决定成败。模型能力固然重要但真正让 Agent 稳定运行的是那些不起眼的工程处理——参数校验、错误重试、上下文压缩、循环控制。我见过太多项目模型选得很好prompt 也写得漂亮但因为没有做好错误处理一遇到工具调用失败就整个崩掉。另一个体会是从简单开始。不要一上来就搞多 Agent、复杂记忆、动态规划。先用单体 Agent 加两三个工具跑通再根据实际瓶颈逐步加东西。很多复杂度是想象出来的真跑起来才发现根本用不上。最后说一个我觉得被低估的点评估体系。没有评估你根本不知道 Agent 改进了还是退步了。我建议从第一天就建测试集哪怕只有 10 个用例。随着项目推进测试集不断扩充它就成了你最可靠的参照系。Agent 这个领域变化很快新框架、新方法层出不穷。但底层的东西——循环、工具、记忆、规划——是相对稳定的。把这七个要素和七个决策点吃透不管上层怎么变你都能快速上手。后续如果想深入可以研究一下多 Agent 协作的通信协议、Agent 的安全防护、以及怎么用强化学习优化 Agent 的决策策略这些都是很有价值的方向。