跳转到内容

Hermes

3 篇包含标签 "Hermes" 的文章

Hermes Agent 集成实践:从协议到生产

Hermes Agent 集成实践:从协议到生产

Section titled “Hermes Agent 集成实践:从协议到生产”

分享 HagiCode 集成 Hermes Agent 的完整实践,包括 ACP 协议适配、会话池管理、前后端契约同步等核心经验。

在构建 AI 辅助编码平台 HagiCode 的过程中,团队需要集成一个既能在本地运行又能扩展到云端的 Agent 框架。经过调研,Nous Research 的 Hermes Agent 被选为综合 Agent 的底层引擎。

其实选型这事儿,说难也不难,说简单也不简单。毕竟市面上能打的 Agent 框架也不少,只是 Hermes 那个 ACP 协议和工具系统确实有点东西,刚好契合 HagiCode “既要又要”的需求场景——本地开发、团队协作和云端扩展。但要把 Hermes 真正融入生产系统,还需要解决一系列工程问题,这可不是闹着玩的。

HagiCode 的技术栈基于 Orleans 构建分布式系统,前端使用 React + TypeScript。集成 Hermes 需要在保持现有架构统一性的前提下,让 Hermes 成为与 ClaudeCode、OpenCode 等并行的”一等公民”执行器。说起来容易,做起来嘛,也就那样吧。

本文分享我们在 HagiCode 项目中集成 Hermes Agent 的实践经验,希望能给面临类似需求的团队提供参考。毕竟,踩过的坑,没必要让别人再踩一遍。

本文分享的方案来自我们在 HagiCode 项目中的实践经验。HagiCode 是一个 AI 驱动的编码辅助平台,支持多种 AI Provider 的统一接入和管理。在集成 Hermes Agent 的过程中,我们设计了一套通用的 Provider 抽象层,使得新的 Agent 类型可以无缝接入现有系统。

如果你对 HagiCode 感兴趣,欢迎访问 GitHub 了解更多。多个人看,多份力量罢了。

HagiCode 的 Hermes 集成采用了清晰的分层架构,每层各司其职:

后端核心层

  • HermesCliProvider: 实现 IAIProvider 接口,作为统一的 AI Provider 入口
  • HermesPlatformConfiguration: 管理 Hermes 可执行文件路径、参数、认证等配置
  • ICliProvider<HermesOptions>: HagiCode.Libs 提供的底层 CLI 抽象,处理子进程生命周期

传输层

  • StdioAcpTransport: 通过标准输入输出与 Hermes ACP 子进程通信
  • ACP 协议方法:initializeauthenticatesession/newsession/prompt

运行时层

  • HermesGrain: Orleans Grain 实现,处理分布式会话执行
  • CliAcpSessionPool: 会话池,复用 ACP 子进程,避免频繁启动开销

前端层

  • ExecutorAvatar: Hermes 视觉标识和图标
  • executorTypeAdapter: Provider 类型映射逻辑
  • SignalR 实时消息传递:保持 Hermes 身份在消息流中的一致性

这种分层设计使得各层可以独立演进,比如未来要添加新的传输方式(如 WebSocket),只需修改传输层即可。毕竟,谁愿意因为改一个传输方式就把整个系统都翻一遍呢?多累啊。

所有 AI Provider 都实现 IAIProvider 接口,这是 HagiCode 架构的核心设计:

public interface IAIProvider
{
string Name { get; }
ProviderCapabilities Capabilities { get; }
IAsyncEnumerable<AIStreamingChunk> StreamAsync(
AIRequest request,
CancellationToken cancellationToken = default);
Task<AIResponse> ExecuteAsync(
AIRequest request,
CancellationToken cancellationToken = default);
}

HermesCliProvider 实现了这个接口,与 ClaudeCodeProviderOpenCodeProvider 等处于平等地位。这种设计带来的好处:

  1. 可替换性: 切换 Provider 不影响上层业务逻辑
  2. 可测试性: 可以轻松 Mock Provider 进行单元测试
  3. 可扩展性: 新增 Provider 只需实现接口即可

说到底,接口这东西,就像规矩一样。有了规矩,大家才能和谐共处,各自发挥所长,互不干扰。这难道不是一种美吗?

HermesCliProvider 是整个集成的核心,它负责协调各个组件完成一次 AI 调用:

