从零构建具备记忆与工具调用能力的AI智能体:Hermes框架实践指南

📅 2026/7/5 5:03:08
从零构建具备记忆与工具调用能力的AI智能体:Hermes框架实践指南
30款热门AI模型一站整合DeepSeek/GLM/Qwen 随心用限时 5 折。 点击领海量免费额度在工程实践中我们常常面临一个困境如何让一个AI助手不仅能理解当前对话还能记住长期上下文、调用外部工具、并随着使用不断进化其能力传统的聊天机器人往往局限于单次会话缺乏记忆和主动学习机制。Hermes项目正是为了解决这一系列问题而设计的开源框架它基于Harness Engineering原理旨在构建一个具备持久记忆、终端操作和技能自进化能力的智能体。本文将带你从零开始理解Hermes的核心概念完成环境搭建并跑通一个具备终端交互、记忆存储和技能学习的最小可运行示例。无论你是对智能体开发感兴趣的开发者还是希望为现有系统添加AI能力的工程师都能通过本文获得一套可复现的实践路径。1. 理解 Hermes 与 Harness Engineering 的核心设计在深入代码之前我们需要先厘清几个核心概念这决定了后续配置和开发的方向是否正确。1.1 Harness Engineering从“提示工程”到“缰绳工程”传统的AI应用开发重度依赖“提示工程”Prompt Engineering即通过精心设计的文本来引导大语言模型LLM输出期望的结果。这种方式存在明显瓶颈提示词难以维护、上下文长度受限、无法形成长期记忆、且每次交互都是独立的。Harness Engineering可译为“缰绳工程”或“驾驭工程”是一种更系统的设计范式。它不再将LLM视为一个需要反复用文本“鞭策”的黑盒而是将其作为一个核心“引擎”通过一套外部的控制体系即“缰绳”来管理其输入、输出、记忆、工具调用和学习过程。这套体系通常包括记忆系统持久化存储对话历史、用户偏好、事实知识。工具系统为LLM提供调用外部API、执行代码、查询数据库等能力。技能系统将复杂的多步操作封装成可复用、可组合的“技能”并能通过使用反馈进行优化和进化。控制流决定何时调用记忆、使用哪个工具、执行哪个技能并处理异常。Hermes框架可以看作是Harness Engineering理念的一个具体实现。它提供了构建这套控制体系所需的基础设施和约定。1.2 Hermes 的核心组件与工作流程一个典型的Hermes智能体由以下几个关键部分组成它们共同构成了智能体的“大脑”和“身体”LLM 核心这是智能体的推理引擎。Hermes本身不提供LLM而是通过接口如OpenAI API、本地部署的Ollama等接入。记忆存储器负责存储和检索信息。记忆可分为短期记忆/对话记忆保存当前会话的上下文。长期记忆/向量记忆将信息转换为向量嵌入存储到向量数据库如Chroma、Weaviate中实现基于语义的相似性检索。技能记忆存储已学会的技能的定义和执行历史。工具执行器提供一组“工具”供LLM调用。最核心的工具之一就是终端Terminal它允许智能体在受控环境下执行Shell命令从而与操作系统交互。其他工具可能包括网络搜索、文件读写、数据库查询等。技能管理器技能是一组预定义或学习得到的操作序列。管理器负责技能的注册、发现、执行和优化。技能自进化指的是智能体能够根据任务执行的成功与否自动调整技能的参数、步骤或生成全新的技能。控制循环这是智能体的主循环。它接收用户输入结合记忆和当前状态让LLM决定下一步行动直接回复、调用工具还是执行技能执行行动将结果反馈给LLM并更新记忆如此循环。理解了这些组件我们就知道部署Hermes不仅仅是启动一个服务而是需要配置好上述每一个环节并让它们协同工作。2. 环境准备与项目初始化我们将在一个干净的Python虚拟环境中搭建Hermes这样可以避免依赖冲突。本文以Linux/macOS系统为例Windows用户建议使用WSL2以获得最佳体验。2.1 系统与软件要求确保你的系统满足以下最低要求组件要求说明操作系统Linux, macOS (或 Windows WSL2)需要稳定的Shell环境以支持Terminal工具。Python3.9 或更高版本这是大多数AI框架的基线要求。包管理器pip (21.0)用于安装Python依赖。版本控制Git用于克隆项目代码。内存建议 8GB运行向量数据库和LLM需要一定内存。网络可访问互联网需要下载模型或连接远程API。首先检查你的Python版本python3 --version如果版本低于3.9请先升级Python。2.2 创建虚拟环境与安装依赖为项目创建一个独立的目录并进入mkdir hermes-quickstart cd hermes-quickstart创建Python虚拟环境这里使用venvpython3 -m venv venv激活虚拟环境Linux/macOS:source venv/bin/activateWindows (CMD):venv\Scripts\activate.batWindows (PowerShell):venv\Scripts\Activate.ps1激活后命令行提示符前应显示(venv)。接下来安装Hermes框架。由于Hermes是一个较新的项目我们假设通过Git仓库安装其最新版本。同时安装一些必要的配套库。# 升级pip pip install --upgrade pip # 克隆 Hermes 仓库 (这里假设仓库地址实际请替换为官方地址) # git clone https://github.com/some-org/hermes.git # cd hermes # pip install -e . # 由于具体仓库地址未知我们以安装常见智能体框架如LangChain和组件为例进行演示。 # 这能帮助你理解Harness Engineering的组件如何拼装。 # 安装核心框架、OpenAI接口、向量数据库客户端和终端工具模拟器 pip install langchain langchain-openai chromadb langchain-experimental # 安装用于解析终端输出的库 pip install pexpect注意以上安装的是演示所需的核心组件。一个完整的Hermes实现可能包含其特定的包名。在实际操作中请根据Hermes项目的官方README.md或requirements.txt文件进行安装。2.3 配置 LLM 访问密钥智能体需要一个“大脑”。我们将使用OpenAI的GPT模型作为示例。你需要一个OpenAI API密钥。访问 OpenAI平台 创建API Key。在项目根目录创建一个名为.env的文件用于安全地存储密钥# .env 文件内容 OPENAI_API_KEYsk-your-actual-api-key-here重要确保.env文件已被添加到.gitignore中切勿提交到版本控制系统。安装python-dotenv来读取环境变量pip install python-dotenv3. 构建最小可运行智能体记忆、终端与技能现在我们将用代码组装一个具备持久记忆和终端调用能力的智能体。虽然这不是完整的Hermes但完全遵循其设计哲学。3.1 项目结构设计创建一个清晰的项目结构有助于管理代码hermes-quickstart/ ├── .env # 环境变量密钥 ├── .gitignore # Git忽略文件 ├── requirements.txt # 依赖列表可由 pip freeze requirements.txt 生成 ├── agents/ # 智能体核心模块 │ ├── __init__.py │ └── basic_agent.py # 基础智能体定义 ├── memory/ # 记忆相关模块 │ ├── __init__.py │ └── vector_store.py # 向量记忆存储 ├── tools/ # 工具定义 │ ├── __init__.py │ └── terminal_tool.py # 终端工具 ├── skills/ # 技能定义 │ ├── __init__.py │ └── file_skill.py # 文件操作技能示例 └── main.py # 主程序入口3.2 实现持久化向量记忆记忆是智能体连续性的基础。我们使用ChromaDB作为向量存储将对话内容保存下来。创建memory/vector_store.pyimport os from langchain_chroma import Chroma from langchain_openai import OpenAIEmbeddings from langchain.schema import Document from dotenv import load_dotenv # 加载环境变量 load_dotenv() class VectorMemory: def __init__(self, persist_directory./chroma_db): 初始化向量记忆存储。 :param persist_directory: 向量数据库持久化目录 self.embeddings OpenAIEmbeddings(openai_api_keyos.getenv(OPENAI_API_KEY)) self.persist_directory persist_directory # 加载或创建向量数据库 self.vectorstore Chroma( embedding_functionself.embeddings, persist_directorypersist_directory ) self.retriever self.vectorstore.as_retriever(search_kwargs{k: 3}) # 检索最相关的3条记忆 def add_memory(self, text: str, metadata: dict None): 添加一段文本记忆到向量库 if metadata is None: metadata {} doc Document(page_contenttext, metadatametadata) self.vectorstore.add_documents([doc]) # Chroma 默认会自动持久化但也可以手动调用 # self.vectorstore.persist() def search_memory(self, query: str) - list: 根据查询检索相关记忆 docs self.retriever.get_relevant_documents(query) return [doc.page_content for doc in docs] def clear_memory(self): 清空所有记忆谨慎使用 # 注意这里只是简单示例。生产环境需要更安全的清理方式。 import shutil if os.path.exists(self.persist_directory): shutil.rmtree(self.persist_directory) self.vectorstore Chroma( embedding_functionself.embeddings, persist_directoryself.persist_directory ) self.retriever self.vectorstore.as_retriever() # 全局记忆实例 memory VectorMemory()这段代码创建了一个VectorMemory类它使用OpenAI的嵌入模型将文本转换为向量并存储到本地的ChromaDB中。add_memory用于保存信息search_memory用于根据当前问题查找相关的历史信息。3.3 实现安全的终端工具赋予智能体操作系统的能力是强大的但也极其危险。我们必须创建一个受严格控制的终端工具。创建tools/terminal_tool.pyimport subprocess import os import platform from typing import Optional from langchain.tools import BaseTool from pydantic import Field class TerminalTool(BaseTool): name: str terminal description: str ( 在安全的子进程中执行一个Shell命令并返回其输出。 仅用于非破坏性的信息查询、文件浏览和简单操作。 禁止执行rm -rf /, dd, mkfs, /dev/sda, 等危险命令。 ) working_dir: str Field(default./workspace, description命令执行的工作目录) def _run(self, command: str) - str: 执行命令的核心方法 # 基础安全过滤非常基础生产环境需要更复杂的策略 dangerous_patterns [rm -rf, mkfs, dd if, /dev/sd, chmod 777, :(){:|:};:] for pattern in dangerous_patterns: if pattern in command: return f安全警告命令被阻止因为检测到危险模式 {pattern}。 # 确保工作目录存在 os.makedirs(self.working_dir, exist_okTrue) try: # 根据平台选择shell shell platform.system() Windows result subprocess.run( command, shellTrue, cwdself.working_dir, capture_outputTrue, textTrue, timeout30, # 设置超时防止长时间运行 # 强烈建议指定可执行路径如 /bin/bash # executable/bin/bash if not shell else None ) if result.returncode 0: output result.stdout if not output: output (命令执行成功无标准输出) else: output f命令执行失败 (返回码: {result.returncode}):\nSTDERR: {result.stderr} return output except subprocess.TimeoutExpired: return 错误命令执行超时超过30秒。 except Exception as e: return f执行命令时发生未知错误: {str(e)} async def _arun(self, command: str) - str: 异步版本暂不实现 raise NotImplementedError(终端工具暂不支持异步执行)这个工具继承了LangChain的BaseTool。_run方法包含了关键的安全检查尽管很简单和执行逻辑。我们限定了工作目录、设置了超时并过滤了明显危险的命令模式。在生产环境中你需要实现更严格的沙箱机制例如使用容器或高度受限的系统用户。3.4 定义一个简单的文件操作技能技能是比工具更高级的抽象。我们定义一个“创建并写入文件”的技能。创建skills/file_skill.pyimport os from typing import Dict, Any from langchain.tools import BaseTool class FileWriteSkill(BaseTool): name: str file_write description: str ( 在指定路径创建文件并写入内容。如果文件已存在可以选择覆盖或追加。 输入应为JSON字符串包含 path, content, mode (w 覆盖 或 a 追加) 字段。 ) def _run(self, tool_input: str) - str: try: # 解析输入这里简化处理实际应由LLM生成结构化输入 import json params: Dict[str, Any] json.loads(tool_input) path params.get(path, ).strip() content params.get(content, ) mode params.get(mode, w) if not path: return 错误未提供文件路径。 # 确保目录存在 os.makedirs(os.path.dirname(os.path.abspath(path)), exist_okTrue) with open(path, mode, encodingutf-8) as f: f.write(content) return f成功文件 {path} 已写入。模式{mode}。 except json.JSONDecodeError: return 错误输入不是有效的JSON格式。 except Exception as e: return f写入文件时发生错误: {str(e)} async def _arun(self, tool_input: str) - str: raise NotImplementedError(此技能暂不支持异步执行)3.5 组装智能体并创建控制循环现在我们将记忆、工具和技能组装起来并创建一个简单的控制循环。创建agents/basic_agent.pyimport os from typing import List from langchain_openai import ChatOpenAI from langchain.agents import AgentExecutor, create_react_agent from langchain.prompts import PromptTemplate from langchain.memory import ConversationBufferMemory from dotenv import load_dotenv # 导入我们自定义的模块 from memory.vector_store import memory as vector_memory from tools.terminal_tool import TerminalTool from skills.file_skill import FileWriteSkill load_dotenv() class BasicHermesAgent: def __init__(self): # 1. 初始化LLM self.llm ChatOpenAI( modelgpt-3.5-turbo, temperature0.2, # 较低的温度使输出更确定 openai_api_keyos.getenv(OPENAI_API_KEY) ) # 2. 准备工具和技能列表 self.tools [TerminalTool(), FileWriteSkill()] # 3. 创建对话记忆短期记忆 self.conversation_memory ConversationBufferMemory( memory_keychat_history, return_messagesTrue ) # 4. 设计提示模板引导智能体使用工具和记忆 prompt_template 你是一个名为Hermes的智能助手可以调用工具和利用记忆来帮助用户。 你拥有以下能力 1. 持久记忆你可以记住和回忆之前对话中的重要信息。 2. 终端操作你可以执行安全的Shell命令来查看文件、目录或系统信息。 3. 文件技能你可以创建或修改文件。 当前对话历史 {chat_history} 用户问题{input} 在回答之前请先思考是否需要从长期记忆中检索相关信息。 检索查询根据用户问题生成一个简短的搜索词{agent_scratchpad} 如果检索到相关记忆它们会出现在下方 [相关记忆开始] {retrieved_memory} [相关记忆结束] 现在请决定下一步行动。你可以 - 直接回答用户问题如果信息充足。 - 使用工具{tools} - 如果问题涉及复杂操作可以分解并使用多个工具。 请严格按照以下格式回应 思考[你的推理过程] 行动[要使用的工具名称必须是 {tool_names} 中的一个] 行动输入[工具的输入必须是一个字符串] 观察[工具返回的结果] ... (这个思考/行动/观察循环可以重复多次) 最终答案[对用户的最终回答] 开始 self.prompt PromptTemplate.from_template(prompt_template) # 5. 创建智能体 self.agent create_react_agent( llmself.llm, toolsself.tools, promptself.prompt ) # 6. 创建执行器 self.agent_executor AgentExecutor( agentself.agent, toolsself.tools, memoryself.conversation_memory, verboseTrue, # 设置为True可以看到详细的思考过程 handle_parsing_errorsTrue, max_iterations5 # 防止无限循环 ) def _retrieve_memory(self, query: str) - str: 从向量记忆中检索相关信息 memories vector_memory.search_memory(query) if memories: return \n.join([f- {m} for m in memories]) return (未找到相关长期记忆) def run(self, user_input: str) - str: 运行智能体的主方法 # 在调用智能体前先检索长期记忆 retrieved self._retrieve_memory(user_input) # 准备输入将检索到的记忆插入到prompt中 # 注意这里简化了流程实际React Agent的输入格式需要调整。 # 更复杂的实现需要自定义Agent或修改Prompt。 # 以下是一个简化版的直接调用示例 try: # 将检索到的记忆和用户输入一起传给智能体 enriched_input f相关背景记忆{retrieved}\n\n用户问题{user_input} response self.agent_executor.invoke({input: enriched_input}) output response.get(output, 智能体未返回输出。) # 将本次有意义的交互存入长期记忆简单策略存入用户问题和最终答案 if error not in output.lower() and len(user_input) 5: memory_text f用户问{user_input}。回答概要{output[:100]}... # 截断存储 vector_memory.add_memory(memory_text, metadata{type: qa}) return output except Exception as e: return f智能体执行过程中出现错误: {str(e)}3.6 创建主程序入口最后创建main.py来启动一个简单的交互循环#!/usr/bin/env python3 from agents.basic_agent import BasicHermesAgent def main(): print(初始化 Hermes 智能体...) agent BasicHermesAgent() print(智能体就绪。输入 quit 或 exit 退出。) print(- * 40) while True: try: user_input input(\n你: ).strip() if user_input.lower() in [quit, exit, q]: print(再见) break if not user_input: continue print(\nHermes 正在思考...) response agent.run(user_input) print(f\nHermes: {response}) except KeyboardInterrupt: print(\n\n程序被中断。) break except Exception as e: print(f\n发生未预期错误: {e}) if __name__ __main__: main()4. 运行验证与结果分析现在让我们启动智能体并进行测试验证记忆、终端和技能功能。4.1 启动智能体在项目根目录下确保虚拟环境已激活然后运行python main.py你应该看到“初始化 Hermes 智能体...”和“智能体就绪...”的提示。由于设置了verboseTrue你会看到类似以下的详细思考过程ReAct模式 进入新的 AgentExecutor 链... 思考用户想列出当前目录的文件。我可以使用终端工具。 行动terminal 行动输入ls -la 观察总用量 12 drwxr-xr-x 4 user group 4096 Apr 10 10:00 . drwxr-xr-x 5 user group 4096 Apr 10 09:55 .. drwxr-xr-x 2 user group 4096 Apr 10 10:00 agents ... 思考我已经获取了目录列表可以回答用户了。 最终答案当前目录下有以下文件和文件夹agents, memory, tools, skills, main.py, .env, requirements.txt。4.2 功能测试案例我们通过一系列对话来测试核心功能。测试 1终端工具基础操作你: 查看当前目录下有什么文件 Hermes: (调用terminal工具执行ls) 当前目录包含 agents, memory, tools 等文件夹和 main.py 等文件。测试 2持久记忆的写入与检索你: 记住我的名字叫张三我喜欢编程。 Hermes: 好的我已经记下了。 你: 我之前告诉你我喜欢什么 Hermes: (从向量记忆中检索“喜欢”相关的信息) 你之前提到你喜欢编程。注意向量记忆的检索基于语义相似度可能不会100%精确召回但通常能关联到相关内容。测试 3技能调用你: 在 workspace 文件夹里创建一个叫 hello.txt 的文件内容写“Hello from Hermes!”。 Hermes: (调用file_write技能传入JSON参数) 成功文件 workspace/hello.txt 已写入。 你: 用终端看看 workspace 里有没有这个文件。 Hermes: (调用terminal工具执行ls workspace) hello.txt测试 4结合记忆与工具的复杂任务你: 我之前创建了一个文件它的内容是什么 Hermes: (首先从记忆检索“创建文件”相关记录找到文件名可能是hello.txt) (然后调用terminal工具执行cat workspace/hello.txt) Hello from Hermes!4.3 验证结果分析通过以上测试我们可以确认终端工具工作正常智能体能够安全地执行ls、cat等命令并返回结果。持久记忆生效智能体能够存储关于“姓名”和“喜好”的信息并在后续对话中成功检索。技能被正确调用智能体能够解析用户意图调用file_write技能并传入正确的参数。控制循环有效智能体能够根据上下文决定是直接回答、检索记忆还是调用工具形成了完整的“感知-思考-行动”循环。5. 常见问题排查与调试在实际运行中你可能会遇到以下问题。这里提供排查路径。5.1 智能体启动失败或报错问题现象可能原因检查方式处理建议ModuleNotFoundError依赖未安装或虚拟环境未激活。运行pip list | grep langchain检查。确认虚拟环境已激活并重新运行pip install -r requirements.txt。AuthenticationError(OpenAI)API密钥错误或未设置。检查.env文件是否存在密钥格式是否正确。确保.env文件在项目根目录且内容为OPENAI_API_KEYsk-...。重启终端或IDE使环境变量生效。ConnectionError网络问题或API服务不可用。尝试curl https://api.openai.com/v1/models(需在Header加Authorization)。检查网络连接和代理设置。确认OpenAI账户有额度。智能体不调用工具总是直接回答。提示词Prompt设计不佳或LLM温度temperature过高。查看verboseTrue输出的“思考”部分。调整Prompt更明确地指示使用工具。将LLM的temperature参数调低如0.1。5.2 终端工具执行异常问题现象可能原因检查方式处理建议命令执行无输出或报Permission denied。工作目录不存在或进程权限不足。检查working_dir路径是否存在。检查命令本身是否需要sudo。确保working_dir目录已被创建。绝对避免在工具中处理需要特权的命令。执行长时间命令导致超时。命令运行时间超过timeout设置默认30秒。观察是否返回“命令执行超时”错误。对于已知耗时命令可在工具调用时提示用户或实现异步执行和进度反馈。安全过滤误拦截正常命令。dangerous_patterns列表过于严格。检查被拦截的命令是否包含无害但被匹配的子串。优化安全过滤逻辑例如使用更精确的正则表达式匹配或结合命令白名单。5.3 记忆系统不工作问题现象可能原因检查方式处理建议智能体“忘记”之前记住的内容。记忆未成功存储或检索查询不匹配。检查chroma_db目录是否生成文件。在代码中打印search_memory的返回结果。确认向量数据库持久化路径可写。尝试用更具体的关键词进行检索。调整检索器参数search_kwargs如增加k值。检索结果不相关。嵌入模型不适合或文本分块策略有问题。检查存储和检索的文本是否过短或过长。对于短文本记忆可以尝试不进行分块直接存储整句。确保存储的文本是有信息量的完整句子。程序报Illegal instruction(CPU不支持AVX)。ChromaDB 使用的向量计算库与CPU不兼容。常见于老款CPU或虚拟环境。尝试安装pip install chromadb --no-binary chromadb从源码编译或使用其他向量库如FAISS。5.4 技能调用失败问题现象可能原因检查方式处理建议智能体无法理解何时使用技能。技能描述description不够清晰。对比工具和技能的描述看LLM能否区分。重写技能描述明确其适用场景、输入格式和预期输出。在Prompt中举例说明。技能执行出错如文件未创建。技能代码逻辑错误或输入参数解析失败。在技能类的_run方法中添加详细日志。确保输入是技能期望的格式如JSON。检查文件路径的权限和目录是否存在。6. 生产环境最佳实践与扩展方向将这样一个演示智能体用于生产环境还需要大量的加固和优化。6.1 安全加固清单终端沙箱化绝对不要在生产环境直接使用subprocess。应使用Docker容器、nsjail、gVisor等沙箱技术隔离执行环境并严格限制资源CPU、内存、网络、文件系统。命令白名单建立安全的命令白名单机制只允许执行预审核过的命令和参数组合。权限最小化使用非root用户运行智能体进程并限制其文件系统访问范围。输入验证与过滤对所有来自LLM决定的和用户输入的、将要传递给工具的参数进行严格的验证、转义和过滤防止注入攻击。审计日志记录每一次工具调用、技能执行和记忆访问的详细信息包括用户、时间、输入、输出便于事后审计和问题追踪。6.2 性能与稳定性优化记忆检索优化对于大规模记忆引入分层记忆系统。高频、重要的记忆放内存历史记忆放向量库。对检索结果进行相关性重排序和去重。工具调用超时与熔断为每一个工具设置独立的超时并实现熔断器模式防止某个故障工具拖垮整个智能体。异步处理将耗时的工具调用如网络请求改为异步避免阻塞主循环。缓存对LLM的响应、工具的结果特别是静态信息查询进行适当缓存减少开销和延迟。6.3 实现技能自进化这是Harness Engineering和Hermes的进阶目标。一个简单的自进化思路可以是技能效果评估在技能执行后由用户或自动规则如任务是否完成给出“成功”或“失败”的反馈。失败分析当技能失败时记录当时的输入、上下文和错误信息。技能优化定期将失败的案例和上下文提交给LLM让其分析原因并提出对技能步骤、参数或描述的修改建议。技能生成对于全新的任务类型可以让LLM根据描述自动生成一段新的技能代码需在安全沙箱中审核和测试后上线。6.4 扩展方向集成更多工具接入数据库客户端、内部API、绘图库、代码解释器等扩展智能体的能力边界。多模态能力结合视觉、语音模型让智能体能处理图片、音频信息。多智能体协作构建多个 specialized 的智能体让它们通过通信协作解决复杂问题。前端交互界面开发Web或聊天软件界面提供更友好的交互体验。通过本文的实践你已经搭建了一个具备Harness Engineering核心思想的智能体原型。真正的Hermes项目可能会提供更完善的基础设施、更优雅的API和更强大的默认技能。但理解了这个原型的设计和实现你就能更好地理解和使用任何类似的智能体框架并能够根据实际需求进行定制和扩展。接下来的关键是将安全、稳定和可观测性作为首要考虑逐步将其应用到合适的场景中。 30款热门AI模型一站整合DeepSeek/GLM/Qwen 随心用限时 5 折。 点击领海量免费额度