资讯动态

大模型Agent框架核心:会话、工具、MCP与记忆设计实践

发布时间:2026/10/16 15:09:01 来源:尧图企业网站定制
做Agent框架这些年我有一个越来越强烈的感觉模型本身的能力曲线已经拉不开差距了真正让一个Agent“好用”还是“难用”的是围绕模型外围那一圈工程能力。Hermes Agent 这个项目就是在这种背景下从零搭起来的。它不是什么全新的理论体系而是一个把会话、工具、MCP、记忆四件事拧在一起的工程集合体。这四件事我从第一天就开始研究。会话能力负责接住用户的每一句话让多轮对话不“断片”工具能力让模型不只会说还能动手操作外部系统MCP把工具接入这件事从“万国码”变成标准接口记忆则让Agent从“每次都是陌生人”进化为“越聊越懂你”。这篇就按照我的实际搭建顺序把这四块能力的职责、设计与踩坑记录完整拆开。适合正在做Agent框架、做智能客服、做个人助理类项目或者准备把一堆工具接入LLM的开发者参考。强烈建议按顺序读因为这些能力是互相咬合的。1. Agent的底座四件事为什么缺一不可先说结论一个成熟的Agent不是“把模型API包一层”就完事了。模型只负责文字生成而Agent要负责的是——在正确的时间、用正确的工具、调取正确的记忆、生成正确的回复。这四件事拆分下来正好对应会话、工具、MCP、记忆。1.1 没有工具模型只是纸上谈兵只靠模型自己它无法查实时天气、无法读写数据库、无法操作第三方系统。它的所有知识都停在训练数据那一时刻。工具调用的本质是给模型“外挂手脚”你说一句话模型决定调用哪个函数系统真正执行函数再把结果回传给模型。没有这层闭环Agent就只是个高级聊天机器人。我在Hermes Agent里最早实现的其实就是工具调用。当时用得非常朴素定义好函数的名称、描述和参数格式塞进系统提示词里让模型输出JSON形式的调用请求然后解析执行。后来用上了正式的Function Calling机制但这套思路至今没变。1.2 没有MCP工具接入就是“万国码”随着工具越来越多问题来了每个外部系统都有自己的API格式、鉴权方式、数据返回结构。每接一个工具就要写一套适配逻辑Agent核心代码里堆满了if else。这就好比插座和插头互相不兼容。MCP出现以后整个局面改变了工具提供方把能力包装成标准协议Agent这边只需要一个通用客户端就能对接任意MCP Server。工具接入从“开发”变成了“配置”。1.3 没有记忆对话永远是“陌生人”记忆能力解决的是另一个维度的痛点。没有记忆的Agent每轮对话都是清空重来用户上一轮说过“我住在上海通勤靠地铁”下一轮Agent就完全不记得。这种体验放在聊天里勉强能忍放在AI助手、AI客服场景里就是灾难。记忆分层的价值在于短期记忆承载当前任务长期记忆承载用户的偏好和历史事实核心档案则记录重要的画像信息。1.4 会话是贯穿以上一切的通道会话能力不能单独看。它既是用户与Agent的交互通道也是工具调用和记忆召回的上下文容器。一个会话里发生了多少次工具调用、每个工具的结果是什么、用户当前关注点在哪里这些都要被记录下来。会话管理做得不好工具调用、MCP、记忆全部会跟着出问题。因此Hermes Agent的整体架构里会话层是绝对的基础服务其他模块都依赖它提供上下文。2. 会话能力上下文是Agent的隐形骨架会话能力看似简单——只要把消息传进模型、把模型回复传出来就行。但真正做深之后你会发现它要处理的问题非常多状态存哪里、上下文太长怎么截断、多个会话之间怎么隔离、Agent内部多个子任务之间怎么切换上下文。2.1 多轮会话的状态到底存在哪里我的第一版实现里会话状态就是内存里的一个字典session_id对应一个消息列表。本地跑通没问题一旦部署成服务就露馅——进程一重启用户会话全丢。后来老老实实做了会话存储层把状态抽出来。一个标准会话记录我建议至少包含这些字段字段说明session_id会话唯一ID建议UUIDuser_id关联用户用于权限和记忆归属messages消息列表含消息角色、内容、时间戳tool_calls当前轮次涉及的工具调用记录memory_refs该会话引用过的记忆ID列表meta扩展字段存会话标签、状态机变量等存储选型上Redis是首选因为会话读写频繁且有自动过期能力。我给每个会话设置了TTL比如30分钟不活跃就清理避免会话池无限膨胀。需要注意的是TTL不能设太短因为用户可能隔几分钟回来看之前的进度。会话状态一定要和记忆分开。会话是会过期的临时上下文记忆是要长期沉淀的资产。把两者混在一起后期清理成本和误召回风险都很高。2.2 上下文窗口不够用怎么办这是绕不开的硬问题。你的业务逻辑、工具描述、历史对话都要占token而窗口是有限的。捏在一段长对话里系统提示词加历史消息很可能直接溢出。我试过几种方案效果从低到高排序暴力截断只保留最近N条消息。简单但会丢失早期关键信息用户两轮前提过的需求可能就被截掉了。关键消息保留给消息打重要性标签。用户明确表达过诉求的消息标为高优先级闲聊内容优先级低。截断时优先丢弃低优先级消息。滚动摘要积累到一定轮次后调用模型把之前的对话压缩成一段摘要塞回上下文里。这是我最推荐的做法。摘要本身不完美但比丢信息强太多。结构化精简系统提示词里的工具描述、业务规则尽量用精炼表达。中文写工具描述时一句话说清楚“你什么时候该用这个工具”比长篇大论有效。预估值上我通常按中文一个字约1.5~2个token、英文一个词约1.3个token来粗算。不是绝对准确但足以做截断预判。2.3 会话隔离与多Agent会话路由单个Agent场景下会话管理没那么复杂。真正麻烦的是Agent内部还存在“多角色”或“子代理”分工。我在一个项目里做了“主控Agent 多个专业Agent”的架构主控负责理解用户意图判断该把请求转给哪个专业Agent。这时每个子Agent自己也有上下文需求。如果共用一个会话消息列表各Agent的消息互相穿插模型很容易混淆。我的做法是会话层支持“子上下文”概念。每个子Agent拥有自己的消息窗口主控窗口只保留路由决策和最终输出。子窗口的上下文独立维护可以单独截断和处理摘要。会话ID统一但用source字段区分上下文来源。这招实测很稳尤其是做客服场景时售后和技术支持两个子窗口互不干扰。3. 工具能力从Function Calling到工具编排工具调用是整个Agent的“手脚”。但我发现很多人第一次接Function Calling时都过于乐观——觉得把函数定义给模型它就会按预期调用。实际情况是模型会选错工具、填错参数、在不需要工具的时候强行调用。工具能力这层一定要做足工程防护。3.1 工具注册与Schema设计的实战细节工具注册的输入是一份类JSON Schema的定义。核心四项函数名一定要语义清晰且唯一。别用do_thing1这种命名。模型是在字符串层面理解函数名的一个叫query_weather_by_city的函数比叫func_101240的函数容易被正确选中得多。描述重点写“什么场景下用这个函数”以及“用这个函数前需要什么前提”。例如“当用户询问某个城市的天气时使用本函数仅在用户提供了城市名称时才可调用城市名称未知时应先向用户确认。”参数Schema每个参数都要写description能加enum就加enum能用format限定就用format限定。给模型越少的自由发挥空间参数就越可控。返回值描述让模型提前知道自己会拿到什么结构的数据分支判断时才不会瞎猜。代码层面我是这样组织的def register_tool_func_registry(): registry {} def decorator(func, nameNone, description, parametersNone): registry[name or func.__name__] { handler: func, description: description, parameters: parameters, execute_count: 0 } return func return decorator这是基础框架实际生产还会给每个工具加权限标识、超时时间、是否需要人工确认等元数据。3.2 参数校验与错误处理不要信模型的参数这是全篇最重要的一个提醒模型返回的function call参数一定要当成“用户输入”来校验绝不能直接透传给底层API。模型可能构造出符合格式但语义错误的参数比如把日期格式写成“2025/1/3”而不是“2025-01-03”把城市名写成“上海市市辖区”这种数据库里查不到的值。我在Hermes Agent里加了一层统一校验器。做法很简单注册工具时同时指定一个Pydantic模型调用前先用它做类型校验和枚举校验不通过就返回错误信息给模型让它重新生成参数。这就是“模型自纠错”的闭环。异常处理同样重要。工具执行可能抛异常可能超时可能返回空数据。我总结了一个规则工具的错误信息必须结构化回传给模型让模型理解发生了什么以便换一种方式处理。例如{ tool_name: query_weather_by_city, error: city_not_found, message: 系统中未找到城市[上海市市辖区]请尝试输入标准城市名如上海 }这种信息回传后模型会自己反思并修正参数一多半的参数错误都能被它自己解决。3.3 工具编排多工具组合与无限循环止损业务里很少有单个工具能解决的事。比如用户要“查上海明天的天气如果晴天就帮我订一间外滩附近的酒店”。这至少涉及天气查询、地点搜索、酒店预订三个工具。我采用“计划-执行-观察”的循环来编排模型先生成一个计划列出需要的工具和调用顺序。Agent按计划逐个调用工具每调完一步都把结果反馈给模型。模型结合结果调整后续步骤。循环直到任务完成或触发终止条件。实际操作中最大的坑是模型陷入死循环同一个工具反复调用或者A工具和B工具互相兜圈。不设置止损机制一次任务可能烧掉大量token还拿不到结果。Hermes Agent的处理方式相当简单粗暴却很有效设定max_iterations默认5步复杂任务最多10步同一个流程内完全相同的工具调用参数只允许出现3次第三次直接终止若连续多次工具调用失败中断并主动向用户坦白“当前需要的信息暂时无法获取”。止损机制必须放在Agent框架内部不能指望模型自己判断“我该停下来了”模型在这件事上并不可靠。4. MCP工具接入的标准化协议如果说工具能力是“Agent的手”那MCP就是“手的USB接口”。没有MCP之前接一个外部系统就要写一套专门的Adapter。有了MCP后只要对端提供了MCP ServerAgent侧用同一个客户端就能接通。我在Hermes Agent里落地MCP时核心改动量比想象中少因为大部分复杂度被协议本身消化了。4.1 MCP解决了什么跨系统工具接入的痛点本质上是一个多对多适配问题。有N个Agent框架、M个外部系统传统做法是每个框架都要为每个系统写适配代码复杂度是N×M。MCP采用了Client-Server架构统一了工具发现、调用、鉴权和数据传输方式复杂度变成NM。放到Hermes Agent的具体场景内部有天气服务、订单系统、知识库、日历系统每个服务都可以独立部署成一个MCP Server。Agent这边只维护一个MCP Client Manager运行时动态加载配置好的服务端。传输层方面本地工具用stdio通过子进程启动远程服务用Streamable HTTP早期是SSE。我的经验是需要低延迟、高频繁调用的工具优先用stdio跨网络、需要独立部署的工具用HTTP方式更灵活。4.2 MCP三大原语Resources、Tools、PromptsMCP协议围绕三个原语展开它们分别解决不同的问题。放在表格里看最清楚原语作用对应场景Resources提供可读取的数据资源类似“文件”读取数据库Schema、读取文档、读取配置文件Tools提供可执行的函数类似“API”创建订单、发送消息、执行查询Prompts提供标准化的提示词模板类似“配方”预置一套Prompt让Agent按照规范处理某类任务我在初学MCP时常常混淆Resources和Tools。后来我自己定义一个判断标准模型拿到一个东西时“只是看看”的属于Resources“执行后有副作用或者需要外部系统配合动作”的属于Tools。比如读天气API的缓存数据是Resources但调用天气服务刷新一次实时数据就是Tools。判断清楚才能让模型做出正确的选择。4.3 Hermes Agent里如何落地MCP落地配置我做成了一份JSON文件驱动的架构。不需要改代码只需要在配置文件里声明要启用哪些MCP Server{ mcp_servers: [ { name: weather_server, transport: stdio, command: python, args: [-m, weather_mcp_server], tools: [get_weather, get_forecast] }, { name: knowledge_base, transport: http, url: https://internal.example.com/mcp, headers: { Authorization: Bearer ${KNOWLEDGE_BASE_TOKEN} } } ] }启动时MCP Client Manager会逐个建立连接拉取服务端的工具列表合并到工具注册表里。这里有个容易踩的坑多个MCP Server可能暴露同名工具。我在合并工具注册表时加了命名空间机制比如weather_server.get_weather和knowledge_base.get_weather可以共存模型侧通过带前缀的完整名称来调用。鉴权方面MCP协议本身就带OAuth成熟的流程但企业内部使用很多是自定义Header加Token。这份Token建议放在环境变量或密钥管理系统里不要落到配置文件里入库否则密钥就等同于代码泄露了。5. 记忆能力短期、长期与语义检索记忆是让Agent真正“越用越顺手”的关键能力同时也是最容易翻车的地方。记忆设计不好要么什么都记不住要么什么都记导致上下文污染严重。Hermes Agent的记忆体系我分为三层工作记忆、长期记忆、核心档案。5.1 记忆分层的设计思路工作记忆当前会话内产生的临时信息比如用户这次打开网页准备预订酒店正在选房型。工作记忆跟随会话层存储会话过期即销毁。它对应的是人类的“短期记忆”。长期记忆跨会话沉淀的重要事实和偏好如“用户偏好高层无烟房”“用户上一次预订时间是去年春节”。长期记忆使用向量化存进向量数据库通过语义检索召回。它对应“长期记忆”。核心档案经过提炼、更新频率较低的高置信度用户画像。例如“用户是商务出行为主公司政策要求酒店价格不超过500元/晚”。核心档案一般用结构化字段存储与向量库解耦查询走精确匹配。三层的写入路径完全不同。工作记忆不用特判每个会话消息都会进上下文长期记忆需要显式提取——我会在每轮对话结束后后台跑一个“记忆提取摘要”让模型判断“这轮对话里有哪些值得以后记住的信息”核心档案的变更则需要较高置信度门槛通常需要用户明确确认或多次行为一致后才写入。5.2 向量检索与记忆召回不能把向量库当聊天记录记忆召回最容易犯的错误是把用户历史聊天记录全部向量化存入库中然后在每轮对话开始前做全文检索把Top3碎片直接塞进prompt。实际效果是灾难——模型会从各种历史碎片里东拼西凑得出不靠谱的结论。我调整后的召回策略是这样的先意图判断再记忆召回。每轮对话开始先判断“当前任务是否需要历史信息”。比如用户问“这周末上海天气怎么样”不需要任何历史偏好直接跳过记忆召回。只有用户明确提到“按我上次的口味”“我还是想要靠窗的位置”等指向历史信息的表达才触发召回。召回结果必须经过重排。向量检索Top20候选再用一个轻量级重排器结合当前会话主题做排序最终取3~5条注入上下文。每条被注入的记忆必须带来源信息。比如“来源用户2024年3月2日对话”让模型在不确定的时候可以追问而不是盲目采信。我用过一个生活化类比向量检索像是图书馆管理员帮你找到了一堆可能相关的书重排是快速翻书确认哪些页面真的有用注入Prompt则是把有用的内容抄在纸条上递进考场。跳步就等着出低级错误。5.3 写入、更新与遗忘策略写入什么内容比怎么写入更重要。Hermes Agent的记忆提取摘要只关注三类信息用户明确表达的事实和偏好“我家里人开新能源车”“我每个月底出差”与当前任务强相关的决策依据“上次选的是离会议地点步行10分钟内的酒店”用户表达过强情绪或强否定态度的内容“我不喜欢高分贝环境”。更新方面遇到最多的问题是旧记忆与新记忆冲突。比如用户说“我家的车卖了以后通勤坐地铁”系统需要把旧的“偏好自驾”标记为过期而不仅是追加新记录。我只信任带时间戳的记忆结构。每条记忆有created_at、updated_at、expired_at三个字段冲突时按时间戳和置信度综合裁决。遗忘策略我也很看重。长期记忆如果没有遗忘机制向量库里很快就会积累大量垃圾数据既浪费存储又干扰检索。我做了两级遗忘TTL软过期超过一定时间的记忆先标记为“候选遗忘”定期做一次重要性衰减评分低价值的记忆直接物理删除或归档。5.4 实操中的记忆安全问题记忆能力做得越好隐私责任越重。用户在对话里说的私密信息可能被模型提取并长期存储。这个问题必须在架构层面就考虑不能事后补救。我的几个基本配置记忆写入前需要脱敏。手机号、身份证、住址等敏感信息默认不进入长期记忆层需要时只存脱敏后的哈希值。记忆访问需要权限控制。同一个人在不同业务线之间的记忆不互通避免跨场景信息泄露。比如客服Agent和生产研发Agent之间记忆存储彻底隔离。提供“记忆遗忘”出口。用户提出删除记忆请求时要能精确定位其所有记忆条目并清除。所以每一条记忆必须带user_id标签这个话题在功能上线前就得定好。记忆安全做不好Agent能力再强也不敢放出去给真实用户。在这件事上我宁可功能少一点也要把边界焊死。6. 常见问题与排查实录最后这一部分把我在开发Hermes Agent过程中踩过的几个典型问题整理成速查。这些问题比较隐蔽网上资料也少我尽量把当时的排查思路交代清楚。6.1 会话上下文莫名其妙丢失现象用户聊了几轮后Agent突然像失忆了一样重复问已经提供过的信息。排查思路第一步查会话存储是否还在。Redis key是否过期我当时遇到的是测试环境没有给会话设置TTL但因为使用了本地内存Store服务一次重启就全部清空。第二步查截断逻辑看是不是历史消息被截断了。我的经验是消息列表的长度限制一旦设得太低会话会在用户完全没察觉的情况下悄悄“断片”。解决办法不要直接限制消息条数按token总量来控制并给关键消息打不可截断标记。6.2 工具调用参数错位现象模型调用了工具但参数明显不符合业务规格比如把金额单位“分”传成了“元”。排查思路先看工具描述里是否明确写了单位要求。很多时候模型传错参数是因为工具描述里压根没提单位。补充描述后错误率大幅下降。再检查参数校验规则是否太宽松。我建议对关键数值字段一律加范围校验比如金额必须大于0、日期必须匹配ISO标准格式。校验失败后确保错误信息回传给模型让它二次修正。6.3 MCP服务连接不稳现象Agent有时能调用工具有时提示MCP服务不可用重启后恢复正常。排查思路stdio传输方式下最常见的原因是子进程意外退出。MCP Server本身没做异常捕获或崩溃保护Agent这边也没有做重连。Hermes Agent解决方案在MCP客户端里加了心跳检测如果连续三次心跳无响应触发重连子进程模式下还要监听退出码异常退出时自动拉起新进程。远程HTTP服务则不稳定往往出在鉴权Token过期排查时先看日志里有没有401错误。6.4 记忆污染与误召回现象Agent在某个任务中突然引用一段完全无关的旧记忆回答变得奇怪。排查思路正常流程是“意图判断-召回-重排”问题多半出在前面两步。打开记忆召回日志看是否在无关意图下做了召回。我遇到过的是“查天气”场景竟然召回了几条历史酒店偏好原因是我当时给“天气类意图”也配置了通用召回策略。修复办法给每个意图定义独立的召回范围和召回字段。最后检查重排逻辑确认重排分数最高的记忆与当前会话主题的语义相似度是否超过阈值低于则不下发。做一个通用的排查清单问题第一检查点根治方案会话失忆会话过期时间、截断逻辑Redis持久化按token截断关键消息保护参数错位工具描述与校验规则描述补全Pydantic强校验错误回传MCP连接异常子进程退出码、Token过期心跳检测自动重连密钥管理记忆误召回意图判断与召回范围分意图召回重排阈值带来源信息这四类问题我基本每周都会在社区里看到有人再踩一遍。提前做防护比事后修命中率高得多。最后分享一个实操心得做Hermes Agent到现在我最大的体会是单独把会话、工具、MCP、记忆某一项做好都只能算完成了20%。真正让你觉得“这个Agent能用了”的瞬间是四者开始协同的那一刻——会话里的上下文承载了工具调用的结果工具返回的数据经过提炼写入了长期记忆MCP让我毫不费力地接入第三个、第四个外部系统记忆又把每一轮对话串成持续进化的脉络。开发这个项目的过程中我把很多周末都花在排查那些“看起来像玄学”的问题上。翻到最后几乎所有问题的根因都很基础一个没设好的TTL一段写得不准确的工具描述一次忘记处理的分页。所以我也建议正在做Agent框架的朋友遇到诡异问题先不要怀疑框架本身先检查底座配置多半是某个基础环节的细节没有压实。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