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_key=os.getenv("LLM_API_KEY"), base_url=os.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": "数学表达式,如 2+3*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( model="your-model-name", messages=messages, tools=tools, tool_choice="auto" ) 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_recent=6): 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( model="your-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 的决策策略,这些都是很有价值的方向。