0%

跟着☤Hermes Agent学AI智能体设计和开发

Hermes Agent 核心教程:从零开始开发强大的 Python AI 应用

写在前面:关于 Hermes Agent

Hermes Agent 是由知名 AI 研究机构 Nous Research 开发的一款具备高度自我进化能力的开源智能体系统。它旨在打破传统大模型“阅后即焚”的单一对话框限制,让 AI 真正“生活”在开发者的终端、团队的通讯软件以及自动化的流水线中。

核心亮点:

  • 闭环学习与长期记忆:它不仅能执行任务,还能在跨会话中持久化记忆,甚至从经验中自主创建和优化专属技能。
  • 全平台无缝接入:内置强大的消息网关,一套代码即可接入 CLI、Telegram、Discord、Slack 等平台,实现跨设备状态同步。
  • 模型无关与热切换:不被单一厂商锁定,支持随时无缝切换底层大模型(如 OpenAI、Anthropic、本地大模型等)。
  • 多智能体协作与沙盒隔离:支持生成隔离的子智能体(Subagents)并行处理复杂任务,并在 Docker、SSH 等多种安全沙盒中执行代码。

本教程将带你由浅入深,掌握如何将其作为 Python 库使用,打造你自己的强大 AI 应用。


1. 环境准备

在开始之前,请确保你已经激活了项目的虚拟环境。

对于配置模型,Hermes Agent 采用了全新的配置管理机制:

⚠️ 重要提示:
过去很多 AI 工具喜欢通过终端 export OPENAI_BASE_URL 或在 .env 中设置 LLM_MODEL 等环境变量来控制模型。但在 Hermes Agent 最新版本中,这些旧的环境变量已被完全废弃,即使在终端 export 也不会生效!
Hermes 的核心配置来源是统一的配置文件:~/.hermes/config.yaml(或者通过代码显式传参)。

配置第三方中转 API(Custom Provider)的正确姿势:

如果你希望全局使用第三方中转站(使得 CLI 和代码调用都默认生效),最推荐的做法是直接修改 ~/.hermes/config.yaml

1
2
3
4
5
6
# 在 ~/.hermes/config.yaml 中配置:
model:
default: gpt-5.4-mini # 你的模型名称
provider: custom # 必须声明 provider 为 custom
base_url: https://api.your-proxy.com/v1 # 中转站的 Base URL
api_key: your-api-key-here # 中转站的 API Key

或者使用交互式命令自动配置:

1
2
3
hermes model
# 选择 "Custom endpoint (self-hosted / VLLM / etc.)"
# 按照提示输入 Base URL、API Key 和模型名称即可。

当然,你也可以完全在代码中动态覆盖这些配置(见下一节)。


2. 基础篇:最简单的单次对话 (Single-turn Chat)

使用 Hermes 最简单的方法是调用 chat() 方法 —— 传入一条消息,返回一段字符串文本。它会在内部自动处理完整的对话循环(包括工具调用、重试等)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from run_agent import AIAgent

# 初始化 Agent
agent = AIAgent(
model="gpt-5.4-mini", # 指定模型
provider="custom", # 明确指定为自定义端点
base_url="https://api.your-proxy.com/v1", # 代码中显式指定第三方中转站
api_key="your-api-key-here", # 代码中显式指定 API Key
quiet_mode=True, # 开启静默模式,不在控制台打印 CLI 动画和终端输出
skip_memory=True, # 不持久化对话历史
skip_context_files=True # 不读取默认的 AGENTS.md 上下文文件
)

# 使用 chat 方法进行简单对话
response = agent.chat("用一句话解释一下什么是 Python 装饰器?")
print("AI 回复:", response)

⚠️ 注意: 将 Hermes 嵌入到你自己的代码中时,请务必设置 quiet_mode=True。否则,Agent 会打印 CLI 的加载动画和进度指示器,这会扰乱你的应用输出。


3. 进阶篇:完全对话控制与多轮对话 (Full Conversation Control)

如果需要对对话有更多的控制权,请直接使用 run_conversation()。它不仅返回最终的文本回复,还会返回完整的消息历史记录和元数据字典。

3.1 获取完整上下文与自定义 System Prompt

你可以通过 run_conversation() 传入临时的 system_message,覆盖该次调用的系统提示词:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from run_agent import AIAgent

agent = AIAgent(
model="gpt-5.4-mini",
provider="custom",
base_url="https://api.your-proxy.com/v1",
api_key="your-api-key-here",
quiet_mode=True,
)

