KEEL · 龙骨 · A CURRICULUM FOR THE AI ERA

05. 让模型第一次用上只读工具 — keel 龙骨

现在你已经知道模型的决定还不是动作。接下来给它一个只读工具 lookup_incident,让它查询事件资料,再根据结果回答用户。

现在你已经知道模型的决定还不是动作。接下来给它一个只读工具 lookup_incident,让它查询事件资料,再根据结果回答用户。

只读工具适合作为第一个工具,因为它不会修改外部世界。你可以先专注于消息往返和权限边界,不必同时处理重复创建、回滚和审批。

一次往返里发生了什么

sequenceDiagram
    participant U as 用户
    participant H as Harness
    participant M as 模型
    participant T as lookup_incident

    U->>H: 查询 INC-001
    H->>M: 用户消息 + 工具描述
    M-->>H: assistant tool_call
    H->>H: 注册、参数、权限检查
    H->>T: 执行已验证参数
    T-->>H: tool result
    H->>M: assistant 请求 + tool result
    M-->>H: 最终回答
    H-->>U: 返回并记录

第二次模型调用不是重复。工具只返回结构化事实,模型需要再次看到事实,才能把它组织成面向用户的诊断。

消息的三次变化

messages = [
    {"role": "user", "content": "查询 INC-001。"}
]

# 1. 保存模型完整的 assistant 消息,其中可能含 tool_calls。
messages.append(assistant_message)

# 2. 只把经过执行器检查的结果作为 tool 消息追加。
messages.append({
    "role": "tool",
    "tool_name": "lookup_incident",
    "content": json.dumps(tool_result),
})

# 3. 再请求模型,根据工具事实生成最终回答。

不能只把工具结果拼成普通用户文本。role=tool 是协议语义的一部分,它告诉模型数据来自执行系统。

运行真实示例

python courses/foundation/agent-harness/course/project/examples/04_tool_calling.py

运行前预测:模型会不会一定请求工具?不会。概率模型可能直接回答,所以 Harness 必须处理“有工具决定”和“无工具决定”两条路径。

运行后检查:

这个例子还没有解决什么

它仍然是一个最小闭环,可能缺少:

下一章会把单次往返收进一个有状态、可停止、可恢复的 Harness.run()。

下一章:把往返变成有边界的运行

进入 keel 阅读