Agent核心选型实践:Hermes如何在综合Agent平台中落地
做 HagiCode 这个项目之前我们对 Agent 核心的选型其实纠结了很久。市面上喊 Agent 的口号很多但真正落到项目里要解决的是模型接入、工具调用、记忆状态、权限控制这一连串工程问题不是“能跑 Claude 还是跑 GPT”那么简单。当时团队内部定了个原则先不谈智能先谈可控可复现。这也是我们最终把 Hermes 放进来当综合 Agent 核心的原因。这篇就把 HagiCode 的选型过程、Hermes 的架构拆解、以及实际接入时的踩坑记录一并写出来给正在做 Agent 平台或想搭一套私有化 Agent 服务的人做个参考。1. 项目背景与核心诉求为什么需要“综合 Agent 核心”1.1 HagiCode 到底想做什么HagiCode 从定位上就不是一个单点工具而是一套面向多业务场景的综合 Agent 平台。我们最初接的需求就有这么几类电商场景的售后自动分单、内容团队的批量创作与审核、企业内部的知识库问答、还有一部分自动化副驾驶类的操作流程。这些场景有一个共同特征不是单个模型调用就能完成的而是模型工具业务规则人的确认环节串起来的完整任务链。举个例子电商售后自动分单这个场景Agent 不是只负责“读懂用户退款原因”还要去查订单系统、判断是否符合售后策略、调起退款接口、生成处理备注、甚至要判断要不要转人工。这背后牵扯的是多个系统的对接、状态流转和异常处理。如果只是用一个 Prompt 把 OpenAPI 拼进去工程上撑不住。所以 HagiCode 从一开始就需要一个“综合 Agent 核心”它不是单纯的 LLM 封装也不是某个对话框架而是能承载会话管理、模型路由、工具注册、记忆存取、任务编排、安全审计这些基础能力的运行时。我们把这块叫 Agent Core也就是整个平台的执行底座。1.2 对 Agent 核心的评估维度选了半年我们最终整理出一份自己的评估清单核心打分项有六个多模型接入能力能不能同时对接 DeepSeek、通义、本地部署模型还要支持随时更换 API Provider部署与运维成本是纯依赖云端服务的 SDK还是可以本地化、私有化部署的运行时性能与资源占用高并发下是否有稳定的执行性能空闲时会不会空转烧资源工具与技能扩展性新增一个业务工具是否要改主工程工具的参数校验和错误传播是否标准记忆与状态管理会话级记忆、项目级记忆有没有分割能不能跨会话继承安全与权限控制Agent 执行外部工具时有没有沙箱机制操作日志是否可审计、可回溯。针对这六项我们把市面上主流的方案都拉回来做了盲测包括几类典型的 Agent 框架、低代码编排平台以及几个开源 Agent 运行时。盲测的结果有点出乎意料框架类方案上手快但越往后用越会发现核心控制权仍然在外层而我们最终看上的 Hermes恰好是一个具备“运行时内核”属性的 Agent Harness这在后续选型考量中成了决定性优势。2. 为什么从“框架思维”转向“运行时思维”2.1 框架类方案解决不了的核心问题先说一个判断LangChain 这类 Agent 框架、Dify 这类低代码平台价值在于快速出原型。但真到生产级综合 Agent它们有几个绕不过去的问题。第一个是工具链重。框架本身不是运行时它只是把模型调用、工具调用组装成一个个 Chain 或者 Workflow。当业务到几十个工具、上百个技能的时候编排层会变得非常臃肿排错基本靠翻整个调用链日志。第二个是状态容易失控。框架类方案的记忆要么全塞在上下文里要么依赖外部向量库没有和任务执行的生命周期强绑定容易串会话。第三个是并发模型受限。多数框架基于同步回调或线程池遇到长耗时工具调用、大并发任务涌入资源调度是肉眼可见地吃力。这些问题不是框架不行而是它的定位问题——它面向“快速搭建”不面向“长期承载系统”。2.2 Hermes 的定位Agent Harness 而不是 Agent Framework我们后来讨论时特别区分了一个概念Agent Framework 和 Agent Harness。Framework 是把 Agent 的“零件”拼起来给你用的工具箱而 Harness 更像是承载 Agent 运行的“座舱”它规定了一整套生命周期任务进来如何解析、模型如何调度、工具如何执行、结果如何回写、异常如何兜底。Hermes 因为早期核心代码用 Rust 实现天然具备高并发、低资源占用的优势同时它的定位一直是“运行时核心”不捆绑具体模型不绑架你的上层业务结构。HagiCode 选 Hermes本质上就是选了一个可以长期依赖的执行内核我们自己的业务代码寄生在 Harness 规定的边界里而不是被某个框架的 Chain 结构绑死。2.3 Hermes 核心模块与执行流水线从实际使用角度Hermes 的核心模块可以分为五层每一层对应 HagiCode 的一个痛点模型网关层负责对接不同厂商的 LLM API统一请求/响应协议支持请求级路由会话与记忆层区分短期会话上下文与长期项目记忆支持按业务维度隔离工具注册与执行层业务工具以 Tool/Skill 方式注册运行时统一加载、校验参数、执行并返回结构化结果编排与调度层负责任务拆解、执行顺序控制、条件分支与重试策略安全与审计层每个工具调用前做权限校验执行过程落审计日志操作可回放。这五层统一跑在 Rust 异步运行时里。事件驱动、无共享状态、按会话隔离。对我们这种要同时跑多个业务 Agent 的平台来说这套结构几乎是照着需求画的。3. 选择 Hermes 的五个硬核理由3.1 Rust 运行时性能、并发和部署体验我记得第一次在测试环境压 Hermes 时印象最深的就是它的资源占用曲线。我们在 4C8G 的机器上同时跑了 50 个会话任务每个会话都要串行调用两个外部工具内存峰值不到 2GCPU 平均负载很低。之前用 Python 写的 Agent 原型同样场景跑十几个任务CPU 就疯狂飘红内存动不动上 3G 多。这个差异对 HagiCode 这种多租户平台来说很关键。我们不可能给每个客户单独跑一套重型 Python 应用但基于 Rust 的 Hermes 作为一个独立 runtime做容器化部署之后单 pod 能承载的会话数高很多。再加上 Rust 的静态编译启动速度非常快没有 Python 那种依赖导入的预热时间扩缩容就变得很干净。补充一点Hermes 的异步运行时对长时间等待外部 API 的场景特别友好。模型响应慢、工具调用耗时长正常情况下线程不会阻塞等待而是挂起到事件循环里继续处理其他请求。我们压测过外部 API 耗时 15 秒以上的场景同时挂 100 个会话整体吞吐几乎不衰减。3.2 模型无关网关一个核心多模型随便换HagiCode 从一开始就不打算绑定某个特定的大模型。原因很简单不同客户有不同数据合规要求不同任务对模型能力的需求也不一样。售后分单可能用快且便宜的模型就够了复杂创作类任务需要更强推理能力。Hermes 的模型网关设计很干净——它把 Provider 层做成了可插拔配置。我们可以给同一个 Agent 配置多个模型路由比如默认走 DeepSeek复杂任务自动切到能力更强的模型知识库场景走本地部署的向量化服务。这里分享一个实际配置样例。Hermes 的 Provider 配置在 YAML 文件里维护核心字段包括provider、base_url、api_key、modelmodel_providers: deepseek: provider: openai base_url: https://api.deepseek.com/v1 api_key: ${DEEPSEEK_API_KEY} model: deepseek-chat timeout: 30s qwen: provider: openai base_url: https://dashscope.aliyuncs.com/compatible-mode/v1 api_key: ${QWEN_API_KEY} model: qwen-plus timeout: 30s切换模型的时候只需要改 Agent 的路由配置业务代码完全不用动。热切换也很稳定我们试过在跑任务过程中直接换 Provider未完成的会话会被统一重试没有出现状态错乱。3.3 工具与技能体系Tool/Skill 的标准注册方式综合 Agent 最怕的就是工具调用变成一团乱麻。在一个项目里光订单查询、库存查询、物流跟踪可能就是三个不同系统表现形式也五花八门有 HTTP API、有消息队列、甚至还有数据库直查。Hermes 把工具调用统一抽象成了 Tool 和 Skill 两层。Tool 是最小执行单元Skill 是多个 Tool 的组合编排。每个 Tool 提供统一的 JSON Schema 描述定义输入参数、输出结构、权限级别和错误码。调用时由 Harness 统一解析模型返回的函数调用再映射到具体 Tool 执行。我用一个实际接入的例子来说。HagiCode 接订单系统时写了一个query_order的 Tool{ name: query_order, description: 按订单号查询订单状态, parameters: { type: object, properties: { order_id: { type: string, description: 订单号 } }, required: [order_id] }, permission: read_only, timeout: 5s }注册到 Hermes 之后模型只需要根据工具描述输出标准函数调用Harness 会自动做参数校验、权限检查、执行超时控制。对我们来说新增业务工具就变成了“写一段描述 一个执行回调”的事不用再改 Agent 核心代码。3.4 记忆与状态管理解决“会话串扰”和“记忆漂移”Agent 的记忆问题特别容易被低估。HagiCode 早期原型用上下文拼接的方式做记忆结果不同会话互相污染A 客户的订单状态跑到了 B 客户的知识库问答里排查了两天。Hermes 在记忆层做了三级隔离会话级短期记忆、用户级偏好记忆、项目级长期记忆。默认情况下短期记忆只跟着当前会话走项目记忆需要显式写入并标注命名空间。我们当时把不同客户的业务数据分成了独立 namespace跑了几轮之后会话串扰的问题基本绝迹。另外Hermes 的记忆写入是追加式的每条记忆附带时间戳、来源 Agent、业务标签。复盘某个任务时可以把这条任务到底基于哪些历史记忆做出的决策完整还原出来。这对平台型产品来说太重要了总不能模型自己都不知道自己为什么要这么做。3.5 安全与审计Agent 权限边界是底线Agent 一旦挂着工具执行安全问题就不是“以后再说”的事。HagiCode 里涉及订单退款、库存修改这类操作权限控不住后果很严重。Hermes 的安全模型分三层会话级授权每个会话创建时可以绑定角色如只读、执行、管理员工具级权限每个 Tool 都有独立 permission 标注执行前由 Harness 强制校验操作审计所有工具调用、模型请求、记忆写入都进审计日志支持按会话ID、工具名、时间范围检索。我们接入完这套体系后安全评审的资料基本一步到位。审计日志里能看到每次退款调用的发起者、触发会话、和调用的订单号真出问题也说得清楚。4. 实操把 Hermes 接入 HagiCode4.1 安装与部署Ubuntu、WSL2 和 PVE 三种姿势Hermes 的安装方式对团队协助很友好支持直接在宿主机装二进制包也支持容器化部署。我们用过的三种方式分享给大家Ubuntu 上安装最直接的是用官方安装脚本curl -fsSL https://hermes.example.com/install.sh | bash装完之后验证版本hermes --version hermes doctorWSL2 环境下同样可以跑。需要注意的是 WSL2 默认的内存分配和 CPU 限制需要手动调不然 Hermes 会跑得很憋屈。建议在%UserProfile%\.wslconfig里配置[wsl2] memory8GB processors4重启 WSL 后生效。如果是 PVE 环境我们更推荐直接跑 LXC 容器或 Docker 镜像docker run -d --name hermes-core -p 8080:8080 \ -v /opt/hermes/config:/etc/hermes \ -v /opt/hermes/logs:/var/log/hermes \ hermes-core:latest无论哪种方式装完第一件事就是跑hermes doctor它会检查配置文件、模型 Provider 连通性、日志目录权限非常省事。4.2 模型 Provider 配置与 API 切换前面提到模型网关的 YAML 配置这里补充一下更换 API 的实际操作。很多初学者容易直接在默认配置里改结果模型 Provider 检测还是走旧地址。我们总结的标准流程是编辑 YAML修改base_url和model字段通过环境变量或.env文件注入新的api_key执行hermes config validate检查格式执行hermes config reload热更新配置跑一个最小会话测试确认模型响应正常。这里有个小坑如果发现切换后模型一直返回旧的错误格式先别怀疑配置没生效看看环境变量优先级。Hermes 读取密钥时环境变量的优先级高于 YAML 文件里的裸文本所以 YAML 里哪怕填错了环境变量也会覆盖。4.3 定义第一个 Tool 和 SkillHagiCode 的第一个外部工具接入是从“订单查询”开始的。我们当时在 Hermes 里注册 Tool 时用的不是硬编码函数而是通过 Harness 提供的回调接口加载本地实现。以 Python 为例一个最小 Tool 实现长这样def query_order(params: dict, context: dict): order_id params[order_id] # 调用订单系统的 HTTP 接口 return {status: shipped, order_id: order_id}然后在注册表里声明tools: - name: query_order type: python path: ./tools/query_order.py function: query_order schema: ./schemas/query_order.jsonHermes 会按 Tool 声明的 schema 做参数校验不符合直接拒绝执行并返回结构化错误给模型模型会重新生成参数。这种模式让 Agent 在误调用工具时不容易把脏数据带进业务系统。Skill 层面我们把电商售后的完整流程编排成了一个 Skill包含query_order、check_refund_policy、create_refund_ticket三个 Tool用 DSL 定义执行顺序和条件分支。新增一个售后策略时基本不用动代码改业务规则文件就行。4.4 接入第三方工作台和 Bot解析企微加密用户IDHagiCode 的落地场景里有不少客户希望通过企业微信 Bot 来触发 Agent。刚接入那会儿我们就遇到一个热搜词里的问题“Hermes 接入企微 Bot 拿到的会话用户 ID 是加密的怎么解析”实际情况是这样的企微回调给应用的消息体里from字段是一串经过 AES 加密的openId不是明文用户标识。如果直接拿它查业务系统会查不到人。两个方案可以解决方案一在企微管理后台配置可信域名后用官方接口的userid_to_openid/openid_to_userid转换。但要注意这个转换接口不是所有应用类型都开放自建应用通常没问题第三方应用限制多一些。方案二在 HagiCode 的接入层做一个 ID 映射表把企微返回的密文openId存为external_user_id业务系统里维护internal_user_id对应关系。后续 Agent 拿到密文ID先去映射表查明文用户查不到就触发绑定流程。我们最后用的是方案二原因很现实官方接口有时限而且用户在不同企业之间的 ID 规则不一致直接在平台层做映射更通用。接入层用一个中间件在会话启动时统一做 ID 解析Hermes 下游拿到的永远是规范化的用户模型。4.5 空闲时会不会空转无活动时的资源占用排查团队里第一次提出“无活动时宿主机会不会也空运行”这个问题是因为看到容器里 Hermes 进程一直有一个内存占用基线。这个担心是合理的尤其是云服务器按内存计费时空转成本很现实。实测下来Hermes 的空闲资源占用保持在很低的水平。默认事件驱动模型下没有会话任务时异步运行时只保留少量线程驻留CPU 占用接近 0内存基线根据已加载工具数量浮动通常在 100M 以内。不过有一点要注意如果给 Agent 配置了定时任务比如每小时自动扫描未处理工单那即使没有人工会话到点还是会触发执行。这不是空转是正常业务动作。我们后来把这类定时任务单独放一个低优先级队列避免高频任务打占资源。5. 常见问题排查与避坑实录5.1 RPC error (-1)empty sid and service name这个报错我们第一次看到时一头雾水后来定位到原因其实很简单。Hermes 的多进程通信模型里客户端发起工具调用或会话请求时必须带上合法的session id和service nameHarness 才能把请求路由到正确的会话上下文。出现这个错误基本就三种情况注册工具时没有正确传递 session 上下文比如在回调函数里丢失了 context 对象使用 Agent SDK 时客户端没有先创建会话就直接调用工具导致 sid 为空服务端配置里service_name和客户端声明不一致RPC 握手失败。排查顺序建议是先查会话创建日志确认 sid 有没有分配成功再比对配置文件里的 service name最后看 SDK 初始化时是否有遗漏的 context 注入。我们最后还把这个问题总结成了一条写进了团队规范任何自定义 Tool 的第一个参数必须是context里面承载 session_id 和 service_name不允许直接传裸参数列表。规范一立这类问题基本没再出现过。5.2 Agent 工具调用超时与重试策略接入初期我们经常遇到模型调了工具但业务方迟迟没返回的情况。Hermes 默认的工具超时是 5 秒有些业务接口本身就要 8 秒于是 Agent 经常误判工具失败。这里要区分两个超时模型等待工具结果的时间和工具实际执行的时间。如果接口确实慢不要只调大 Harness 的超时更合理的做法是把耗时操作变成异步轮询。我们把create_refund_ticket改成了提交异步任务 轮询状态机Tool 提交任务后立即返回task_id状态为pendingHermes 结束工具调用把task_id回传给模型业务方完成处理后通过回调通知 Harness再由下一个 Skill 节点读取最终结果。这样既不会占着工具调用超时时长也能让 Agent 平滑衔接长事务。这是接入复杂业务系统时非常值得参考的思路。5.3 记忆“写穿”和幻觉回顾记忆层也踩过坑。Hermes 的追加式记忆虽然隔离做得不错但如果不控制写入白名单模型会把一些临时决策当成长期策略写进项目记忆导致后续任务出现莫名其妙的“经验幻觉”。我们的解决方法有三个只允许特定 Skill 在特定时机调用memory.write接口比如订单分单完成、知识库答案被用户采纳时所有记忆写入前必须经过一条校验规则比如是否包含具体业务数据、是否有时间戳、是否和当前任务强相关每周跑一次记忆清洗任务删除过期和低置信度的记录。这套规则执行之后Agent 的行为稳定性明显提升特别是在多轮任务串联的时候。5.4 权限遗漏与越权工具多了之后最怕的是忘记给新工具配置权限。我们有过一次事故上线了一个批量导出工具初始化时权限字段给的是admin结果测试环境验证时直接用普通会话调用成功差一点流到生产。排查之后发现是工具注册表里权限字段拼错了。现在所有 Tool 的权限审核都走一个硬校验权限字段必须是枚举值read_only、executor、admin之一注册时校验不通过直接拒绝加载。另外我们会在测试环境跑一套越权探测用例用只读会话尝试调用所有写操作工具确保都返回 403 权限拒绝。提示权限配置是最不适合“先上线后补”的模块一开始就要从工具的 schema 设计上卡死。5.5 日志检索经验Agent 出问题的时候日志检索效率直接决定排障速度。我们会在每条请求的开始和结束都打印带有session_id的结构化日志然后接一个简单的日志聚合服务。排查问题时直接按 session_id 过滤全链路记录从模型请求到工具执行再到记忆写入一条链路点下来基本能定位问题。6. 一些个人体会写在最后HagiCode 选择 Hermes 作为综合 Agent 核心最核心的判断依据可以总结成一句话我们不能把业务平台建在玩具上。框架层带来的快速原型让我们开心了两周但生产环境的并发、隔离、权限、审计这些硬要求最后都是 Hermes 这类偏向“内核”的运行时来接管的。如果你也在做类似的 Agent 平台我的建议是先别被各种模型头条带偏先明确自己是否需要长期运行、多工具协同、多租户隔离。如果答案是肯定的那就在 Agent 核心层面多花点时间考察别省这一步的功夫。Hermes 不是唯一解但它确实让我们在工程确定性上少走了不少弯路。后续我们还在做技能市场和多 Agent 协作调度这些动作也越来越多的建立在 Hermes 提供的底层能力之上。等跑通了再来分享一波新数据。