result = agent.run_conversation(
user_message="解释一下什么是快速排序",
system_message="你是一个计算机科学导师。请使用生活中的简单比喻来解释。",
task_id="my-task-1", # 用于环境隔离的任务 ID
)

print("最终回复:", result["final_response"])
print(f"总共交互的消息数: {len(result['messages'])}")

返回的字典包含:

  • final_response — Agent 的最终文本回复
  • messages — 完整的消息历史(包含 system, user, assistant, tool calls)
  • task_id — 用于虚拟机隔离的任务标识符

3.2 保持多轮对话状态与持久化机制

Hermes 的对话历史状态保存有两种模式:

模式 A:纯内存传递(适合无状态 API)

要在多个回合之间在纯内存中保持对话状态,只需将上一次返回的 messages 历史记录重新传入 conversation_history 参数即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from run_agent import AIAgent

agent = AIAgent(
model="gpt-5.4-mini",
provider="custom",
base_url="https://api.your-proxy.com/v1",
api_key="your-api-key-here",
quiet_mode=True,
skip_memory=True, # 关闭自动持久化
)

# 第一轮对话
result1 = agent.run_conversation("你好,我叫 Alice,我最喜欢的颜色是蓝色。")
history = result1["messages"]
print("第一轮回复:", result1["final_response"])

# 第二轮对话 —— Agent 能从 history 中回忆起上下文
result2 = agent.run_conversation(
"你还记得我叫什么名字,喜欢什么颜色吗?",
conversation_history=history,
)
print("第二轮回复:", result2["final_response"]) # "你叫 Alice,喜欢蓝色。"

模式 B:SQLite 自动持久化存储(适合 CLI/聊天机器人)

如果你想让对话记录持久化到本地硬盘,即使程序重启也能继续聊天,你只需要在初始化 AIAgent 时传入一个固定的 session_id

Hermes 底层使用了 hermes_state.py 提供的 SessionDB。它会将所有的对话消息自动存入 ~/.hermes/state.db (SQLite 数据库) 中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from run_agent import AIAgent

# 初始化时设定 session_id,并确保没有设置 skip_memory=True
agent = AIAgent(
model="gpt-5.4-mini",
provider="custom",
base_url="https://api.your-proxy.com/v1",
api_key="your-api-key-here",
quiet_mode=True,
session_id="my_tutorial_session", # 关键:指定会话 ID
# skip_memory=False, # 默认就是 False,允许读写 SQLite
)

# 只要指定了 session_id,AIAgent 会在每次对话后自动将历史追加到 SQLite 数据库中。
res1 = agent.run_conversation("我最喜欢的水果是苹果。")
print("回复:", res1["final_response"])

# --- 假设在这里程序崩溃重启 ---
# 下次运行同样的脚本,传入相同的 session_id,Hermes 会自动从 SQLite 中加载历史记录
res2 = agent.run_conversation("我最喜欢的水果是什么?")
print("回复:", res2["final_response"]) # "你最喜欢的水果是苹果。"

4. 配置篇:工具权限与运行轨迹

4.1 开启或禁用工具 (Configuring Tools)

你可以通过 enabled_toolsets(白名单)或 disabled_toolsets(黑名单)来控制 Agent 有权使用哪些工具集:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 仅启用网络工具(浏览、搜索),适合做纯粹的“研究助手”
agent_web_only = AIAgent(
model="gpt-5.4-mini",
provider="custom",
base_url="https://api.your-proxy.com/v1",
api_key="your-api-key-here",
enabled_toolsets=["web"],
quiet_mode=True,
)

# 启用所有工具,但禁用终端执行权限(适合在不安全的共享环境中运行)
agent_no_terminal = AIAgent(
model="gpt-5.4-mini",
provider="custom",
base_url="https://api.your-proxy.com/v1",
api_key="your-api-key-here",
disabled_toolsets=["terminal"],
quiet_mode=True,
)

4.2 保存对话轨迹 (Saving Trajectories)与临时人设

如果你需要收集数据用于模型微调,可以开启轨迹保存。同时,使用 ephemeral_system_prompt 可以设定专属人设,且该设定不会污染保存的轨迹数据:

1
2
3
4
5
6
7
8
9
10
11
agent = AIAgent(
model="gpt-5.4-mini",
provider="custom",
base_url="https://api.your-proxy.com/v1",
api_key="your-api-key-here",
ephemeral_system_prompt="你是一个 SQL 专家。只回答与数据库相关的问题。",
save_trajectories=True, # 开启后,对话将以 ShareGPT 格式保存到 trajectory_samples.jsonl
quiet_mode=True,
)

