📚 Harness 学习计划 / 第1周 / Day01_精读HermesModelCard

Day 1 · 精读 Hermes-3 Model Card

属性
日期 2026-08-12(周三)
周次 第1周:双轨认知框架建立
轨1 · Hermes 技术认知
时间 1 小时
状态 ✅ 已完成

📋 Checklist

📖 阅读材料

材料 链接
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 备选方案——当数据隐私或成本是首要考虑时。

❓ 疑问

  1. Hermes 的 Function Calling 准确率在实际业务中够用吗?(需 Day 7 实测验证)
  2. 如果中文能力不足,SmallRig 的 Agent 场景是否可以用「英文 prompt + 翻译层」来绕过?
  3. 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 对话的正确顺序排列:

  1. 模型生成最终文本回复给用户
  2. 用户输入需求
  3. 模型输出 <tool_call> 决定调用工具
  4. 系统执行工具,拿到真实数据
  5. 系统把 <tool_response> 喂回给模型
  6. 模型读结果,判断信息是否足够
点击看答案

正确顺序:2 → 3 → 4 → 5 → 6 → 1

用户输入 → 模型判断需调工具 → 系统执行 → 结果回传 → 模型再判断 → 生成回复

如果第 6 步「信息不够」,链路会回到第 3 步(再次调用工具),形成循环。


第 5 题:对比题

当前 SmallRig AI 搜索的流程是:

用户输入 → 一次 API 调用 → 返回 aiReply 文本

如果要升级成 Agent,需要在中间插入哪两个步骤?

点击看答案

插入「模型自主决策调用工具」和「工具执行结果回传」。

具体来说,缺少的是:

  1. 模型判断是否需要调用工具 → 输出 tool_call
  2. 系统执行工具 → 返回 tool_response

当前 AI 搜索是「每次都直接调 API」,Agent 是「模型自己决定要不要调、调哪个、调几次」。


第 6 题:部署方式判断

SmallRig 计划把购物助手 Agent 部署到公司服务器上,用户在 mall 网站上通过聊天框使用。这种部署方式叫什么?

A. 本地 Agent
B. 自部署 Agent
C. 云端 Agent

点击看答案

B. 自部署 Agent。 模型跑在公司服务器上,用户通过网页访问。「本地 Agent」指模型跑在个人电脑上(如 Ollama),只有自己能用。「云端 Agent」指模型跑在 OpenAI 等第三方服务器上。


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