尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Hermes Agent 不走各家官方 API,改走 TaoToken,企业还能照抄那套三层架构吗?

Hermes Agent 不走各家官方 API,改走 TaoToken,企业还能照抄那套三层架构吗? 翻 Hermes 的代码时run_agent.py 里 AIAgent 那段主循环我看了不止一遍组装 system prompt 和当前消息、调模型、模型发起 tool call 就当场执行、把工具结果塞回上下文、继续下一轮直到模型不再调用工具才输出结论。这套「走一步、看结果、再决定下一步」的闭环不难理解难的是企业把它搬进自己系统时第一个闹别扭的往往不是工具层而是模型入口。同一个 Agent 要接两家供应商Key 存在哪、Base URL 填什么、模型名怎么对齐三份配置各写各的三层架构还没跑通光模型接入就先把人拖住了。我的做法是把这一层收掉先打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 创建一把 Key再把 Hermes 的模型 Base URL 改成 https://taotoken.net/api原来面向各家官方 API 的配置项就收敛成一个兼容通道。三层分离不用动run_agent.py 主循环也不用动改的只是它下面那层 client 从哪里取地址和密钥。1. 从 run_agent.py 的主循环说起三层分离里最先卡住的是模型接入1.1 AIAgent 的循环到底循环了什么Hermes 的中枢不在 CLI而在 run_agent.py 里的 AIAgent。它的主循环没什么玄学把 system prompt 和当前消息组装好调用模型模型如果返回 tool call就立刻执行执行结果不吞掉原样塞回上下文然后带着新的上下文再调一轮。循环退出条件是模型不再发起工具调用直接把结论说出来。很多人第一次读会以为这跟普通 ReAct 差不多区别在于 Hermes 每一步都拿真实执行反馈重新喂回决策而不是开局把计划写死再照单执行。这个差异在复杂任务里会被放大同一条命令报错预先编排好的流程只会继续往下走而它会把报错当成本轮输入重新判断下一步该做什么。这就是它给企业最值钱的启发大脑层要闭环不是流程要好看。1.2 企业照抄时卡点往往在模型接入而不是编排企业要把这套主循环搬进自己系统通常不是卡在「怎么循环」而是卡在「模型从哪来」。一个中台可能同时服务几个部门A 部门用这家模型B 部门偏好另一家预算还要分开算。每接一家就要多一份 Key、多一个 Base URL、多一套模型名映射run_agent.py 里每加一个分支测试和排障成本就翻一倍。原文在讲企业版搭法时把「模型路由和降级」放在第三阶段其实更靠前的痛点是接入本身没有统一只要 provider 的数量超过两个配置就会先乱。把模型调用收成一个兼容通道是让三层架构能尽早跑通的前提不是锦上添花。先把出口统一后面才有资格谈路由和降级。2. 大脑层换供应商肌肉层和神经层为什么不用跟着改2.1 肌肉层管的是能力注册跟模型从哪来无关Hermes 的肌肉层不是一堆散装脚本。model_tools.py 在启动时集中导入 tools/ 下的模块每个工具再通过 tools/registry.py 注册自己的 schema、handler、toolset 和可用条件。模型看到的不是「后端有一堆函数」而是「当前场景下哪些能力可以被调用、参数长什么样」。这层描述的是能力边界不关心模型是这家还是那家。所以你把 Base URL 换掉工具注册表不需要改一行schema 还是那些 schemahandler 还是那些 handler按场景裁剪 toolset 的逻辑照常生效。真正要确认的是新模型对 tool call 的 schema 支持是否到位这属于模型选型问题不是架构问题。2.2 神经层管的是状态与边界也不依赖供应商神经层里最典型的是 hermes_state.py会话状态落在 SQLite开 WAL 让多读单写更稳用 FTS5 让历史会话可以全文检索messages_fts 通过 trigger 和消息表联动。另一块是 tools/delegate_tool.py 的委托机制每个子 Agent 拿独立上下文、独立 task_id、独立终端会话默认禁止递归委托、禁止直接写共享 memory。这两块依赖的是「状态怎么存、边界怎么划」和「模型由谁提供」没有耦合。换句话说供应商差异只影响大脑层外面那圈调用接口影响不到记忆结构和协作边界。这也是为什么统一通道之后企业最容易慌的那部分其实可以稳住你换的是模型出口不是整套系统的骨架。3. 把 Hermes 的模型接入收到 https://taotoken.net/api两处改动3.1 准备在 TaoToken 上创建一把统一 Key打开 TaoToken 注册账号进控制台创建一把 API Key这就是后面 Hermes 要读的 YOUR_API_KEY。模型 ID 不要凭记忆写去 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 的模型广场看当时可用的列表记下你要用的那个标识。这一步的意义在于以后无论是给 Hermes 配模型还是给别的执行端配模型都是同一把 Key、同一个入口换供应时只改模型 ID 和用量策略不用重新走一遍注册和记账。有人会问既然要统一为什么不直接把某家官方地址写进配置再包一层函数可以但包函数解决的是代码复用解决不了 Key 和账期分散的问题。企业里真正烦的是每接一家就要新开一个账号、走一遍财务流程、单独看一份用量。统一通道把入口收在一处之后模型 ID 变成一个可替换的值切换成本从「接一个新供应商」降到「换一个字符串」。3.2 .env 里只留 Base URL、Key 和模型 ID 三个变量# Hermes Agent 运行前加载的环境变量 # Base URL 填 TaoToken 兼容通道末尾不要加 /v1 HERMES_MODEL_BASE_URLhttps://taotoken.net/api # Key 从 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 创建 HERMES_MODEL_API_KEYYOUR_API_KEY # 模型 ID 以模型广场当时列表为准不要自己拼日期后缀 HERMES_MODEL_IDYOUR_MODEL_ID提示Base URL 只需要写到 https://taotoken.net/api末尾不要补 /v1。很多 OpenAI 兼容 SDK 会自己在后面拼路径多写一层会直接给你 404。这三行的排布有个讲究Base URL 和 Key 是基础设施模型 ID 是业务选择。前者一次配好基本不动后者按任务换。把两类东西放在同一个文件里是为了让「换模型」这件事看起来像一个配置改动而不是一次代码发布。3.3 run_agent.py 里的 client 初始化改成从环境变量取值# run_agent.py 里 AIAgent 初始化模型 client 的部分 import os from openai import OpenAI client OpenAI( # 统一走兼容通道不写死任何一家官方地址 base_urlos.environ[HERMES_MODEL_BASE_URL], # https://taotoken.net/api api_keyos.environ[HERMES_MODEL_API_KEY], # YOUR_API_KEY ) def run_agent(messages, tools): while True: resp client.chat.completions.create( modelos.environ[HERMES_MODEL_ID], messagesmessages, toolstools, # schema 仍来自 tools/registry.py ) msg resp.choices[0].message if not msg.tool_calls: return msg.content messages.append(msg) for call in msg.tool_calls: # handler 从 model_tools.py 的注册表里取和模型来源无关 output dispatch_registered_tool( call.function.name, call.function.arguments ) messages.append({ role: tool, tool_call_id: call.id, content: output, })这段是示意字段名按你仓库里实际的配置读取方式对齐即可。要改的只有两处client 的 base_url 和 api_key 不再硬编码成某一家。主循环的五步一步没少tool call 仍然走原来的注册表分发唯一的变化是模型请求打到了同一个出口。4. 切换模型时最容易顺手改坏的三处4.1 run_agent.py 里的 prompt 组装不要因为换模型就重写换掉模型之后总有人手痒觉得新模型更强顺手把 system prompt、工具说明、上下文裁剪策略一起重构。结果任务一旦跑歪你根本分不清是模型换了还是 prompt 改了。更稳的做法是一次只动一个变量这次只改 Base URL 和模型 IDprompt 组装保持原样等基线稳定后再单独做 prompt 实验。原文把 run_agent.py 的主循环称为中枢中枢的价值就在于它足够稳定别拿它当试验场。4.2 hermes_state.py 的 frozen snapshot 不要改成每轮重注入原文里长期记忆的做法是会话开始时把记忆快照注入 system prompt中途继续写盘但不再反复改 system prompt目的就是保住 prompt cache。换了上下文窗口更大的模型之后很容易产生「那我每轮都重新注入一遍最新记忆」的冲动。这么改成本会先涨命中率反而可能掉因为前缀一直在变缓存全失效。4.3 delegate_tool.py 的隔离别在「新模型更强」的错觉下放开子 Agent 的独立上下文、独立 task_id、独立终端会话以及默认禁止递归委托、禁止直接写共享 memory这些限制和模型强弱无关是协作不失控的前提。模型一换就把限制放开短期看像是让系统更灵活长期看是把上下文串味、权限串味、预算串味的老问题重新请回来。切供应商的时候神经层的边界一动都别动。5. 企业自建版 Hermes 五层里模型治理放在哪5.1 接入层统一入口模型调用统一出口原文给企业版排的五层是接入层、Agent 编排层、记忆层、技能层、知识库与治理层。接入层原本解决的是「人怎么进来」企业微信、门户、OpenAPI、内部工单。照这个思路再往前推一步模型调用也需要一个统一出口解决的是「请求怎么出去」。入口和出口都统一之后编排层就不需要认识任何一家的 SDK 细节只需要知道模型 ID 和这个兼容通道。这才是三层分离在企业里能落地的完整形态大脑层负责想肌肉层负责做神经层负责记模型出口负责把所有对外的调用收成一条线。5.2 记忆层和技能层照原方案走治理层补 Key 与用量记忆还是那三层偏好和执行元数据放关系型库会话与操作日志放检索库语义知识放向量库技能还是用 Git 管版本、用元数据中心管权限和适用部门。这两层不需要因为换了模型出口而重新设计。治理层要补的是和模型调用直接相关的部分Key 的归属、调用量的统计、按部门或项目拆分的用量视图。因为调用出口从 N 个变成 1 个之后审计日志里的模型调用记录可以和工具调用、委托记录挂在同一条时间线上出了问题能顺着一次 run 把「谁发起、调了哪个模型、执行了哪些工具、花了多少」串起来。这些在多个官方入口并存时是很难对齐的。6. 切完通道先验证这几件事配置保存之后别急着跑长任务先用同一把 Key 做两件小事。第一去 TaoToken 模型对话 发一条普通消息确认模型 ID 是列表里真实存在的Base URL 也没填错。这一步排掉的是纯配置错误成本最低。第二回到 Hermes 跑一个带工具调用的最小任务比如让它读取一个本地文件再总结重点看 tool call 能不能正常回灌、能不能触发第二轮。多轮工具调用是大脑层闭环的关键如果第一轮就断问题多半不在模型本身。最后去 控制台 API Keys 看一下这次的调用有没有记上账模型 ID 对不对。如果后面打算长期跑 Agent 任务先看一眼 Coding Plan 的额度是否够用别等跑到一半才发现配额见底。7. 排障401、来自 /v1 的 404以及 tool schema 报错最常见的第一个错是 401。它一般不是 Key 本身失效而是环境变量没被读到.env 放在项目根目录但启动脚本用了别的工作目录或者用了 source 加载却没 export。排查时先打印一下 os.environ.get(HERMES_MODEL_API_KEY) 是否存在再确认值没有多余空格和引号。第二个是 404而且报错里往往能看到路径被拼成了 /v1/chat/completions。原因就是 Base URL 多写了一段把 https://taotoken.net/api 写成了带 /v1 的版本。改回来只留 https://taotoken.net/api。第三个是 tool call 相关的 schema 报错典型信息是模型声称要调用的工具不在提供的列表里或者参数结构对不上。这通常不是通道的问题而是模型对工具 schema 的支持程度不同或者工具名和 tools/registry.py 里注册的名字没对齐。换模型之后如果只在这类任务上出问题优先对照注册表的 schema 检查而不是怀疑 Key。把这三类错分开看排障就不会一上来就乱改配置401 查环境变量404 查 Base URL 末尾schema 错查工具注册表。三个位置互不重叠改动也互不牵连。模型出口统一之后Hermes 的三层分离才算真正可搬运。你要接着做的是把这次跑通的配置固化下来Key 放在统一的地方管理模型 ID 写进配置而不是散在代码里调用记录挂在同一条审计线上。想先试模型就打开 TaoToken 模型对话 发一条消息要长期跑就去看 Coding PlanKey 在 控制台 API Keys 创建。后面如果你还要把 Claude Code 这类执行端接到同一把 Key 上环境变量对照可以参考 接入文档。
返回列表