
1. 项目概述从“执行”到“学习”的Agent进化最近在拆解 Hermes Agent 的源码当深入到第七部分时感觉像是打开了一个新世界的大门。之前我们聊了它的通信、任务分解、工具调用那些都像是 Agent 的“四肢”和“反射神经”让它能动、能干活。但到了“记忆”与“技能”这一层事情开始变得有趣了——这关乎 Agent 的“大脑”和“经验”是它能否从一个单纯的指令执行者进化成一个能“学习”、能“成长”的智能体的关键。很多刚接触 Agent 开发的朋友可能觉得记忆就是存点聊天记录技能就是调用几个 API。但当你真正去看像 Hermes 这样设计精良的框架源码时你会发现这里的“记忆”和“技能”被赋予了更深的含义它们共同构成了 Agent 的持续学习能力和个性化适应性的基石。简单来说一个没有记忆的 Agent每次对话都是“初次见面”一个没有技能学习机制的 Agent其能力边界在部署那一刻就被框死了。而 Hermes 在这两方面的设计恰恰是为了打破这些限制。2. 记忆系统深度解析不止于记住更在于组织与激活记忆模块是 Agent 实现上下文连贯和个性化交互的核心。在 Hermes 的源码中记忆不是一个简单的键值对数据库而是一个结构化的、多层次的系统。2.1 三层记忆架构从短期缓存到长期沉淀Hermes 的记忆系统通常借鉴了人类记忆的分层模型在源码中我们可以清晰地看到至少三个层次的划分短期/工作记忆这相当于 Agent 的“思维缓存”。它保存当前会话轮次中的上下文信息比如用户刚刚说的最后一句话、上一步工具调用的结果。这部分记忆容量小、存取速度快但“遗忘”也快一旦会话主题切换或经过一定时间就会被清理或压缩。在代码里这通常体现为一个在内存中维护的上下文列表或缓冲区。长期记忆这是 Agent 的“知识库”或“经验库”。它存储跨越多个会话的、被认为有价值的信息。例如用户的偏好“喜欢用 Markdown 格式回复”、历史完成的重要任务总结、从成功或失败中提炼的模式。这部分记忆需要持久化存储如向量数据库、关系型数据库并配有高效的检索机制。源码中会涉及记忆的写入、索引创建和查询接口。元记忆这是比较高级的一层可以理解为“关于记忆的记忆”。它管理记忆的元数据比如某条记忆的创建时间、关联度、使用频率、重要性评分等。元记忆用于指导记忆的检索策略优先召回高频使用的记忆、执行记忆的定期清理淘汰陈旧、低关联的记忆以及实现记忆的抽象与泛化。在 Hermes 中这可能通过为每条记忆附加嵌入向量和属性标签来实现。注意记忆的写入时机和策略至关重要。不是所有对话内容都值得进入长期记忆。源码中通常会有一个“记忆提炼”或“摘要生成”的环节将一段冗长的交互压缩成结构化的关键点如用户目标、采取的行动、最终结果后再存入这能极大提升存储效率和后续检索的准确性。2.2 记忆的存储与检索向量化与相似性搜索记忆如何存、如何找是记忆系统设计的重中之重。Hermes 大概率采用了当前的主流方案向量数据库。存储过程当一条信息被判定需要存入长期记忆时源码中的流程通常是首先使用一个嵌入模型Embedding Model将文本信息转换为一个高维度的向量即嵌入向量。这个向量捕获了文本的语义信息。然后将这个向量连同原始文本或摘要、以及相关的元数据来源、时间戳、类型标签等一起写入向量数据库如 Chroma, Weaviate, Pinecone 等。检索过程当 Agent 需要回忆时例如处理新任务需要历史参考它会将当前的查询或上下文也转化为向量。接着向向量数据库发起一次“相似性搜索”寻找与当前查询向量最相似的若干个记忆向量。这种基于语义相似度的检索比单纯的关键词匹配更能找到关联性强的记忆即使表述方式不同。在阅读相关源码时你会关注几个关键类MemoryManager总控、VectorMemoryStore向量存储实现、EmbeddingProcessor嵌入处理。你需要看明白记忆写入的触发条件、嵌入模型的选择与调用、以及相似性搜索的阈值如何设置。2.3 记忆隔离与上下文管理为什么你的Agent记忆不会“乱窜”这是记忆系统一个非常实际且重要的问题也对应了网络上的一个热词。所谓记忆“乱窜”指的是 Agent 在处理不同用户、不同会话或不同任务时错误地引用了不相关的历史记忆导致回复混乱或信息泄露。Hermes 的源码中必然有相应的隔离机制会话隔离这是最基本的。每个独立的对话会话Session拥有独立的工作记忆上下文。在代码中这通常通过一个唯一的session_id来实现所有记忆的读写操作都关联到这个 ID。用户/角色隔离更细粒度的控制。长期记忆的存储和检索可以绑定user_id或agent_role。这意味着一个为用户A服务的Agent不会在回忆时搜到用户B的记忆。这在源码中体现为在构建检索查询时将用户ID作为过滤条件metadata filter加入向量搜索。命名空间隔离有些框架会使用“命名空间”的概念来划分不同的记忆领域。比如一个Agent可能同时处理“日程管理”和“邮件处理”两种技能这两种技能的记忆可以存放在不同的命名空间下避免交叉干扰。检查源码中的MemoryRetriever或相关查询函数你会看到类似filter{“session_id”: “xxx”, “user_id”: “yyy”}这样的参数这就是隔离机制在起作用。3. 技能系统剖析动态扩展与组合执行如果说记忆是 Agent 的“知识”那么技能就是它运用知识的“方法”。Hermes 的技能系统设计目标是让 Agent 的能力可以像插件一样动态增删并且能够灵活组合。3.1 技能的定义与注册从函数到可被调用的能力在源码中一个“技能”通常被抽象为一个标准化的对象或描述。关键属性包括技能名称唯一标识符。技能描述用自然语言描述这个技能是做什么的。这部分描述至关重要因为大语言模型LLM需要根据描述来决定何时调用该技能。输入参数模式定义技能需要哪些输入以及每个输入的类型、描述和是否必需。执行函数实际的代码逻辑可以是调用一个外部API执行一段计算或者操作一个内部工具。输出模式定义技能返回结果的结构。技能的注册过程在框架启动或动态加载时发生。源码中会有一个SkillRegistry技能注册表的类负责收集所有定义的技能并将其以 LLM 能理解的格式通常是符合 OpenAI Function Calling 或类似规范的 JSON Schema暴露给规划或决策模块。3.2 技能的动态发现与加载实现“热插拔”一个优秀的 Agent 框架应该支持技能的动态扩展。Hermes 的源码可能会提供以下几种机制配置文件驱动在一个指定的目录如skills/下放置技能定义的 YAML 或 JSON 文件框架启动时自动扫描并加载。API 注册提供一个 RESTful 端点允许在运行时动态注册新的技能。这对于需要高度灵活性的云服务场景非常有用。模块化加载技能以独立的 Python 模块或包的形式存在通过入口点entry_points机制被框架发现和导入。阅读这部分源码重点是看SkillLoader或PluginManager这样的类理解它们如何从文件系统、网络或配置中读取技能定义并实例化为可用的技能对象。3.3 技能的组合与编排从单技能到工作流复杂的任务往往需要多个技能按顺序或条件来执行。这就是技能的编排。Hermes 可能通过两种方式实现LLM 规划这是更常见和灵活的方式。任务规划模块或LLM本身根据用户请求和可用技能描述自主规划出一个技能调用序列。例如要完成“查天气并建议是否带伞”LLM 可能规划为先调用get_location技能再用其结果调用get_weather技能最后根据天气结果调用generate_advice技能。源码中的Planner或TaskDecomposer模块负责这部分逻辑。预定义工作流对于一些非常固定和常见的复杂任务可以预先定义好一个技能执行流程图可能用 DSL 或配置文件描述。当触发该任务时直接按图执行。这提供了更高的确定性和可控性。你需要查看是否有WorkflowEngine或Orchestrator这样的组件。在代码跟踪时可以关注一个复杂任务请求进来后是如何被解析成一系列技能调用以及这些调用之间的输出是如何作为下一个技能的输入进行传递的。4. 记忆与技能的协同实现真正的“学习”循环记忆和技能不是孤立的模块它们的联动才是 Agent 产生“学习”行为的关键。源码中体现了以下几种协同模式4.1 基于记忆的技能选择与参数填充当 Agent 面临一个新任务时它首先会检索长期记忆。检索到的相关记忆可以用于技能选择如果记忆显示过去用户在处理类似任务时更喜欢使用技能A而非技能B那么本次决策可以倾向于技能A。参数预填充例如记忆里存储了用户的默认城市是“北京”。当用户简单地说“今天天气怎么样”时Agent 在调用天气查询技能时可以直接将“city”参数填充为“北京”而无需再向用户询问。这部分的逻辑通常存在于DecisionMaker或ContextEnhancer模块中它在调用 LLM 进行规划或决策前先用相关记忆丰富了任务上下文。4.2 技能执行结果沉淀为记忆这是“学习”的核心环节。每次技能执行完成后其输入、输出、成功与否的状态、以及整个子任务的上下文都可以被有选择地提炼并存入长期记忆。成功经验的积累将成功完成任务的步骤、关键决策点和最终结果总结成一条“案例记忆”。未来遇到相似任务可以直接参考或复用。失败教训的记录记录技能调用失败的原因如参数错误、API异常、逻辑冲突。这能帮助 Agent 在未来避免重复犯错。源码中可能会有专门的FailureHandler或ExperienceRecorder来负责这件事。用户偏好的学习通过观察用户对技能执行结果的反馈显式的如“不对”隐式的如用户后续纠正了结果来调整未来技能的选择和使用方式。这部分可能更复杂涉及对交互序列的强化学习或偏好建模。在源码中你需要找到技能执行链的“后置处理器”看看在哪里调用了MemoryManager.save_experience()之类的方法。4.3 技能的自我优化与生成更高级的“学习”是技能本身的进化。Hermes 可能通过以下方式支持技能描述的优化根据技能被调用和使用的实际情况自动优化其自然语言描述使其更容易被 LLM 准确理解和调用。例如如果某个技能经常被误调用可以分析日志调整其描述文本。新技能的代码生成对于重复出现的、模式固定的复杂操作序列Agent 可以尝试将其自动化并生成一个新的、可复用的技能函数。这通常需要代码生成能力如利用 LLM和一定的安全沙箱环境来验证生成的技能。这可能是 Hermes 框架更前瞻性的特性需要仔细在源码中寻找类似SkillGenerator或AutomationCreator的痕迹。5. 源码关键模块与类追踪要深入理解 Hermes Agent 的记忆与技能系统建议在源码中重点追踪以下模块类名可能因版本而异agent/memory/目录memory_manager.py: 记忆系统的总入口提供统一的读写接口。short_term_memory.py: 实现对话上下文的滚动窗口管理。long_term_memory.py/vector_memory.py: 实现与向量数据库的交互包括嵌入、存储、检索。memory_retriever.py: 封装检索逻辑可能包含相关性评分、重排序、结果融合等。agent/skills/目录skill.py: 定义技能基类或技能描述的数据结构。skill_registry.py: 全局技能注册表维护所有可用技能。skill_executor.py: 负责调用技能的实际函数并处理输入输出转换。skill_loader.py: 从文件或配置中动态加载技能。agent/core/或agent/brain/目录planner.py: 任务规划模块利用 LLM 和可用技能描述生成执行计划。orchestrator.py: 工作流编排引擎按计划依次执行技能管理数据流。context_builder.py: 在每次与 LLM 交互前组装当前上下文其中就包括从记忆系统检索到的相关信息。主 Agent 类如hermes_agent.py查看其初始化过程如何组装记忆和技能模块以及主循环中如何协调它们工作。6. 实践中的注意事项与避坑指南结合源码分析和实际开发经验这里有几个关键的注意事项记忆的隐私与安全长期记忆存储了用户数据必须加密存储并在检索时严格执行隔离。在开发涉及多租户的 Agent 应用时这一点是底线。务必仔细审查记忆查询中的所有过滤条件是否完备。技能描述的准确性技能描述是 LLM 理解技能的“说明书”。描述不清会导致误调用描述过于宽泛则可能导致无关调用。最好的实践是让描述清晰、具体并包含典型用例示例。在 Hermes 源码中可以看看是否有对技能描述进行验证或优化的机制。控制记忆膨胀如果不加控制长期记忆会无限增长导致检索变慢、成本增加。需要实现记忆的“遗忘”策略例如基于时间衰减、使用频率或重要性评分来定期清理不重要的记忆。在MemoryManager中寻找类似cleanup或compress的方法。技能执行的稳定性与超时技能可能调用外部服务必须设置合理的超时和重试机制并做好异常处理避免一个技能的失败导致整个 Agent 卡死。SkillExecutor里应该有完善的错误处理逻辑。测试记忆与技能的联动单独测试记忆检索和技能调用可能都正常但联动起来可能出现意想不到的问题。例如记忆检索出的旧参数格式可能与新版本技能要求的格式不兼容。需要设计集成测试模拟完整的“记忆检索-规划-技能执行-记忆保存”循环。拆解 Hermes Agent 的记忆与技能源码就像是在观察一个智能体如何构建它的经验库和方法论。记忆让它变得“有阅历”技能让它变得“有本事”而两者的协同则开启了“学习”和“进化”的可能性。这套设计模式不仅仅是 Hermes 的实现也代表了当前主流 Agent 框架在构建可持续智能体方面的核心思路。通过深入这些源码细节我们不仅能更好地使用 Hermes更能将这些设计理念应用到自己的智能体项目中打造出真正具备适应性和成长性的 AI 应用。