public sealed class HermesCliProvider : IAIProvider, IVersionedAIProvider
{
private readonly ICliProvider<LibsHermesOptions> _provider;
private readonly ConcurrentDictionary<string, string> _sessionBindings;
public ProviderCapabilities Capabilities { get; } = new()
{
SupportsStreaming = true,
SupportsTools = true,
SupportsSystemMessages = true,
SupportsArtifacts = false
};
public async IAsyncEnumerable<AIStreamingChunk> StreamAsync(
AIRequest request,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
// 1. 解析会话绑定 key
var bindingKey = ResolveBindingKey(request.CessionId);
// 2. 通过会话池获取或创建 Hermes 会话
var options = new HermesOptions
{
ExecutablePath = _platformConfiguration.ExecutablePath,
Arguments = _platformConfiguration.Arguments,
SessionId = _sessionBindings.TryGetValue(bindingKey, out var sessionId) ? sessionId : null,
WorkingDirectory = request.WorkingDirectory,
Model = request.Model
};
// 3. 执行并收集流式响应
await foreach (var message in _provider.ExecuteAsync(options, request.Prompt, cancellationToken))
{
// 4. 映射 ACP 消息到 AIStreamingChunk
if (_responseMapper.TryConvertToStreamingChunk(message, out var chunk))
{
yield return chunk;
}
}
}
}

这里有几个关键设计点:

  1. 会话绑定: 通过 CessionId 将多个请求绑定到同一个 Hermes 子进程,实现多轮对话的上下文连续性
  2. 响应映射: 将 Hermes ACP 消息格式转换为统一的 AIStreamingChunk 格式
  3. 流式处理: 使用 IAsyncEnumerable 支持真正的流式响应

其实会话绑定这事儿,就像人和人之间的关系一样。一旦建立了联系,后续的交流就有了上下文,不用每次都从头开始。只是这关系要维护好,不然断了就断了。

Hermes 使用 ACP(Agent Communication Protocol)协议,与传统的 HTTP API 不同。ACP 是基于标准输入输出的协议,有几个特点:

  1. 启动标记: Hermes 进程启动后会输出 //ready 标记
  2. 动态认证: 认证方法不是固定的,需要通过协议协商
  3. 会话复用: 通过 SessionId 复用已建立的会话
  4. 响应分散: 完整响应可能分散在多个 session/update 通知中

HagiCode 通过 StdioAcpTransport 处理这些特性:

public class StdioAcpTransport
{
public async Task InitializeAsync(CancellationToken cancellationToken)
{
// 等待 //ready 标记
var readyLine = await _outputReader.ReadLineAsync(cancellationToken);
if (readyLine != "//ready")
{
throw new InvalidOperationException("Hermes did not send ready signal");
}
// 发送 initialize 请求
await SendRequestAsync(new
{
jsonrpc = "2.0",
id = 1,
method = "initialize",
@params = new
{
protocolVersion = "2024-11-05",
capabilities = new { },
clientInfo = new { name = "HagiCode", version = "1.0.0" }
}
}, cancellationToken);
}
}

协议这东西,就像人与人之间的默契。有了默契,交流就会顺畅很多。只是建立默契需要时间,磨合嘛,谁都免不了。

频繁启动 Hermes 子进程的开销很大,因此我们实现了会话池机制:

services.AddSingleton(static _ =>
{
var registry = new CliProviderPoolConfigurationRegistry();
registry.Register("hermes", new CliPoolSettings
{
MaxActiveSessions = 50,
IdleTimeout = TimeSpan.FromMinutes(10)
});
return registry;
});

会话池的关键参数:

  • MaxActiveSessions: 控制并发上限,避免资源耗尽
  • IdleTimeout: 空闲超时,平衡启动成本和内存占用

实践中我们发现:

  1. 空闲超时设置太短会导致频繁重启,设置太长会占用内存
  2. 并发上限需要根据实际负载调整,过大可能导致系统卡顿
  3. 需要监控会话池的使用情况,以便及时调整参数

这就好比人生中的许多选择,太激进容易出问题,太保守又错失机会。找个平衡点罢了。

前端需要正确识别 Hermes Provider 并显示对应的视觉元素:

executorTypeAdapter.ts
export const resolveExecutorVisualTypeFromProviderType = (
providerType: PCode_Models_AIProviderType | null | undefined
): ExecutorVisualType => {
switch (providerType) {
case PCode_Models_AIProviderType.HERMES_CLI:
return 'Hermes';
default:
return 'Unknown';
}
};

Hermes 有专属的图标和颜色标识:

ExecutorAvatar.tsx
const renderExecutorGlyph = (executorType: ExecutorVisualType, iconSize: number) => {
switch (executorType) {
case 'Hermes':
return (
<svg viewBox="0 0 24 24" fill="none" className="h-4 w-4">
<rect x="4" y="4" width="16" height="16" rx="4" fill="currentColor" opacity="0.16" />
<path d="M8 7v10M16 7v10M8 12h8" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
</svg>
);
default:
return <DefaultAvatar />;
}
};

毕竟,美的东西也要有美的呈现。只是这美要被人看见,还得靠前端同学的努力。

前后端通过 OpenAPI 生成保持契约一致。后端定义了 AIProviderType 枚举:

public enum AIProviderType
{
Unknown,
ClaudeCode,
OpenCode,
HermesCli // 新增
}

前端通过 OpenAPI 生成对应的 TypeScript 类型,确保枚举值一致。这是避免前端显示 “Unknown” 的关键。

契约这东西,就像承诺一样。说好了就要做到,不然就会出现”Unknown”这种尴尬的局面。

Hermes 的配置通过 appsettings.json 管理:

{
"Providers": {
"HermesCli": {
"ExecutablePath": "hermes",
"Arguments": "acp",
"StartupTimeoutMs": 10000,
"ClientName": "HagiCode",
"Authentication": {
"PreferredMethodId": "api-key",
"MethodInfo": {
"api-key": "your-api-key-here"
}
},
"SessionDefaults": {
"Model": "claude-sonnet-4-20250514",
"ModeId": "default"
}
}
}
}

这种配置驱动的设计带来了灵活性:

  • 可以覆盖可执行文件路径,方便开发测试
  • 可以自定义启动参数,适配不同版本的 Hermes
  • 可以配置认证信息,支持多种认证方式

配置这东西,就像人生的选择题。给足了选项,总能找到适合自己的那一个。只是有时候选项太多,也会让人犯选择困难症。

实现一个可靠的 Provider 需要完善的健康检查:

public async Task<ProviderTestResult> PingAsync(CancellationToken cancellationToken = default)
{
var response = await ExecuteAsync(new AIRequest
{
Prompt = "Reply with exactly PONG.",
CessionId = null,
AllowedTools = Array.Empty<string>(),
WorkingDirectory = ResolveWorkingDirectory(null)
}, cancellationToken);
var success = string.Equals(response.Content.Trim(), "PONG", StringComparison.OrdinalIgnoreCase);
return new ProviderTestResult
{
ProviderName = Name,
Success = success,
ResponseTimeMs = stopwatch.ElapsedMilliseconds,
ErrorMessage = success ? null : $"Unexpected Hermes ping response: '{response.Content}'."
};
}

健康检查需要注意:

  1. 使用简单的测试用例,避免复杂场景
  2. 设置合理的超时时间
  3. 记录响应时间,便于性能分析

就像人需要体检一样,系统也需要健康检查。早发现早治疗,省得到时候出大问题。

HagiCode 提供专用控制台用于验证 Hermes 集成:

Terminal window
# 基础验证
HagiCode.Libs.Hermes.Console --test-provider
# 完整套件(含仓库分析)
HagiCode.Libs.Hermes.Console --test-provider-full --repo .
# 自定义可执行文件
HagiCode.Libs.Hermes.Console --test-provider-full --executable /path/to/hermes

这个工具在开发过程中非常有用,可以快速验证集成是否正确。毕竟,谁愿意在发现问题的时候才想起来去测试呢?

认证失败

  • 检查 Authentication.PreferredMethodId 与 Hermes 实际支持的认证方法是否匹配
  • 确认认证信息格式正确(API Key、Bearer Token 等)

会话超时

  • 增加 StartupTimeoutMs
  • 检查 MCP 服务器可达性
  • 查看系统资源使用情况

响应不完整

  • 确保正确聚合 session/update 通知和最终结果
  • 检查流式处理的取消逻辑
  • 验证错误处理是否完整