response = agent.chat("我该怎么写一个 JOIN 查询?")

5. 架构篇:并发场景下的多用户隔离机制

当你准备将 Hermes Agent 接入 FastAPI、Discord Bot 或 Telegram 机器人时,多用户隔离是绕不开的话题。

Hermes 提供了两个层级的多用户隔离方案:

5.1 代码层级的软隔离 (Session ID)

在同一个 Python 进程中,如果你只是希望让模型能够分别记住不同用户的对话,你只需要为不同的用户请求分配不同的 session_id

⚠️ 核心规则: AIAgent 实例维护着自身的对话历史、工具会话和迭代计数器,它不是线程安全的。因此,必须为每个并发任务或每个用户请求创建一个新的 AIAgent 实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import concurrent.futures
from run_agent import AIAgent

def handle_user_message(user_id: str, message: str):
# 为每个并发请求实例化独立的 AIAgent 以保证线程安全
agent = AIAgent(
model="gpt-5.4-mini",
provider="custom",
base_url="https://api.your-proxy.com/v1",
api_key="your-api-key-here",
session_id=f"user_session_{user_id}", # 动态 session_id 隔离不同用户记忆
quiet_mode=True
)
return agent.chat(message)

# 模拟多用户并发请求
users_requests = {
"u1001": "你好,我是用户A",
"u1002": "你好,我是用户B"
}

with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor:
# 并发执行
futures = {
executor.submit(handle_user_message, uid, msg): uid
for uid, msg in users_requests.items()
}

for future in concurrent.futures.as_completed(futures):
uid = futures[future]
print(f"用户 {uid} 的专属回复: {future.result()}")

5.2 物理层级的硬隔离 (Profiles)

如果你不仅需要隔离对话历史,还需要为不同用户配置完全不同的 API Key、不同的模型、不同的系统提示词(人设)、甚至不同的可用工具集,你需要使用 Hermes 的 Profiles(配置文件) 功能。

每一个 Profile 都拥有独立的 ~/.hermes/profiles/<name>/ 目录。

你可以通过 CLI 预先创建 Profile:

1
2
hermes profile create alice
hermes profile create bob

然后在 Python 代码中,你可以在初始化 AIAgent 之前,通过修改环境变量 HERMES_HOME 来让当前进程或 Agent 绑定到特定的 Profile 目录下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import os
from pathlib import Path
from run_agent import AIAgent

def run_agent_for_profile(profile_name: str, message: str):
# 动态切换当前执行上下文的 HERMES_HOME 到指定的 profile 目录
profile_dir = Path.home() / ".hermes" / "profiles" / profile_name
os.environ["HERMES_HOME"] = str(profile_dir)

# 此时初始化的 Agent 会自动读取对应 profile 目录下的 config.yaml, .env 和 state.db
agent = AIAgent(
quiet_mode=True
# 不需要再传 model 和 key,它会自动从该用户的专属配置中读取
)
return agent.chat(message)

6. 实战集成示例 (Integration Examples)

6.1 FastAPI 接口端点

将 Hermes 包装成一个 HTTP API 服务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from fastapi import FastAPI
from pydantic import BaseModel
from run_agent import AIAgent

app = FastAPI()

class ChatRequest(BaseModel):
message: str
model: str = "gpt-5.4-mini"

@app.post("/chat")
async def chat(request: ChatRequest):
# 每次请求实例化一个全新无状态的 Agent
agent = AIAgent(
model=request.model,
provider="custom",
base_url="https://api.your-proxy.com/v1",
api_key="your-api-key-here",
quiet_mode=True,
skip_context_files=True,
skip_memory=True,
)
response = agent.chat(request.message)
return {"response": response}

6.2 CI/CD 自动化代码审查流水线

利用 Agent 在 CI/CD 流程中自动进行 Code Review:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/env python3
"""CI step: auto-review a PR diff."""
import subprocess
from run_agent import AIAgent

# 获取最新的代码变更
diff = subprocess.check_output(["git", "diff", "main...HEAD"]).decode()

agent = AIAgent(
model="gpt-5.4-mini",
provider="custom",
base_url="https://api.your-proxy.com/v1",
api_key="your-api-key-here",
quiet_mode=True,
skip_context_files=True,
skip_memory=True,
disabled_toolsets=["terminal", "browser"], # CI 环境下关闭敏感工具
)

