ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

大模型Agent开发核心指南:工具调用、记忆与循环决策工程实践

大模型Agent开发核心指南:工具调用、记忆与循环决策工程实践 坦白说大模型Agent开发这个方向现在最不缺的就是概念文和Demo演示。我这两年看了太多人用几行代码调通一个LLM接口就管它叫Agent结果生产环境一跑就露馅上下文爆掉、工具结果解析不了、模型在一个死循环里打转。我甚至见过不少项目因为设计的循环结构有问题token损耗是理论值的三倍月底一算账直接被砍。如果你也是那种CURD写得很熟但面对LLM API时不知道怎么把它接进业务系统里的开发者这篇文章就是写给你的。做Agent开发这几年我最大的体会是核心难点从来不在模型本身而在于你怎么把一个有记忆、有工具、有循环决策能力的系统干净利落地搭出来。这是一个工程问题不是一个提示词问题。很多人拿着一个大模型API调了几个月做出来的东西看起来能跑但换个场景就废原因就在于他们没有真正理解Agent的运行闭环只是做了一层高级聊天窗口。这篇文章我会掰开来讲这些事Agent和普通聊天机器人的本质区别是什么、选型和架构怎么做、最小闭环怎么实现、我踩过的那些坑长什么样、排查思路是什么。内容偏工程实践不搞花哨概念。读完你至少能动手搭出一个结构清晰、可扩展、能上生产的Agent雏形。我建议你先把文章整体过一遍然后从第三章的最小闭环开始动手跑通了再回头看第四章和第五章的调优细节这个学习路径我实测下来效率最高。1. 先搞懂你做的Agent和聊天机器人到底差在哪里1.1 判断Agent的硬标准很多团队做了一年所谓Agent开发最后交付的东西本质上还是一个聊天机器人。这个判断不是看长相是看系统能力。我一般用三个标准来判断一个系统算不算Agent它有没有权限调用外部工具。纯靠模型内部知识生成文本的不管吹得多神都只是LLM应用。真正的Agent必须能通过函数调用、API请求、代码执行等方式与外部世界交互。它有没有一个自主决策的循环。聊天机器人是用户提问→模型回答→结束一次会话就一个回合。Agent是接收任务→思考→调用工具→观察结果→再思考→再调用直到任务完成或达到终止条件。这个loop是灵魂。它有没有多状态记忆能力。不只是记住用户说了啥还要能记住在完成任务过程中自己已经做了哪些步骤、获取了哪些中间结果、还剩哪些没做。窗口记忆也好、外部存储也好必须有一个状态维护机制。用这三条去对照你自己做的东西会很扎心但很清晰。很多号称Agent的产品三条一条不占那它就是套了一层Agent外套的搜索框或者翻译器。1.2 一个Agent系统的基本骨架我画过无数遍这个图了用文字描述就是输入层→编排层→工具层→记忆层→模型层。输入层处理用户目标的多模态信息一段文本、一个文件、一个语音甚至是一个JSON格式的任务描述。编排层是整个Agent的CPU负责决定下一步该干什么它通常是给模型发一个带历史上下文的请求让模型基于当前状态选择执行哪个动作。工具层是Agent的手包括搜索引擎、数据库查询器、计算器、HTTP请求器、终端命令执行器等等每一个工具应该以标准化的函数schema暴露给模型。记忆层负责存取历史会话、中间推理步骤和领域知识简单场景可以用上下文窗口硬扛复杂场景必须上向量库。模型层就是那个提供推理能力的大模型。这个骨架确定了后面所有开发工作其实就是往各个层里填东西。我见过无数项目失败根本原因都是把模型层当成了整个项目本身疯狂研究提示词和few-shot却对工具层和记忆层毫无设计。模型只是一个推理引擎Agent的实用性来自系统协同没有工具闭环的模型调用谈不上Agent开发。2. 动手前的选型模型、框架和基础环境怎么定2.1 底模选择能力、成本与部署方式Agent开发对模型的核心要求是函数调用能力稳定。所谓函数调用就是模型能输出一个结构化动作比如调用get_weather参数为北京。如果模型的这个能力弱你设计的工具再完善也没有用模型会自己瞎编函数名和参数。从当前市场可选方案来看我把模型分成三档闭源商用API。OpenAI的GPT-4o系列、Anthropic的Claude系列、Google的Gemini 2.0系列函数调用能力都处于第一梯队。优点是省心开箱即用函数调用格式和各家官方SDK深度集成。缺点是成本高、有合规和数据出境问题不适合敏感数据场景国内企业落地时还得考虑网络可达性与支付方式。开源可私有化部署的大模型。Qwen系列、DeepSeek系列、GLM系列是现阶段国内用得最多的。它们对工具调用的支持也做得相当好特别是Qwen2.5和DeepSeek-V3之后在很多场景下跟闭源商用模型的函数调用能力差距已经不大。优点是可以私有部署、成本可控、数据不出内网缺点是部署和运维成本你得自己扛GPU集群不是免费的。国内免费/低成本API。追求快速验证的时候各家云厂商开放平台的免费额度也够用了适合个人项目和PoC。但免费额度一般有并发限制真要上生产还是得换付费档或者走私有部署。我在不同阶段都试过个人建议是第一版Agent就用你最熟悉的模型快速跑通函数调用能力验证OK之后再用抽象层封装好模型接口方便随时切换。把换模型做成一个配置项而不是在业务代码里到处写死这是Agent架构里第一个要养成的工程习惯。2.2 框架到底用不用用谁框架问题我每次都被问到。我的回答比较直接做学习项目别用框架做生产项目选一个能让你掌控循环过程的框架。现在市面上的Agent框架可以粗暴分成三类全流程编排平台。Dify、Coze这一类提供可视化界面和托管运行环境适合产品经理、运营或者想快速做Demo的人。它们的Agent能力内聚度很高但对复杂定制逻辑来说比较受限遇到要深度介入业务系统时可视化平台的抽象往往兜不住。代码级框架。LangChain、LlamaIndex、Semantic Kernel这些都算。LangChain生态最全组件多但抽象层也多出了问题排查成本不低。你真正调不下去的时候80%的时间是在看它封装背后的源码。框架的优势是迭代快、社区成熟缺点是你很难做深度定制遇到底层循环结构不满足业务需求时你就开始和框架打架了。自研轻量循环。基于模型的函数调用能力自己写一个循环调度器。代码量并不大核心只需要处理好模型返回工具调用请求→执行工具→把结果回传给模型→继续决策这个循环的完整实现差不多200到400行代码。自研的优势是每个环节都透明出了任何问题都能直接定位性能优化也好做。我的态度是如果你是一个追求在生产环境中可控性的工程师最好至少先从自研一个最小闭环开始跑通了再往LangChain等框架迁移。因为只有你亲手写过一遍这个循环你才能真正理解框架里的那些Chain、Tool、Memory是怎么协同的才不会在框架的报错堆栈里瞎猜。2.3 环境准备的最低配置开发Agent的最小环境其实不苛刻Python 3.10以上虚拟环境管理。一个可用的模型API密钥或者内网部署好的OpenAI兼容协议服务地址。现在大多数开源模型的推理服务都兼容OpenAI的chat/completions格式这意味着你可以用一套SDK代码切换不同的模型后端。一个向量数据库如果第三阶段要加RAGChroma就够起步Qdrant和Milvus适合生产。基础网络设施。如果走本地虚拟机部署还要考虑多端口、多域名映射的问题我后面在实践阶段再说这块的一个偷懒技巧。我自己最开始做的时候环境极其简陋就是一个Python虚拟环境加一个API密钥跑通了整个循环。所以不要被Agent开发需要多复杂的基建这种话忽悠了核心永远是循环逻辑。3. 最小闭环从0实现一个带工具调用的Agent3.1 定义工具的Schema一切工具对模型暴露的方式都是JSON Schema。你可以把工具理解为一道菜Schema就是菜单。模型不直接执行代码它只负责根据菜单点菜真正炒菜的是你的执行环境。下面是一个最简工具定义的例子我以查天气为例tools [ { type: function, function: { name: get_weather, description: 查询指定城市的当前天气情况包括温度和天气现象, parameters: { type: object, properties: { city: { type: string, description: 城市名称例如北京、上海、广州 }, unit: { type: string, enum: [celsius, fahrenheit], description: 温度单位默认摄氏度 } }, required: [city] } } }, { type: function, function: { name: calculator, description: 执行精确的四则运算返回计算结果。当用户需要计算数学表达式时使用, parameters: { type: object, properties: { expression: { type: string, description: 数学表达式例如2 3 * 4 - 5 / 2 } }, required: [expression] } } } ]这里有三个容易踩的坑。第一个是description必须写清楚什么时候用这个工具模型靠这个做意图判断含糊描述会让模型在错误场景里调用工具。第二个是参数描述里要给足示例值特别是枚举值全列出来否则模型会编造不在枚举内的值。第三个是required字段别漏漏了之后模型可能不传这个参数你的执行层就要做额外的参数校验和兜底。很多教程在这里随便给几个字段就过去了我强烈建议你认真对待Schema的质量因为函数调用Schema的质量直接决定了Agent决策的准确率。你把这个JSON当成API文档来写模型才不会乱来。3.2 核心循环思考→行动→观察有了工具定义接下来写Agent的主循环。这里我给一个非常精简但结构完整的代码你就知道一个Agent的核心循环长什么样了。from openai import OpenAI client OpenAI() def execute_tool(name: str, arguments: dict): 根据模型给出的工具名和参数在本地执行对应的函数 if name get_weather: # 实际上这里应该调用真实的天气API return f{arguments[city]}当前温度25摄氏度晴 elif name calculator: try: result eval(arguments[expression]) return f计算结果: {result} except Exception as e: return f计算失败: {str(e)} return f未知工具: {name} def run_agent(user_query: str, max_steps: int 5): messages [ {role: system, content: 你是一个智能助手可以调用工具来解决问题。每次只调用一个工具根据工具结果决定下一步。}, {role: user, content: user_query} ] for step in range(max_steps): response client.chat.completions.create( modelgpt-4o-mini, messagesmessages, toolstools, tool_choiceauto ) assistant_message response.choices[0].message # 情况1模型没有要求调用工具直接结束并返回答案 if not assistant_message.tool_calls: return assistant_message.content # 情况2模型要求调用工具执行并回填结果 for tool_call in assistant_message.tool_calls: tool_name tool_call.function.name tool_args eval(tool_call.function.arguments) result execute_tool(tool_name, tool_args) messages.append({ role: assistant, tool_calls: [{ id: tool_call.id, type: function, function: { name: tool_name, arguments: tool_call.function.arguments } }] }) messages.append({ role: tool, tool_call_id: tool_call.id, content: result }) return 已达最大执行步数任务未完成。 print(run_agent(北京天气怎么样顺便帮我算一下 2 × (17 3)))这个循环我把关键点拆开讲一下。模型的返回有三种情况直接返回文本、请求调用一个工具、一次性请求调用多个工具。上面代码里如果model直接返回文本说明它认为自己的回答已经足够满足用户循环结束。如果它请求调用工具你必须把执行结果以role tool且关联到对应的tool_call_id的方式回传给模型模型才能基于这个观察结果进行下一步推理。那个tool_call_id的关联是绝对不能省的很多新手第一次写这循环都会把工具结果直接以user角色塞回去结果模型在后续轮次里不知道这个结果对应的是哪一次请求推理逻辑就乱了。这个ID就是模型锁存调用上下文的钥匙你把它丢了上下文就崩了。另外一个值得注意的细节是max_steps。这是Agent循环的熔断机制没有它模型万一陷入反复调用同一个工具的死循环你的token预算就废了。凡是上生产的Agent必须有步数上限。3.3 实际运行效果和调试感知跑上面的代码单次任务过程是这样的模型先看到北京天气怎么样和算一下2×(173)它会根据自己的意图决策先调用get_weather拿到结果判断天气问题已经回答完了然后可能同时调用calculator拿到计算结果后整理成自然语言回复给你。整个过程里面工具调用和LLM决定是交替进行的你观察入参会发现模型其实是在看懂工具结果之后才组织最终回答而不是预知结果。这里面有一个常见的调试体验差异很多人第一次跑Agent循环会觉得很卡壳因为模型可能决定一次发多个工具调用你一次性执行完再回传它可能还需要再次调用或者总结。这看起来不如聊天机器人流畅但其实是Agent的正常运行节奏。我实际测试中最有效的调试方式是在循环里把每一步的messages内容都打印出来特别是assistant的tool_calls内容和tool返回的content。你会发现绝大多数决策错误都是在这两层里出现的要么是模型调错了工具要么是工具结果格式让模型误解了。把这些日志保留下来后面做问题排查特别有用。4. 提示词工程与关键参数调优4.1 系统提示词的结构比你想的重要很多人在Agent开发中把系统提示词当成给AI写个人设我觉得这是一个认知错误。在Agent场景中系统提示词应该是一个操作手册而不是性格设定。它至少要承担四个职责定义Agent的角色边界和任务范围明确什么该做什么不该做。描述可用的工具行为和调用策略比如当用户问天气时必须先调用get_weather获取实时数据不要编造天气信息。规定多步任务的拆解原则比如对于需要多步骤才能完成的任务请你一步一步来处理第一步调用A第二步基于结果调用B。设定输出格式要求包括最终答应的组织方式、要不要引用数据来源、要不要给出置信度。我写系统提示词的时候有一条底线每个工具都要在系统提示词里给一个调用红线。比如搜索工具你要告诉模型搜索返回结果不可用时不要重复调用超过两次直接基于已有信息回答。比如计算器你要告诉模型计算前检查表达式不接受未闭合括号。这些红线能让Agent行为更可控也能省掉大量无效的循环调用。4.2 温度Agent开发里最容易被忽略的参数做纯聊天应用的时候很多人习惯把temperature调到0.7到1.0让回答更有创造力。但在Agent开发里这是毒药。Agent的推理是任务导向的每调动一个工具就有概率出错温度越高出错概率越大。模型可能在一个本来该调用工具的地方突然灵感来了直接编造了一个工具名这种错误在低温度下几乎不会发生。我的经验值是这样的工具调用和代码生成场景temperature设置为0到0.2追求确定性和可控性。需要一些策略多样性的规划类Agent可适当放宽到0.4但不要超过0.5。只有最终面向用户的、需要创造性表达的生成环节才建议把温度调高但这个环节应该单独设计一个模型调用不放在Agent主循环里。实测下来在工具调用型Agent中temperature设为0能让函数的调用成功率提升一个明显档次。如果你做的是流程型Agent把全局温度压到0.1左右让稳定性优先。4.3 max_tokens卡住循环的隐形杀手max_tokens这个参数在Agent开发中承载的语义和普通聊天不一样。它不仅约束输出长度还约束了模型想多少步的空间。有些模型在max_tokens设置过小时会出现工具调用序列截断的问题比如它打算一步调用多个工具但输出长度不够结果截断在一个未完成的tool_calls块里。这种情况在OpenAI的gpt-3.5-turbo上特别常见后来的4o系列好很多但仍要注意。我给一个合理的配置策略如果工具参数较复杂单次模型请求的max_tokens最好不低于1024。这不是让你每轮都输出那么多而是给模型留出做完整决策的空间。如果你发现工具调用的返回时有时无、半截子先检查是不是max_tokens太小了。4.4 上下文窗口克扣与管理的艺术上下文窗口是Agent项目最大的敌人之一。多轮工具调用的中间结果会不断累积在messages里每个消息都带着token成本。一个复杂任务经过四五次工具调用之后上下文可能已经到了两三万token然后你再回头处理用户信息、系统提示词、few-shot示例……全都挤在一个窗口里。要对上下文做管理我目前使用的方式是三层裁剪策略第一层是系统提示词固定化把不随任务变化的部分独立出来不要每次请求都重复拼装。第二层是历史对话摘要化超过N轮之后把之前的对话内容用一次LLM调用压缩成一个摘要替换掉原始消息。第三层是工具结果截断化工具返回的原始结果往往包含大量噪声我要么在工具执行层直接做过滤只把关键字段返回给模型要么把超过512字符的内容做截断。这里特别说一下工具结果截断这是很多人不知道的优化点。假设你接了一个数据库查询工具返回了100行数据模型真的需要全部看到吗大部分情况下不需要。你完全可以只返回前20行加一个共100行显示前20行的说明。如果模型需要更多它会通过新的工具调用来请求。你在工具层做得越干净模型在推理层的输入越清爽token消耗和决策质量都受益。5. 进阶玩法记忆、RAG和多Agent协作5.1 给Agent加上长期记忆前面提到的最小闭环里Agent除了当前这场会话的上下文外没有长期记忆。用户昨天提过的事情今天再问它一点都不知道。要让Agent真的像个人一样连续成长就得加长期记忆系统。我的实现方案很简单每次对话结束后用一次LLM调用从对话中抽取结构化的记忆条目存储到向量数据库。抽取什么内容呢用户的事实信息、偏好信息、对话中出现的实体和关系、任务历史。下次对话开始时基于用户当前query做向量检索把Top-K条相关记忆注入系统提示词或作为上下文消息。这套方案很多框架已经内置了但我建议你自己实现一遍因为你会深刻理解一个道理记忆注入不是越多越好而是越相关越好。你塞了20条记忆进去模型反而不知道哪条重要决策被低相关记忆干扰。把记忆检索的score阈值设严格一点宁缺毋滥。5.2 RAG在Agent里的真实角色RAG检索增强生成和大模型Agent经常被混为一谈但严格来说它们解决的问题不一样。RAG解决的是模型不知道的问题Agent解决的是模型不会做的问题。在实际的Agent系统里RAG通常作为一个工具存在Agent感知到需要特定领域知识时调用retrieve_from_knowledge_base这个工具检索后把结果作为观察输入进行推理。这么做和传统先检索再生成的流水线有本质区别传统RAG是强制的不管你需不需要每次回答都先检索一遍Agent里的RAG是按需触发的模型根据当前任务判断是否检索、检索什么。后者在token成本、回答质量上都更优但也更依赖模型的工具调用准确性。我实际做知识库类Agent的时候遵循这样一个数据流水线文档解析→文本清洗→分块→向量化→存储→检索。其中分块策略的影响特别大固定字数分块通常效果不好我推荐按语义段落结构分块。如果你的文档有明显的标题层级按标题分块比按字数分块好得多。做RAG不是拿一个向量库就完事的分块、检索、重排序每个环节都决定你的Agent回答质量问题。5.3 多Agent协作是个大坑别急着跳多Agent是今年最热的概念之一但我必须泼一盆冷水绝大多数业务场景下单Agent加工具调度已经足够解决问题强行上多Agent只会让你的系统失控概率指数级上升。多Agent本质上是在多个模型之间做任务编排和消息传递每个Agent都有各自的上下文和记忆任何一个环节的自循环、错误传播排查起来都极其痛苦。如果你真的需要多Agent我建议先理解清楚harness和Agent的区别。说的是harness是承载Agent运行的控制框架负责生命周期管理、任务调度、消息路由、工具注入Agent是实际执行推理和动作的单元。很多号称多Agent平台的产品其实只是给多个单一Agent套了一层harness真正的Agent间协作、共享记忆、任务委派这些能力实现得都很初级。我目前看到比较可靠的多Agent模式是仲裁者模式一个主控Agent负责任务分解多个子Agent分别执行子任务子Agent之间不直接通信所有通信通过主控Agent中转。这种模式可控性最好子Agent各自负责一个领域上下文隔离干净是最推荐起步的架构。6. 实际问题排查并发、超时和循环失控6.1 我踩过的坑逐个列出来先讲并发问题。Agent开发的并发和普通Web开发的并发思考方式完全不一样。普通Web服务你给每个请求分配一个线程/协程处理完就释放。Agent服务一次Agent任务可能持续数秒到数分钟期间要多次调用LLM、多次调用工具对后端资源的占用是长周期的。如果你按普通接口的并发模型去设计很快就会发现资源被拖垮了。我在一个实际项目里就被迫面对过这个问题。我们有一个Agent服务要对上百个事件做批处理每个事件走完完整循环大概要调用6次LLM单次2到4秒。如果单线程串行一轮要几分钟完全不能忍。后来改成了用异步队列加并发信号量的方式做并发控制核心是两层限流第一层是全局并发上限防止把下游LLM API打爆第二层是每个用户会话级别的并发上限防止单用户多任务把共享资源占满。另外必须给每个Agent任务设置一个总超时时间比如120秒强制终止不然你的任务队列会被僵尸任务堵死。再说循环失控。我曾经遇到过一个Agent在踩到工具结果格式异常时反复用同一个工具调用然后被上一步的报错继续触发同一个调用变成了工具调用死循环。排查的时候日志显示它在短短30秒内消费掉了几百万token然后被迫终止。后来我在主循环里加了三个保险丝最大步数限制、相同的工具调用出现三次以上就强制终止并返回当前结果、每当工具执行出错时在回传给模型的tool消息里附一句该工具执行失败请换一种方式或直接回答用户让模型有机会止损。还有一个差点被忽略的坑是工具返回值的数据类型不一致。有一次我们返回的是JSON字符串模型用的时候当成对象去解析然后在自己的推理里反复报错。最后发现问题不在模型在于执行层返回给模型的content里应该把JSON序列化成字符串而我在调试时一直对着模型报错怀疑浪费了一天时间。6.2 问题排查速查表症状可能原因排查方向与解法模型反复调用同一个工具工具结果让模型不满意或提示词缺少停止条件给工具结果加明确标记在系统提示词加调用红线启用相同调用三次强制终止逻辑工具调用结果返回了但最终回答里完全没用到messages中tool结果的关联性出了问题模型没感知到这是它要的数据检查tool_calls的id是否正确回填确认tool消息里没有多余的干扰信息用打印日志确认单步messages结构上下文爆掉响应越来越慢token越来越贵中间过程全部堆积在messages里没有做摘要或裁剪实施历史摘要化工具结果截断系统提示词静态化复用模型在没有工具调用的情况下直接编造数据模型幻觉常见于温度过高、提示词没约束、模型本身函数调用能力弱降低temperature到0附近系统提示词明确必须调用工具才能回答事实类问题评估换模型任务执行到一半无故停止模型判断任务已完成但实际没有检查system提示词中是否有清晰的完成标准增加请回顾你是否真正完成了用户诉求的反思步骤提高max_steps并发一高就出现随机超时和失败下游LLM API限流或Agent任务时间过长做请求级别重试和指数退避引入信号量做并发控给Agent总任务加120秒超时多轮对话后Agent忘了工具上下文上下文过长导致模型注意力被稀释手动增加最近一次工具调用结果的局部消息权重把工具调用历史单独摘出来不要和历史聊天混在一起这个表是我在一线运维环境里整理的很多排查方向不是靠文档看出来的是踩坑踩出来的。特别是模型忘了工具上下文这个在复杂的多轮Agent里出现的概率比想象中高得多。6.3 日志、监控与调试技巧最后分享几个好用的监控细节。第一每步Agent循环必须输出结构化的日志至少要包括当前步骤数、模型调用时传入的消息条数、模型返回的是文本还是工具调用、调用了哪个工具和参数、工具返回的内容摘要。这些日志就是你的排障全景图是最高效的武器。第二Agent的任务耗时和token消耗要做明细记录。做成本优化的时候你一眼就能看出哪一步的token消耗黑洞在哪里。我优化过一个项目就是把Agent单任务的平均token消耗从4万降到了1.2万靠的全是这类明细日志。第三给每个Agent会话分配一个唯一的trace_id沿整个调用链传递。不管中间跨了多少次LLM调用、工具调用通过trace_id把它们串起来。排查用户反馈的问题时用trace_id从日志系统里拉出整条链路不需要用户复述一堆细节你就能断定问题出在哪一层。第四投入时间去了解你所使用的模型厂商的能力清单和限制。免费模型API和付费模型在速率限制上的差别不是一星半点知道自己能打多少并发、百万元素消耗多少token是在做Agent并发设计之前的前提。按我个人这些年的心得Agent的开发过程更像是在驯服一个聪明但偶尔不靠谱的协作者。你把它的工具边界划定越清晰、把它的上下文管理越利落、把它的失败路径设计越充分它回报给你的可用性就越高。做Agent没有一招鲜就是循环加工具加记忆这三大件翻来覆去地设计好骨架然后一处处填肉。如果这篇文章能让你少踩一半我曾经踩过的坑那就算没白写。
返回列表