前端显示 Unknown

  • 确认 OpenAPI 生成已包含 HermesCli 枚举值
  • 检查类型映射是否正确
  • 清除浏览器缓存重新生成类型

问题嘛,总会有的。只是遇到问题的时候,别慌,慢慢找原因,总能解决的。毕竟,办法总比困难多。

  1. 使用会话池: 复用 ACP 子进程,减少启动开销
  2. 合理设置超时: 平衡内存和启动成本
  3. 复用会话 ID: 批量任务使用同一个 CessionId
  4. 按需配置 MCP: 避免不必要的工具调用

性能这东西,就像生活中的效率。做对了,事半功倍;做错了,事倍功半。只是找到那个”对”的点,需要经验和运气。

集成 Hermes Agent 到生产系统需要考虑多个层面的问题:

  1. 架构层面: 设计统一的 Provider 接口,实现可替换的组件架构
  2. 协议层面: 正确处理 ACP 协议的特殊性,如启动标记、动态认证等
  3. 性能层面: 通过会话池复用资源,平衡启动成本和内存占用
  4. 前端层面: 确保契约同步,提供一致的视觉体验

HagiCode 的实践表明,通过良好的分层设计和配置驱动,可以将复杂的 Agent 系统无缝集成到现有架构中。

其实这些道理说起来都挺简单的,只是真正做起来的时候,总会遇到各种各样的问题。不过没关系,问题解决了就是经验,解决不了就是教训,都是有价值的东西。

美的事物或人,不一定要占有,只要她还是美的,自己好好看着她的美就好了。技术也是如此,只要能让系统变得更好,用什么框架、什么协议,其实都没那么重要…

感谢您的阅读,如果您觉得本文有用,欢迎点赞、收藏和分享支持。 本内容采用人工智能辅助协作,最终内容由作者审核并确认。

如何安装和使用 Hermes:从本地 CLI 到 Feishu 接入快速上手

想安装并开始使用 Hermes,最短路径其实只有三步:

  1. 运行官方安装命令
  2. 在终端里用 hermes 启动 CLI
  3. 如果你想在飞书里继续用,再配置 hermes gateway setup

这篇文章不打算把 Hermes 的所有能力一次讲完,而是先帮你完成最关键的入门闭环:装上、跑起来、开始用,然后再接一个最常见的消息平台场景。

Hermes Agent 是一个既可以在本地终端使用,也可以通过消息平台网关使用的 AI agent。

对大多数开发者来说,它有两个最常见的入口:

  • CLI:在终端里输入 hermes,直接进入交互式界面
  • Messaging Gateway:运行 hermes gateway,再从 Feishu、Telegram、Discord、Slack 等平台和它对话

如果你现在的目标只是快速上手,建议顺序不要反过来,先走这条路线:

  • 先安装 Hermes
  • 先从 CLI 验证是否可用
  • 再决定要不要接消息平台

这样更容易定位问题,也更适合第一次接触 Hermes 的用户。

根据 Hermes README,官方快速安装路径支持这些环境:

  • Linux
  • macOS
  • WSL2
  • Android via Termux

Hermes 当前不支持原生 Windows 直接运行。如果你使用 Windows,推荐先安装 WSL2,再在 WSL2 里执行安装命令。

这点最好在文章开头就说清楚,因为很多安装失败其实不是命令问题,而是运行环境不符合要求。

Hermes README 给出的快速安装命令是:

Terminal window
curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash

这条命令会执行官方安装脚本,处理平台相关的初始化流程。

安装结束后,先重新加载 shell 环境。最常见的是:

Terminal window
source ~/.bashrc

如果你用的是 zsh,也可以改成:

Terminal window
source ~/.zshrc

最直接的检查方式就是运行:

Terminal window
hermes

如果你想进一步确认配置和依赖是否正常,可以再执行:

Terminal window
hermes doctor

hermes doctor 适合在这些时候使用:

  • 安装后命令行为不正常
  • 模型配置失败
  • gateway 启动失败
  • 不确定环境依赖是否完整

如果你只是想尽快确认 Hermes 能不能用,最简单的方法就是:

Terminal window
hermes

这会启动 Hermes 的交互式 CLI。对于第一次接触 Hermes 的用户,这也是最推荐的起点,因为你可以先验证最核心的几件事:

  • 命令是否真的可用
  • 当前模型配置是否正常
  • 终端工具链是否工作正常
  • 交互体验是不是你需要的那种方式

