1. 从零定制 Hermes Agent为什么我建议先用 uv 把工具调用循环跑通Hermes Agent 是一个把「对话循环 工具调用 多平台网关」打包好的开源智能体框架你可以把它理解成一个已经装好发动机和变速箱的底盘核心的AIAgent._run_agent_loop()负责和模型来回对话、解析tool_calls、分发到具体工具、再把结果塞回消息历史直到模型给出纯文本回答。对想定制开发的开发者来说它最大的价值不是「又一个 Agent 框架」而是模块边界切得足够干净——工具注册在tools/registry.py工具发现与分发在model_tools.py系统提示词组装在agent/prompt_builder.pyMCP 服务器在~/.hermes/config.yaml里声明即可自动注册。但真正上手时第一个坑往往不是代码而是环境。Hermes Agent 依赖面很宽pip install -e .[all,dev]在裸 Python 环境里跑很容易出现依赖版本互相打架、装到一半报编译错误、或者装完了hermes doctor又提示某个包版本不对。我试过用 uv 来管这套依赖体验差别很明显uv 的解析器快、锁文件确定性强uv venv建出来的虚拟环境干净uv pip install -e装可编辑包时对 extras 的处理也更稳。这篇面向的是想从零定制 Hermes Agent 的开发者重点讲三件事用 uv 初始化项目并锁定依赖、把工具调用循环的最小示例跑起来、以及把模型 endpoint 改到 TaoToken 的统一 Key/API 通道最后用一次本地验证动作确认整条调用链打通。适合谁适合已经会写 Python、想给 Agent 加自定义工具或接 MCP 服务、但不想在环境配置上耗掉半天的人。下面每一步都给可复制的命令和配置你照着敲就能复现。2. 用 uv 初始化 Hermes Agent 项目并锁定依赖uv 依赖锁定配置教程先把仓库拉下来。假设你已经装好 uvcurl -LsSf https://astral.sh/uv/install.sh | sh或pip install uv然后git clone repo-url hermes-agent cd hermes-agent uv venv venv --python 3.11 source venv/bin/activate这里指定 Python 3.11 是有原因的Hermes Agent 的部分依赖尤其是异步和类型相关的库在 3.11 上兼容性最好3.12 偶尔会遇到某些包还没出预编译 wheel 的情况。uv venv建环境比python -m venv快很多而且默认不带 pip后面统一用uv pip管理。接下来装依赖。Hermes Agent 的pyproject.toml里定义了all和dev两个 extrasall是全部功能依赖dev是测试和调试工具uv pip install -e .[all,dev]装完之后跑一次自检hermes doctorhermes doctor会检查 Python 版本、关键依赖是否可导入、配置目录是否存在、API Key 是否配置。如果这一步报某个包缺失大概率是 extras 没装全重新执行上面的 install 命令即可。依赖锁定是 uv 的强项。如果你想让团队里每个人装出来的版本完全一致可以生成锁文件uv pip compile pyproject.toml -o requirements.lock --all-extras uv pip sync requirements.lockuv pip compile会把所有依赖含传递依赖解析成确定版本写进requirements.lockuv pip sync则严格按照锁文件同步环境——它会删掉锁文件里没有的包保证环境纯净。这在 CI 里特别有用避免「我本地能跑服务器上不行」的经典问题。配置目录默认在~/.hermes/结构是这样的~/.hermes/ ├── config.yaml # 主配置 ├── .env # API 密钥 ├── skills/ # 技能Markdown ├── memories/ # 记忆 ├── state.db # 会话数据库 ├── cron/ # 定时任务 └── profiles/ # 多配置隔离你可以用HERMES_HOME环境变量覆盖这个路径做多套配置隔离时很有用export HERMES_HOME/path/to/my-hermes-config依赖装好、目录就绪下一步就是理解并跑通工具调用循环。这是 Hermes Agent 的心脏也是你后续所有定制开发的落点。3. 工具调用循环最小示例与 TaoToken settings 配置片段工具调用循环的流程可以拆成五步构建系统提示词 → 组装 API 请求参数模型名、消息历史、工具定义 JSON Schema、推理配置→ 调用 LLM → 解析响应含tool_calls就执行工具并把结果加回消息历史然后回到第 3 步纯文本就返回最终回答→ 上下文压缩接近 token 上限时触发摘要。核心代码在run_agent.py的AIAgent类里。要加一个自定义工具在tools/下新建文件用 registry 注册# tools/my_tool.py from tools.registry import registry def check_available(): import os return os.environ.get(MY_API_KEY) is not None async def handle_my_action(arguments: dict, **kwargs) - str: param1 arguments.get(param1, ) return f结果: {param1} registry.register( namemy_action, toolsetmy_toolset, schema{ type: function, function: { name: my_action, description: 执行我的操作, parameters: { type: object, properties: { param1: {type: string, description: 参数说明} }, required: [param1] } } }, handlerhandle_my_action, check_fncheck_available, requires_env[MY_API_KEY], is_asyncTrue, )然后在model_tools.py的_discover_tools()里加一行from tools import my_tool工具就会被自动发现。如果新建了工具集还要在toolsets.py里注册TOOLSETS[my_toolset] [my_action]。现在把模型 endpoint 改到 TaoToken 的统一通道。编辑~/.hermes/config.yaml关键配置项如下model: default: claude-sonnet-4-20250514 provider: custom base_url: https://taotoken.net/api terminal: env_type: local compression: enabled: true threshold: 0.5 agent: max_turns: 50 system_prompt: null delegation: max_iterations: 20 default_toolsets: [terminal, file, web] toolsets: enabled: [web, terminal, file, skills, memory, cron, delegate] disabled: [browser, vision] memory: provider: builtinAPI Key 放在~/.hermes/.env里TAOTOKEN_API_KEY你的Key如果你用的是 OpenAI 兼容的调用方式base_url填https://taotoken.net/apiKey 用 TaoToken 控制台生成的统一 Key。这样模型对话、工具调用都走同一条通道不用为每个 provider 单独配 Key。需要生成 Key 的话去控制台https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewriteMCP 服务器也在同一个 config.yaml 里声明工具会自动注册mcp: servers: - name: my-server command: npx args: [-y, my/mcp-server] env: API_KEY: ...这里有个细节MCP 服务器的工具注册和内置工具走的是同一套 registry所以你在toolsets.enabled里控制开关时MCP 工具也会一并生效。如果你只想让某个 MCP 工具在特定场景可用可以在工具集层面做隔离而不是全局启用。配置改完跑一次验证请求确认调用链打通。最直接的方式是启动交互式 TUIhermes然后在对话里让它调用你刚注册的工具比如输入「用 my_action 处理 param1hello」。如果配置正确你会看到模型返回tool_calls、工具被执行、结果被加回历史、模型给出最终回答的完整过程。想直接验证工具注册是否成功可以在 Python 里查from tools.registry import registry print(registry.get_tool_to_toolset_map()) from model_tools import handle_function_call result handle_function_call(web_search, {query: test}) print(result)get_tool_to_toolset_map()会打印所有已注册工具及其所属工具集确认你的my_action在里面就说明注册成功。handle_function_call则绕过模型直接调用工具用来单独验证工具逻辑。4. 验证请求与成功结果一次完整的本地调用链确认配置和代码都就位后需要一次端到端的验证来确认「模型 → 工具调用 → 结果回填 → 最终回答」这条链路真的通了。这一步不能省因为很多问题Key 不对、base_url 写错、工具没注册、MCP 没启动在静态检查里看不出来只有实际发一次请求才暴露。先开调试日志这样能看到 API 请求和工具分发的细节HERMES_LOG_LEVELDEBUG HERMES_LOG_API1 hermesHERMES_LOG_API1会把每次 API 请求的 URL、模型名、消息数量打出来HERMES_LOG_LEVELDEBUG则输出工具注册和分发的调试信息。启动后在 TUI 里输入一个会触发工具调用的请求比如「搜索一下 Python 3.11 的新特性」。观察日志输出正常流程应该是[DEBUG] Building system prompt... [DEBUG] Registered tools: 52 [DEBUG] API request - https://taotoken.net/api/v1/chat/completions [DEBUG] Model: claude-sonnet-4-20250514 [DEBUG] Response contains tool_calls: web_search [DEBUG] Dispatching tool: web_search [DEBUG] Tool result added to history [DEBUG] API request - https://taotoken.net/api/v1/chat/completions [DEBUG] Final response received看到Response contains tool_calls和Final response received这两行基本就说明调用链通了。如果卡在API request之后没有响应多半是 Key 或 base_url 的问题如果Response contains tool_calls之后没有Dispatching tool则是工具注册或工具集开关的问题。再验证一下 MCP 接入。假设你在 config.yaml 里声明了一个 MCP 服务器启动后日志里应该能看到 MCP 工具的注册信息[DEBUG] MCP server my-server connected [DEBUG] Registered MCP tools: my_server_tool_1, my_server_tool_2然后在对话里请求调用 MCP 工具确认它和内置工具一样能被模型选中并执行。MCP 工具的执行结果同样会被加回消息历史参与后续推理。如果你想在代码层面做自动化验证可以写一个最小的测试脚本import asyncio from run_agent import AIAgent async def main(): agent AIAgent() result await agent.run(用 my_action 处理 param1test) print(result) asyncio.run(main())这个脚本会走完整的_run_agent_loop()如果返回的结果里包含工具执行后的内容说明整条链路在代码层面也是通的。跑测试套件的话pytest tests/ -v pytest tests/test_agent_loop.py -v pytest tests/ --cov. --cov-reporthtml测试目录和源码是对应的tests/agent/、tests/gateway/、tests/hermes_cli/、tests/plugins/。需要 API 的工具用unittest.mock模拟避免测试时真的发请求。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth 报错对照配置过程中最容易撞上的几类报错这里按真实错误信息对照排查。401 Unauthorized。日志里出现401或invalid api key先检查~/.hermes/.env里的 Key 名和 config.yaml 里引用的名字是否一致。Hermes Agent 读取环境变量的方式和 provider 有关如果你用的是自定义 providerKey 名要和你代码里requires_env声明的一致。另外确认 base_url 没有多写或少写/v1——TaoToken 的 API 地址是https://taotoken.net/api具体路径拼接由客户端处理不要手动加/v1/chat/completions到 base_url 里。local proxy failed。这个报错通常出现在终端工具或网络工具执行时说明工具尝试走本地代理但代理没起来。检查terminal.env_type配置如果是local但你的环境需要特定网络配置工具执行会失败。排查方式是先用handle_function_call直接调用该工具看是工具本身的问题还是模型调用的问题。reading choices 报错。日志里出现reading choices或KeyError: choices说明 API 返回的 JSON 结构不符合预期。常见原因是 base_url 指向了一个返回非标准格式的端点或者模型名写错了导致服务端返回错误信息而不是正常的 chat completion 结构。确认model.default填的是 TaoToken 支持的模型 IDprovider设为custombase_url设为https://taotoken.net/api。OAuth 相关报错。如果你在接某些需要 OAuth 的 MCP 服务器或平台网关报错里出现OAuth、token expired、refresh failed检查 MCP 服务器的env里 OAuth token 是否过期。MCP 服务器的认证信息在 config.yaml 的mcp.servers[].env里配置token 过期需要重新生成并更新配置。工具注册了但模型不调用。这种情况不是报错但很常见。原因通常是工具没被加入toolsets.enabled列表或者check_fn返回了 False比如requires_env里的环境变量没设置。用registry.get_tool_to_toolset_map()确认工具在注册表里再检查toolsets.enabled是否包含它所属的工具集。MCP 服务器启动失败。日志里出现MCP server failed to start或command not found检查command和args是否正确。npx方式启动的 MCP 服务器需要 Node.js 环境确认npx在 PATH 里。如果是 Python 写的 MCP 服务器command填python或uvargs填脚本路径。排查时有个通用技巧把HERMES_LOG_LEVEL设为DEBUG然后从日志的最后一行往前看第一个报错的位置就是根因。很多表面上的「模型不回复」其实是工具执行失败导致循环卡住日志里会有明确的工具执行错误。6. 把定制开发落到日常从工具循环到 MCP 接入的下一步工具调用循环跑通、MCP 接入验证过之后你的 Hermes Agent 定制开发就有了一个可靠的地基。接下来可以往几个方向延伸给工具加更复杂的参数校验和错误处理让handle_my_action在参数缺失时返回结构化错误而不是抛异常把常用工具组合成工具集通过toolsets.enabled做场景隔离或者写技能SKILL.md把多步操作固化成可复用的流程。技能放在~/.hermes/skills/类别/技能名/SKILL.md格式是带 frontmatter 的 Markdown--- platforms: [macos, linux] tags: [automation] requires: [GITHUB_TOKEN] --- # 技能名称 简短描述第一段作为索引摘要。 ## 步骤 1. ... 2. ...技能会在 prompt 构建时被扫描索引匹配后注入系统提示词。参考agent/skill_utils.py和agent/prompt_builder.py里的build_skills_system_prompt()看具体实现。如果你想让 Agent 长期跑编码或 Agent 类任务可以考虑用 Coding Plan 来管理调用额度避免频繁换 Keyhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite需要生成或管理 API Key 时控制台在这里https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite接入文档和 MCP 配置细节可以参考https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite想先验证模型对话是否正常可以直接在模型对话页测试https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite最后说一个实际踩过的坑改完 config.yaml 后一定要重启 hermes 进程配置不会热加载。我一开始改完 base_url 直接在当前会话里测试一直报 401重启后就好了。另外~/.hermes/.env的权限建议设为600避免 Key 被其他用户读到。
阅读完成 · 觉得有帮助?