🤖HermesBlog
Hermes 功能详解 · 第26篇2026/8/9· Easy Understand Hermes Agent

第26篇:API Server——把 Hermes 变成服务

Hermes 功能详解第26篇:API Server。用 HTTP API 调用 Hermes。

API Server:给管家开对外窗口

第26篇:API Server——把 Hermes 变成服务

嘿,朋友们!今天咱们来玩点刺激的——把 Hermes 从“命令行小助手”升级成“7x24小时在线服务”。没错,就是那个传说中的 API Server,让 Hermes 变成一个 OpenAI 兼容的 HTTP 接口。

为啥要这么干?

想象一下:你辛辛苦苦调教好的 Hermes,带着全套工具(终端、文件操作、网页搜索、记忆、技能),现在能直接接入 Open WebUI、LobeChat、LibreChat、NextChat、ChatBox 等几百种前端。这些前端只要会说 OpenAI 的“方言”,就能把 Hermes 当后端用,而且工具调用的进度条还能实时显示,酷不酷?

💡 小贴士:Hermes 自己需要配置好模型提供商和工具后端才能干活。如果你有 Nous Portal 订阅,跑一次 hermes setup --portal 就全搞定了——300+ 模型加上网页/图片/TTS/浏览器工具,一步到位。

三步起飞

第一步:开启 API Server

打开 ~/.hermes/.env,加上这几行:

API_SERVER_ENABLED=true
API_SERVER_KEY=change-me-local-dev
# 可选:如果浏览器要直接访问 Hermes
# API_SERVER_CORS_ORIGINS=http://localhost:3000

第二步:启动网关

hermes gateway

看到这行就说明成功了:

[API Server] API server listening on http://127.0.0.1:8642

第三步:连接前端

把任何 OpenAI 兼容的客户端指向 http://localhost:8642/v1 就行。先用 curl 试试:

curl http://localhost:8642/v1/chat/completions \
  -H "Authorization: Bearer change-me-local-dev" \
  -H "Content-Type: application/json" \
  -d '{"model": "hermes-agent", "messages": [{"role": "user", "content": "Hello!"}]}'

两个核心接口

1. POST /v1/chat/completions —— 标准 OpenAI 聊天格式,无状态,每次请求都带上完整对话历史:

{
  "model": "hermes-agent",
  "messages": [
    {"role": "system", "content": "You are a Python expert."},
    {"role": "user", "content": "Write a fibonacci function"}
  ],
  "stream": false
}

2. POST /v1/responses —— 新版 Responses 格式,支持服务端记忆!用 previous_response_id 就能串联多轮对话,上下文(包括工具调用)全由服务器管理:

{
  "model": "hermes-agent",
  "input": "What files are in my project?",
  "store": true
}

下一轮直接带上 "previous_response_id": "resp_abc123" 就行,省心!

另外,如果你不想自己追踪 response ID,还可以用 conversation 参数给对话起个名字,服务器会自动接到该对话里最新的那条 response 上。/v1/runs 和 /v1/responses 还会保留 X-Hermes-Session-Key 请求头声明的对话;显式的 session 或 response 链优先,且不会把它的对话身份转移到别的请求头上:

{"input": "Hello", "conversation": "my-project"}
{"input": "What's in src/?", "conversation": "my-project"}
{"input": "Run the tests", "conversation": "my-project"}

幂等键:重试不重复干活

POST /v1/chat/completions 和 POST /v1/responses 都接受 Idempotency-Key 请求头。在网关运行会话权威的规范模式下,这个键就是持久的准入身份:第一次带它的请求被准入并只执行一次,之后这个键就归属那次准入。键按已认证的 API profile 和凭据隔离,换个 profile 或轮换了 API_SERVER_KEY 再用同一个客户端键,会被当成新请求。

重试只有在键相同、身份字段相同、目标也相同时才算“精确重试”。改了身份字段,或把键发到另一个会话,就是冲突:请求被拒(admission_conflict),什么都不会执行。Responses(JSON 或流式)和非流式 Chat Completions 返回 HTTP 409 加错误码 admission_conflict;流式 Chat Completions 因为流已经以 HTTP 200 打开,拒绝会作为最后一个 chunk 出现,带 finish_reason: "error" 和 error.message 为 "admission_conflict",随后是 data: [DONE]——要看这个 chunk,而不是状态码。

身份字段按端点不同:Responses 是 input、instructions、previous_response_id、conversation、conversation_history、model、provider、model_options 和 tools,发送时还包括 truncation;Chat Completions 是最后一条用户消息、之前的消息(除非发了 X-Hermes-Session-Id,此时历史来自会话)、系统提示词,以及请求的模型、提供商和 model_options 等轮次设置。tools 和 tool_choice 不算在内:只改这两项的重试会重放原答案,而不是冲突。两个端点的身份都不包含投递方式,所以重试可以在 JSON 和 stream: true 之间切换,拿到同样答案的对应形式。

图片输入?没问题!

两种接口都支持图片。用户消息里用数组传 text 和 image_url 部分,远程 URL 和 base64 的 data:image/... 都行:

{
  "model": "hermes-agent",
  "messages": [
    {
      "role": "user",
      "content": [
        {"type": "text", "text": "What is in this image?"},
        {"type": "image_url", "image_url": {"url": "https://example.com/cat.png", "detail": "high"}}
      ]
    }
  ]
}