这几个命令足够你完成第一轮配置

Section titled “这几个命令足够你完成第一轮配置”

Hermes README 里列出的几条高频命令,基本就构成了第一轮上手路径:

Terminal window
hermes model
hermes tools
hermes config set
hermes setup
hermes update
hermes doctor

如果你不知道它们各自是做什么的,可以先这样记:

  • hermes model:选模型、切模型
  • hermes tools:看和配当前可用工具
  • hermes config set:改具体配置项
  • hermes setup:跑一次完整初始化向导
  • hermes update:更新 Hermes
  • hermes doctor:做故障排查

对新手最实用的顺序通常是:

  1. 先运行 hermes model
  2. 如果你希望一次把常用项配完整,再运行 hermes setup

1. 在终端里把 Hermes 当成日常开发助手

Section titled “1. 在终端里把 Hermes 当成日常开发助手”

CLI 模式适合这些场景:

  • 本地写代码时直接问问题
  • 查项目、改文件、跑命令
  • 做一次性调试或 review
  • 在当前工作目录里持续协作

它最大的优点就是路径最短:不用额外接平台,不用先处理机器人配置,也最适合建立第一轮使用习惯。

如果你希望在飞书、Telegram、Discord 等平台上和 Hermes 对话,就需要使用 messaging gateway。

最常见的入口命令是:

Terminal window
hermes gateway setup
hermes gateway

其中:

  • hermes gateway setup 用来做交互式平台配置
  • hermes gateway 用来启动网关进程

根据官方文档,gateway 是一个统一的后台进程,用来连接你已配置的平台、管理会话,并处理定时任务等功能。

以 Feishu 为例,如何把 Hermes 接入消息平台

Section titled “以 Feishu 为例,如何把 Hermes 接入消息平台”

如果你的日常工作主要在飞书里,那么 Feishu/Lark 会是一个很自然的 Hermes 接入方式。

官方文档对 Feishu/Lark 的推荐入口是:

Terminal window
hermes gateway setup

运行后,在向导中选择 Feishu / Lark 即可。

Feishu 文档给出的两种连接模式是:

  • websocket:推荐
  • webhook:可选

如果 Hermes 跑在你的笔记本、工作站或者私有服务器上,优先使用 websocket 会更简单,因为不需要额外暴露公网回调地址。

如果你手动配置,至少要知道这些变量

Section titled “如果你手动配置,至少要知道这些变量”

如果你不是通过向导配置,而是手动写配置,Feishu 文档里列出的核心变量包括:

Terminal window
FEISHU_APP_ID=cli_xxx
FEISHU_APP_SECRET=***
FEISHU_DOMAIN=feishu
FEISHU_CONNECTION_MODE=websocket
FEISHU_ALLOWED_USERS=ou_xxx,ou_yyy
FEISHU_HOME_CHANNEL=oc_xxx

其中最值得注意的是两项:

  • FEISHU_ALLOWED_USERS:建议配置,避免任何能接触到 bot 的人都可以直接使用它
  • FEISHU_HOME_CHANNEL:可以预先指定一个 home chat,用来接收 cron 结果或默认通知

这一点很容易被忽略:在 Feishu 群聊里,Hermes 默认不是看到每条消息都响应。

官方文档明确说明:

  • 私聊时,Hermes 会响应消息
  • 群聊里,必须显式 @ bot,它才会处理消息

如果你想把某个飞书会话设成 home channel,也可以在聊天里使用:

/set-home

或者提前在配置里写:

Terminal window
FEISHU_HOME_CHANNEL=oc_xxx

不管你是在 CLI 里,还是在消息平台里,先记住下面这些命令就已经够用了:

  • /new/reset:开始新会话
  • /model:查看或切换模型
  • /retry:重试上一轮
  • /undo:撤销上一轮交互
  • /compress:手动压缩上下文
  • /help:查看帮助

如果你主要在消息平台里使用,再额外记住一个:

  • /sethome/set-home:把当前聊天设为 home channel

这些命令覆盖了新手阶段最常见的操作:重开、调整、回退、查看和继续用。

不能。当前官方文档明确说明,原生 Windows 不支持,推荐使用 WSL2。

安装之后输入 hermes 没反应怎么办?

