快速开始:首个 Hermes 风格 Agent
本指南在 可运行代码 与 决策解释 之间建立桥梁:你会完成环境准备、构建天气 Agent、理解 Hermes 标签解析循环、用 Tool Call Inspector 建立可观测心智,并实现 PDF → 摘要 → 计算器 文件处理链及 Retry/Fallback。全文假设 Python 3.10+;Node 栈读者可对照 LangChain.js API,结构相同。
边练边看
打开 Tool Call Inspector 与子站 Code Sandbox,把本文每一步的 model_raw 与解析结果对照粘贴,比单读文档快三倍。
一、环境准备
1.1 硬性要求
| 项目 | 要求 | 说明 |
|---|---|---|
| Python | 3.10+ | 需 match 语句、类型联合语法 |
| 包管理 | venv 或 uv | 隔离依赖,避免污染系统 Python |
| 模型 API | OpenAI 兼容 | OpenAI、DeepSeek、硅基流动等;或本地 Ollama |
| 推荐模型 | Hermes-2-Pro、Qwen2.5、GPT-4o mini | 需稳定 function calling 或 Hermes 标签输出 |
| 环境变量 | OPENAI_API_KEY | 若用 Ollama:OPENAI_API_BASE=http://localhost:11434/v1 |
1.2 创建虚拟环境并安装依赖
cd ~/hermes-lab
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -U pip
pip install langchain-openai langchain-core pydantic pypdf
| 包 | 用途 |
|---|---|
| langchain-openai | ChatOpenAI + bind_tools |
| langchain-core | @tool、消息类型 |
| pydantic | 参数校验、Tool Schema |
| pypdf | 文件处理 Agent 读取 PDF(Day 1 实战) |
1.3 验证 API 连通
# verify_api.py — 运行通过再写 Agent
import os
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
print(llm.invoke("回复 OK 两个字母").content)
若报错 AuthenticationError,检查 API Key;若 Connection error,检查 OPENAI_API_BASE 与网络。
1.4 项目目录建议
hermes-lab/
├── .env # OPENAI_API_KEY=sk-...
├── agents/
│ ├── weather_agent.py
│ ├── hermes_parser_loop.py
│ └── file_pipeline_agent.py
├── tools/
│ └── registry.py
└── tests/
└── test_tool_selection.py
不要把 Key 提交进 Git;.env 加入 .gitignore。
二、首个天气 Agent(LangChain + OpenAI Functions 路径)
本节使用 OpenAI Functions 路径(LangChain 默认),因为 SDK 帮你处理了 tool_calls 解析。第三节再切换到 Hermes 标签 手写循环——两种路径你都要会。
2.1 定义工具:Passive vs Active
# tools/weather.py
from langchain_core.tools import tool
@tool
def get_weather(city: str) -> str:
"""当用户询问某城市当前天气、温度、是否下雨时调用。
不要用于历史天气统计或地震查询。
参数 city: 中国城市名,如「北京」「上海」,不要带「市」后缀。"""
# 演示:真实项目替换为 HTTP 天气 API
mock_db = {
"北京": "晴,25°C,湿度 40%,北风 2 级",
"上海": "多云,28°C,湿度 65%,东南风 3 级",
}
key = city.replace("市", "").strip()
if key not in mock_db:
return f"ERROR: 未找到城市 {city},请确认中文名"
return f"{key}:{mock_db[key]}"
@tool
def get_weather_backup(city: str) -> str:
"""仅当 get_weather 返回 ERROR 或超时时调用,作为备用数据源。"""
return f"{city}(备用源):阴,24°C,数据可能有延迟"
为何 Active 描述重要: 用户问「北京今天适合跑步吗」——模型需识别这是 天气意图,不是闲聊。Passive 描述「查询天气」容易被忽略;Active 的「当用户询问当前天气…」提高触发率。
2.2 绑定工具并手动执行一轮
# agents/weather_agent.py
import json
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, ToolMessage
from tools.weather import get_weather, get_weather_backup
TOOLS = {t.name: t for t in [get_weather, get_weather_backup]}
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
llm_with_tools = llm.bind_tools([get_weather, get_weather_backup])
messages = [HumanMessage(content="北京今天天气怎么样?")]
response = llm_with_tools.invoke(messages)
# 模型为何选 get_weather?见 2.4 节
if response.tool_calls:
messages.append(response)
for tc in response.tool_calls:
fn = TOOLS[tc["name"]]
result = fn.invoke(tc["args"])
messages.append(ToolMessage(content=str(result), tool_call_id=tc["id"]))
final = llm_with_tools.invoke(messages)
print(final.content)
else:
print(response.content)
2.3 模型为什么选 get_weather 而不是 get_weather_backup?
逐步拆解 注意力 + 描述 + 用户句 三因素:
| 步骤 |
|---|