review = agent.chat(
f"请审查以下 PR 的代码变更,检查是否存在 bug、安全漏洞或代码风格问题:\n\n{diff}"
)
print(review)

6.3 从零开发自定义工具

开发自定义工具非常简单,只需调用 tools.registry.registry.register 将其注册到全局系统中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import json
from tools.registry import registry, tool_result
from run_agent import AIAgent

# 1. 编写业务逻辑函数
def get_weather(location: str) -> str:
data = {"location": location, "weather": "晴朗", "temp": "25°C"}
# 工具必须返回 JSON 字符串(可以通过自带的 tool_result 辅助函数包裹)
return json.dumps(tool_result(success=True, data=data), ensure_ascii=False)

# 2. 编写符合 OpenAI Function Calling 标准的 Schema
WEATHER_SCHEMA = {
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的天气信息",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string", "description": "城市名称,如:北京、上海"}
},
"required": ["location"],
},
}
}

# 3. 将工具注册到系统中
registry.register(
name="get_weather", # 工具名称
toolset="weather_tools", # 归属的工具集名称
schema=WEATHER_SCHEMA, # 描述文件
handler=lambda args, **kw: get_weather(args.get("location")),
emoji="🌤️"
)

# 4. 在 AIAgent 中启用你的自定义工具集
agent = AIAgent(
model="gpt-5.4-mini",
provider="custom",
base_url="https://api.your-proxy.com/v1",
api_key="your-api-key-here",
enabled_toolsets=["weather_tools"],
quiet_mode=False
)

print(agent.chat("今天北京的天气怎么样?"))

7. 高阶篇:复杂任务编排与子智能体委托 (Agent-to-Agent 通信)

当面对超大型任务(例如“帮我从头开发一个贪吃蛇游戏并运行测试”)时,单线程执行往往容易遇到上下文瓶颈。Hermes 支持一种受控的 A2A (Agent-to-Agent) 协作模式——即子智能体委托机制 (Subagent Delegation)

当开启 delegate 工具集时,主 Agent 可以化身为“项目经理”,它会为不同的子任务创建隔离的 Child AIAgent 进行并行或串行的任务攻坚。

A2A 机制的核心特性:

  • 上下文隔离:子 Agent 会获得全新的对话会话和专属任务 ID,主 Agent 的庞大上下文不会拖慢子 Agent 的执行速度。
  • 防止递归失控:系统硬编码了最大委派深度(MAX_DEPTH = 2),即子 Agent 无法再创建孙 Agent,且被禁止向人类提问(clarify 工具被禁用),确保它们默默打工不打扰用户。
  • 并行处理:主 Agent 可以一次性派发多个任务,系统会自动利用线程池并发运行多个子 Agent。
1
2
3
4
5
6
7
8
9
10
11
agent = AIAgent(
model="gpt-5.4-mini",
provider="custom",
base_url="https://api.your-proxy.com/v1",
api_key="your-api-key-here",
enabled_toolsets=["delegate", "terminal", "file_tools"],
quiet_mode=False
)

# 主 Agent 发现任务复杂后,会自主调用 delegate 工具,通过 A2A 协议派生子 Agent 完成代码编写和测试
agent.chat("请帮我写一个 Python 贪吃蛇游戏,保存到 snake.py 中,然后运行并修复可能存在的 bug。")

此外,Hermes Agent 还可以接入 auxiliary_client.py 辅助客户端来支持视觉多模态识别,以及通过 cron/ 目录下的调度器实现自动化定时任务,这些都是其作为生产级 AI 框架的核心优势。


8. 前沿探索:支持标准 A2A Protocol (Agent2Agent)

最近,由 Linux 基金会主导的 A2A Protocol (Agent-to-Agent) 成为了跨框架智能体协作的开放标准。与前文提到的 Hermes 内部的 delegate(父子智能体委派)不同,标准的 A2A 协议允许 Hermes Agent 与完全不同的框架(如 LangGraph, CrewAI 等)构建的外部智能体进行去中心化的通信

虽然目前 Hermes 官方暂未原生内置 A2A 协议,但得益于其高度可扩展的工具注册表(Tool Registry)和网关(Gateway)架构,将其作为一个插件接入是非常容易的!

概念验证 1:作为 A2A 发起方 (Caller)

如果你想让 Hermes 能够调用外部支持 A2A 协议的 Agent(例如一个专门用于金融分析的 LangGraph 智能体),你可以轻松地为其编写一个自定义工具:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import json
from tools.registry import registry, tool_result
from run_agent import AIAgent