Section titled “安装之后输入 hermes 没反应怎么办?”

建议按下面顺序排查:

  1. 先重新加载 shell,例如 source ~/.bashrc
  2. 再重新运行 hermes
  3. 如果还是异常,执行 hermes doctor

先检查这三项:

  • 你有没有在群里 @ Hermes
  • FEISHU_ALLOWED_USERS 是否限制了当前用户
  • 当前群聊策略是否允许处理群消息

根据官方 Feishu 文档,群聊场景里,显式 @mention 是必要条件。

如果你只是想尽快开始使用 Hermes,最推荐的顺序是:

  1. 先执行安装命令
  2. 先用 hermes 在本地 CLI 里开始
  3. 再用 hermes modelhermes setup 补齐基础配置
  4. 如果你希望在飞书里继续使用,再配置 hermes gateway setup

如果这篇文章作为一个系列的第一篇,它最适合承担的角色不是“把所有高级功能一次讲完”,而是先把用户带进门。

后续更适合继续拆分成这些主题:

  • Hermes Feishu 接入完整指南
  • Hermes 常用 slash commands 指南
  • Hermes gateway 配置与排错指南

如果你准备继续做 Hermes 内容,这篇就可以作为后续文章的起点,并逐步把内部链接体系补起来。

HagiCode 为什么选择 Hermes 作为综合 Agent 核心

HagiCode 为什么选择 Hermes 作为综合 Agent 核心

Section titled “HagiCode 为什么选择 Hermes 作为综合 Agent 核心”

在构建 AI 辅助编码平台时,选择合适的 Agent 核心直接决定了系统能力的天花板。毕竟有些事情,勉强不来——选错了框架,怎么折腾都不得劲。本文分享 HagiCode 在技术选型中的思考,以及 Hermes Agent 的集成实践。

做 AI 辅助编码这事儿,最头疼的莫过于选择底层 Agent 框架了。其实市面上可选的方案也挺多的,只是吧——有的功能太简单,有的部署太复杂,有的扩展性又不够看。我们要的是一个既能跑在 5 美元 VPS 上,又能接入 GPU 集群的方案,这要求说高也不高,说低吧,也不少人被劝退了。

但实际情况是,很多所谓的”全能 Agent” 要么只能跑在云端,要么本地部署要求高得离谱。花了两周时间调研各种方案后,我们做了一个大胆的决定:整个 Agent 核心推倒重来,采用 Hermes 作为综合 Agent 的底层引擎。

这决定带来的一切,或许都是冥冥之中罢。

本文分享的方案来自 HagiCode 项目中的实践经验。HagiCode 是一个 AI 辅助编码平台,通过 VSCode 扩展、桌面客户端和 Web 服务,为开发者提供智能编码助手。或许你也用过类似的工具,只是总觉得差了那么一口气——这我们也理解。

在详细介绍 Hermes 之前,先说说 HagiCode 为什么会有这样的需求。这世上的事情啊,往往不是你想怎么样就能怎么样的,总得找个合适的由头。

作为一个 AI 代码助手,HagiCode 需要同时支持多种使用场景:

  • 本地开发环境:开发者希望在自gu电脑上运行,数据不出本地——这年头,数据安全这事说大不大,说小也不小
  • 团队协作环境:小团队可以共享部署在服务器上的 Agent——省钱嘛,大家都不容易
  • 云端弹力扩展:处理复杂任务时,能自动扩展到 GPU 集群——有备无患

这种”既要又要”的需求,让我们把目光投向了 Hermes。这选择对不对我不知道,只是当时也没别的更好的办法了。

Hermes Agent 是由 Nous Research 创建的自主 AI Agent。可能有人对 Nous Research 不熟悉——他们就是开发了 Hermes、Nomos 和 Psyché 等开源大模型的实验室。说起来他们也挺不容易的,做了这么多好东西,知道的人却不多。

跟传统的 IDE 编程助手或者简单的 API 聊天包装器不同,Hermes 有一个特点:运行时间越长,能力越强。它不是一次性完成任务就完事,而是能在长时间运行中持续学习和积累经验。这点也挺像人的,是不是?

Hermes 的几个核心特性,正好契合了 HagiCode 的需求。你说巧不巧?

