首页 / 资讯中心 / 文章详情

智能体四能力实战:会话、工具、MCP与记忆系统全解析

智能体四能力实战:会话、工具、MCP与记忆系统全解析 ★ FEATURED ARTICLE
一直在做Hermes Agent这个智能体项目从最早的单一模型对话到现在的会话管理、工具调用、MCP接入、记忆系统四块能力齐全中间踩了不少坑。招人聊架构的时候我经常把Hermes Agent拿来做例子很多项目不是模型不行而是周围这圈能力基础设施没搭好。这篇就顺着Hermes Agent的能力拆解来写把会话、工具、MCP、记忆这四个模块的设计思路、实现要点和实战中反复踩过的坑一次说清楚。想自己搭Agent、或者正在研究怎么把大模型真正落地到业务里的朋友这篇应该能帮上忙。1. 能力全景Agent的四个支柱是如何协作的1.1 为什么是这四块能力先说一个总体的判断一个人要完成复杂的真实任务需要四样基本能力——能听懂和回应会话、能动手做事工具、能连接周围环境里的各种设备和系统接口、能记住之前发生过什么记忆。Agent要完成的任务逻辑也是一模一样的。会话是Agent的神经系统负责理解用户意图、组织回复、维持多轮对话的上下文。工具是双手模型通过工具调用把思考变成行动比如查询数据库、发送请求、操作文件。MCP是接驳外部世界的标准化接口相当于给Agent换了一排万能插口想接什么外部系统都可以标准化接入。记忆则是长期档案库让Agent在上一次对话结束后还能记住用户的偏好和关键上下文。很多人做Agent时只关注模型本身强不强实际跑起来才发现决定体验上限的往往是这四块外围能力的协作质量。它们之间的关系不是独立的四条线而是一条循环链路会话层接收请求意图被理解后决定是否调用工具或外部MCP能力过程中和结束后记忆被更新下次会话又能从记忆中召回相关内容。1.2 一次完整请求的主流程以Hermes Agent处理帮我查一下上周某项目的报表顺便提醒我明天之前把结论同步给团队这个请求为例完整的主流程大概是这样的会话层启动一个Session载入system prompt和对话历史更新上下文token计数。模型分析请求识别出两个子任务——查报表、设置提醒。工具层解析模型输出的工具调用指令执行查报表操作返回结构化数据。模型基于工具返回结果继续生成回复并触发一个日程提醒工具调用。MCP层如果涉及外部系统比如某协作平台、日历服务通过标准协议完成连接与调用。会话结束时记忆系统把本次交互的关键信息项目名称、截止时间、用户偏好等异步写入长期记忆。这个过程看起来很常规但每一环都有大量容易翻车的细节。尤其是当请求变复杂、工具数量变多、外部系统连接不稳时任何一个环节的脆弱设计都会让整条链路崩掉。下面逐个拆解。2. 会话能力状态管理与上下文工程2.1 会话是什么Session的生命周期会话Conversation不是简单地把用户消息和模型回复堆在一起它本质上是一段有状态的服务交互。Hermes Agent里每个会话都有一个唯一标识里面至少包含这几样东西会话ID全局唯一用于查找会话历史、恢复状态。消息列表按时间排序的完整交互记录。元数据创建时间、更新时间、关联用户、关联业务场景。系统级变量当前工作目录、当前任务状态、临时标记等。生命周期管理是容易忽略的地方。会话需要明确的创建、活跃、归档和销毁过程。我自己最开始做的时候只关心能聊结果线上跑了没几天内存里积压了几万个会话对象查询性能直线下降。后来加了三条策略超过30天未活跃的会话自动归档活跃会话数量做上限控制会话销毁前把关键信息写入记忆库。会话不是越长寿越好关键是有始有终。2.2 上下文窗口不是越大越好上下文窗口Context Window是模型一次能看到的token数量。很多人觉得窗口越大就越能装下更多历史事实恰恰相反有三个问题同时存在Token成本每轮请求都在重新发送全部历史历史越长单个请求的成本越高。注意力稀释模型对长上下文的中间部分记忆显著变差像什么都没看见一样。延迟恶化输入token多首token生成时间明显变慢。所以在Hermes Agent里我做了上下文预算机制。简单来说每轮对话开始时计算当前消息列表的token总量设定一个硬性上限比如模型支持窗口的60%超过这个上限就触发压缩策略。压缩策略有两种一种是滑窗截断把最早的对话扔掉只保留最近几轮另一种是摘要压缩用一次额外的模型调用把早期对话总结成几条摘要替代原文放回窗口。实际用下来摘要压缩的效果远好于直接截断。截断丢掉了关键细节而摘要能保留主干信息。但摘要压缩也有坑——被压缩掉的部分如果是多轮对话中的关键指令比如用户改过一次需求压缩后的信息可能失真。所以我会额外维护一个关键指令列表把用户明确提出的要求、修改过的条件用结构化字段单独保存不依赖模型对对话历史的压缩。2.3 流式输出与工具调用的会话体验会话里最影响体验的细节是流式输出。用户在等回复时一句话都不显示比显示一半字丑要可接受得多——大多数人等不了5秒白屏。Hermes Agent一开始直接把模型返回的全部文本一次性吐出被测试用户吐槽像个哑巴。后来改成了基于SSE的流式输出每个token生成后立即下发用户在几百毫秒内就能看到首字。流式和工具调用之间的冲突值得一提。工具调用场景下模型经常会先输出一段解释文本然后输出一个函数调用指令。这时候如果直接把解释文本流式发给用户用户就会看到我来帮你查询一下数据这几个字刚出来然后消息就卡住了——因为实际上模型正在等待工具返回而工具可能需要好几秒。解决思路是会话层在流式过程中检测到工具调用指令时暂停后续文本流的推送直到工具执行结果返回后再继续生成和推送。这需要在流式管道里做一层缓冲不能简单地把模型输出往客户端直推。3. 工具能力从函数调用到任务执行3.1 工具调用机制的核心链路工具Tool是让模型从只会说到能做事的关键一环。主流实现思路是Function Calling模型在生成回复时除了输出文本还可以输出一个结构化的工具调用指令包含函数名和参数对象。Hermes Agent里的调用链路是这样走的模型输出包含一个工具调用对象比如{name: query_report, arguments: {project: 报表项目, date: 上周}}。工具框架解析这个名字在工具注册表中查找对应的处理函数。参数校验用JSON Schema校验参数是否合法。执行函数拿到返回值。把返回值作为一条工具消息重新喂给模型模型基于真实数据生成最终回复。这套机制看起来简单但细节非常多。模型经常给出错误格式的参数字符串传成了数字、字段拼错、工具函数的执行结果经常是异常或超时、工具存在依赖关系时需要先调用A再调用B。所以工具框架要做的不仅是执行函数还有错误兜底和调度编排。3.2 工具Schema设计的三条经验工具Schema是模型理解有哪些工具可用和如何调用的说明书设计质量直接决定模型调用的准确度。Hermes Agent的项目里我自己总结了三条经验基本都是被坑过才长出来的描述要写清楚什么场景下用这个工具而不是只写功能。比如get_user_orders单纯写获取用户订单模型容易误用写当用户询问历史购买记录、订单状态或物流信息时使用参数userId是用户唯一标识status可选模型就很容易选对。参数要少而精。能用三个参数解决的问题绝不用十个参数参数越多模型出错的概率越高。实在需要大量参数时可以设计成传入一个集中配置对象降低模型逐一生成参数的负担。必填参数要少可选参数尽量带默认值。实际效果差非常明显模型时常漏填某个字段导致工具执行失败。给可选参数合理的默认值能大幅降低失败率。还有一个小技巧模型在多个相似工具之间做选择时容易犯迷糊。比如get_team_calendar和get_personal_calendar功能相近模型会随机选一个。规范做法是在描述里明确区分适用场景甚至可以在描述里直接写当请求涉及多人日程选择团队日历仅涉及个人日程选择个人日历。3.3 多工具编排与错误处理当一个任务需要多个工具协作时编排逻辑就变得关键。最简单的方案是不做编排每轮让模型自己决定调哪个工具、下一步干什么这在工具数量少于5个时能正常工作。当工具数量多了以后模型容易陷入反复调用同一个工具兜圈子或者在不满足条件时强行调用工具。Hermes Agent里引入了两层机制第一层是动作序列检测。模型每轮只能输出一个目标工具但工具框架会维护一个当前任务状态机记录已经完成的步骤和下一步需要的前置条件。第二层是最大重试计数同一个工具调用如果连续失败超过3次就不再自动重试转为向用户输出错误说明。错误处理这块最容易砸口碑。工具执行报错时如果把原始异常堆栈直接抛给模型模型会一本正经地编一个解决方案实际毫无作用。我现在做法是工具函数内部统一捕获异常并转成结构化的错误码简短说明比如{error_code: DB_TIMEOUT, message: 数据库连接超时请稍后重试}。模型看到这个结构化错误后能基于错误码做更合理的决策比如换个工具重试、或者明确告知用户暂时无法执行。4. MCP集成打通AI与外部世界的任意门4.1 MCP的本质给Agent配一套万能插口MCPModel Context Protocol是一套让AI应用和外部数据源/工具进行标准化交互的开放协议。把它理解为AI应用的USB-C接口是最容易上手的类比——以前每种外设都要专用的线缆和驱动MCP统一了接口和通信规范Agent想接什么服务就插上支持MCP的服务端即可。在Hermes Agent里MCP的作用是把各种外部能力统一转化成Agent可调用的工具。比如接一个数据库查询服务、接一个文件系统服务、接一个浏览器操作服务每个服务只需要实现一套MCP标准协议Agent这边通过统一的MCP客户端就能发现并调用这些工具。不用为每个外部系统单独写适配代码这是它最大的价值。我刚开始接触MCP时最大的疑问是这不就是RPC吗为什么单独立个协议后来实际操作才明白MCP的关键不是远程调用这个动作而是让模型能发现自己可以调什么也就是能力发现Capability Discovery。MCP服务端启动后会声明自己提供哪些工具、哪些资源、哪些提示词模板Agent基于这些声明拼接到自己的工具列表里从而让模型在运行时就知道外部有哪些能力可用不需要把每个工具的Schema都硬编码到代码里。4.2 MCP的三种角色与两种传输MCP体系里有三个身份容易混Host宿主程序一般是Agent应用本身负责协调整个会话和工具调度。Client在Host内部运行专门负责跟某个MCP Server建立连接、发送请求。Server提供能力的一方暴露工具或资源比如一个文件系统的MCP Server、一个数据库的MCP Server。传输层主流有两种。一种是基于标准输入输出的本地传输Agent通过子进程启动Server用进程的标准输入输出进行JSON-RPC通信。适合本地工具启动快、不需要网络配置。另一种是远程HTTP传输支持跨机器、跨网络的连接。国内场景下本地stdio传输更常用因为延迟低且不容易受网络限制。MCP的消息格式基于JSON-RPC 2.0核心方法就几个initialize初始化连接、tools/list获取可用工具列表、tools/call调用某个工具、resources/list获取可用资源。语言不限制我自己的实现里用Python写Server、用Node.js写Client也完全没问题。4.3 在Hermes Agent里落地MCP客户端的步骤我这里给出一份可行的MCP客户端接入清单适合在Agent项目里按顺序走定义MCP Server配置表包括server名称、启动命令本地传输或URL远程传输、环境变量。用一个JSON文件集中管理。启动阶段遍历配置表逐个创建连接。本地传输需要拉起子进程并做好超时控制。调用tools/list获取工具清单把工具Schema转换成Agent框架内部的统一工具格式主要是函数名、描述、JSON Schema参数定义。把这些动态工具合并到静态工具表中交给模型做工具选择。会话过程中模型一旦选中某个MCP工具Client侧将参数转发给Server执行结果以JSON返回并回填给模型。实际操作中第2步最容易出问题。子进程启动后并不是立刻可用需要等待初始化握手完成。曾经有个Server启动就要两秒多期间Agent已经发起了请求直接连接失败。后来我统一加了启动探测建立连接后轮询initialize结果直到成功设置总超时为10秒超时则标记该Server不可用自动剔除。MCP还有一个和记忆系统结合的点MCP Server提供的资源形态天然适合作为长期记忆的存储后端。比如用文件系统MCP Server把记忆文件直接写到本地目录或用数据库MCP Server做向量检索。这样记忆系统不用自己实现一套存储全部走MCP协议扩展起来非常灵活。5. 记忆能力从短期上下文到长期常识5.1 记忆为什么难做记忆和上下文窗口是两个层级的事情。上下文窗口是会话中临时可见的信息会话结束就丢失记忆是跨会话持续可用的信息存在于对话之外的存储中。最难的一点是记忆系统不能塞太多否则Agent会在记忆检索时被干扰反而忘了用户本轮说的是什么。举一个反面的例子早期我给Hermes Agent接了一个把所有历史对话全文存下来的记忆系统。效果可想而知——模型动不动就把几个月前的某句话翻出来当现在的需求搞得对话风马牛不相及。后来我才明白记忆系统不是存档越多越好而是检索越精准越好。5.2 记忆的分层架构Hermes Agent最终采用的记忆架构分四层每一层用不同的存储方案工作记忆当前会话进行中需要的信息本质上就是会话层的上下文窗口由会话管理模块负责。语义记忆关于用户和世界的事实性知识比如用户倾向于每天上午处理报表项目名称与代码库的对应关系。这部分适合用结构化字段存比如KV存储或关系表。情景记忆过往交互事件的记录比如上周五用户修改了数据源的连接配置。这部分适合用向量化存储检索方式以相似度召回为主。程序性知识关于如何做事的偏好和模式比如用户喜欢先看概览再深入细节。这部分可以抽象成规则或备忘录在生成答复时注入System Prompt。会话结束后工作记忆里的一部分重要信息会通过记忆写入管道沉淀到语义记忆和情景记忆。写入不是一个简单的事件需要先做关键信息抽取——可以直接让模型对本次对话做摘要把用户提了什么需求、明确了什么偏好、改变了什么设置提取出来。摘要后的内容再做向量化入库。5.3 记忆的写入、检索与遗忘写入的关键是控制什么值得记。Hermes Agent里的规则是三条用户明确表达偏好时以后都用这种格式我不喜欢XX必须记。涉及业务关键参数变更时项目代号改了截止时间调整为周五必须记。一次性交谈内容不主动记除非用户要求。检索的关键是混合召回。单独用向量相似度有局限——用户可能用完全不同的措辞查询同一件事。我在后续迭代里加了关键词作为辅助信号先做一次基于全文关键词的粗筛再做向量相似度的精排最后把命中结果按时间衰减排序。这样既能找出语义相近内容又能把无关但用词相似的内容滤掉。遗忘机制是很多人忽略的。永远记住一切的记忆系统其实是负担。Leake 面对一个动态世界正确的做法是给记忆条目加上强度分每次被成功检索到时加分长期未被检索到分数自然衰减。低于阈值时归档。这个设计让我手头的记忆库每个月都能自动清理出一部分过时信息保持检索质量。5.4 记忆系统的两个实际坑第一个坑是离线评测困难。记忆系统好不好只能在真实对话里感受难以用标准数据集衡量。我采取的做法是每次人工测试完都用固定的记录评分卡记录用户明确提过的偏好是否被正确记住和跨会话检索是否命中关键信息作为回归基准。第二个坑是记忆污染。一次错误的记忆写入比如模型摘要时产生了幻觉会影响后续很多次对话。所以记忆写入必须有人工/规则兜底——对高权限的记忆写入操作比如删除某项目强制要求用户确认对自动抽取的记忆保留摘要原文便于随时溯源修正。6. 常见问题与排查技巧实录6.1 问题速查表问题现象直接原因解决思路对话越到后面回复越慢上下文窗口接近上限单次请求token过多启用摘要压缩限制单次会话最长轮数对长对话做滑窗截断模型重复调用同一个工具工具描述不清晰或者缺少执行状态判断优化工具描述引入动作序列检测增加最大重试次数外部MCP工具调用超时子进程启动慢或网络握手失败启动探测超时控制失败自动重试并降级剔除检索到的记忆和当前问题无关向量检索精度不足或记忆数据过于臃肿混合检索关键词向量引入分数衰减与归档机制工具参数解析报错率高Schema定义太复杂、必填项太多简化参数、减少必填项、提供合理默认值编造工具执行结果工具异常未结构化返回模型自行脑补异常统一转换为结构化错误码给模型明确执行失败信号6.2 排查工具的实战心得用日志排查Agent问题的效率远低于对话回放。我的习惯是每个请求带上requestId完整记录模型输入、模型输出、工具调用链、记忆检索结果再配合一次性的会话重演功能。当用户反馈刚才你说要查但没有结果时通过回放能立刻定位是哪一环丢了——是模型没触发工具调用还是工具返回空结果还是结果被后续对话覆盖了。排查MCP问题还有一个常用技巧先用独立的MCP调试工具单独连Server发请求看协议层是否正常再回到Agent里测集成。这样能快速区分是Server本身的问题还是Client接入的问题。如果Server单独调用正常但Agent里总是失败八成是工具Schema转换环节丢了参数定义。工具调用失败还有一个容易误导人的场景模型会高情商地告诉用户我查了一下没有找到但实际是工具执行抛异常。这就是为什么异常必须结构化返回——让模型明确知道这个工具没跑成功而不是让模型默认自己查无结果。加了这个设计后误报查不到的情况几乎消失了。6.3 关于性能的几个经验数字性能调优的经验数据这里也算一笔账。Hermes Agent在接入摘要压缩后平均单轮请求的上下文token从9000降到了4000左右首token延迟下降约40%。工具Schema优化后多工具场景下的工具选择准确率从接近80%提升到95%以上。MCP的stdiio传输平均单次工具调用耗时在几十毫秒到几百毫秒之间远优于远程HTTP方案的几百毫秒以上所以凡是本地能解决的场景我都优先用stdio。记忆系统方面混合检索相比纯向量检索命中率大约提升15个百分点尤其在高频关键词不一致但语义相近的场景下差距更明显。给记忆条目加分衰减机制运行一个月后历史库里无效条目占比下降了约30%检索噪音明显减少。我个人在实际操作里的体会是Agent的这四块能力就像桌子的四条腿任何一条短了都会让整个系统站不稳。画架构图的时候很多人只在意模型的参数和提示词但把会话状态管好、工具Schema写好、MCP连接稳定、记忆系统分清层级这些看似不起眼的工程活才是决定Agent能不能真正跑起来的核心。Hermes Agent走到今天踩过的坑几乎都落在这四块里后续如果再扩展能力我也会优先往这四条主线上补纵深而不是急着加新花样。
阅读完成 · 觉得有帮助?
咨询建站