📚 Harness 学习计划 / 第2周 / Day07_测试HermesFC

Day 7 · 测试 Hermes Function Calling

属性
日期 2026-08-24(实际完成)
周次 第2周:动手体验+场景深挖
轨1 · Hermes 技术认知
时间 1 小时
状态 ✅ 已完成

📋 Checklist


✍️ 学习笔记

新增概念: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 帮你转) 拼字符串 + 正则解析

🧪 实测结果

测试环境

七项测试结果

测试 场景 是否正确 参数准确度 实际输出 备注
测试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 本身,而在:

  1. 延迟:本地推理 15-30s vs Claude 1-3s,差 10 倍
  2. 判断力:模糊场景下 Hermes 倾向于"强行调 Tool",Claude 会先追问
  3. 参数遗漏:中文场景下"预算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 是什么?

Q4:Ollama 发的是 JSON,为什么说 ChatML 是"大字符串"?

Ollama 是翻译层。 我们发 JSON 给 /api/chat,Ollama 内部转成 ChatML 大字符串再喂给模型。我们享受 JSON 的便利,模型收到的还是它只懂的 ChatML。


📤 产出


🧪 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。


第 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 可行。


⏭️ 完成后:更新 当前进度