这意味着 HagiCode 可以根据用户场景,选择最合适的部署方式。个人用户本地跑,团队用户服务器部署,复杂任务上 GPU——一套代码搞定。这世道,能省一事算一事罢。

多平台消息网关 Hermes 原生支持 Telegram、Discord、Slack、WhatsApp 等平台。对 HagiCode 来说,这意味着未来可以轻松支持这些渠道的 AI 助手。毕竟谁不想多几条路呢?

丰富的工具系统 40+ 内置工具,加上 MCP(Model Context Protocol)扩展能力。这对于代码助手来说太重要了——执行 shell 命令、操作文件系统、调用 Git,这些都需要工具支持。没有工具的 Agent,就像没有翅膀的鸟——想飞也飞不起来。

跨会话记忆 Hermes 有持久记忆系统,用 FTS5 全文检索召回历史对话。这让 Agent 能记住之前的上下文,不会每次都”失忆”。有时候我也想失忆一下,什么都不想,可就是做不到。

说完了”为什么”,接下来看看”怎么做”。有些事情想明白了,就得动手,光想不做也不是个事儿。

在 HagiCode 的架构中,所有 AI Provider 都实现统一的 IAIProvider 接口:

public sealed class HermesCliProvider : IAIProvider, IVersionedAIProvider
{
public ProviderCapabilities Capabilities { get; } = new ProviderCapabilities
{
SupportsStreaming = true, // 支持流式输出
SupportsTools = true, // 支持工具调用
SupportsSystemMessages = true, // 支持系统提示
SupportsArtifacts = false
};
}

这个抽象层让 HagiCode 可以无缝切换不同的 AI Provider,无论是 OpenAI、Claude 还是 Hermes,上层调用方式完全一致。说白了,就是省事儿。

Hermes 使用 ACP (Agent Communication Protocol) 进行通信。这是一个专门为 Agent 通信设计的协议,主要方法包括:

方法说明
initialize初始化连接,获取协议版本和客户端能力
authenticate处理认证,支持多种认证方法
session/new创建新会话,设置工作目录和 MCP 服务器
session/prompt发送提示并获取响应

HagiCode 通过 StdioAcpTransport 实现 ACP 传输层,启动 Hermes 子进程并通过标准输入输出进行通信。这事儿听起来复杂,做起来也还行——主要是要有耐心。

通过 HermesPlatformConfiguration 类管理配置:

public sealed class HermesPlatformConfiguration : IAcpPlatformConfiguration
{
public string ExecutablePath { get; set; } = "hermes";
public string Arguments { get; set; } = "acp";
public int StartupTimeoutMs { get; set; } = 5000;
public string ClientName { get; set; } = "HagiCode";
public HermesAuthenticationConfiguration Authentication { get; set; }
public HermesSessionDefaultsConfiguration SessionDefaults { get; set; }
}

appsettings.json 中配置 Hermes:

{
"Providers": {
"HermesCli": {
"ExecutablePath": "hermes",
"Arguments": "acp",
"StartupTimeoutMs": 10000,
"ClientName": "HagiCode",
"Authentication": {
"PreferredMethodId": "api-key",
"MethodInfo": {
"api-key": "your-api-key-here"
}
},
"SessionDefaults": {
"Model": "claude-sonnet-4-20250514",
"ModeId": "default"
}
}
}
}

配置这东西吧,看着简单,真要调对了也得费些功夫。

HagiCode 使用 Orleans 构建分布式系统,Hermes 集成通过以下组件实现:

  • HermesGrain:Orleans Grain 实现,处理会话执行
  • HermesPlatformConfiguration:平台特定配置
  • HermesAcpSessionAdapter:ACP 会话适配器
  • HermesConsole:专用的验证控制台

Orleans 这名字起得挺好听的,传说中的阿里巴巴——虽然此 Orleans 非彼 Orleans,但名字好听总是加分的。

以下是 Hermes Provider 的核心执行逻辑:

