切换深色模式
08 · 真实模型接入:把候选动作接到受控执行器
前置:完成 01、02、05、06 与 L6。本课预计 3–4 小时。交付:一个异步循环、一个模型适配器、模型响应契约测试,以及一份明确区分模拟与真实请求的运行记录。
在前面的示例里,下一步是脚本写死的。本课让模型选择搜索、读取、提交答案或澄清,但执行权限和完成条件仍由程序掌握。源码中提供可选 Claude Messages 适配器,默认仍运行离线回放。
**验证状态:**已通过真实文件与模拟模型的端到端测试,以及 HTTP 请求构造测试;未使用 API 密钥调用真实模型。因此本课证明的是本地运行与适配契约,不提供真实模型成功率。你完成在线实验后,需要保存自己的运行证据。
1. 先看三层边界
text
模型适配器:messages + tools → 工具候选动作
↓
运行时:检查结构、调用 ID、权限、时限 → 调用工具
↓
知识库:搜索元数据 / 读取精确版本 → tool_result
↓
回传观察,下一轮模型继续决策claude.mjs 负责 HTTP 形状,runtime.mjs 负责执行规则,knowledge.mjs 负责真实文件。更换模型提供方时,应替换适配器;不能为了迁就模型输出而放松读取权限。
本课使用五个工具:search_notes、read_note、submit_answer、request_input、report_insufficient。后三个是本项目定义的控制动作,并非提供方自带工具。将结束也建模为结构化工具请求,便于用相同参数校验入口处理。
2. 下载与运行
推荐下载 完整实战包,解压后在包含 docs 的目录打开 PowerShell。也可以直接在本站项目根目录运行:
powershell
node docs/public/examples/research-project/cli.mjs "延时任务 故障 恢复"
node --test docs/public/examples/research-project/project.test.mjs默认输出 mode: offline-replay。正常情况经过搜索、读取、提交,最后为 awaiting_review。回放器不理解问题,只取第一个搜索结果;它用于验证工具链,没有模型调用费用。
源码入口:运行时、适配器、命令入口、测试。单独下载源码时需要保持同目录关系,检索器详见下一课。
3. 为什么选显式适配器
本项目直接使用 Node.js 的 fetch,让学生看到请求与返回的边界,不依赖 Agent 框架。请求使用顶层 system,对话保存在 messages;助手发出 tool_use 后,由客户端执行,再在用户消息内回传对应的 tool_result。这些是 Messages API 的接口约定。Messages API
以下是本课内部保存的简化交互形状,不包含密钥或完整正文:
json
[
{ "role": "user", "content": "请研究延时任务" },
{ "role": "assistant", "content": [
{ "type": "tool_use", "id": "call-17", "name": "search_notes",
"input": { "query": "延时任务", "limit": 3 } }
] },
{ "role": "user", "content": [
{ "type": "tool_result", "tool_use_id": "call-17",
"content": "{\"ok\":true,\"items\":[]}", "is_error": false }
] }
]不要根据数组位置猜结果属于哪次调用。tool_use_id 必须引用原始 ID。参数错误也要作为工具观察回传,让模型有机会生成修正后的新调用。本实现的所有请求仍消耗决策轮数。
4. 每轮只执行一个完整请求
适配器配置 tool_choice: { type: 'any', disable_parallel_tool_use: true },要求每次使用一个工具;服务端返回后,运行时仍检查只有一个候选调用。该组合并非所有模型都支持,必须选择支持强制工具调用的模型;不能仅凭账户可用就认为兼容。本课未启用扩展思考。单工具约束与模型限制
工具参数由 input_schema 描述,运行时执行前再次校验。工具定义
| 返回情况 | 当前处理 | 原因 |
|---|---|---|
| 一个完整且合法的工具请求 | 检查后执行 | 符合本课契约 |
| 同轮两个工具请求 | 整轮失败,不执行其中一个 | 避免半执行和未配对结果 |
stop_reason 为 max_tokens | 不执行候选动作 | 生成可能不完整 |
| 只有普通文本,没有工具请求 | 返回协议形状错误 | 本版统一用控制工具结束 |
| 重复调用 ID | 停止,不重复执行 | 无法可靠区分新意图与重放 |
| 参数有未知字段 | 返回业务错误供修正 | 防止模型偷偷夹带身份或副作用 |
选择单调用不是性能结论,而是本课的复杂度边界。扩展并行前,要定义每个 ID 的结果、失败策略和共享预算,不能直接把 for 改成 Promise.all。
5. 异步化最容易遗漏的两个时间点
第一次检查在请求前,防止已到期任务发起新请求。第二次在等待返回后,防止迟到的模型结果继续触发工具。只在 while 顶部检查,可能让慢响应越过总期限。
源码中的 bounded 把操作与截止计时器竞争,同时传入 AbortSignal。合作式网络客户端会收到取消信号;即使某个适配器忽略信号,本地等待也会结束。超时以后,迟到结果不会新增证据或调度下一步。
这不保证远端已经停止计费,也不保证非合作式工具取消了外部效果。本项目只有读取;未来加入写操作时,还要记录结果未知并对账。不能把本地 exhausted 翻译为“远端从未执行”。
6. usage 和费用分别保存
每次收到模型响应,保存模型标识、耗时、原始 usage 与汇总的输入/输出 token。任何一次缺 usage 或调用失败,usage.complete 设为 false;汇总数字只是已知部分,不能当成整个任务的费用依据。
回放模式没有 usage,所以数字为 0 且 complete 为 false,另有 cost.reason: no_model_request。真实模式的 cost.amount 保持 null:价格、缓存及其他计费维度需要按实际账户和请求核算,不在代码里填一个会过期的费率。
默认每次输出上限是 1800 token,总轮数 8、总时限 60 秒。这些是教学参数,不是适合所有任务的建议,也不是严格的总费用上限。调用前若要限制现金消耗,应另做账户预算与输入估算。
7. 可选在线实验
只在你自己的终端配置环境变量,不把密钥粘贴到文章、源文件或聊天。使用自己账户实际可用且支持上述强制工具模式的模型标识;若接口返回不支持的参数,先核对模型能力,不修改执行器来偷偷接受不完整请求。适配器固定请求 Anthropic 官方端点;本项目不会自动寻找任何本机凭证。
powershell
# ANTHROPIC_API_KEY 应已由你在本机安全配置。
$env:ANTHROPIC_MODEL = "替换为你账户可用的模型标识"
node docs/public/examples/research-project/cli.mjs --live "现有资料能证明哪种延时方案的容量吗?"此命令会发送问题,以及两篇允许文章中被搜索或读取的内容到模型提供方,并产生 API 用量。默认资料范围由 cli.mjs 的可信 MANIFEST 固定;不要把私人资料随手加入在线实验。运行程序本身不需要向用户提供站点公网地址。
预期行为不是固定措辞:模型应根据证据说明材料缺少容量测量,或者提交带缺口的候选答案。若它编造吞吐数值,即使引用合法,也应在人工评测中拒绝。保留模型失败样本,才知道适配之后的真实质量。
8. 实验:先破坏,再修复
- 在测试副本中让模拟响应同时返回两个
tool_use,确认没有工具执行。 - 首次返回空 query,检查下一轮收到
is_error:true且 ID 配对;再给一个合法请求。 - 让模型 Promise 一直不返回,确认 deadline 到期后结束且没有证据。
- 对一个未读 ID 提交答案,确认不能到达
awaiting_review。 - 有在线条件时,至少运行正常、容量缺证、未知主题三题;逐条人工检查,不只看状态。
参考答案与验收
前四项在 project.test.mjs 有可运行参考。通过意味着本地控制分支符合约定,不能证明模型能正确选择工具。第五项没有统一成功文本:记录每题问题、资料快照、模型标识、usage、真实轨迹、支持关系与最终判定。缺密钥时第五项标为“未执行”,不能填写 0 失败。
9. 常见接入故障
| 现象 | 判断依据 | 下一步 |
|---|---|---|
| 启动失败但没有轨迹 | 工作目录、文件清单、环境变量 | 先跑默认离线命令,定位本地还是配置问题 |
provider_http_401 | 提供方拒绝认证 | 在本机检查凭证,勿输出密钥 |
provider_http_429 | 提供方限流 | 当前版本停止;后续设计有限退避,不自动无限重试 |
expected_one_complete_tool_call | 返回形状或停止原因不符合契约 | 检查模型能力和实际响应类型,不执行半段参数 |
awaiting_review | 引用结构已检查 | 人工检查结论是否受原文支持 |
本课不提供流式输出、扩展思考、Prompt Cache、自动重试或跨进程恢复。保持这些边界可见,下一课专门完善模型看到的资料。