先说个场景。你调用大模型接口,输入“帮我查一下下周北京的天气,顺便对比一下和上海的温差,最后写一段出行建议”,模型大概率会给你一段“我无法直接查询实时天气”之类的回复。但如果你把这个任务交给一个Agent,它会自己去调天气API、把两个城市的数据拉出来、做对比、写建议,一气呵成。这个差距,就是Agent存在的意义。
我研究Agent有两年多,从最开始对着LangChain源码一脸懵,到后来带团队做多Agent协作系统,踩过的坑不算少。本篇就用一个通用概念版的框架,把Agent的原理拆开揉碎讲清楚。它适合刚接触这个概念的人,也适合已经写过一些Agent但想系统化梳理的人。不涉及某个具体框架的绑定,讲的是内核逻辑。
1. 核心概念:Agent到底是什么,以及它和普通LLM调用的本质区别
1.1 Agent不是模型,而是一种“模型使用方式”
这是最容易绕晕的地方。很多人把Agent当成一种新模型,其实它根本不是。Agent是在LLM之上构建的一套推理与执行循环机制。模型还是那个模型,但你不是简单地“输入-输出”,而是给它一个目标,让它自己决定要怎么完成,包括要调用什么工具、按什么顺序调用、中间结果怎么处理、错了怎么补救。
我常用一个类比:普通LLM调用就像一个刚入职的实习生,你问什么他答什么,但答错了他不会自己察觉。Agent则像是一个带工具箱的老员工,你给他一个目标,他会说“我先查资料,再做个方案,然后拉同事评审,最后交付”,遇到问题还会调整方案。这个“自己规划、自己执行、自己纠错”的能力,就是Agent的核心。
所以严格来说,“Agent原理”讲的是如何把LLM包装成这样一个具备自主行为的系统。核心组件就四个:模型(大脑)、工具(手脚)、记忆(经验)、编排(行动策略)。
1.2 从Chain到Agent:控制权的转移
理解Agent,有个很好的参照物是Chain。早期的LangChain等框架推崇Chain模式,把任务拆成固定步骤,写死在代码里:“第一步调A接口,第二步把结果给模型总结,第三步输出”。这种方式稳定可控,但有一个致命问题——应对不了没有预料到的情况。
Agent模式把控制权交还给了模型本身。还是那个流程,但具体步骤怎么走、用哪个工具、什么时候停下来不干了,都由模型基于当前上下文动态决策。这在工程上的感受就是:你从写流程变成了写条件、写工具、写边界。你不再控制每一步的走向,而是控制“允许走的路有哪些”。
这也是为什么很多团队从Chain迁移到Agent后,会经历一阵阵痛期。因为感觉上“失控”了,模型可能会走你完全没想到的路线。但正是这种自由度,带来了处理复杂任务的能力。Chain适合稳定流水线,Agent适合开放场景。
1.3 AI Agent的核心能力图谱:感知、决策、行动、记忆
把Agent拆解成能力维度,比直接看论文好理解得多。我习惯把它分为四环:
- 感知(Perception):获取任务相关的外部信息。可以是用户输入,也可以是从数据库、API拉取的数据。这是Agent判断的依据。
- 决策(Decision):基于当前状态和目标,选择下一步行动。这里主要靠LLM的推理能力,常见的有ReAct模式下的“思考-行动”循环。
- 行动(Action):调用工具、执行代码、发送请求、操作文件。这是Agent影响外部世界的方式。
- 记忆(Memory):短期的上下文窗口内容,中期的会话摘要,长期的知识沉淀。记忆决定了Agent能不能在长任务、多轮对话中保持一致性和积累经验。
这四个环不是顺序执行一次就结束,而是形成一个闭环循环。Agent执行一个行动后,观察结果(相当于新的感知),重新决策(更新计划),执行下一步行动。循环一直到任务完成,或者触碰你设定的终止条件。所以看Agent系统,本质上看它是怎么把四个环组织成一个高效、可控的闭环。
2. 核心细节解析:记忆、规划、工具调用三大支点
2.1 记忆体系:短期、中期、长期到底怎么实现
“Agent记忆”是所有做Agent的人绕不过去的坎,尤其是当你做的是有状态的多轮任务时。没有记忆的Agent就像一个每次见面都忘了你是谁的朋友,聊两句就跑偏。
短期记忆就是上下文窗口(context window)本身。对话记录直接拼进Prompt交给LLM。实现最简单,但受限于模型上下文长度。超出后,最简单粗暴的做法是丢弃旧的,或者做截断。可一旦丢弃了关键信息,Agent的逻辑就断了。
中期记忆通常叫会话摘要(conversation summary)。随着对话变长,你不可能把所有历史都塞进上下文。常见做法是每隔若干轮,调用LLM把前面的内容压缩成摘要,存起来,后续只带摘要加上最近的几轮完整对话。这个做法的好处是省token,坏处是摘要会丢失细节。比如用户在两小时前说过一个特定的API名称,摘要可能只写了“用户提出了一个技术问题”,后续Agent就懵了。
长期记忆则存储在外部数据库中,通常是向量数据库。实现路径很成熟:把需要记住的信息切片、用embedding模型向量化、存入向量库,然后在需要时,把当前问题向量化,做相似度检索,把命中的记忆块塞进Prompt。这块的痛点不在技术,而在工程:什么时候该写入记忆、写入什么、怎么避免检索到过期的错误信息。
我的实际经验是,长期记忆不要什么东西都往里塞,要做筛选。我一般定义一个“值得记忆”的条件——比如用户明确修正过的事实、任务中频繁出现的实体、结论性的内容。筛选的动作可以靠LLM做,也可以靠规则,也可以两者结合。很多人一上来就把全量对话灌进向量库,检索结果全是噪音,效果反而比精简记忆更差。
2.2 规划能力:任务拆解、反思修正、以及ReAct模式
规划是Agent最像“人”的地方。接到一个复杂目标,不是闷头干,而是先拆。
任务拆解有两种主流路线。一种是一次性拆解,让LLM把大目标分解成子任务清单,然后按顺序执行。适合结构相对清晰的任务,比如“写一篇行业分析报告”可以拆成“收集资料、梳理框架、撰写初稿、润色校对”。另一种是动态拆解,走一步看一步,每次只决策当前这一步该做什么。最近流行的LLM Compiler思路也是这种动态规划的变体,先规划一个大致的骨架,再逐层填补细节。
ReAct是这里绕不开的名字,我建议所有学Agent的人都先手写一遍ReAct。ReAct就是把“推理(Reason)”和“行动(Act)”交错进行。每一次循环中这样走:模型先观察当前状态,输出一段思考(Thought),然后决定行动(Action),系统执行行动得到观察结果(Observation),再把这个结果反馈给模型,继续下一轮思考。这个过程跟人类解决问题的思路一模一样:我先想想看这问题是什么性质,然后去做个实验,看到实验结果,再调整思路。
**反思机制(Reflection)**是进阶玩法。在Agent执行完一轮任务后,额外调用一次LLM,让它回顾整个执行过程,找出哪里做得不好,下次怎么改进,然后把这个反思结果存进记忆。有人觉得这不就是多花一次token吗?实际效果非常显著。LLM很擅长在做完事后马后炮式地审查自己的过程,这种“事后改进”积累几轮之后,Agent的准确率提升明显。我之前用Reflexion框架做实验,在特定代码生成任务上,加上反思后成功率提升了接近20个百分点。
2.3 工具调用:Function Calling、工具注册与选择的逻辑
Agent的能力上限,一半取决于它能不能调用工具。没有工具,Agent只能凭训练数据说话,有了工具,它就能连接到实时世界。
当前主流实现是Function Calling。你把工具描述成JSON Schema传给模型,比如定义一个函数叫get_weather,参数是city和date。模型在决策时如果觉得需要查询天气,就不会直接输出天气,而是输出一个结构化的函数调用请求,比如{"name": "get_weather", "arguments": {"city": "北京", "date": "2025-01-01"}}。然后由你的代码来执行这个工具,把结果反馈给模型。
这里有个关键细节:Agent并不真正直接执行代码中的函数,它只是生成调用请求,真正的执行发生在你的程序里。这是所有Agent框架的通用安全设计——模型不直接操作执行环境,而是通过你的代码来间接操作。所以工具函数里你可以放权限校验、参数合法性检查、日志记录,给Agent一个“戴着镣铐”的行动能力。
工具注册这块,实践中我建议维护一个工具清单,给每个工具写清楚:它能做什么、什么时候用、参数说明、注意事项。工具描述的质量直接决定了模型选工具的准确率。描述写得太烂,模型就瞎调。举例:某个工具其实专门用于重试失败的网络请求,如果你描述写的是“发送HTTP请求”,模型遇到需要重试的场景可能就直接调别的工具去了,你要在描述里明确加上“当请求失败且需要重试时,使用此工具”。
工具选型的另一个层面是工具数量。同一场景下,提供的工具数量不是越多越好。工具太多,模型在筛选时容易混乱,响应时间和准确率都会受影响。我的建议是分层:每个Agent只挂载它这个角色需要的工具,宁可拆成多个专用Agent,也不要一个Agent挂几十个工具。
3. 从0到1手写一个最小可用ReAct Agent
3.1 设计思路与整体流程
理论说了那么多,该上手了。很多框架把Agent封装得面目全非,反而不利于理解。我建议你亲手写一个极简的ReAct Agent——不用任何Agent框架,就靠原生LLM接口加一个工具函数。写完之后,你对整个工作流程的掌控感会完全不一样。
这个最小版本做一件事:根据用户的问题,决定是否调用一个“计算器工具”来完成数学运算。整体循环流程是这样的:
- 组装系统Prompt,告诉模型它有哪些工具可用、应该遵循什么样的思考和行动模式。
- 把用户问题和历史轨迹发给模型。
- 模型返回结果。如果包含Thought和Action,我们就解析出工具名和参数,执行工具,拿到Observation,把它拼接到上下文,回到第2步继续。
- 如果模型返回的是Final Answer,就终止循环,把答案返回给用户。
这个循环本质上就是上面说的感知-决策-行动闭环的最简实现。
3.2 代码实现与关键讲解
我用Python加上OpenAI兼容接口来写。如果你用的是其他家的模型,改一下base_url和api_key就行。
import json import openai client = openai.OpenAI( api_key="your-api-key", base_url="https://your-model-endpoint" # 各家模型的兼容接口 ) # 工具定义:一个计算器 tools = [ { "type": "function", "function": { "name": "calculator", "description": "执行数学运算,支持加减乘除和指数运算。", "parameters": { "type": "object", "properties": { "expression": { "type": "string", "description": "要计算的数学表达式,例如 (12 + 34) * 2", } }, "required": ["expression"], }, }, } ] def calculator(expression: str) -> str: # 这里为了演示用eval,生产环境不要这样写,会有代码注入风险 try: result = eval(expression, {"__builtins__": {}}, {}) return str(result) except Exception as e: return f"计算出错: {str(e)}" def run_agent(user_query: str, max_steps: int = 8): # 消息历史:包含系统Prompt、用户请求,以及后续的动态轨迹 messages = [ { "role": "system", "content": ( "你是一个能调用工具的智能体。当用户的问题需要计算时," "你会使用 calculator 工具。你必须严格按照 Thought → Action → Observation 的循环来处理," "最终给出 Final Answer。" ) }, {"role": "user", "content": user_query} ] for step in range(max_steps): print(f"\n--- 第 {step + 1} 轮循环 ---") # 调用模型,让它决定下一步是调用工具还是给出最终答案 response = client.chat.completions.create( model="your-model-name", messages=messages, tools=tools, tool_choice="auto" ) msg = response.choices[0].message messages.append(msg) # 情况一:模型决定调用工具 if msg.tool_calls: tool_call = msg.tool_calls[0] fn_name = tool_call.function.name fn_args = json.loads(tool_call.function.arguments) print(f"Tool Call: {fn_name}({fn_args})") if fn_name == "calculator": observation = calculator(fn_args.get("expression", "")) # 把工具结果作为 tool 角色的消息追加到对话历史中 messages.append({ "role": "tool", "tool_call_id": tool_call.id, "content": observation, }) print(f"Observation: {observation}") # 继续循环,让模型看到工具结果后决定下一步 continue # 情况二:模型直接输出最终答案(没有工具调用) if msg.content: print(f"Final Answer: {msg.content}") return msg.content return "已达到最大执行步数,任务提前终止。" if __name__ == "__main__": query = "计算 (23 + 45) * 6 的结果,然后告诉我结果再加上 100 是多少?" run_agent(query)这段代码的核心逻辑就两个分支:模型要调用工具,我们就执行并回填;模型直接给答案,就结束。看起来简单,但这就是所有Agent框架的地基。LangGraph、AutoGPT这些重框架,底层都是一样的循环逻辑,只是加了状态管理、恢复机制、并发处理这些工程能力。
3.3 这个实现的关键细节与扩展方向
第一个细节是消息历史的管理。注意看,tool_call的id要和tool消息里的tool_call_id严格对应。这是各家LLM接口的通用约定:模型发起一个tool调用后会有一个ID,你执行完工具后,要把结果以tool角色、带着同一个ID发回去。ID对不上,模型就不知道这个观察结果对应的是哪个工具调用。
第二个细节是循环终止条件。我这写了max_steps限制,这是保命用的。没有这个限制,理论上模型可能陷入无限循环——调用工具、看结果、再调用、再看结果,永远不输出Final Answer。真实项目中,除了步数限制,还要加时间限制和token预算限制。
第三个细节是错误处理。工具执行可能失败,比如计算器遇到非法表达式。我在工具内部做了try-except,把错误信息作为observation返回给模型。模型看到错误信息后,通常会尝试修正调用或者换一种方式。这非常关键——错误本身也是信息,要把错误反馈给模型,而不是直接让整个流程崩溃。
扩展方向上,最直接的是加记忆。你可以把历史对话存到数据库,下次启动时把之前的摘要加载进来。其次是加多个工具——比如加一个搜索工具、一个文件读写工具,模型会根据问题自行选择。再进阶一点,就是让模型自己写代码并执行,这就是Code Interpreter类的实现路径了。这些都是从这段基础代码生长出来的枝干。
4. 主流Agent框架横评:LangGraph、AutoGPT、CrewAI、OpenAI Swarm等
4.1 框架分层:低阶编排与高阶自动化的不同设计哲学
现在市面上的Agent框架多得让人眼花,但如果你俯瞰一下,会发现它们分两个流派。
低阶编排框架,代表是LangGraph。这类框架不替你做决策,而是给你提供一套精细的控制工具:节点、边、状态、条件跳转。你把任务流程画成一张图,然后每个节点可以是一个LLM调用,可以是一个工具执行。路径如何选择,可以用LLM判断,也可以写死代码逻辑。LangGraph适合复杂生产场景,因为你可以精确控制每一步、每一条跳转路径,可观测性和容错性都很好。代价是学习曲线陡峭,你得先想清楚整个图的结构。
高阶自动化框架,代表是AutoGPT。这类框架强调“给个目标,模型自己搞定一切”。你输入“帮我调研竞品A的定价策略并生成报告”,它就自己规划步骤、自己调用工具、自己组装报告。听起来很美好,但实际用的时候你会发现,过度自由会带来不稳定。任务越开放,模型越容易在某个环节跑偏,且一旦跑偏,排查起来不容易。AutoGPT这类框架适合原型验证和比较简单的自动化任务,生产环境用起来要非常小心,必须做任务边界裁剪。
我的建议是,个人学习和简单项目,可以先用高阶自动化框架找感觉,但真正要交付给业务系统用,还是低阶编排框架更可靠。本质上,Agent系统的可靠性跟“可控性”强相关,越低阶,你掌控的细节越多,越稳定。
4.2 多Agent框架与协作模式
多Agent协作是最近的热点。当一个任务足够复杂,单个Agent包办一切往往不如多个专职Agent分工合作来得稳定。这就像你开公司,一个人既当前台又当会计又当销售,容易出错,但各司其职的团队反而能稳定运行。
CrewAI是代表性的轻量级多Agent框架。核心概念是Role(角色)、Goal(目标)、Backstory(背景故事)、Task(任务)、Crew(团队)。你定义几个角色,比如“市场分析师”和“文案写手”,每个角色有自己的目标和约束,然后创建任务分配给不同角色,最后组成一个Crew来协同完成。CrewAI的设计对新手很友好,理解起来很直觉。
OpenAI Swarm则更轻量,设计哲学是让Agent通过手递手(handoff)的方式进行协作。每个Agent负责特定领域,当它判断自己搞不定时,可以把会话交接给另一个更合适的Agent。这种handoff机制实现起来很简单,却很实用。我们做客服系统时就用过类似的设计:一个前台Agent接单,它判断用户问的是技术问题,就把会话转给技术Agent,是账单问题就转给财务Agent。
多Agent协作有个避不开的坑:上下文共享。不同Agent之间是共享一套消息历史,还是各存各的、只在交接时传递摘要?这是架构设计时要想清楚的问题。共享历史简单但浪费token,而且信息噪音多;各存各的省token,但交接时容易丢失细节。我们实践中用的是“核心档案共享,过程记录隔离”的方案——用户的基本需求和偏好共享,每个Agent自己的工作记录独立存储,交接时由LLM生成交接摘要。
4.3 无法绕开的名字:OpenAI的Assistants API与Function Calling生态
严格来说,OpenAI提供的不是“Agent框架”,而是Agent的底层构件。Function Calling是工具调用的标准方式,已经成了行业事实标准。Assistants API提供的是会话管理、文件检索、代码解释器这些托管能力,你可以在此基础上构建自己的Agent逻辑。
MCP(Model Context Protocol)也值得关注。它本质上是一个开放协议,定义了“工具如何标准化地暴露给模型”。在MCP出现之前,每个框架都要自己对接不同应用的工具,兼容性堪忧。MCP把工具定义、调用、鉴权做了标准化,有了它,一套工具可以接入多个Agent系统。这很像USB标准——之前每个设备都有自己的接口,现在统一了。目前主流的Agent框架基本都支持MCP协议了,新项目我建议直接上MCP标准,减少未来适配成本。
另外还有一个概念容易被混用,就是Skill和Agent的关系。Skill本质上是某个Agent可复用的一组能力封装——比如“处理PDF文档”这个Skill可能包含“读取PDF、提取表格、总结内容”三个操作,它不是一个独立的Agent,而是挂载在Agent上的能力模块。Harness则是执行环境的概念,是Agent跑在里面的沙箱容器,定义了代码执行、文件系统、网络等边界。明白这些概念的区别,面试和设计时就不会说混。
5. 落地部署与工程化避坑指南:从Demo到生产
5.1 上下文管理的工程细节:Token预算与内存控制
很多人在Demo里跑通Agent后就往生产推,然后被上下文爆炸打了一个措手不及。Agent和普通Chat有本质区别——普通Chat就一轮问答,Agent要循环多轮,每轮的上下文还要不断拼接工具结果,Token消耗速度是指数级别的。
举一个实际例子。我们有个Agent任务,平均每轮执行5次工具调用。每次工具调用产生大约1000字符的观察结果。一次任务下来,工具观察文本就有5000字符,加上历史对话和系统Prompt,轻松突破上万token。如果任务日志不禁掉或压缩,跑几个小时,上下文窗口直接打爆——也就是搜索引擎里常见的“agent execution terminated due to error”报错。这不是LLM的问题,是我们没管好上下文预算。
我的工程建议,是三段式管理:
- 固定前缀区:系统Prompt、工具Schema、长期记忆。这个区域尽量精简,工具Schema描述要精炼但要准确,长期记忆只保留高价值信息。
- 滚动窗口区:最近N轮对话(包括Thought、Action、Observation)。经验值N在4到6之间比较合适,太少了Agent会丢失过程信息,太多了浪费token。
- 压缩归档区:在此之前的对话信息,用摘要方式存储。每5轮左右把旧内容压缩成一段摘要,替换原始内容。
这套机制看着简单,但效果立竿见影,能让Agent的长时运行稳定很多。需要留意的是,压缩和摘要本身也要消耗token和时间,所以阈值要按任务复杂度调。轻量任务窗口设短一些,复杂推理任务可以适当加长。
5.2 工具设计与安全边界:权限、校验、审计三位一体
工具设计是Agent工程里最容易出安全问题的一环。模型不像人,它在调用工具时不会天然地去想“这个操作会不会有副作用”。如果你给Agent挂上一个“删除服务器文件”的工具,它真干起来不会犹豫。
我第一次做Agent工具安全的时候,参考的准则可以归纳成三条:
最小权限原则。Agent能用的工具,没明说需要就不要开。每个工具在分配时问自己:这个任务真的需要访问数据库?真的需要发邮件?不需要就不挂载。宁可后面再加,也不要一开始全开。
参数校验前置。工具内部在真正执行动作之前,一定要校验参数。比如一个“发送邮件”的工具,接收参数之前一定要校验收件人、校验邮件长度、校验有没有附件安全性问题。不要相信模型传来的参数一定合法。
人审机制。对于有副作用的高危操作——删除、修改、转账、发消息——加上人工确认步骤。模型生成请求之后,先挂起,由人工审核再执行。这在设计多Agent系统时尤其重要,因为一个Agent可能会被另一个Agent诱导去执行危险操作。
我还特别建议做全量审计日志。记下每一次工具调用:谁调的、什么参数、结果是什么、耗时多少。出了问题可以回溯。没有日志的Agent系统,排查问题就像盲人摸象,非常痛苦。
5.3 多Agent协作的常见冲突与处理策略
多Agent协作不是把多个Agent凑在一起就能自动好好配合的,实际跑起来你会遇到各种问题。
最常见的冲突是角色职责不清。两个Agent都能处理某类任务,结果用户请求到来时,两个Agent都抢着处理,或者互相以为对方会处理然后谁都不动。解决思路有两种:一是把职责边界画得非常清晰,每个Agent只能处理它专属领域的任务,其他一律转交;二是引入一个调度的路由Agent,它不直接处理任务,只负责判断谁来处理。我推荐后者更灵活,因为真实任务经常跨领域。
第二个常见问题是信息传递失真。Agent A把任务交接给Agent B时,A的总结摘要如果写得不好,B就理解偏了。这本质上是摘要质量问题。我的做法是让A在交接时不仅写自由文本摘要,还要把关键变量以结构化字段的形式传给B,比如“user_id=12345, issue_type=cancel_order, priority=high”,用结构化信息兜底,B即使摘要理解偏了,关键数据也不会丢。
第三个问题是死锁与循环。AgentA等AgentB的结果,AgentB又等AgentA的结果,两人干瞪眼。这是流程设计层面的缺陷,在编排图上就要避免形成循环依赖。如果确实需要多Agent来回讨论,一定要设置最大交互轮数,超时强制熔断。
5.4 Agent评测:不评测,不优化
Agent系统的评测是我见过最少被讨论、但实际最要命的问题。传统的LLM评测是一问一答,好判断对错。Agent是一串动作序列,你怎么评它好不好?看最终结果正确?如果过程非常低效呢?如果第一次执行错了,但它自己修正回来了呢?
我建议至少从三个维度建立评测体系:
- 任务成功率:最终产出是否符合预期。比如一个数据分析Agent,成功标准是“给出正确的计算结论和图表”。
- 执行效率:完成相同任务,用了多少轮循环、多少token。两个Agent任务成功率都是80%,但A平均5步完成,B平均15步,高下立判。
- 稳定性:同一个任务跑10次,成功率波动大不大?有些Agent在简单变体上表现好,换复杂变体就全线崩溃,这类系统在真实场景里不敢随便上。
评测集的构建也有讲究,别只用几个精心挑选的样本。要覆盖正常情况、边界情况、异常情况,尤其是异常输入——比如用户输入了不相关的内容、工具返回了错误数据、模型生成了非法的工具调用。这些“脏数据”场景,往往是Agent系统在实际生产中最容易翻车的地方。
6. 常见问题与面试高频考点经验实录
6.1 实际踩坑问题速查表
我把这几年的实践沉淀成一个问题速查表,分享出来。这些问题几乎每个做Agent的人都会碰到。
| 现象 | 根本原因 | 解决方案 |
|---|---|---|
| Agent反复调用同一个错误工具 | 工具描述不准确或工具区分度太低 | 重写工具描述,突出使用边界和适用场景,必要时减少工具数量 |
| Agent在工具调用后陷入死循环,不输出最终结果 | 循环终止条件缺失,模型在思考-action循环里出不来 | 加入max_steps限制、时间限制、Token预算 |
| 上下文增长过快,超限报错 | 没有做消息压缩,工具观察结果全部保留 | 实施滚动窗口加压缩摘要策略,控制上下文增长 |
| 工具执行报错后Agent行为变得混乱 | 错误信息没有结构化地反馈给模型 | 把错误捕获后格式化为观察结果,明确告知模型“这次调用失败,可能的原因是……” |
| 多Agent协作出现信息丢失 | 交接时只传递自由文本摘要,关键结构化信息丢失 | 增加结构化字段传递关键数据和状态 |
| Agent不调用工具而是直接编造答案 | 文章中的系统提示没有强调“必须使用工具”或工具Schema有误 | 强化系统提示约束,检查工具定义是否符合模型接口要求 |
| 同一个任务,效果时好时坏 | 模型温度过高或任务本身开放度过高 | 降低温度,细化任务边界,引入反思机制收敛行为稳定性 |
6.2 Agent面试高频考点与回答要点
最近有不少读者问Agent面试会问什么。我结合自己做面试官的经验,把高频考点拉一个单子,每个题我都会说清楚想听到什么样的答案。
“你怎么理解Agent?”别上来就背定义。好的回答是:先区分LLM和Agent,再讲Agent的能力闭环(感知-决策-行动-记忆),最后落到一个具体的架构设计上。这能说明你不是背概念,而是真的做过。
“ReAct为什么会有效?”这个问题的核心是:ReAct把推理过程和工具使用显式地交替展开,相当于让LLM在行动中“思考”。每一步的行动结果作为新的观察输入,再继续推理,这样能把隐式的推理过程外显化,模型就能够边做边调整。
“你在实际项目中遇到的Agent最大挑战是什么?”这道题考察的是你的真实经验。说上下文管理的挑战、工具选择准确率、多Agent冲突都是好素材。关键是讲清楚你是怎么定位、怎么解决的,比炫技术重要得多。
“Agent记忆是怎么做的?”从短期、中期、长期三个层次分别说实现,再说你做的记忆筛选策略和检索策略,最后点一句“长期记忆要定期清理和重写”。
“多个工具要调,先调哪个?怎么决定?”让模型自己决定的前提是工具描述足够好、功能无重叠。如果出现复杂依赖关系,可以考虑把工具编排成工作流,或者通过LLM规划器先输出一份行动方案再执行。
一些在面试里常被口语化提的问题,也需要顺便提一下。比如有人问“你是直接调LLM接口吗”,答案其实很简单:Agent本身不直接调底层接口,实际工程中我们都会统一封装一层模型路由层,方便切换不同供应商和监控token消耗。还有人说“Agent框架太求助”,我自己也经历过,一开始总觉得不装LangGraph就没法做Agent,后来发现手写循环反而对原理理解更透彻,框架是你真正了解全貌之后才做减法的工具。
6.3 避坑心得与优化技巧
最后,结合个人项目经验,把几个经过验证的优化技巧分享给各位。
工具调用失败时给模型“纠正的机会”。Agent执行工具报错后,直接中止会让整个任务失败;但如果你把错误信息作为观察结果反馈回去,大概率它会在下一轮重新尝试正确的调用方式。这在代码生成、API调用场景尤其明显。我见过不少次模型第一次把参数搞错了,看到错误信息后第二次就改对了。
反思机制不要每轮都做。反思很贵,尤其任务本身简单时。我一般只在任务结束时、或者检测到工具连续报错时,才触发反思。关键是要让反思产生的内容能沉淀下来,下次遇到类似问题就有“经验”可用了。
系统提示词里明确“流程规范”。除了告诉Agent它能做什么,还要告诉它不能做什么。比如“不要绕过工具直接给出答案”、“如果工具连续三次失败,报告问题并请求用户确认,不要无限重试”。这样能避免很多层出不穷的失控行为。
给小模型留退路。如果你用的是能力较弱的小模型,它对Function Calling的遵循能力会差一些,经常会出现该调用工具的时候不调用。解决方式之一是用更强的模型做规划层,用小模型做执行层——规划层负责决策要调哪个工具、按什么顺序,执行层负责具体干活。这个分层结构在成本和效果之间能取得很不错的平衡。
7. 写在最后:Agent项目还能怎么玩
我个人在实际操作中有个深刻体会:Agent学再多理论,也不如自己动手改造一个具体案例来得实在。比如你做一个“全网热点追踪”Agent,用搜索API加摘要能力,让它每隔几小时自动生成热点日报。再比如做一个“会议纪要自动整理”Agent,输入会议录音转写文本,它自动提取待办事项并按负责人分派。这些看着很小,但跑通之后,你对Agent的整体认知会上一个台阶。
另外,一个小技巧分享给你:做Agent时,刚开始不要追求“全自动”。前端问题简单化、复杂任务保持“人审”介入。把一个高难度任务拆成几个子任务,第一版落一个最核心、最不会给业务带来风险的,跑起来看效果再迭代。全自动的Agent是理想,可落地的Agent才是现实。
Agent这个方向还在快速演进,框架和论文更新速度很快,但底层原理是稳定的:感知、决策、行动、记忆,加上工具和编排。把这个内核吃透,无论是换模型、换框架还是换场景,你都能快速适应。剩下的事,就是多踩坑、多总结、多分享了。