ARTICLE DETAIL

资讯详情

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

大模型Agent开发实战:从工具调用到记忆管理全指南

大模型Agent开发实战:从工具调用到记忆管理全指南 哪怕到了现在提起大模型Agent业内的评价依然两极分化。一边是各家公司铺天盖地的智能体产品一边是不少开发者在群里吐槽“搭个Agent容易让它稳定干活难”。但如果你正打算入这个方向我劝你先别急着被这些声音带着走。所谓大模型Agent简单说就是以大语言模型为“大脑”让它自主规划任务、调用工具、读取记忆最终完成一整套流程的应用形态。它不再是单纯的聊天框而是帮你干活的数字员工。这篇文章我打算按照自己从零带团队做Agent项目的路线来写先解决认知问题再讲框架选型然后逐个拆解核心组件的工程化实现最后把最容易翻车的几个坑和排查思路一起倒给你。适合刚接触大模型开发、有Python基础、想快速跑通一个真正能用的Agent项目的读者。我不讲太多学院派概念尽量说人话给你能直接抄的代码和步骤。1. Agent开发前的认知准备先想清楚它和聊天机器人的区别很多新手一上来就调API把模型返回结果直接丢给用户就说自己做了个Agent。这其实还停留在聊天机器人的阶段。Agent和聊天机器人最大的区别在于聊天机器人只负责“说”Agent要负责“做”。而“做”这件事牵扯到的就远不止模型本身了。1.1 Agent的四个基本单元大脑、手、记事本和调度器我习惯把Agent拆成四个组成部分这样无论是学习还是设计架构脑子都会清晰很多。首先是LLM也就是大模型本身它充当“大脑”。大脑负责理解用户意图、拆解任务、决定下一步做什么。但大脑不能亲自执行所有动作比如它没法真的去查数据库、调接口、发邮件——它只能“想”。这时候就需要第二个部分工具。工具是Agent的“手”是模型对外部世界发起动作的通道。一个工具可以是一个函数、一个API接口也可以是一段可执行脚本。第三部分是记忆。人在干活的时候需要记住上下文Agent也一样。它需要知道用户刚才说了什么、自己已经完成了哪一步、有哪些关键信息是之前确认过的。记忆如果不做Agent就是“金鱼脑”对话超过几轮就开始胡言乱语。第四部分我把它叫做调度器也就是Agent循环。模型输出一个“我想调用某个工具”程序拿到这个意图后执行工具、把结果返回给模型模型再根据结果决定下一步是继续调用工具还是给出最终回答。这个循环就是Agent的工作主流程也是最需要工程化的地方。这四样缺一个严格来说都不算完整的Agent。你如果搭过一个项目回来看这句话会特别有感觉——大部分翻车现场都出在这四个单元的衔接上而不是模型本身不够聪明。1.2 从“对话”到“任务执行”三个认知转变从做传统API开发转过来的人最容易踩的坑是把Agent当成一个“更智能的接口”。但实际上Agent应用有三个非常重要的认知转变不转过来后面每一步都会别扭。第一个转变是输出从“文本”变成了“动作”。传统开发的接口返回JSON字段是固定的模型返回什么你解析什么。但Agent场景下模型经常直接输出一个工具调用请求你要去执行这个请求再把执行结果喂回给模型。这里就不再是“解析返回结果”那么简单而是要处理“模型想干什么、我让它干、干完的结果怎么反馈”这一整条链路。第二个转变是模型结果从“可接受”变成了“需校验”。以前你调NLP接口模型给个分类结果错了就错了重新调一次。但Agent会让模型执行真实操作比如删除文件、发请求、改配置。如果不对模型输出做严格校验一次幻觉可能引发线上事故。所以Agent系统里必须有一个校验层宁可让流程多绕一圈也不能让模型直接触碰高危动作。第三个转变是系统从“一次性调用”变成了“循环闭环”。普通接口调用一次结束但Agent要在一个循环里反复执行“理解-决策-行动-观察结果”这个过程直到任务完成或达到上限。这意味着你的系统架构必须支持多轮状态流转每一轮的中间结果都要妥善保存和传递。这三个转变不一定需要你先学多少理论才能动手但你写第一版代码的时候最好把这几点内化到设计里。我就是因为一开始没想清楚后面返工了两次。1.3 入门阶段的核心目标先跑通最小闭环很多新手一上来就陷入框架焦虑LangChain要不要学AutoGen是不是更高级Dify是不是更省事我的建议是入门阶段先别纠结框架你的核心目标只有一个用最少的代码跑通一个“用户提需求→模型规划→调用工具→返回结果”的完整闭环。等你亲眼看到模型在循环里“自己决定调用哪个函数、拿到结果再继续思考”这个过程之后你对Agent的理解会瞬间上一个台阶。这时候再去学框架你会发现框架里的那些抽象概念突然全都对得上号了。反之如果你一上来就钻进框架里很容易被一堆概念绕晕最后做出一个“跑得通但说不清原理”的玩具。2. 框架选型从最小闭环到工程化落地等你理解了Agent的基本结构接下来就是选型问题。市面上的Agent框架多到眼花缭乱但真到生产环境里没有一个是银弹。我用了大半年的经验是框架帮你省掉的是重复劳动但核心的工程问题还得你自己扛。2.1 主流Agent框架横向对比我把自己实际用过的几类方案放在一张表里方便你对照自己的场景选型。方案适合场景上手难度优点需要注意的坑LangChain / LangGraph深度定制、复杂流程编排中高组件全生态大社区资料多抽象层级多排查问题时要剥好几层版本升级经常破坏APILlamaIndex偏知识库/RAG的Agent中文档处理和数据检索做得细做通用Agent编排不如LangChain顺手Dify快速验证、低代码搭建低可视化编排接入模型方便适合产品原型深度定制受限复杂逻辑还是要写代码AutoGen多Agent协作、对话式任务中多角色讨论场景很灵活调度过程黑盒化生产环境稳定性需要大量调参自研核心循环生产级项目、严格可控高完全可控逻辑透明便于排查前期工作量大但长期维护最省心这六个方案不是互斥的。我见过不少团队用Dify快速搭MVP验证后换成自研循环上生产也有人用LangChain做POC最后把核心循环抽出来自己维护。关键是要清楚每个框架的边界在哪里。2.2 项目骨架怎么搭一个可以直接抄的结构如果你决定自己维护核心循环我建议项目一开始就按下面的结构组织。这个结构是我踩过不少坑之后总结出来的优点是每个模块边界清晰出了问题上手就能定位。my_agent/ ├── agent/ │ ├── core.py # Agent主循环调度、状态管理、轮次控制 │ ├── tools/ # 工具注册目录每个工具一个文件 │ │ ├── __init__.py │ │ └── calculator.py │ ├── memory/ # 记忆模块短期、长期、向量召回 │ │ ├── __init__.py │ │ └── store.py │ └── prompts/ # 提示词模板目录 │ └── system.py ├── config.py # 全局配置模型名称、API地址、轮次上限 ├── requirements.txt └── main.py # 入口接收输入调用Agent返回结果这个结构最核心的设计原则是“工具与主循环解耦”。每个工具都是独立文件新增一个能力不需要改动主循环代码只要在tools的注册表里加一条就行。同理记忆模块和提示词模板也独立出来方便随时替换策略。2.3 最小Agent代码按这个思路写一个能跑的工具调用闭环下面这段代码我尽量精简保留Agent最核心的循环逻辑适合用来理解原理。实际生产代码会比这个复杂不少但骨架是一样的。import json from openai import OpenAI # 指向任意兼容OpenAI接口的模型服务 client OpenAI( base_urlhttp://localhost:8000/v1, api_keyEMPTY ) def calculate(expression: str) - str: # 注意eval有安全风险生产环境请用表达式解析器替代 return str(eval(expression)) tools [ { type: function, function: { name: calculate, description: 计算数学表达式比如 34*17 或 (12)*3, parameters: { type: object, properties: { expression: { type: string, description: 需要计算的数学表达式 } }, required: [expression] } } } ] def run_agent(user_input: str, max_turns: int 5): messages [{role: user, content: user_input}] for turn in range(max_turns): resp client.chat.completions.create( modelyour-model-name, messagesmessages, toolstools, tool_choiceauto ) msg resp.choices[0].message messages.append(msg) # 模型请求调用工具 if msg.tool_calls: for tc in msg.tool_calls: args json.loads(tc.function.arguments) print(f[turn {turn}] 调用工具: {tc.function.name}, 参数: {args}) result calculate(args[expression]) messages.append({ role: tool, tool_call_id: tc.id, content: result }) else: # 模型没有请求工具说明任务已完成 print(最终回答:, msg.content) break if __name__ __main__: run_agent(请帮我计算 34*17 的结果然后加上 86)我给你拆解一下这段代码的流程。首先用户输入被放进messages列表。模型第一次返回时如果它认为需要计算就会在返回里带上tool_calls里面说明要调用哪个函数、参数是什么。代码检测到tool_calls后执行本地calculate函数把结果以“tool”角色回填给模型。模型拿到工具结果后再继续推理直到它认为不需要调用任何工具输出最终回答。这里我特别想提醒几个细节。第一tool_choiceauto的意思是让模型自己决定要不要用工具如果你希望强制它用某个工具可以改为{type: function, function: {name: calculate}}。第二max_turns必须设置否则模型在某些场景下会无限循环白白消耗token。第三工具返回的结果不要太长能精简就精简因为这段内容也会占用上下文。3. 核心组件的工程化实现从能跑通到能落地跑通最小闭环只是第一步真正让Agent稳定干活需要在工具、提示词、上下文和记忆这几个核心组件上做工程化打磨。这一章我讲的全是生产环境里花时间最多的部分。3.1 工具层设计Agent的“手”能不能干活全看描述模型并不知道你的工具内部怎么实现的它对工具的全部认知都来自两样东西函数描述和参数定义。我见过太多人随便写一句“计算数学表达式”就完事结果模型老在边界情况上犯迷糊。工具描述需要做到三件事说明这个工具是干什么的、什么情况下该用它、什么情况下不该用它。举个例子同样是计算工具好的描述长这样{ type: function, function: { name: calculate, description: 计算用户给出的数学表达式结果。适用于加减乘除、括号、幂运算等基础算术。如果用户提到汇率、物理单位换算等专业计算不要使用本工具。, parameters: { type: object, properties: { expression: { type: string, description: 标准数学表达式例如 (128)*3/2 } }, required: [expression] } } }你看我把“什么情况下不该用”也写进去了这能显著减少模型误调用。另外一个重要原则是一次给模型提供的工具不要太多。工具数量超过10个以后模型的选择准确率会明显下降。如果业务确实需要几十个工具建议按场景分组先用一个“工具路由Agent”决定交给哪一组处理。工具返回结果的设计同样关键。工具执行完成后返回给模型的内容相当于“观察结果”一定要是模型能直接使用的信息。比如查询订单接口返回了一堆数据库原始字段模型并不知道哪些字段要紧。最好的做法是在工具内部就完成加工返回类似“该用户最近一笔订单编号是xxx金额是xxx元状态为已发货”这种可直接引用的句子。宁可多写几行加工代码也不要让模型去一堆JSON里猜重点。3.2 提示词编排与上下文管理Agent的“脑回路”不能断很多人以为写提示词就是跟模型客套几句。但在Agent系统里提示词是约束模型行为最重要的手段之一而且要写成“操作手册”而不是“对话开场白”。我的System Prompt模板一般包含四个部分角色定位告诉模型它是谁负责什么任务。可用能力列出它能使用的工具以及使用顺序。行为约束不允许干什么比如“未经验证不要直接删除数据”。流程示例给一个完整的调用示例让模型照着格式来。这里有个容易被忽略的点行为约束不要用“你要注意安全”这种模糊描述要写成可执行规则比如“当工具返回错误时必须把错误信息原样反馈给用户不要自行编造修复结果”“当你认为工具参数不完整时必须追问用户而不是猜测默认值”。规则越具体模型越不容易跑偏。上下文管理是Agent工程的另一个重头戏。模型的上下文窗口是有限资源而Agent多轮调用会不断往消息列表里追加内容。如果不做管理跑个十几轮就可能超出窗口上限。我常用的管理策略是三层第一层是截断给对话历史设置一个上限超出的部分直接丢最久远的对话。第二层是摘要当history超过一定长度时用一次轻量模型调用把前面的对话压成一段摘要替换掉原文。第三层是向量召回把历史对话按片段存入向量库需要时只取与当前问题最相关的几段。截断最省事但会丢信息摘要效果好一些但要多一次模型调用向量召回质量最高但工程复杂度也最大。实际项目里推荐“截断兜底摘要压缩”的组合向量召回等业务量大了再上。3.3 记忆设计短期记忆、长期记忆和向量检索到底怎么分工“Agent记忆”这个热词被炒得很多但实际做起来就三件事。短期记忆指的是本轮对话内的工作上下文包括用户输入、工具返回结果、中间步骤。这部分直接用messages列表就能承载主要靠上下文管理策略来控制体积。它解决的是“同一任务里别忘记前面做过什么”的问题。长期记忆指的是跨对话持久化的信息比如用户偏好、历史结论、业务规则。这部分要写入数据库最简单的方案是SQLite或PostgreSQL按用户ID和会话ID组织。比如用户说过“我常用顺丰快递”你可以抽成一条用户偏好下个对话开始时注入System Prompt。向量检索用于“回忆与当前问题相关的历史片段”。比如用户问“我上月提到过的那款咖啡豆”单靠结构化字段查不到需要把历史对话片段向量化通过语义相似度召回。轻量方案用Chroma或sqlite-vec就能扛数据量大了再考虑独立向量库。我给一个很朴素的记忆模块设计短期记忆靠循环里的messages数组每轮对话结束后抽取关键信息写入长期记忆表每次新会话开始时从长期记忆表里拉最近N条偏好注入提示词当问题明显包含“之前/上次/那个”这类指代词时触发一次向量召回。这套组合覆盖了90%以上业务场景而且计算成本可控。4. 实战排查Agent开发最容易翻车的六个场景最后这部分我把自己和团队在实际项目中反复踩过的坑整理出来。每个问题都有现象、排查思路和解决方法你可以直接拿来对照。4.1 模型陷入死循环出不来现象Agent一直在调用同一个工具或重复相似步骤直到轮数耗尽。常见于模型没理解“任务已经完成”或者它对工具结果不满意试图不断重试同一个失败动作。排查思路第一步看日志里的工具调用序列确认是不是同一个工具反复触发。第二步看工具返回内容如果返回的是错误信息模型可能会尝试无限重试。第三步看System Prompt里是否缺少“当工具返回错误时停止并上报”这类规则。解决手段是我在前面代码里就埋过的设置max_turns同时要求模型每个工具调用的参数必须与上一轮不同。也可以在循环里加一个简单的去重判断当检测到完全相同的工具调用连续出现三次以上强制终止并让模型总结失败原因。这个机制在刚上线调试时特别有用。4.2 上下文越用越大预算翻倍现象Agent跑一段时间后响应变慢token消耗明显增加甚至报上下文超限。排查思路看消息列表长度常见的元凶有两个。一是工具返回内容过大比如查了整张表的数据丢给模型二是循环没有清理中间过程导致messages里堆了大量工具结果。解决手段工具返回前做裁剪只保留关键信息定义上下文预算比如超过8K字符就触发摘要压缩。还有一个容易忽略的地方模型请求里带上max_tokens限制防止单次生成长度过长。4.3 并发一上来Agent就崩现象测试环境跑得好好的生产上一有用户并发不是超时就报错严重时整个服务卡死。排查思路大多数Agent服务都不是无状态的问题出在状态管理上。常见做法是把messages、中间结果放在服务内存里导致每个请求占用的内存随轮数上涨。另一个坑是调用模型API时共用一个无连接池的HTTP客户端阻塞了事件循环。解决手段核心是“Agent无状态化”——把每次请求的消息列表、记忆内容放到Redis这类外部存储中请求结束后无需保留任何本地状态。同时给模型API调用加上连接池和超时配置再用信号量做并发限制。如果预计并发很高优先考虑队列化处理把Agent任务拆成可异步执行单元而不是同步阻塞等待模型返回。4.4 模型不调用工具或者返回格式错乱现象模型该用工具时不用直接给出一个编造的回答或者按文本返回而不是按工具调用的格式返回。后者在切换模型时尤其常见。排查思路不调用工具通常是工具描述写得不够具体模型不知道什么时候该用。返回格式错乱则大概率是模型对tools参数格式支持不完整或者System Prompt里没有给出明确示例。解决手段如果模型对Function Calling支持不好可以在提示词里要求“如果用户请求的计算/查询类任务你必须先输出{tool: xxx, args: {...}}不要直接回答问题”然后程序侧解析这段JSON。如果模型支持但表现为不稳定就在System Prompt中加一个完整的工具调用示例。预算允许的话给模型开response_format{type: json_object}也能提升格式稳定性。4.5 常见问题速查表症状可能原因快速排查方法建议方案Agent反复调用同一工具缺乏终止条件或失败重试逻辑查看工具调用序列日志增加去重判断、轮数上限、失败上报规则上下文超限/费用暴涨工具返回内容过大、消息列表无裁剪统计单次工具返回token裁剪工具输出配置摘要压缩策略并发时报错超时状态存内存、API调用阻塞看服务错误日志和在线请求数改无状态架构、加连接池、做队列异步化模型不调用工具工具描述不清或缺少触发示例用指定输入实测工具调用优化工具描述补充few-shot示例模型输出JSON解析失败模型对格式支持不佳或提示词约束不足打印原始响应查看用response_format约束或加一层解析重试Agent回答明显编造数据工具结果未正确回填或模型幻觉检查tool消息是否正确拼接强制校验工具结果发现缺失时直接拒绝回答4.6 一个容易被忽视的环节工具调用的安全校验Agent一旦接上真工具安全问题就是头等大事。模型是不可完全信任的执行者所以工具调用一定要过一道校验层。我常用的做法是给工具定义“危险等级”只读类工具直接放行写操作类工具要经过二次确认比如先生成操作预览让用户确认高危操作类工具直接禁止通过Agent自动触发必须走人工审批流程。同时所有工具调用都要有审计日志记录是谁在什么时间要求执行了什么操作。这套规则看着简单但能挡住大多数线上事故。我个人在实际项目中的体会是Agent开发最大的难点从来不是“让模型理解一句话”而是“让整个系统在模型的随机性下仍然稳定工作”。工具编排、上下文管理、记忆设计、安全校验这些环节每一个都比想象中更需要打磨。如果你正准备入这个方向建议先别急着追各种新框架新概念老老实实把最小闭环跑通再把这一章讲的组件一个个加进去这个过程中踩过的坑都会变成你真正的竞争力。
返回列表