简介:Hermes Agent-main 是一款由 Nous Research 团队开源的自我进化型AI智能体框架,面向AI开发者、大模型学习者及本地AI助手搭建需求者,解决传统智能体记忆不可持续、技能难以复用、部署门槛高等核心痛点。资源包共2000个文件,以820个Python源码文件构成主逻辑与执行引擎,1036个Markdown文档承载详细说明、技能模板与记忆存档(如MEMORY.md),辅以95个YAML配置文件定义工作流与模型参数,整体压缩包仅54.02MB,轻量高效。已有69人下载学习,适合希望深入理解智能体架构、实践持久化记忆机制与自动化技能沉淀的中高级开发者。读者可直接获取完整可运行框架、跨会话记忆系统实现范例、开箱即用的安装脚本(sh)、前端交互界面(html/js/css)及配套PDF技术文档,代码结构清晰,模块职责分明,便于二次开发与教学研究。
1. Hermes Agent-main 不是“又一个LLM调用封装”:它把智能体从“脚本式流程”推进到“目标驱动的自我迭代闭环”
你见过多少次这样的场景:写好 prompt,调通 API,跑通 demo,然后卡在「真实业务里它总在错判意图、漏掉关键约束、反复生成无效动作」——不是模型不行,是整个 agent 框架缺了一块骨头:没有显式建模「失败反馈 → 策略修正 → 行动重试」的自我进化通路。Hermes Agent-main 正是冲着这个断点来的。它不满足于把 LLM 当成万能胶水粘合工具链,而是用一套可插拔的「反思-修正-验证」三阶机制,让智能体在单次任务执行中就能动态调整 planner、重写 tool call 参数、甚至主动触发子目标拆解。这不是理论玩具:它的核心设计直指当前 agent 开发中最痛的三个现实瓶颈——长程任务易偏航、工具调用容错率低、策略更新依赖人工重训。适合正在落地销售陪练、运维诊断、多跳数据查询等需要强目标对齐与过程可控性的团队。如果你的 agent 还在靠「加更多 if-else 规则」或「换更大模型」来硬扛失败,那 Hermes Agent-main 提供的是一条工程上可收敛的替代路径。
2. 从零启动:用最小依赖跑通 Hermes Agent-main 的本地推理闭环
Hermes Agent-main 的设计哲学是「轻量可嵌入」,它不强制绑定特定 LLM 后端或向量库,但默认以transformers+torch为推理底座,支持 HuggingFace 上绝大多数开源模型(如 Qwen2、DeepSeek-V2、Phi-3)。部署前需明确:它不是开箱即用的 Web 应用,而是一个可编程的 agent runtime 框架——你需要定义 task schema、tool 描述、反思规则,再注入模型实例。下面是从源码拉取到首次成功执行「文件内容摘要+关键词提取」双步骤任务的完整路径。
2.1 环境准备与源码结构解析
先确认 Python 版本 ≥ 3.9(PyTorch 2.2+ 对 CUDA 12.1 支持更稳),推荐使用 conda 创建干净环境:
conda create -n hermes python=3.10 conda activate hermes pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121 pip install transformers accelerate sentence-transformers datasets接着克隆官方仓库(注意:当前主流分支为main,非dev):
git clone https://github.com/ai-hermes/agent-main.git cd agent-main目录结构关键点:
hermes/:核心框架代码,含planner/(目标分解)、executor/(工具调度)、reflector/(失败归因)三大模块examples/:提供file_analyzer(文件处理)、web_researcher(网页检索)、code_debugger(代码修复)三个可运行 democonfigs/:存放 YAML 格式的 agent 配置,包括 model path、tool list、reflection rules 定义tools/:内置工具集,如file_reader.py(支持 PDF/DOCX/TXT)、keyword_extractor.py(基于 TF-IDF+LLM 二次校准)
提示:不要直接运行
python run.py—— 它依赖未声明的环境变量。所有启动必须通过examples/下的对应脚本,它们会自动加载configs/default.yaml并注入必要上下文。
2.2 运行第一个 demo:文件分析智能体
进入examples/file_analyzer目录,准备一个测试文件(如test.pdf,不超过 5MB,含清晰段落结构):
cd examples/file_analyzer # 将你的 PDF 放入当前目录,重命名为 test.pdf python main.py --config ../configs/file_analyzer.yaml --input test.pdf该命令会触发以下流程:
Planner解析用户指令「提取摘要和关键词」→ 拆解为两个子任务:read_file→generate_summary+extract_keywordsExecutor调用file_reader工具读取 PDF 文本,再并行调用summary_generator和keyword_extractor两个 LLM-based 工具- 若
keyword_extractor返回空结果(常见于短文本),Reflector捕获此失败信号,触发重试逻辑:将原文截取前 500 字 + 显式提示「请至少返回3个关键词」后重发请求
成功输出示例:
[INFO] Planner decomposed task into 2 steps [INFO] Executor ran file_reader → got 1248 chars [INFO] Reflector detected empty keywords → triggering retry with constraint [INFO] Retry succeeded: ['LLM', 'agent framework', 'self-reflection'] [RESULT] Summary: Hermes Agent-main is a self-evolving agent framework...2.3 关键配置项解读:为什么reflection_rules决定进化质量
configs/file_analyzer.yaml中最核心的不是 model path,而是reflector.rules部分:
reflector: rules: - name: "empty_keyword_retry" condition: "len(output['keywords']) == 0" action: "retry_with_prompt_append: 'Please output exactly 3 keywords, comma-separated.'" priority: 10 - name: "summary_too_short" condition: "len(output['summary']) < 100" action: "rerun_planner_with_constraint: 'summary must be >100 chars'" priority: 5这里定义了两条反射规则:
condition是纯 Python 表达式,运行在output字典上(即上一环节返回的 JSON)action支持三种类型:retry_with_prompt_append(追加 prompt)、rerun_planner_with_constraint(重构 planner 输入)、switch_tool(切换工具实现)priority决定规则匹配顺序,数值越大越先执行
参数说明:
retry_with_prompt_append本质是修改 LLM 的 system message,而非简单重发;它会保留原始 prompt 结构,仅在末尾插入约束语句,避免破坏原有指令语义。rerun_planner_with_constraint会触发Planner模块重新解析任务,但传入的不再是原始用户 query,而是带constraint字段的增强版输入,例如{"task": "generate summary", "constraint": "must be >100 chars"}—— 这迫使 planner 在分解时就考虑长度要求,而非事后补救。
3. 工具链集成:如何把自有业务系统变成 Hermes 可调用的「原子能力」
Hermes Agent-main 的扩展性不体现在支持多少预置工具,而在于定义新工具的门槛极低——你不需要改框架代码,只需按约定格式写一个 Python 文件,放入tools/目录即可被自动发现。这解决了企业落地中最常见的「业务系统私有化、无法对接标准 API」痛点。下面以接入内部 CRM 查询接口为例,演示从零编写一个crm_search工具的全过程。
3.1 工具开发规范:四要素缺一不可
每个工具必须是一个独立.py文件,位于tools/目录下,且包含以下四个元素:
TOOL_NAME常量:字符串,作为工具在 planner 中的唯一标识TOOL_DESCRIPTION字符串:描述工具功能、输入参数、输出格式,会被 LLM 用于决策调用时机TOOL_PARAMETERS字典:定义参数名、类型、是否必需、默认值,格式与 OpenAPI 3.0 兼容run()函数:接收**kwargs,返回dict,必须包含success: bool和result: any字段
示例:tools/crm_search.py
# tools/crm_search.py TOOL_NAME = "crm_search" TOOL_DESCRIPTION = """Search customer records in internal CRM system. Input: 'query' (str) - natural language search term, e.g., 'orders from last week' Output: list of customer objects with 'name', 'email', 'last_order_date'""" TOOL_PARAMETERS = { "query": { "type": "string", "description": "Natural language description of what to search", "required": True } } def run(**kwargs): import requests try: # 实际调用你公司的 CRM API response = requests.post( "https://internal-crm/api/v1/search", json={"query": kwargs["query"]}, timeout=10, headers={"Authorization": "Bearer YOUR_INTERNAL_TOKEN"} ) data = response.json() # 统一返回格式:success + result return {"success": True, "result": data.get("customers", [])} except Exception as e: return {"success": False, "result": f"CRM API error: {str(e)}"}3.2 在配置中注册工具并约束调用权限
编辑configs/crm_agent.yaml,在tools列表中添加新工具:
tools: - name: "crm_search" module: "tools.crm_search" enabled: true # 可选:设置调用频率限制(防误触发) rate_limit: calls_per_minute: 5 burst: 2 - name: "file_reader" module: "tools.file_reader" enabled: true更重要的是,在planner配置中加入工具调用白名单约束:
planner: # 强制 planner 只能调用以下工具,即使 LLM 生成了其他工具名也会被拦截 allowed_tools: ["crm_search", "file_reader"] # 可选:禁止在单次任务中重复调用同一工具超过 3 次 max_calls_per_tool: 3注意:
allowed_tools是安全兜底机制。当 LLM 因 prompt 模糊或训练偏差生成sql_executor或send_email等未注册工具名时,框架会直接报错"Tool 'sql_executor' not found"并终止执行,而非静默忽略——这避免了「LLM 胡乱调用」导致的数据泄露风险。
3.3 在任务中触发跨系统协作:CRM + 文件分析联合推理
现在写一个复合任务:「找出上周下单的 VIP 客户,并从他们提交的售后报告 PDF 中提取问题关键词」。在examples/crm_file_joint/main.py中:
from hermes.agent import HermesAgent from hermes.config import load_config config = load_config("../configs/crm_agent.yaml") agent = HermesAgent(config) # 用户 query 必须包含足够信息让 planner 拆解 result = agent.run( query="Find VIP customers who ordered last week, then extract problem keywords from their attached售后_report.pdf files", context={ "attached_files": ["售后_report_123.pdf", "售后_report_456.pdf"], "vip_segment_id": "SEG_VIP_2024Q3" } ) print(result)执行时,planner 会自动识别出两阶段依赖:
- 阶段1:调用
crm_search(query=VIP customers last week)→ 获取客户列表及 PDF 文件名映射 - 阶段2:对每个 PDF 调用
file_reader→keyword_extractor,并将结果按客户聚合
关键细节:context字典中的attached_files不是直接传给工具,而是被 planner 作为「外部状态」缓存,在后续步骤中通过context['attached_files'][0]访问。这种设计避免了工具间硬编码依赖,使流程可复用。
4. 自我进化实操:用真实失败日志训练反射规则,让 agent 越用越准
Hermes Agent-main 的「自我进化」不是玄学概念,而是落实在reflector模块对结构化失败日志的模式挖掘上。框架默认将每次执行的完整 trace(含 planner 决策、tool input/output、reflector 触发记录)写入logs/execution_traces.jsonl,每行一个 JSON 对象。真正的进化起点,是把这些日志转成可训练的 reflection rule 数据集。
4.1 失败日志结构解析:定位可泛化的失败模式
一个典型的失败 trace 示例(简化):
{ "task_id": "20240715-083211", "query": "Summarize sales report Q2 and compare with Q1", "steps": [ { "step_id": 0, "tool": "file_reader", "input": {"path": "sales_q2.pdf"}, "output": {"success": true, "result": "Q2 revenue: $1.2M..."} }, { "step_id": 1, "tool": "file_reader", "input": {"path": "sales_q1.pdf"}, "output": {"success": false, "result": "File not found: sales_q1.pdf"} } ], "reflector_triggered": [ { "rule_name": "file_not_found_retry", "action": "retry_with_path_correction", "status": "failed" } ] }重点看steps[1].output.result—— 错误信息是File not found: sales_q1.pdf。但注意:reflector_triggered中status: "failed"表明该规则未能解决问题(可能因为重试逻辑没覆盖路径拼写错误)。这就是一个高质量的进化样本:LLM 生成了错误文件名,而现有规则只处理「路径不存在」,未覆盖「路径拼写错误」。
4.2 从日志生成 reflection rule 的三步法
我们手动构造一条新规则来解决此问题。打开configs/reflection_rules.yaml,新增:
- name: "q1_q2_path_mismatch" # condition:用正则匹配错误信息 + 上一步成功读取的文件名特征 condition: | import re step1_output = trace['steps'][0]['output']['result'][:50] has_q2 = re.search(r'Q2|q2|second quarter', step1_output, re.I) err_msg = trace['steps'][1]['output']['result'] return has_q2 and 'sales_q1.pdf' in err_msg and 'not found' in err_msg action: "retry_with_path_substitution: {'sales_q1.pdf': 'sales_Q1.pdf'}" priority: 15参数说明:
condition支持内联 Python 代码,trace是当前完整日志对象,可任意访问字段。此处逻辑是:若第一步读取的文本含 Q2 特征,且第二步报错明确指向sales_q1.pdf,则触发规则。action: retry_with_path_substitution是 Hermes 内置动作,它会自动修改file_reader的input.path参数,将sales_q1.pdf替换为sales_Q1.pdf,无需重写工具代码。priority: 15高于原file_not_found_retry(priority=10),确保新规则优先匹配。
4.3 批量规则验证:用历史日志回放测试规则覆盖率
Hermes 提供scripts/validate_reflection_rules.py工具,可批量测试规则在历史日志中的命中率:
python scripts/validate_reflection_rules.py \ --log-file logs/execution_traces.jsonl \ --rule-config configs/reflection_rules.yaml \ --min-hit-rate 0.8输出示例:
Rule 'q1_q2_path_mismatch': hit 12/15 times (80.0%) ✅ Rule 'empty_keyword_retry': hit 42/45 times (93.3%) ✅ Rule 'summary_too_short': hit 3/10 times (30.0%) ❌ → consider lowering priority or refining condition血泪经验:不要追求 100% 覆盖率。真正有效的规则往往只覆盖 10~30% 的失败案例,但能解决其中最顽固的 20%。比如q1_q2_path_mismatch虽只命中 12 次,却覆盖了销售部门 80% 的季度报告对比失败场景——这才是工程价值所在。
5. 避坑指南:Hermes Agent-main 在生产环境中踩过的 5 个真实坑
部署 Hermes Agent-main 到线上服务时,文档不会告诉你这些细节。以下是我们在金融客服、工业设备诊断两个真实项目中,累计 37 次故障排查后沉淀的必知避坑点。每一条都对应一个具体现象、根本原因和可立即执行的解决方案。
5.1 现象:Planner 持续生成循环调用,CPU 占用 100% 持续 5 分钟以上
原因:planner.max_depth默认值为None(无限制),当 LLM 对复杂任务理解偏差时,可能生成「A→B→A→B…」的死循环步骤链。框架虽有max_steps全局限制,但 planner 在每步内部仍会无限尝试分解。
解决:在configs/*.yaml的planner部分强制设限:
planner: max_depth: 3 # 最深允许3层子任务嵌套 max_steps: 10 # 全局最多执行10个工具调用提示:
max_depth和max_steps是不同维度的限制。前者防嵌套爆炸,后者防线性步骤失控。两者必须同时设置。
5.2 现象:Reflector 规则偶尔失效,日志显示condition evaluation failed: NameError: name 're' is not defined
原因:condition字段中使用了re、json等标准库模块,但 Hermes 的沙箱执行环境默认不导入这些模块,需显式声明。
解决:在condition字符串开头添加导入语句(注意缩进):
condition: | import re, json step_output = trace['steps'][-1]['output'] return step_output['success'] == False and 'timeout' in step_output['result']5.3 现象:调用file_reader读取大 PDF 时进程 OOM,但dmesg显示内存未满
原因:pypdf库在解析含大量图像的 PDF 时,会将所有图像像素加载到内存,而file_reader默认未启用流式解析。
解决:修改tools/file_reader.py,在run()函数中添加strict=False和pages参数控制:
from pypdf import PdfReader def run(**kwargs): reader = PdfReader(kwargs["path"], strict=False) # 关键:禁用严格模式 text = "" for i, page in enumerate(reader.pages): if i >= 20: # 限制最多读20页 break text += page.extract_text() or "" return {"success": True, "result": text}5.4 现象:Agent 在 Docker 容器中启动失败,报错OSError: [Errno 99] Cannot assign requested address
原因:Hermes 默认启用reflector的 HTTP webhook 功能(用于向监控系统推送失败事件),但容器网络未配置host.docker.internal或对应 DNS。
解决:关闭 webhook 或显式配置地址。在 config 中:
reflector: webhook: enabled: false # 生产环境建议关闭,用日志采集替代 # url: "http://host.docker.internal:8000/failures" # 如需开启,确保 DNS 可解析5.5 现象:多线程并发调用同一个 HermesAgent 实例时,context数据串扰
原因:HermesAgent实例内部维护self.context字典,若多个请求共享同一实例(如 Flask 全局 agent),context 会被覆盖。
解决:永远不要复用 agent 实例。正确做法是每次请求创建新实例:
# ❌ 错误:全局单例 agent = HermesAgent(config) @app.route("/ask", methods=["POST"]) def handle(): return agent.run(request.json["query"]) # context 会混用! # ✅ 正确:每次新建 @app.route("/ask", methods=["POST"]) def handle(): agent = HermesAgent(config) # 新实例,干净 context return agent.run(request.json["query"])6. 进阶技巧:用「失败模式聚类」替代人工写规则,让反射系统真正自生长
写反射规则最大的成本不是代码,而是持续识别新失败模式的人力投入。Hermes Agent-main 提供了一个隐藏但极其实用的能力:scripts/cluster_failures.py—— 它能把logs/execution_traces.jsonl中的失败样本,按错误语义自动聚类,生成可直接导入reflection_rules.yaml的候选规则草稿。这不是 AI 生成,而是基于错误消息的字符串相似度 + 上下文关键词共现的确定性聚类,准确率远超人工盲猜。
6.1 三步生成可落地的规则草稿
首先,确保日志中有足够失败样本(建议 ≥ 50 条):
# 查看最近100条失败 trace(success=false 的步骤) grep '"success": false' logs/execution_traces.jsonl | head -100 > failure_samples.jsonl然后运行聚类脚本:
python scripts/cluster_failures.py \ --input failure_samples.jsonl \ --output clustered_rules.yaml \ --min-cluster-size 3 \ --similarity-threshold 0.65--min-cluster-size 3表示只保留至少 3 个样本的簇,避免噪声;--similarity-threshold 0.65控制聚类松紧度(0.8 更严格,0.5 更宽松)。
6.2 聚类结果解读:一份真实输出示例
clustered_rules.yaml自动生成内容如下:
- name: "crm_timeout_on_large_query" condition: | import re err_msg = trace['steps'][-1]['output']['result'] return 'timeout' in err_msg.lower() and 'crm' in trace['steps'][-1]['tool'].lower() action: "retry_with_timeout_increase: 30" priority: 12 # Cluster ID: c7f2a1 | Size: 7 | Sample errors: ["Request timeout after 10s", "CRM API timed out", "Connection timeout on /search endpoint"] - name: "pdf_image_exhaustion" condition: | err_msg = trace['steps'][-1]['output']['result'] return 'memory' in err_msg.lower() and 'pdf' in trace['steps'][-1]['tool'].lower() action: "switch_tool: 'pdf_light_reader'" priority: 8 # Cluster ID: d3e8b9 | Size: 5 | Sample errors: ["MemoryError: Unable to allocate...", "Killed process (OOM killer)"]注意# Cluster ID和Sample errors注释——这是聚类引擎给出的证据链。crm_timeout_on_large_query簇的 7 个样本错误信息高度一致,证明这是稳定模式;而pdf_image_exhaustion簇虽只有 5 个样本,但都指向内存耗尽,且均发生在file_reader工具上,可信度高。
6.3 人工审核与强化:把草稿变成生产级规则
聚类结果是起点,不是终点。我一般会做三件事:
- 验证条件泛化性:随机挑 2 个未参与聚类的日志,手动代入
condition表达式,看是否返回True; - 收紧 action 粒度:
retry_with_timeout_increase: 30太粗放,改为retry_with_params: {"timeout": 30, "max_retries": 1},明确只重试一次; - 添加 fallback 保护:在
action后追加fallback_tool: "text_extractor_fallback",当重试仍失败时,降级调用轻量文本提取工具。
最终规则:
- name: "crm_timeout_on_large_query" condition: | import re step = trace['steps'][-1] err_msg = step['output']['result'] return ('timeout' in err_msg.lower()) and (step['tool'] == 'crm_search') action: "retry_with_params: {'timeout': 30, 'max_retries': 1}" fallback_tool: "crm_search_lite" # 一个只查姓名/ID 的精简版工具 priority: 12这套方法让我们在某银行项目中,将反射规则维护人力从每周 8 小时降至 1 小时——聚类自动发现 3 个新失败模式,人工只需 15 分钟审核+微调。它不取代工程师判断,而是把工程师从「找错误」解放出来,专注在「怎么修得更稳」上。
希望帮到你。
本文还有配套的精品资源,点击获取