Appearance
Hermes Harness核心架构解析:上下文、工具、权限与执行控制
Agent要进入真实工作流,需要一套围绕模型的工程约束。模型是能力源,Harness决定这股能力能不能走出demo。
为什么需要Harness?
大模型的本质是文字输入→推理→文字输出。但它自己不会调工具,不会管理上下文、处理错误、记住上次做了什么。这些能力需要外面有一层系统来提供。
在软件工程里,test harness是一个成熟概念——围绕被测代码搭的那层基础设施,提供输入、捕获输出、管理执行环境。Harness是Agent的运行时:模型负责提供能力,但任务怎么推进、工具怎么用、状态怎么保存,都由这层系统处理。
现在做Agent项目,一开始都一个样:接一个模型,写一段系统提示词,加几个工具函数。这个阶段很容易出效果。但用户意图是无限的——今天查资料,明天改方案,后天加新限制。Agent做一半发现缺权限、环境不对、工具返回错误无法理解。原来那个模型加函数的结构很快就撑不住了。
这些判断不能都靠模型在prompt里猜,得在模型外面有一层系统管起来。
一、上下文管理
Hermes的上下文管理是分层结构,不是简单的"把历史消息全塞进去"。
分层设计
每一层解决的问题不同,管理粒度也不同:
| 层级 | 内容 | 特点 |
|---|---|---|
| 模型上下文 | 当前轮次的prompt | 最浅的一层 |
| 数据库会话 | 用户的消息记录 | 持久化存储 |
| 记忆 | 冻结在会话开始时的快照 | 不随对话漂移 |
| 技能 | 可复用的操作笔记 | 跨会话共享 |
| 知识 | 项目文档和PRD | 最新状态 |
几个关键设计:
| 设计 | 说明 |
|---|---|
| 系统提示词越稳定越靠前 | 前缀固定有助于缓存命中,降低token消耗 |
| 记忆在会话开始时冻结成快照 | 保证同一会话内记忆不漂移,避免Agent自己改自己 |
| 上下文压缩后开新会话接父子链 | 长对话压缩后不覆盖旧会话,保留可回溯的历史 |
二、工具编排
工具是Agent影响真实世界的唯一通道。工具接口设计决定了Agent的稳定上限。
| 要求 | 说明 |
|---|---|
| 参数名要自描述 | 好的工具参数名本身就是文档 |
| 枚举值配说明 | Agent需要知道每个选择意味着什么 |
| 失败原因要可判断 | 错误信息不只是给人看日志,还要让Agent决定下一步 |
最容易被忽略的是工具的描述和参数描述。模型不看源码,只读接口签名。如果参数名叫 param1,描述是"参数1",模型根本不知道怎么填。
工具文档不光写给开发者看,更要写给Agent看。好的工具接口,Agent不用猜就能用对。
三、执行控制
预算控制
| 机制 | 作用 |
|---|---|
| 子任务心跳 | 父Agent每30秒给子Agent发一次心跳 |
| 级联中断 | 父被中断后心跳断开,子Agent连锁停下 |
| 用户中断处理 | break出循环→持久化已有结果→返回interrupted=True |
关键细节:用户中断时,如果前面有工具调用已追加到消息列表但还没执行,系统会补一个伪造的错误tool result,保证消息结构对API合法。下次恢复对话时不会被Provider拒绝。
错误恢复
主循环每一步都可能出问题:上下文不够、API超时、凭证限流、服务器500。Hermes的做法是按错误分类,各走各的恢复路径,而不是一个大try/except。
14种FailoverReason枚举 → ClassifiedError → 4个布尔恢复标记:
| 标记 | 含义 |
|---|---|
| retryable | 能不能直接重试 |
| should_compress | 要不要先压缩上下文再重试 |
| should_rotate_credential | 要不要切到下一个API Key |
| should_fallback | 要不要切到fallback模型 |
为什么分这么细? 一个典型对比:HTTP 402(额度耗尽)和429(临时限流)。
| 错误 | 表面 | 实际处理 |
|---|---|---|
| 429 临时限流 | 请求太快 | 退避重试同一个Key |
| 402 额度耗尽 | 账户没钱 | 立即切到下一个Key |
不分清楚的话,Agent会在一个已经没钱的Key上反复退避到天荒地老。
权限与安全
Agent不是只在聊天框里生成文字——它开始影响真实环境:改文件、跑命令、调外部API、发消息。
权限控制最好绑定到具体动作和上下文,而不是只绑定到某个工具名:
| 动作 | 策略 |
|---|---|
| 写文件到/tmp | 直接放行 |
| 改.env/配置文件 | 必须确认 |
| ls/cat/git status | 读状态命令通常放行 |
| 删除/覆盖/部署 | 必须确认 |
| 查订单信息 | 读操作放行 |
| 取消订单 | 必须确认 |
| 发消息/改共享记忆 | 必须审批 |
Hermes的设计:
- 工具集可启停,危险命令要审批
- 子Agent不能无限套娃,不能直接写共享记忆
- 父Agent中断后子Agent连锁停下
四、经验沉淀:Skills
Agent做完一次任务,如果留下的只是聊天记录,那它没有变聪明。
Hermes的做法:任务结束后,另起一个安静的mini Agent回看对话,判断有没有值得保存的方法。这个动作放在用户收到回复之后,不抢主任务注意力,不增加用户等待时间。
Skills = 可复用的操作笔记
- 某个项目怎么跑测试 → 沉淀为Skill
- 某类问题怎么排查 → 沉淀为Skill
- 某工具有什么坑 → 沉淀为Skill
一个团队不会因为项目做完了就自然变强,Agent也一样。Skills机制让Agent不只是把眼前事做完,还把经验带到下一轮。
五、软件要适应Agent
如果Harness继续成熟,软件本身也会被反向改造。
过去做软件,默认使用者是人。但Agent进入工作流以后,软件会多出另一种使用者。
| 对API的要求 | 说明 |
|---|---|
| 当前状态能否提交 | 前置条件 |
| 提交前要补齐什么字段 | 输入要求 |
| 失败了是缺字段还是没权限 | 错误语义 |
| 这个动作会造成什么后果 | 风险边界 |
核心变化:软件除了给人看、给人点,还要把一部分能力整理成Agent能理解、能判断、能安全调用的形式。功能入口不仅是页面按钮,也可能是Agent编排任务时的一块积木。
总结
| 层面 | 关键能力 |
|---|---|
| 上下文 | 分层管理,记忆快照冻结,压缩不丢失 |
| 工具 | 接口自描述,参数名即文档 |
| 执行控制 | 预算+中断+级联 |
| 错误恢复 | 分类器映射14种错误到4个恢复标记 |
| 权限 | 绑定到具体动作,而非工具名 |
| 经验 | Skills机制,持续积累 |
一个Demo能跑通,说明不了太多。真正值得看的,是它连续跑十几轮之后还稳不稳;出错的时候,会不会停下来而不是继续硬冲;任务做完以后,有没有把过程里的经验留下来。
关键词:Hermes Agent, Harness架构, Agent运行时, 上下文管理, 工具编排, 权限控制, 错误恢复