private async IAsyncEnumerable<AIStreamingChunk> StreamCoreAsync(
AIRequest request,
string? embeddedCommandPrompt,
[EnumeratorCancellation] CancellationToken cancellationToken)
{
// 1. 创建传输层,启动 Hermes 子进程
await using var transport = new StdioAcpTransport(
platformConfiguration.GetExecutablePath(),
platformConfiguration.GetArguments(),
platformConfiguration.GetEnvironmentVariables(),
platformConfiguration.GetStartupTimeout(),
_loggerFactory.CreateLogger<StdioAcpTransport>());
await transport.ConnectAsync(cancellationToken);
// 2. 初始化,获取协议版本和认证方法
var initializeResult = await SendHermesRequestAsync(
transport, nextRequestId++, "initialize",
BuildInitializeParameters(platformConfiguration), cancellationToken);
// 3. 处理认证
var authMethods = ParseAuthMethods(initializeResult);
if (!isAuthenticated)
{
var methodId = platformConfiguration.Authentication.ResolveMethodId(authMethods);
await SendHermesRequestAsync(transport, nextRequestId++, "authenticate", ...);
}
// 4. 创建会话
var newSessionResult = await SendHermesRequestAsync(
transport, nextRequestId++, "session/new",
BuildNewSessionParameters(platformConfiguration, workingDirectory, model), cancellationToken);
var sessionId = ParseSessionId(newSessionResult);
// 5. 执行提示并收集流式响应
await foreach (var payload in transport.ReceiveMessagesAsync(cancellationToken))
{
// 处理 session/update 通知,转换为流式块
if (TryParseSessionNotification(root, out var notification))
{
if (_responseMapper.TryConvertToStreamingChunk(notification, out var chunk))
{
yield return chunk;
}
}
}
}

代码嘛,看多了也就那么回事。重要的是思路,对吧?

为了保证 Hermes 服务的可用性,HagiCode 实现了健康检查机制:

public async Task<ProviderTestResult> PingAsync(CancellationToken cancellationToken = default)
{
var response = await ExecuteAsync(
new AIRequest
{
Prompt = "Reply with exactly PONG.",
CessionId = null,
AllowedTools = Array.Empty<string>(),
WorkingDirectory = ResolveWorkingDirectory(null)
},
cancellationToken);
var success = string.Equals(response.Content.Trim(), "PONG", StringComparison.OrdinalIgnoreCase);
return new ProviderTestResult
{
ProviderName = Name,
Success = success,
ResponseTimeMs = stopwatch.ElapsedMilliseconds,
ErrorMessage = success ? null : $"Unexpected Hermes ping response: '{response.Content}'."
};
}

这大概就是所谓的”健康检查”了罢。其实人也一样,总要时不时检查一下自己——只是通常没人告诉我们应该检查什么。

集成 Hermes 过程中,有一些坑值得提前了解。这年头,谁还没踩过几个坑呢?

Hermes 支持多种认证方法(API Key、Token 等),需要根据实际部署情况选择。配置错误会导致连接失败,但错误信息可能不够直观。有时候报错信息跟实际原因差了十万八千里,得慢慢排查。

创建会话时可以配置 MCP 服务器列表,让 Hermes 调用外部工具。但要注意:

  • MCP 服务器地址必须可访问
  • 超时时间要合理设置
  • 服务器不可用时的降级处理

这世道,防不胜防啊。

每个会话都需要指定工作目录,确保 Hermes 能正确访问项目文件。对于多项目场景,需要动态切换工作目录。说起来简单,做起来要考虑的情况也挺多的。

Hermes 的响应可能分散在 session/update 通知和最终结果中,需要正确合并处理,否则会出现内容丢失。这事儿我也没少吃亏,慢慢就好了。

运行时错误应该明确返回,而不是静默回退到其他 Provider。这样用户才知道是 Hermes 出了问题,而不是莫名其妙换了别的模型。毕竟糊弄事儿也不是这么个糊弄法。

HagiCode 选择 Hermes 作为综合 Agent 核心,不是拍脑袋的决定,而是基于实际需求和技术特点的慎重选择。这选择对不对,现在说也为时过早,只是目前用起来还算顺手。

Hermes 提供的灵活部署能力,让 HagiCode 可以适应各种使用场景;强大的工具系统和 MCP 支持,让 AI 助手能真正干实事;而 ACP 协议和 Provider 抽象层,则让整个集成过程清晰可控。

如果你正在为你的 AI 项目选择 Agent 框架,希望这篇文章能提供一些参考。毕竟,选对底层架构,后续开发会轻松很多…

感谢您的阅读,如果您觉得本文有用,欢迎点赞、收藏和分享支持。 本内容采用人工智能辅助协作,最终内容由作者审核并确认。