注意:上传文件(file / file_id)和非图片的 data: URL 会返回 400 unsupported_content_type。另外,结构化图片内容在执行过程中会保持结构化,不会被当成网关的斜杠命令来解析。

流式输出 & 工具进度

设置 "stream": true 就能开启 SSE 流式响应。Chat Completions 用标准的 chat.completion.chunk 事件,外加 Hermes 自定义的 hermes.tool.progress 事件——前端能实时显示“Agent 正在调用终端工具…”的进度,体验拉满!

Responses 接口则用 OpenAI 原生事件类型(response.created、response.output_text.delta 等),工具调用会以 function_call 和 function_call_output 形式出现在流里,结构化展示工具 UI 毫无压力。

终态语义也统一了:runs 轮询和 SSE 对 cancelled 或 failed 的判断一致;Responses 用同样的终态和 response.cancelled / response.failed 事件(即使带有诊断文本也一样);Chat Completions 对被中断的轮次报 finish_reason: "cancelled",失败报 "error",而不是成功的 "stop"。另外,用光迭代预算(agent.max_turns)的轮次仍会返回 agent 对已发现内容的收尾总结:Chat Completions 用 finish_reason: "length" 和 hermes.error_code: "iteration_budget_exhausted" 交付这段文本,Responses 则报 status: "incomplete"。把它当成一个中途停下但可用的答案,而不是取消。会话聊天回复会带上 status,其流也会报告匹配的终态 run 事件——assistant 的收尾帧本身并不代表执行成功。

顺便说一句,所有 SSE 流(Chat Completions、Responses、/api/sessions/{id}/chat/stream、/v1/runs/{id}/events)在 10 秒没事件时都会发一行 : keepalive 注释,防止长时间工具调用把客户端“晾”到超时。标准 SSE 客户端会自动忽略注释行,自己写解析器的话记得跳过以 : 开头的行。

模型思考过程也能流出来

如果模型本身会输出推理内容,而且配置允许,那思考过程也会一并返回:

  • Chat Completions:思考内容走 choices[0].delta.reasoning_content,正文还是 delta.content。Open WebUI、opencode、Vercel AI SDK 这些前端会把它渲染成“思考块”。
  • Responses:每段思考是一个原生的 reasoning output item,在下一个 message 或 function_call 之前闭合,response.completed 里也会带上。
  • 非流式:/v1/chat/completions 在 choices[0].message.reasoning_content 返回;/v1/responses 则在 message 之前返回 reasoning item,GET /v1/responses/{id} 回放时也一样。
  • 想关掉的话,输入端设 model_options.reasoning.enabled: false 就行。能力开关在 GET /v1/capabilities 里看 features.reasoning_streaming。

另外,Responses 流式模式下,模型在工具调用旁边写的“中途解说”(比如 openai-codex 后端的 phase="commentary" 前言)会作为独立的 message item 返回,带 "phase": "commentary",不会混进最终答案里。不想要的话,display.interim_assistant_messages: false 可以关掉。

还有几个实用接口

除了上面两个核心接口,API Server 还提供了一些辅助端点:

  • GET /v1/models —— 列出可用的模型名(默认就是 profile 名,默认 profile 下是 hermes-agent),大多数前端靠它做模型发现。注意它只是 OpenAI 兼容的“轻量版”,不会枚举所有可路由的提供商/模型组合,也不带价格和能力信息。
  • GET /api/model/options —— Hermes 感知的客户端可以用它拿到和 Dashboard、TUI 一样的精选模型清单,包含提供商、模型能力提示和价格元数据。默认只探测当前选中的自定义端点,加 ?refresh=1 才会全量探测并刷新缓存。
  • GET /v1/capabilities —— 返回一份机器可读的能力描述,告诉外部 UI 当前 Hermes 版本是否支持 runs、流式、取消、会话连续性等,方便做集成时自动发现。
  • GET /api/sessions/{id}/messages —— 拉取某个会话的消息历史。默认只返回“活的”对话记录;加上 include_compacted=true,被上下文压缩归档掉的那些轮次也会一并返回,方便你回看完整来龙去脉。另外,如果客户端是走网络读取、不想被大图拖慢,可以加 inline_images=false,这样图片附件会渲染成 [image] 占位符,而不是内联的 data URI——整个对话记录只有几 KB,传输飞快。

已经退休的老接口:浏览器扩展控制

早期版本有一组给浏览器扩展用的控制协议——POST /v1/browser-control/register、GET /v1/browser-control/ws,以及 /v1/artifacts/* 路由、面板里的 browser.controller.* RPC 和 browser.extension_control 配置项。这些已经整块移除了,因为它们驱动的老工具(browser_navigate / browser_click 那一套)本身也不存在了:现在浏览器自动化统一走 browser_exec(over CDP)。

想让 Hermes 驱动你已经在跑的浏览器,把 config.yaml 的 browser.cdp_url 指向它的 DevTools 端点,或者用 /browser connect。升级时会自动清掉 config.yaml 里残留的 browser.extension_control 段,不用你手动删。

最后说两句

API Server 让 Hermes 从“单机工具”变成了“服务基础设施”。前端随便换,后端不用动。而且工具调用已经在服务器端执行完毕,返回的结果都是 "status": "completed",客户端只管展示,不用操心执行逻辑。

赶紧试试吧!把 Hermes 变成你的私人 AI 后端,配上 Open WebUI 之类的漂亮前端,那感觉,真香!

📖 官方文档

本文根据 Hermes Agent 官方文档编写,原文见:官方文档 › user-guide/features/api-server