ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

深入源码:Hermes Agent 的 Self-Improving 机制如何通过 TaoToken 统一 Key 通道验证

深入源码:Hermes Agent 的 Self-Improving 机制如何通过 TaoToken 统一 Key 通道验证 1. 从 Hermes Agent 源码看 Self-Improving 循环到底在跑什么Hermes Agent 的 Self-Improving 机制简单说就是让 Agent 在干完活之后自己复盘、自己写笔记、自己攒技能下次遇到同类任务直接调用。它不是一个玄学概念而是由 Memory、Skill、Nudge Engine 三个子系统拼起来的一个闭环。Memory 负责记事实Skill 负责记步骤Nudge Engine 负责定时提醒 Agent “该回头看看有没有值得沉淀的东西了”。这套机制适合谁适合已经在用 Hermes Agent 做日常编码、运维、数据处理但每次都要重复交代背景、重复踩坑的人。也适合想研究 Agent 自我进化实现细节的开发者——因为它的源码结构相对清晰关键模块都有注释适合拿来拆解。我这次要做的是在本地搭一个可复现的验证环境用 TaoToken 统一 Key 通道把模型调用接进来然后逐步观察 Self-Improving 的触发条件、日志输出和实际效果。TaoToken 在这里的角色是统一 API 入口省去在多个模型供应商之间来回切换 Key 的麻烦让验证过程聚焦在机制本身。验证目标有三个第一确认 Memory 写入和读取的完整链路第二确认 Skill 创建和 patch 的触发条件第三确认 Nudge Engine 的计数器和后台 review 是否按预期工作。这三个目标对应源码里的三个关键文件tools/memory_tool.py、tools/skill_manager_tool.py、run_agent.py。在开始之前你需要准备一台能跑 Python 的本地机器、Hermes Agent 源码github.com/NousResearch/hermes-agent、一个 TaoToken API Key。不需要 GPU因为模型调用走 API。整个验证过程大概需要 30 到 40 分钟取决于你读源码的细致程度。我试过把这套流程跑通之后最大的感受是Self-Improving 不是“自动变聪明”而是“自动把经验结构化”。Agent 本身不会突然学会新东西但它会把已经做过的事情整理成可复用的 Skill把用户偏好整理成 Memory。这个区别很重要决定了你对它的预期。2. TaoToken 前置统一 Key 通道与本地环境准备TaoToken 在这里的作用是提供一个统一的 API 通道让你用同一个 Key 访问不同模型而不需要在 Hermes 的配置文件里为每个供应商单独写一套认证信息。对于验证 Self-Improving 机制来说这能减少配置层面的干扰——你只需要关心 Agent 的行为不需要关心 Key 的管理。首先去 TaoToken 官网注册并获取 API Key。地址是https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content。注册完成后在控制台里创建一个新的 API Key复制保存。这个 Key 后面会写进 Hermes 的配置文件。接下来克隆 Hermes Agent 源码git clone https://github.com/NousResearch/hermes-agent.git cd hermes-agent创建 Python 虚拟环境并安装依赖python3 -m venv venv source venv/bin/activate pip install -r requirements.txtHermes 的配置文件默认在~/.hermes/config.yaml。如果目录不存在手动创建mkdir -p ~/.hermes然后写入基础配置。这里的关键是把 TaoToken 的 Base URL 和 API Key 填进去# ~/.hermes/config.yaml model: provider: openai-compatible base_url: https://taotoken.net/api api_key: sk-your-taotoken-key-here model_id: claude-sonnet-4-20250514 memory: enabled: true memory_char_limit: 2200 user_char_limit: 1375 skills: enabled: true creation_nudge_interval: 10 nudge: memory_interval: 10 skill_interval: 10注意base_url写的是https://taotoken.net/api不要加 UTM 参数。model_id可以根据你实际想用的模型调整TaoToken 支持多个模型 ID具体可以在模型对话页面查看。配置写完后验证一下 Key 是否可用curl -X POST https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer sk-your-taotoken-key-here \ -H Content-Type: application/json \ -d { model: claude-sonnet-4-20250514, messages: [{role: user, content: ping}], max_tokens: 10 }如果返回正常的 JSON 响应说明 Key 和通道都没问题。如果返回 401检查 Key 是否复制完整如果返回 model not found检查model_id是否拼写正确。这一步完成后你的本地环境就具备了运行 Hermes Agent 并观察 Self-Improving 行为的基础条件。接下来进入源码关键模块的读取和最小调用链路的构造。3. 可复制配置读取源码关键模块与最小调用链路这一节的核心是让你能在本地把 Self-Improving 的三个子系统跑起来并且能观察到它们的行为。我们先从源码里定位关键模块然后构造一个最小调用链路。3.1 Memory 模块容量限制与写入失败的处理打开tools/memory_tool.py找到MemoryStore类的初始化部分# tools/memory_tool.py:116-122 class MemoryStore: def __init__(self, memory_char_limit2200, user_char_limit1375): self.memory_entries: List[str] [] self.user_entries: List[str] [] self.memory_char_limit memory_char_limit self.user_char_limit user_char_limit self._system_prompt_snapshot: Dict[str, str] {memory: , user: }这里定义了两个容量上限MEMORY 2200 字符USER 1375 字符。容量有限是故意的目的是倒逼 Agent 做信息压缩只记高密度事实。继续看写入逻辑找到add方法里超过限制时的处理# tools/memory_tool.py:248-259 if new_total limit: current self._char_count(target) return { success: False, error: ( fMemory at {current:,}/{limit:,} chars. fAdding this entry ({len(content)} chars) would exceed the limit. fReplace or remove existing entries first. ), current_entries: entries, usage: f{current:,}/{limit:,}, }关键点超过限制时不会静默丢弃也不会自动压缩而是返回失败并把当前所有条目返回给模型。模型看到current_entries后自己决定哪些该删、哪些该合并。这就是“自我反思”在 Memory 层面的体现。3.2 Skill 模块创建与 patch 的触发条件打开tools/skill_manager_tool.py找到SKILL_MANAGE_SCHEMA# tools/skill_manager_tool.py:681-701 SKILL_MANAGE_SCHEMA { name: skill_manage, description: ( Manage skills (create, update, delete). Skills are your procedural memory — reusable approaches for recurring task types.\n\n Create when: complex task succeeded (5 calls), errors overcome, user-corrected approach worked, non-trivial workflow discovered, or user asks you to remember a procedure.\n Update when: instructions stale/wrong, OS-specific failures, missing steps or pitfalls found during use. If you used a skill and hit issues not covered by it, patch it immediately with skill_manage(actionpatch) — dont wait to be asked.\n\n After difficult/iterative tasks, offer to save as a skill. Skip for simple one-offs. ), }创建 Skill 的触发条件写得很清楚工具调用超过 5 次、克服了错误、用户纠正过的做法、发现了非平凡工作流。简单的一次性任务不创建。patch 的逻辑在_patch_skill函数里# tools/skill_manager_tool.py:397-485 def _patch_skill(name, old_string, new_string, file_pathNone, replace_allFalse): Targeted find-and-replace within a skill file. from tools.fuzzy_match import fuzzy_find_and_replace new_content, match_count, _strategy, match_error fuzzy_find_and_replace( content, old_string, new_string, replace_all ) if match_error: return {success: False, error: match_error, file_preview: content[:500]} original_content content _atomic_write_text(target, new_content) scan_error _security_scan_skill(skill_dir) if scan_error: _atomic_write_text(target, original_content) return {success: False, error: scan_error}patch 用的是模糊匹配因为 Agent 给出的old_string可能和原文有格式差异。修改后还会跑一次安全扫描不通过就回滚。3.3 Nudge Engine计数器与后台 review打开run_agent.py找到计数器初始化# run_agent.py:1328-1331 self._memory_nudge_interval 10 self._turns_since_memory 0 # run_agent.py:1428-1431 self._skill_nudge_interval int(skills_config.get(creation_nudge_interval, 10)) self._iters_since_skill 0Memory 按用户回合计数Skill 按迭代次数计数。到阈值就触发 review。后台 review 的 fork 逻辑# run_agent.py:2665-2711 def _spawn_background_review(self, messages_snapshot, review_memoryFalse, review_skillsFalse): def _run_review(): with open(os.devnull, w) as _devnull, \ contextlib.redirect_stdout(_devnull), \ contextlib.redirect_stderr(_devnull): review_agent AIAgent( modelself.model, max_iterations8, quiet_modeTrue, ) review_agent._memory_store self._memory_store review_agent._memory_enabled self._memory_enabled review_agent._user_profile_enabled self._user_profile_enabled review_agent._memory_nudge_interval 0 review_agent._skill_nudge_interval 0 review_agent.run_conversation( user_messageprompt, conversation_historymessages_snapshot, ) thread threading.Thread(target_run_review, daemonTrue) thread.start()几个关键细节输出重定向到/dev/null用户无感知最多 8 次工具调用不会无限消耗 APIreview agent 自身的 nudge 被禁用避免无限递归和主 agent 共享同一个 MemoryStore写入直接生效。3.4 最小调用链路配置现在构造一个最小配置让 Agent 跑起来并触发 Self-Improving。在~/.hermes/config.yaml里补充agent: max_iterations: 20 quiet_mode: false logging: level: DEBUG file: ~/.hermes/logs/agent.log然后写一个简单的测试脚本# test_self_improving.py import os from run_agent import AIAgent agent AIAgent( modelclaude-sonnet-4-20250514, max_iterations20, quiet_modeFalse, ) # 第一轮让 Agent 做一个需要多步操作的任务 result agent.run_conversation( user_message帮我在当前目录创建一个 Python 脚本读取 data.csv计算每列平均值输出到 result.json。如果 data.csv 不存在先生成一个示例文件。 ) print( 第一轮完成 ) print(result)运行这个脚本观察日志输出。你应该能看到 Agent 执行多步操作工具调用次数超过 5 次然后 Nudge Engine 触发 Skill Review。4. 验证请求与成功结果观察自我改进触发条件这一节我们实际跑一遍观察 Memory 写入、Skill 创建、Nudge 触发的完整过程。4.1 第一轮冷启动触发 Skill 创建运行上面的测试脚本。在日志里你会看到类似这样的输出[DEBUG] Tool call: write_file(generate_sample.py) [DEBUG] Tool call: terminal(python generate_sample.py) [DEBUG] Tool call: read_file(data.csv) [DEBUG] Tool call: write_file(calc_avg.py) [DEBUG] Tool call: terminal(python calc_avg.py) [DEBUG] Tool call: read_file(result.json) [DEBUG] Iteration count: 6 [DEBUG] Skill nudge triggered: _iters_since_skill6 10? No, waiting...等等这里有个细节_iters_since_skill是 6还没到 10。但 Skill 创建的触发条件里写的是“5 calls”。这两个条件不冲突——5 calls 是模型自己判断是否值得创建10 是 Nudge Engine 强制提醒的阈值。模型可以在 6 次调用后自己决定创建 Skill不需要等 Nudge。继续看日志如果模型决定创建 Skill你会看到[DEBUG] Tool call: skill_manage(actioncreate, namecsv-average-calc, categorydata-processing) [DEBUG] Security scan passed for skill: csv-average-calc [DEBUG] Skill written to ~/.hermes/skills/data-processing/csv-average-calc/SKILL.md检查生成的 Skill 文件cat ~/.hermes/skills/data-processing/csv-average-calc/SKILL.md你应该能看到类似这样的内容--- name: csv-average-calc description: Calculate column averages from a CSV file and output to JSON version: 1.0.0 --- # CSV Average Calculation ## When to use - User wants to calculate averages from a CSV file - User mentions data.csv, column statistics, or result.json ## Steps 1. Check if data.csv exists; if not, generate a sample file 2. Read data.csv with pandas 3. Calculate mean for each numeric column 4. Write results to result.json ## Pitfalls - Handle missing values before calculating mean - Ensure numeric columns are correctly typed4.2 第二轮Skill 复用与自我修补现在再跑一个类似任务但换一个 CSV 文件result agent.run_conversation( user_message帮我计算 sales.csv 里每列的平均值输出到 summary.json。 )观察日志[DEBUG] Skill index loaded: csv-average-calc available [DEBUG] Tool call: skill_view(csv-average-calc) [DEBUG] Tool call: read_file(sales.csv) [DEBUG] Tool call: write_file(calc_avg_v2.py) [DEBUG] Tool call: terminal(python calc_avg_v2.py) [DEBUG] Error: KeyError date — non-numeric column [DEBUG] Tool call: write_file(calc_avg_v3.py) # 跳过非数值列 [DEBUG] Tool call: terminal(python calc_avg_v3.py) [DEBUG] Tool call: skill_manage(actionpatch, namecsv-average-calc, old_stringCalculate mean for each numeric column, new_stringCalculate mean for each numeric column, skip non-numeric columns like dates) [DEBUG] Security scan passed [DEBUG] Skill patched successfully这里发生了自我修补Agent 在使用 Skill 时遇到了 Skill 没覆盖的坑非数值列于是 patch 了 Skill把“跳过非数值列”加进了 Pitfalls。4.3 第三轮验证 Memory 写入Memory 的触发需要用户回合数达到 10。我们可以通过多轮对话来触发for i in range(12): result agent.run_conversation( user_messagef这是第 {i1} 轮对话请记住我偏好用 pandas 而不是 csv 模块处理表格数据。 )在第 10 轮左右你会看到[DEBUG] Memory nudge triggered: _turns_since_memory10 [DEBUG] Spawning background review agent for memory [DEBUG] Review agent: memory_manage(actionadd, contentUser prefers pandas over csv module for tabular data) [DEBUG] Memory written to ~/.hermes/memories/USER.md检查 Memory 文件cat ~/.hermes/memories/USER.md你应该能看到类似§ User prefers pandas over csv module for tabular data § User works on data processing tasks involving CSV files4.4 成功结果的判断标准验证成功的标志有三个第一~/.hermes/skills/目录下出现了自动创建的 Skill 目录且 SKILL.md 内容合理。第二~/.hermes/memories/目录下的 MEMORY.md 或 USER.md 出现了新的条目且条目是声明式事实而非命令式指令。第三日志里出现了Skill nudge triggered或Memory nudge triggered以及对应的skill_manage或memory_manage工具调用。如果这三个都出现了说明 Self-Improving 机制在你的本地环境里按预期运行。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth在验证过程中你可能会遇到几类典型错误。这一节按真实报错来排查。5.1 401 Unauthorized报错原文Error: 401 Unauthorized {error: {message: Invalid API key, type: invalid_request_error}}原因TaoToken API Key 没填对或者配置文件里的api_key字段有空格、换行。排查步骤检查~/.hermes/config.yaml里的api_key是否完整复制前后无空格。用 curl 单独测试 Key 是否有效。如果 curl 也返回 401去 TaoToken 控制台重新生成一个 Key。5.2 local proxy failed报错原文Error: local proxy failed: connection refused原因Hermes 尝试连接本地代理但代理没启动。如果你在配置里写了proxy字段检查代理地址和端口是否正确。如果不需要代理把proxy字段删掉。排查步骤检查~/.hermes/config.yaml里是否有proxy配置。如果有注释掉或删除。然后确认base_url直接指向https://taotoken.net/api。5.3 reading choices 相关报错报错原文Error: reading choices: unexpected end of JSON input原因API 返回的响应体不完整通常是网络中断或超时导致。也可能是max_tokens设置过小响应被截断。排查步骤检查网络连接是否稳定。把max_tokens调大比如从 10 调到 1024。如果问题持续在 curl 测试里加-v查看完整响应。5.4 OAuth 相关报错报错原文Error: OAuth token expired or invalid原因如果你在配置里用了 OAuth 认证方式但 token 过期了。TaoToken 的 API Key 认证不需要 OAuth所以这个错误通常出现在你混用了两种认证方式。排查步骤确认~/.hermes/config.yaml里只用了api_key字段没有oauth相关配置。如果有删掉 OAuth 部分统一用 API Key。5.5 Skill 创建失败Security scan blocked报错原文Security scan blocked this skill (reason: suspicious_pattern): Pattern matched: curl.*\$\{?\w*(KEY|TOKEN|SECRET|PASSWORD)原因Skill 内容里包含了可能泄露密钥的模式比如curl命令里引用了环境变量中的 KEY。排查步骤检查 Skill 的 SKILL.md 内容把涉及密钥引用的部分改成占位符描述比如把curl -H Authorization: Bearer $API_KEY改成curl -H Authorization: Bearer your-api-key。修改后重新创建 Skill。5.6 Memory 写入失败exceed limit报错原文Memory at 2,150/2,200 chars. Adding this entry (120 chars) would exceed the limit. Replace or remove existing entries first.原因Memory 容量满了。这是预期行为不是 bug。排查步骤查看current_entries返回的内容手动删除或合并一些过时条目。或者让 Agent 自己处理——在下一轮对话里告诉它“Memory 满了请整理一下”它会调用memory_manage的 replace 或 remove 操作。5.7 三件套配置检查清单如果你用的是 Claude Code、Cline MCP 或 Codex确保以下三件套都写全Base URL:https://taotoken.net/apiAPI Key:sk-your-taotoken-key-hereModel ID:claude-sonnet-4-20250514或你实际使用的模型 ID以 Codex 的auth.json为例{ base_url: https://taotoken.net/api, api_key: sk-your-taotoken-key-here, model: claude-sonnet-4-20250514 }以 Cline MCP 的 settings 为例{ mcpServers: { taotoken: { command: npx, args: [-y, taotoken/mcp-server], env: { TAOTOKEN_BASE_URL: https://taotoken.net/api, TAOTOKEN_API_KEY: sk-your-taotoken-key-here, TAOTOKEN_MODEL_ID: claude-sonnet-4-20250514 } } } }三件套缺一不可。少了 Base URL 会走默认端点少了 Key 会 401少了 Model ID 会报 model not found。6. 语义一致 CTA继续验证与深入方向如果你已经跑通了上面的验证流程接下来可以往几个方向深入。第一个方向是观察 Skill 的生命周期。目前 Hermes 的 Skill 只有name、description、version三个 frontmatter 字段。你可以手动在 SKILL.md 里加上last_used、use_count、success_rate然后观察 Agent 是否会根据这些字段做优先级判断。这需要改源码但改动量不大。第二个方向是验证多 Skill 组合。创建两个相关的 Skill比如csv-average-calc和json-output-format然后给一个需要同时用到两者的任务观察 Agent 是否会依次加载并组合使用。第三个方向是压力测试 Nudge Engine。把creation_nudge_interval从 10 改成 3然后跑一个简单任务观察是否会出现过度创建 Skill 的情况。这能帮你理解阈值设置对 Agent 行为的影响。如果你在验证过程中需要查看模型的实际响应可以用 TaoToken 的模型对话页面直接测试 prompt。地址是https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content。如果你打算长期用 Hermes Agent 做编码或 Agent 开发建议关注 Coding Plan地址是https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content。它适合需要稳定 API 通道和统一 Key 管理的场景。接入文档在https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content里面有各语言 SDK 的调用示例和错误码说明。API Keys 管理页面在https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content可以在这里创建、删除、查看 Key 的使用情况。最后说一个实际经验Self-Improving 机制的效果取决于你给它的任务复杂度。如果每次都是简单的一次性任务它不会创建 Skill也不会写入 Memory。只有当你反复做同类复杂任务时这套机制才会真正发挥作用。所以验证的时候尽量构造需要多步操作、有踩坑过程的任务这样更容易观察到自我改进的触发。
返回列表