实战:把 Hermes 当 Python 库用
Hermes 实战教程第4篇:Python 库。在代码里直接调用 Hermes。
实战:把 Hermes 当 Python 库用
嘿,朋友们!今天咱们来聊点硬核又好玩的东西——把 Hermes 当成一个库来用。别被“库”这个字吓到,其实意思就是:让你的外部程序(比如你自己的 Python 脚本、IDE、网页前端)直接驱动 Hermes 干活。
官方这次一口气给了我们三种协议,就像三把不同的钥匙,开同一扇门(AIAgent 核心)。选哪把,取决于你的“门框”长啥样。
三把钥匙,开同一扇门
| 协议 | 传输方式 | 适合谁 | 代码位置 |
|---|---|---|---|
| ACP | stdio 上的 JSON-RPC | VS Code、Zed、JetBrains 等 IDE 插件 | acp_adapter/ |
| TUI Gateway | stdio 或 WebSocket 上的 JSON-RPC | 想要精细控制会话、审批、流式事件的自定义宿主 | tui_gateway/server.py |
| API Server | HTTP + SSE | Open WebUI、LobeChat 等 OpenAI 兼容前端 | gateway/platforms/api_server.py |
核心思想:三种协议驱动的是同一个 AIAgent 核心,只是“线材”和“接口面板”不同。
钥匙一:ACP(Agent Client Protocol)
这是给 IDE 用的。VS Code、Zed 这些编辑器已经会说 ACP 这门“外语”,所以 Hermes 直接说同一种语言就行。
hermes acp # 在 stdio 上启动 ACP 服务
hermes acp --check # 检查依赖是否装好
hermes acp --setup # 交互式配置提供商和模型
它支持会话创建、提示词提交、流式消息块、工具调用事件、权限请求,甚至**会话分叉(fork)**和取消。工具输出会被渲染成 IDE 能懂的 Diff/ToolCall 块。
钥匙二:TUI Gateway(最灵活)
这是 Ink TUI(hermes --tui)自己用的协议,但任何外部程序都可以通过 stdio 或 WebSocket 说同样的“方言”。
方法列表超丰富,挑几个眼熟的:
prompt.submit session.create session.list
session.activate session.close session.interrupt
config.set / get command.dispatch client.capabilities
gateway.capabilities ping clarify.lock
terminal.resize clipboard.paste image.attach
注意:session.active_list、session.activate、session.close 这三个是进程内活会话控制,用于 TUI 的会话切换器。想找历史记录?用 session.list 或 /resume。
建会话时就能指定模型
session.create 现在支持按会话传 model / provider 覆盖。如果这对组合提供商根本伺候不了(比如 model: gpt-5.5 配 provider: anthropic),网关会当场拒绝,报 JSON-RPC 错误码 -32602,而不是先建好会话、等第一轮才在提供商那边炸掉。错误里还会带上 model、provider 和最多五条 suggestions 供你参考。放心,这个检查是离线的,只拦 Hermes 明确知道“不属于这家”的名字,自定义端点、聚合器、以及目录还没收录的新模型都照常放行。
重写历史:prompt.submit 的“时光倒流”
这个新特性很酷——编辑/重写/重新生成本质上就是一个带“截断”的 prompt.submit。但因为是破坏性写入,网关要求你明确声明意图:
| 参数 | 含义 |
|---|---|
truncate_before_user_ordinal |
从第几个用户轮次开始砍(从 0 数)。必须是整数,传布尔值会报 4004 |
truncate_before_row_id |
SQLite 行 ID,推荐用这个。和 ordinal 同时传会校验是否匹配(不匹配报 4030) |
confirm_truncate |
必须传!声明“我就是要重写,不是普通发送” |
confirm_empty_truncate |
如果砍完整个对话空了(ordinal 0),还得额外传这个 |
重要:截断提交不会被“忙碌输入策略”吞掉。如果当前还有一轮在跑,普通的 prompt.submit 会被转向、改道或排队,但重写/编辑/重新生成会直接报 4009(session busy)——因为排队会把“砍历史”这个动作丢掉,变成在未编辑的轮次后面追加一条普通消息。宿主应该调 session.interrupt 然后重试同一个提交,直到成功。桌面版 App 已经自动这么做了,所以 Hermes 还在思考时你编辑消息,它会先停掉当前轮次,再从编辑后的提示词重新跑。
还有:截断后,prompt.submit 结果会带 survivor_user_row_ids——这是幸存轮次的新行 ID 列表。因为重写会重新插入保留的前缀,所以你之前缓存的所有 row ID 都作废了!记得从这个列表重新绑定,否则下次重写会报 4018。
钥匙三:API Server(HTTP + SSE)
这个最“大众脸”——OpenAI 兼容的 HTTP 接口。Open WebUI、LobeChat、LibreChat 这些前端直接就能接,任何语言的 Web 客户端都能用。
事件流
不管哪把钥匙,事件都长差不多:message.delta、tool.start、gateway.ready、request.cancel…… 注意,审批、澄清、sudo/secret 这些“要你回答的问题”其实是网关发给客户端的 JSON-RPC 请求,不是事件。帧里带一个字符串 id,客户端用同样 id 的普通 JSON-RPC 响应来回答就行。
WebSocket 客户端注意了:连接建立、收到 gateway.ready 之后,记得调一次 client.capabilities 并传 {"server_requests": true},声明“我能回答这些请求”。不调的话,网关会把你当成不支持服务端请求的老版本,所有审批/澄清/sudo 请求都会立刻失败(审批算撤回,不算拒绝),而不是傻等超时。stdio TUI、桌面版和 dashboard 都通过共享的 JsonRpcRequestChannel 自动声明了。
网关撤回一个问题时(超时、中断、或在别处已回答),会发 request.cancel { id, method, reason },外部宿主只清除匹配的那个待处理提示,别误伤。session.resume / session.activate 的结果里还会带 open_requests,重连的客户端可以重新渲染并继续回答。
小结
三种协议,一个核心。选 ACP 给 IDE,选 TUI Gateway 要精细控制,选 API Server 图省事兼容。从今天起,Hermes 不只是命令行工具,更是你程序里的一个“智能引擎”。动手试试吧!
📖 官方文档
本文根据 Hermes Agent 官方文档编写,原文见:官方文档 › developer-guide/programmatic-integration