Day 7 · 测试 Hermes Function Calling
| 属性 | 值 |
|---|---|
| 日期 | 2026-08-24(实际完成) |
| 周次 | 第2周:动手体验+场景深挖 |
| 轨 | 轨1 · Hermes 技术认知 |
| 时间 | 1 小时 |
| 状态 | ✅ 已完成 |
📋 Checklist
- 阅读 Hermes Function Calling 示例
- 定义 Tool:
search_product+get_product_detail— 模拟 SmallRig 商品搜索 - 用 Ollama API 测试 Hermes FC(7 个测试用例)
- 测试多轮对话中的 Function Calling(tool_result 回传)
- 对比 Claude Tool Use 格式差异
- 记录准确性、格式合规率、延迟数据
✍️ 学习笔记
新增概念:Function Calling 的本质
Function Calling 不是模型"变聪明了",而是模型的输出格式变了——从"自由文本"变成"结构化 JSON"。
普通对话:
用户: "推荐一款兔笼"
模型: "我推荐 SmallRig 1234..." ← 纯文本输出
Function Calling:
用户: "推荐一款兔笼"
模型输出: <tool_call>{"name": "search_product", "arguments": {"query": "兔笼"}}</tool_call>
→ Harness 执行搜索,拿到真实数据
→ 模型基于真实数据生成推荐
新增概念:三个概念的区分
| 概念 | 是什么 | 谁负责 |
|---|---|---|
| Function Calling(能力) | 模型能输出结构化工具调用 | 模型本身 |
| Tool 定义(配置) | 告诉模型有哪些工具可用 | 开发者 |
| Agent Loop(执行) | 收到 tool_call → 执行函数 → 回传结果 → 再调模型 | Harness 框架 |
模型只管"输出 tool_call",不管"执行"。执行是 Harness 的事。
新增概念:ChatML 四角色的使用时机(不是必须全部出现)
system — 每次对话都有(定义规则+工具)
user — 每次对话都有(用户输入)
assistant — 模型每轮都输出(可能是文本,也可能是 tool_call)
tool — 只在需要回传工具结果时才出现
"角色不完整"不是 bug,而是 Agent Loop 的常态——tool 角色只有在"模型已经调过工具、Harness 执行完、需要把结果喂回去"时才出现。
新增概念:Ollama 的三层转换
我们发给 Ollama(JSON) Ollama 内部转成 ChatML 发给模型
──────────────────────────── ────────────────────────────── ──────
{ <|im_start|>system
"messages": [ You are a function calling AI...
{"role": "system", <tools>[...]</tools>
"content": "..."}, <|im_end|>
{"role": "user", <|im_start|>user
"content": "..."}, I need a cage...
{"role": "assistant", <|im_end|>
"content": "<tool_call>"}, <|im_start|>assistant
{"role": "tool", <tool_call>...</tool_call>
"content": "<tool_response>"} <|im_end|>
] <|im_start|>tool
} <tool_response>...</tool_response>
<|im_end|>
Ollama 是"翻译官"——对上讲 JSON(方便开发者),对下讲 ChatML 大字符串(模型只懂这个)。
新增概念:Temperature 原理
模型对每个可能的下一个 token 都算了一个概率。temperature 在"选 token"之前对这些概率做缩放:
原始概率 → ÷ temperature → softmax → 新概率分布
temperature = 0.0(贪婪解码):最高概率 token → 100%,每次必选这个
temperature = 0.5(压低):高的更高,低的更低
temperature = 1.0(不缩放):原样输出
temperature = 2.0(拉平):大家都差不多,随机性最大
| 场景 | temperature | 为什么 |
|---|---|---|
| 数学计算 / Tool 调用 | 0.0 | 必须确定性,不能随机 |
| 写广告文案 | 0.7 | 每次生成不同版本做 A/B |
| 写小说 | 0.9 | 剧情需要多样性 |
| 头脑风暴 | 1.2 | 越天马行空越好 |
Agent 的 FC 场景必须用 0。
新增概念:Here are the available tools: 不是必须的
它是 Hermes 官方推荐的 system prompt 模板的一部分,作用是给模型一个"上下文锚点"——告诉模型"接下来这段 XML 是工具定义"。去掉也能工作,但保留它能让 FC 触发更稳定。多几个 token 换稳定性,值得。
新增概念:Claude Messages API vs Ollama JSON vs ChatML 的层级关系
Claude Messages API Ollama /api/chat Hermes ChatML
(3 个顶层字段) (全塞 messages) (大字符串)
system: "..." → messages[0] = system → <|im_start|>system\n...\n<|im_end|>
tools: [...] → 嵌在 system content 里 → <tools>...</tools>
messages: [...] → messages[1..n] → <|im_start|>user/assistant/tool\n...\n<|im_end|>
| 维度 | Claude Messages API | Ollama /api/chat | Hermes ChatML |
|---|---|---|---|
| 工具定义位置 | 顶层 tools 字段(JSON) |
system content 内嵌 <tools> |
system 文本内 <tools> |
| 工具调用格式 | content block type:"tool_use" |
assistant content 文本 <tool_call> |
文本 <tool_call> |
| 工具结果回传 | content block type:"tool_result" + ID |
tool role 文本 <tool_response> |
文本 <tool_response> |
| Harness 操作 | 操作 JSON 对象 | 操作 JSON 对象(Ollama 帮你转) | 拼字符串 + 正则解析 |
🧪 实测结果
测试环境
- 模型:Hermes-3-8B (Q4_0 量化)
- 接口:Ollama
/api/chat(OpenAI 兼容格式) - 参数:
temperature=0.0, num_predict=256-512
七项测试结果
| 测试 | 场景 | 是否正确 | 参数准确度 | 实际输出 | 备注 |
|---|---|---|---|---|---|
| 测试1 | 英文单次 Tool | ✅ | ⭐⭐⭐⭐⭐ | search_product({"query": "Sony A7III", "category": "camera-cage"}) |
完美 |
| 测试2 | 英文多轮首步 | ✅ | ⭐⭐⭐⭐⭐ | search_product({"query": "Sony FX3", "category": "camera-cage"}) |
完美 |
| 测试3 | 中文单次 | ✅ | ⭐⭐⭐⭐⭐ | search_product({"query": "BMPCC 6K", "category": "camera-cage"}) |
中文理解正确 |
| 测试4 | 中文参数提取 | ✅ | ⭐⭐⭐⭐ | search_product({"query": "A7M4", "category": "camera-cage"}) |
遗漏了"预算500" |
| 测试5 | 无需 Tool | ✅ | N/A | 直接英文解释 camera cage | 正确判断不调 Tool |
| 测试6 | 模糊意图 | ⚠️ | ⭐⭐⭐ | search_product({"query": "camera-cage", "category": "all"}) |
强行调 Tool,query 不够精确 |
| 测试7 | 多轮结果回传 | ✅ | ⭐⭐⭐⭐⭐ | 完美消化 tool_result,生成自然推荐 | 含价格+SKU+追问 |
格式合规率
7 次调用中 7 次 JSON 有效,格式合规率 100%。 没有出现 JSON 解析失败的情况。
延迟数据
| 阶段 | 典型耗时 |
|---|---|
| 模型加载(首次) | 8-14s |
| 模型加载(热启动) | 1-3ms |
| Prompt 评估 | 1-15s(取决于上下文长度) |
| Token 生成 | 4-10s(30-75 tokens) |
| 总延迟(含加载) | 15-30s |
| 总延迟(热启动) | 5-15s |
🔄 与 Claude 对比
| 维度 | Hermes-3 8B | Claude (Sonnet) | 差距 |
|---|---|---|---|
| 英文 FC 准确率 | 5/5 | 5/5 | 无 |
| 中文 FC 准确率 | 4/5 | 5/5 | 小 |
| 参数提取精度 | 遗漏"预算500" | 能提取预算约束 | 中 |
| 不调 Tool 的判断 | 1/1 | 1/1 | 无 |
| 模糊意图处理 | 强行调 Tool | 先追问澄清 | 中 |
| 多轮结果消化 | 完美 | 完美 | 无 |
| 格式合规率 | 100% JSON 有效 | 100% API 保证 | 无 |
| 延迟 | 15-30s(含加载) | 1-3s | 大 |
核心发现:Hermes 8B 的 FC 能力出乎意料地好。 格式合规率 100%,中文也能正确提取参数。主要差距不在 FC 本身,而在:
- 延迟:本地推理 15-30s vs Claude 1-3s,差 10 倍
- 判断力:模糊场景下 Hermes 倾向于"强行调 Tool",Claude 会先追问
- 参数遗漏:中文场景下"预算500"被忽略
💡 关键认知
1. FC 格式比想象中可靠
Day 6 担心"正则解析可能格式错误",实测 7 次 JSON 全部有效。Hermes 8B 对 <tool_call> 标签的格式遵守度很高。
2. 中文 FC 可用,但不如英文
参数提取主体正确(query/category),但细节可能遗漏(预算约束)。中文 Agent 场景需要在 Harness 层做参数校验兜底。
3. 延迟是真实瓶颈
热启动 5-15s 对实时对话场景偏慢。如果 Agent 需要 3 轮 Tool 调用,用户可能等 15-45s。需要异步化体验设计(如"正在为您搜索..."加载态)。
4. 模糊意图需要 Harness 兜底
Hermes 在模糊场景下倾向于"强行调 Tool"而非追问。Claude 的判断力更强。用 Hermes 做 Agent 时,Harness 需要在"调 Tool 之前"加一层意图清晰度判断。
❓ 疑问与解答
Q1:ChatML 四角色不完整也能输出吗?
答:能。 四角色不是"必须全部出现",而是"按需出现"。system 和 user 每轮都有,assistant 是模型输出,tool 只在"模型已调工具、需要回传结果"时才出现。第一个请求只有 system+user 时模型照样输出 tool_call——因为 tool 角色是下一步才需要的。
Q2:Here are the available tools: 一定要吗?
答:不是必须的。 它是 Hermes 官方推荐的 system prompt 模板的一部分,作用是给模型一个"上下文锚点"。去掉也能工作,但保留它能让 FC 触发更稳定。实战建议保留。
Q3:Ollama API 参数 stream/temperature/num_predict 是什么?
stream:false= 全部生成完一次性返回;true= 逐 token 流式返回temperature: 0~2,控制输出随机性。0=确定(每次相同),2=高度随机。Agent FC 必须用 0num_predict: 最多生成多少 token,类似max_tokens
Q4:Ollama 发的是 JSON,为什么说 ChatML 是"大字符串"?
Ollama 是翻译层。 我们发 JSON 给 /api/chat,Ollama 内部转成 ChatML 大字符串再喂给模型。我们享受 JSON 的便利,模型收到的还是它只懂的 ChatML。
📤 产出
- 7 项 FC 测试结果
- Hermes vs Claude FC 对比表
- 延迟数据记录
- 格式合规率统计(100%)
- 关键认知 4 条
🧪 Day 7 自测题
第 1 题:概念区分
以下关于 Function Calling 的描述,哪个是正确的?
A. Function Calling 是模型变聪明了,能自己执行代码
B. Function Calling 是模型输出格式变了——从自由文本变成结构化 JSON,但执行是 Harness 的事
C. Function Calling 和 Agent Loop 是同一件事
D. Function Calling 只能调用 Python 函数
点击看答案
B。 Function Calling 只是模型输出格式的变化(输出 <tool_call> 而非纯文本)。执行工具、回传结果、循环调度都是 Harness 框架的职责。A 错在"模型自己执行",C 混淆了两个概念,D 错在 Tool 可以是任何外部能力(API、数据库、文件系统)。
第 2 题:ChatML 四角色
第一个请求只有 system + user 两个角色,模型照样输出了 <tool_call>。这说明什么?
A. Hermes 模型有 bug,不应该输出
B. ChatML 四角色必须全部出现才能工作
C. tool 角色只在需要回传工具结果时才出现,不是每轮都必须有
D. Ollama 自动补全了缺失的角色
点击看答案
C。 四角色是"按需出现"的——system 和 user 每轮都有,assistant 是模型输出,tool 只在"模型已调工具、Harness 执行完、需要把结果喂回去"时才出现。这是 Agent Loop 的常态,不是 bug。
第 3 题:Temperature 原理
在 Agent Function Calling 场景中,为什么 temperature 必须设为 0.0?
A. 因为 0.0 能让模型运行更快
B. 因为 0.0 是 Ollama 的默认值
C. 因为 Tool 调用需要确定性——不能让模型随机决定要不要调工具,或随机生成参数值
D. 因为 temperature > 0 会导致模型崩溃
点击看答案
C。 temperature=0 是贪婪解码,每次都选概率最高的 token,输出确定。FC 场景中,你不希望模型"随机决定"调不调工具,也不希望 search_product("FX3") 随机变成 search_product("banana")。A 错在 temperature 不影响速度,B 错在默认值是 0.7,D 过于夸张。
第 4 题:Ollama 的三层转换
我们调用 Ollama /api/chat 时发的是 JSON,但 Hermes 模型只懂 ChatML 大字符串。中间发生了什么?
A. 模型自己把 JSON 转成了 ChatML
B. Ollama 是一个翻译层——对上接收 JSON,内部转成 ChatML 大字符串,再喂给模型
C. JSON 和 ChatML 是同一个东西,不需要转换
D. curl 命令自动做了格式转换
点击看答案
B。 Ollama 的 /api/chat 端点接收 OpenAI 兼容的 JSON 格式,内部把它拼成 ChatML 大字符串(<|im_start|>system\n...<|im_end|>)再发给推理引擎。Ollama 是"翻译官"——我们享受 JSON 的便利,模型收到的还是它只懂的 ChatML。
第 5 题:实测发现
今天 7 项 FC 测试中,Hermes 8B 暴露了哪些真实弱点?(多选)
A. JSON 格式经常出错,解析失败率高
B. 中文场景下参数提取可能遗漏细节(如"预算500")
C. 延迟 15-30s,多轮 Tool 调用等待时间过长
D. 模糊意图下倾向于强行调 Tool,而非追问用户
E. 完全无法理解中文
点击看答案
B、C、D。
- A 错:格式合规率 100%,7 次 JSON 全部有效。
- B 对:中文参数提取主体正确,但细节(预算约束)被遗漏。
- C 对:热启动 5-15s,3 轮 Tool 调用可能 15-45s,需异步体验设计。
- D 对:测试 6 中"beginner photographer what should I buy"被强行调了 search_product。
- E 错:中文 FC 可用(测试 3/4 都正确提取了 query 和 category)。
第 6 题:场景应用题
Day 6 结论说"System Prompt 控制行为,Tool 提供数据"。结合今天的 FC 实测,如果要设计一个 SmallRig 前台 Agent 帮助用户找兔笼,以下哪个架构设计最合理?
A. 在 System Prompt 里写死所有 SmallRig 产品信息,让模型直接推荐
B. 给 Agent 配置 search_product Tool,用户提问 → 模型调 Tool → 获取真实数据 → 生成推荐
C. 让用户自己输入 SKU 编号,模型只做格式校验
D. 放弃 Hermes,所有请求都走 Claude API
点击看答案
B。 这正是今天测试 7 验证的完整链路:用户说"需要 FX3 兔笼" → 模型输出 search_product("FX3", "camera-cage") → Harness 执行搜索 → 回传结果 → 模型基于真实数据生成推荐。A 的 token 有限且无法覆盖所有产品,C 体验太差,D 过于绝对——后台场景 Hermes 可行。
⏭️ 完成后:更新 当前进度