# 假设你已经安装了官方的 A2A Python SDK (pip install a2a-python)
# import a2a

def call_external_a2a_agent(agent_address: str, task_query: str) -> str:
"""通过 A2A 协议向外部智能体发送任务并等待结果"""
print(f"正在通过 A2A 协议联系外部智能体 [{agent_address}]...")

# --- 以下为伪代码,展示与 A2A SDK 的集成逻辑 ---
# client = a2a.Client()
# response = client.send_message(
# to=agent_address,
# content={"task": task_query}
# )
# result = response.get_result()
# ---------------------------------------------

# 模拟外部 Agent 的返回
result = f"来自 {agent_address} 的分析结果:已完成关于 '{task_query}' 的任务。"
return json.dumps(tool_result(success=True, data={"result": result}), ensure_ascii=False)

# 注册 A2A 通信工具
registry.register(
name="call_a2a_agent",
toolset="a2a_tools",
schema={
"type": "function",
"function": {
"name": "call_a2a_agent",
"description": "通过标准 A2A 协议将特定领域的任务委派给外部智能体",
"parameters": {
"type": "object",
"properties": {
"agent_address": {"type": "string", "description": "外部智能体的 A2A 寻址地址"},
"task_query": {"type": "string", "description": "需要外部智能体完成的任务详情"}
},
"required": ["agent_address", "task_query"],
},
}
},
handler=lambda args, **kw: call_external_a2a_agent(args.get("agent_address"), args.get("task_query")),
emoji="📡"
)

# 启动支持 A2A 协议的 Hermes 主控 Agent
agent = AIAgent(
model="gpt-5.4-mini",
provider="custom",
base_url="https://api.your-proxy.com/v1",
api_key="your-api-key-here",
enabled_toolsets=["a2a_tools", "web_search"],
quiet_mode=False
)

agent.chat("我需要一份专业的市场分析报告。请通过 A2A 协议联系地址为 'a2a://finance-expert-agent' 的智能体,让它帮你生成报告,然后你再结合最新的网络搜索结果发给我。")

概念验证 2:作为 A2A 接收方 (Server)

除了主动调用其他 Agent,你也可以将 Hermes 包装成一个 A2A 协议的服务端,监听并处理来自外部框架(如 CrewAI 或 AutoGen)发送的 A2A 请求。这在 Hermes 的架构中相当于构建一个自定义的 Gateway Platform 适配器。

以下是最简单的伪代码实现思路,展示了如何监听 A2A 请求、将请求内容交给 Hermes AIAgent 处理,再将结果通过 A2A 协议返回:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
from run_agent import AIAgent

# 假设安装了官方的 A2A Python SDK (pip install a2a-python)
# import a2a

def handle_incoming_a2a_task(request):
"""处理外部 Agent 发送来的 A2A 请求"""
print(f"收到来自 {request.sender} 的任务:{request.content['task']}")

# 实例化一个 Hermes Agent 来处理该任务
agent = AIAgent(
model="gpt-5.4-mini",
provider="custom",
base_url="https://api.your-proxy.com/v1",
api_key="your-api-key-here",
quiet_mode=True,
# 可以根据 request.sender 动态设置 session_id 以隔离不同 Agent 的记忆
session_id=f"a2a_session_{request.sender}"
)

# 核心:将 A2A 请求转换为 Hermes 的内部聊天指令
result = agent.chat(request.content["task"])

# 将 Hermes 的回复通过 A2A 协议返回给发送方
# return request.reply(content={"result": result})
print(f"任务完成,回复给 {request.sender}{result}")

def start_a2a_server():
"""启动 A2A 监听服务"""
# client = a2a.Client(address="a2a://hermes-research-agent")
# client.on_message(handle_incoming_a2a_task)
# print("Hermes A2A 节点已启动,监听地址: a2a://hermes-research-agent")
# client.start()
pass

if __name__ == "__main__":
start_a2a_server()

正如你所见,A2A 协议(用于 Agent 间通信)与 MCP 协议(用于 Agent 访问工具资源)是完美的互补组合。随着生态的成熟,你完全可以通过上述方式将 Hermes 接入到由无数异构 AI 智能体组成的“互联网”中!


结语

通过本教程,你已经掌握了如何使用 Python 库的方式调用 hermes-agent,从单次/多轮对话控制,到安全地进行并发处理和工具定制。它既可以作为你的本地终端 Copilot,也能轻易集成到 FastAPI 后端、Discord Bot 甚至自动化 CI/CD 流水线中!