Day 1 · 精读 Hermes-3 Model Card
| 属性 | 值 |
|---|---|
| 日期 | 2026-08-12(周三) |
| 周次 | 第1周:双轨认知框架建立 |
| 轨 | 轨1 · Hermes 技术认知 |
| 时间 | 1 小时 |
| 状态 | ✅ 已完成 |
📋 Checklist
- 打开 Hermes-3 Model Card,通读 Overview
- 重点理解 ChatML 角色格式(system / user / assistant / tool)
- 重点理解
<tool_call>XML 标签格式 - 阅读 Function Calling 示例代码
- 记录 3 个关键发现
- 记录 3 个不理解的问题
📖 阅读材料
| 材料 | 链接 |
|---|---|
| Hermes-3-8B Model Card | https://huggingface.co/NousResearch/Hermes-3-Llama-3.1-8B |
| 补充:Hermes-3-70B | https://huggingface.co/NousResearch/Hermes-3-Llama-3.1-70B |
| 补充:Nous Research 官网 | https://nousresearch.com/ |
✍️ 学习笔记
在此记录你的笔记...
关键发现 1
Hermes 3 的 Function Calling 使用
<tool_call>XML 标签包裹 JSON,与 Claude 的 API 级 tool_use 块本质相同但格式不同。对 SmallRig 项目来说,接入 Hermes 需要额外的 prompt 格式适配层。
关键发现 2
ChatML 的四角色体系(system/user/assistant/tool)和 Claude 的 API 角色体系一一对应。这意味着如果未来要在 admin 后台用本地 Hermes 做数据查询 Agent,交互逻辑可以直接复用现有设计。
关键发现 3
Hermes 3 8B 的中文能力未经专门训练(Model Card 全是英文示例),对 SmallRig 的多语言站点(中/英/德/日/韩)是显著短板。Agent 场景如果要覆盖中文用户,需要评估 70B 版本或考虑其他模型。
📖 PM 精读指引(本节课内容)
四大角色体系(ChatML)
<|im_start|>system ← 定义 Agent 行为规则 + 工具清单(你提前写好)
<|im_start|>user ← 用户输入
<|im_start|>assistant ← 模型决策层:判断调用哪个工具 → 输出 tool_call
读取 tool_response → 再次决策 → 生成最终文本回复
<|im_start|>tool ← 提供给assistant决策输入用什么tool,然后让后端代码执行完毕,把结果喂回给模型
assistant 不止是「文本回复」,它是模型的决策中枢。每次轮到 assistant,模型都在做判断:要不要调工具?调哪个?参数是什么?拿到结果后信息够了吗?要再调一个还是直接回复?
Function Calling 流程
1. System Prompt 定义可用工具(<tools> 标签内含 JSON Schema)
2. 用户输入后,模型决定是否调用工具
3. 调用工具时输出:<tool_call>{"name":"xxx","arguments":{...}}</tool_call>
4. 外部执行工具,返回结果用 <tool_response> 包裹
5. 模型读取 tool_response,生成最终回复
与 SmallRig 项目对照
| Hermes 概念 | 项目对应 | 文件 |
|---|---|---|
<tools> 函数定义 |
AI 搜索的 prompt 模板 | OpenAiUtils.java |
<tool_call> 返回 |
AiSearchProductResp | AiSearchProductResp.java |
| Assistant 文本回复 | aiReply 字段 | 同上 |
| System Prompt | 搜索服务 prompt | SearchServiceImpl.java |
一句话总结
Hermes 3 的本质是一个「开源的、擅长调用工具的模型」。它的 Function Calling 机制和 Claude 逻辑一致,只是格式不同。对 SmallRig 项目,它的价值在于本地 Agent 备选方案——当数据隐私或成本是首要考虑时。
❓ 疑问
- Hermes 的 Function Calling 准确率在实际业务中够用吗?(需 Day 7 实测验证)
- 如果中文能力不足,SmallRig 的 Agent 场景是否可以用「英文 prompt + 翻译层」来绕过?
- 8B 和 70B 版本在 Agent 能力上的差距有多大?有没有必要为了 Agent 场景直接上 70B?
📤 产出
- 笔记已写入本文件 ✅
💬 关键概念澄清 Q&A(2026-08-12 补充)
Q1: 谁决定调用什么工具?PM 还是模型?
模型自己决定。 PM 做的事是提前在 System Prompt 里定义「有哪些工具可用」,但具体什么时候调用、调用哪个、传什么参数,全部由模型自主判断。
类比:你给员工一本操作手册(System Prompt + 工具清单),但每次遇到客户问题,员工自己决定翻手册的哪一页、打哪个电话。
Q2: Assistant 的输出是什么?
Assistant 有两种输出:
| 输出类型 | 格式 | 给谁看 |
|---|---|---|
| 文本回复 | 自然语言 | 给用户看的最终答案 |
| Tool Call | <tool_call> JSON |
给系统看的「帮我执行这个工具」 |
Tool Call 是中间产物,文本回复是最终产物。
Q3: Function Calling 的完整链路
用户输入 "推荐 A7III 兔笼"
↓
模型判断:我需要查商品库 → 输出 <tool_call>search_product(...)
↓
系统执行查询,拿到真实数据
↓
系统把结果喂回模型:<tool_response>{"products": [...]}
↓
模型读结果,判断:信息够了吗?
├── 够了 → 生成最终回复给用户
└── 不够 → 再次输出 <tool_call> 调用下一个工具 → 循环
Q4: System Prompt 能控制什么?
| 能做到 | 做不到 |
|---|---|
| 定义角色和语气 | 100% 防止幻觉 |
| 列出可用工具及参数 | 保证每次都选对工具 |
| 设置行为边界 | 防止 prompt injection 攻击 |
Q5: 「本地 Agent」vs「自部署 Agent」
| 术语 | 含义 | 用户范围 |
|---|---|---|
| 本地 Agent | 模型跑在你自己的电脑上(Ollama) | 仅你自己 |
| 自部署 Agent | 模型跑在公司服务器上,用户通过网页访问 | 所有用户 |
| 云端 Agent | 模型跑在 OpenAI/Anthropic 服务器上 | 所有用户 |
对 SmallRig 项目:前台/后台用户访问的是网站,模型跑在公司服务器上——这叫「自部署 Agent」,不是「本地 Agent」。用户不关心模型跑在哪。
📐 完整示例:SmallRig 购物助手 Agent(附 System Prompt)
System Prompt(你提前写好的,只出现一次)
<|im_start|>system
你是 SmallRig 的 AI 购物助手,帮助摄影师选购配件。
行为规则:
- 只推荐 SmallRig 品牌商品
- 如果用户预算不足,主动推荐更便宜的替代品
- 推荐时说明理由(为什么这款适合用户的设备)
你可以使用以下工具:
<tools>
[
{
"name": "search_product",
"description": "搜索 SmallRig 商品库。按关键词和品类查找",
"parameters": {
"query": "搜索关键词,如 'A7III 兔笼'",
"category": "品类:cage/tripod/monitor/mic/other",
"max_price": "最高预算(可选)"
}
},
{
"name": "get_product_detail",
"description": "获取单个商品的详细信息,包括兼容性、规格",
"parameters": {
"product_id": "商品 ID"
}
},
{
"name": "check_compatibility",
"description": "检查某个商品是否兼容用户的相机型号",
"parameters": {
"product_id": "商品 ID",
"camera_model": "相机型号,如 'Sony A7III'"
}
}
]
</tools>
<|im_end|>
完整对话流程(四个角色依次出现)
第 1 轮:user 发消息
<|im_start|>user
我想给 Sony A7III 配一个兔笼,预算 1000 以内
<|im_end|>
第 2 轮:assistant 判断需要查库,输出 tool_call(用户看不到)
<|im_start|>assistant
<tool_call>
{
"name": "search_product",
"arguments": {
"query": "兔笼",
"category": "cage",
"max_price": 1000
}
}
</tool_call>
<|im_end|>
↑ 参数是模型自己从用户的话里提取的(query="兔笼", max_price=1000),不是你提前写的
第 3 轮:tool——后端代码执行完查询,把结果塞回来(用户看不到)
<|im_start|>tool
<tool_response>
{
"name": "search_product",
"content": {
"products": [
{"id": 101, "name": "A7III 全包兔笼", "price": 899},
{"id": 102, "name": "A7III 半包兔笼", "price": 599}
]
}
}
</tool_response>
<|im_end|>
↑ tool_response 是后端代码生成的,不是模型生成的
第 4 轮:assistant 读了 tool_response,生成最终回复(用户看到这个)
<|im_start|>assistant
为你找到 2 款适配 A7III 的兔笼,都在预算内:
1. A7III 全包兔笼 - ¥899
全包式设计,保护性更好,适合专业拍摄
2. A7III 半包兔笼 - ¥599
半包式设计,轻便便携,日常拍摄够用
需要我帮你对比这两款的详细规格吗?
<|im_end|>
📊 四个角色总结
| 角色 | 谁写的 | 什么时候出现 | 作用 |
|---|---|---|---|
system |
**你(PM)**提前写好 | 对话最开始,只出现一次 | 定义 Agent 行为规则 + 工具清单 |
user |
用户 | 每次用户发消息 | 用户的需求输入 |
assistant |
模型 | 每次模型决策(可能是 tool_call 也可能是文本) | 决策中枢:判断用哪个工具 → 输出 tool_call → 读 tool_response → 再决策 → 生成文本回复 |
tool |
后端代码 | 每次工具执行完毕 | 把查询结果喂回模型 |
关键对比:当前 AI 搜索 vs Agent
当前 AI 搜索:
user 输入 → [一次 API 调用] → aiReply 文本 → 展示给用户
升级成 Agent 后:
user 输入 → 模型判断 → tool_call → 系统执行 → tool_response → 模型再判断 → 回复
↑
多了这个循环,就是 Agent 的核心
Q6: 后端怎么知道 tool_call 调的是哪个工具?tool_response 怎么生成?
后端需要提前为每个 tool 开发对应的 handler(处理函数)。 运行时根据 tool_call 里的 name 字段路由到正确的 handler。
模型输出 tool_call:
{"name": "search_product", "arguments": {"query": "兔笼"}}
│
↓ 后端根据 name 字段路由
│
┌──────┴──────────┐
│ switch(name) │
├─────────────────┤
│ "search_product" → handlerA(query, category, max_price)
│ "get_product_detail" → handlerB(product_id)
│ "check_compatibility" → handlerC(product_id, camera)
└─────────────────┘
│
↓ handler 执行(查数据库/调 API),拿到真实数据
│
包装成 tool_response,喂回给模型
关键认知:
| tool_call | tool_response | |
|---|---|---|
| 谁生成 | 模型 | 后端代码 |
| 格式 | {"name": "...", "arguments": {...}} |
{"name": "...", "content": {...}} |
| 内容来源 | 模型从用户话里提取 | 数据库/API 真实返回 |
| 格式谁定 | 协议约定(ChatML) | 协议约定(ChatML) |
每个 tool 都需要提前开发:你在 System Prompt 里定义了几个 tool,后端就要写几个对应的 handler。Agent 项目的后端工作量不在模型本身,而在于这些 handler 的开发和维护。
🧪 Day 1 自测题
每题先自己回答,再看答案。目的是检验理解,不是背诵。
第 1 题:角色填空
一个用户在 SmallRig 购物助手 Agent 中说「帮我查一下 A7III 的兔笼」,以下对话片段中,____ 处应该填入什么角色?
<|im_start|>____
<tool_call>
{"name": "search_product", "arguments": {"query": "兔笼"}}
</tool_call>
<|im_end|>
点击看答案
assistant。因为这是模型在输出决策指令(调用工具),不是用户说的话,也不是工具返回的数据。
第 2 题:判断对错
「System Prompt 里定义了 tool_call 的格式和 tool_response 的格式,所以模型知道怎么调用工具。」
点击看答案
错。 System Prompt 里定义的是工具清单(有哪些工具、参数是什么),但 tool_call 是模型在对话中自己输出的,tool_response 是后端代码生成的。System Prompt 不定义 tool_call 和 tool_response 的具体内容。
第 3 题:场景判断
用户问:「A7III 全包兔笼兼容我的 Atomos Ninja V 监视器吗?」
Agent 需要调用 check_compatibility(product_id=101, camera="Atomos Ninja V") 来回答。
谁决定调用这个工具?
A. PM 在 System Prompt 里预设了规则
B. 模型自己判断需要调用
C. 后端代码检测到关键词自动触发
点击看答案
B。 模型自己判断。PM 只定义了「check_compatibility 这个工具存在」,但模型根据用户的问题自主判断「现在需要调用它」。这就是 Agent 的自主性。
第 4 题:链路排序
将以下步骤按 Agent 对话的正确顺序排列:
- 模型生成最终文本回复给用户
- 用户输入需求
- 模型输出
<tool_call>决定调用工具 - 系统执行工具,拿到真实数据
- 系统把
<tool_response>喂回给模型 - 模型读结果,判断信息是否足够
点击看答案
正确顺序:2 → 3 → 4 → 5 → 6 → 1
用户输入 → 模型判断需调工具 → 系统执行 → 结果回传 → 模型再判断 → 生成回复
如果第 6 步「信息不够」,链路会回到第 3 步(再次调用工具),形成循环。
第 5 题:对比题
当前 SmallRig AI 搜索的流程是:
用户输入 → 一次 API 调用 → 返回 aiReply 文本
如果要升级成 Agent,需要在中间插入哪两个步骤?
点击看答案
插入「模型自主决策调用工具」和「工具执行结果回传」。
具体来说,缺少的是:
- 模型判断是否需要调用工具 → 输出 tool_call
- 系统执行工具 → 返回 tool_response
当前 AI 搜索是「每次都直接调 API」,Agent 是「模型自己决定要不要调、调哪个、调几次」。
第 6 题:部署方式判断
SmallRig 计划把购物助手 Agent 部署到公司服务器上,用户在 mall 网站上通过聊天框使用。这种部署方式叫什么?
A. 本地 Agent
B. 自部署 Agent
C. 云端 Agent
点击看答案
B. 自部署 Agent。 模型跑在公司服务器上,用户通过网页访问。「本地 Agent」指模型跑在个人电脑上(如 Ollama),只有自己能用。「云端 Agent」指模型跑在 OpenAI 等第三方服务器上。
⏭️ 完成后:更新 当前进度 为 Day 2