HARNESS / 代理工程下载 EPUB ↓
22 / 32

第二十一章:实验一,把流式协议接到真正的循环

21.1 从数据类型开始

Call 包含 id、name 和 arguments,Reply 包含文字与工具调用列表。两者采用不可变数据类,让一次完整模型回复成为执行边界。模型流接口只产生事件,不直接获得文件系统工具对象。

DemoModel 根据当前已提交的回复步数产生下一次回复。第一步读文件,第二步从真实工具结果提取旧哈希并请求写入,第三步检查内容,第四步给出结束文字。它没有直接改文件,也没有自己产生 verified 状态。

21.2 参数故意拆成两段

模型替身把每个工具参数 JSON 在中间切开,先发第一段,再发第二段。这样即使没有真实网络,也能检验宿主没有把“事件到达”当成“调用完整”。decode_stream 累积片段,遇到正常结束后才解析为 Call。

读者可以把正常结束原因改成 length,再运行对应测试。此时应该没有任何 tool.started,也不能出现文件写入。若程序仍然执行,说明完整性判断放在了副作用之后。

21.3 Engine 只推进已持久接受的工作

主循环先处理历史里已记录但尚未结算的调用,再决定是否需要请求下一次模型。收到完整回复后先保存 model.reply,下一轮才记录 tool.started 并执行。这样重启时,不必让模型重新猜一份同样的调用。

处理顺序可以写成:

完整接收模型回复
  -> 校验调用身份
  -> 持久保存 model.reply
  -> 持久保存 tool.started
  -> 执行工具
  -> 持久保存 tool.result
  -> 组织下一次模型视图

这不是跨所有组件的原子事务,却清楚划出了恢复器能看到哪些状态。

21.4 重复身份与预算

同一回复中的参数片段共享一个 call ID;后续回复再次使用已接受 ID,则被拒绝。否则恢复器会无法判断一个结果关联的是哪个动作。生产协议还可能需要供应商请求 ID、嵌套调用 ID 或重试尝试 ID,但这些身份应分别定义。

请求预算统计每次模型开始,包括临时失败后的重试。工具预算在进入新一次执行前检查。不能只限制循环次数,却让一个回复携带无限多个工具;也不能在执行完之后才发现已经超预算。

21.5 练习:插入一个可恢复错误

让第一次读取使用不存在路径,观察错误结果进入模型视图。本书 DemoModel 在读取失败后结束,由宿主验收决定停止;你可以扩展替身,让它第二次请求正确路径。验收条件是:错误有稳定身份,成功读取真实内容,最后的完成仍由独立检查确认。

这个练习研究宿主闭环,不是训练模型。等错误路径稳定后,再替换模型提供方,才有机会分清“模型选择不佳”和“循环实现不正确”。

非官方学习读物 · 固定源码快照 · 原始代码保留各自许可。GitHub · 源码依据 · 实验代码