第二十章:运行自己的最小 Harness
20.1 先完成一个完整闭环
随书代码位于 lab/。它只依赖 Python 3.10+ 标准库,不需要安装模型 SDK、保存 API 密钥或修改四套上游工程。脚本模型负责产生确定的流事件,文件工具、策略、日志、预算与验收由真实宿主代码执行。
请在本书仓库根目录运行,工作区使用一个新的临时目录。例如:
python3 lab/demo.py --workspace /tmp/harness-book-first-run程序会在目录不存在时创建它;若 hello.txt 不存在,写入初始拼写错误文本。它不会为了重复演示而覆盖已有文件。会话日志放在工作区 .harness/events.jsonl,工具拒绝访问这段保留状态路径。
20.2 预期看到什么
正常运行输出一个 JSON 对象,其中 status 为 verified。它并不是模型自己选择的状态,而是宿主在工具执行和 acceptance 通过后输出的结果。本版实跑包含十八个事件,最终文件为 hello, harness\n。
{"status":"verified","answer":"工具阶段结束,是否完成由宿主验收。","events":18}这个输出来自本书实验的实际运行,结果保存在 book/lab-results.json。临时目录名不属于稳定接口,事件数量也只对应这份教学流程,后续扩展不应为了保持数字不变而阻止合理新增事件。
20.3 重开同一会话
再次使用同一工作区执行相同命令,宿主会读取日志、核对目标和策略,并重新检查当前文件。若仍满足验收,直接返回已记录答案,不再发模型请求,也不重复三个工具调用。实跑事件数仍为十八。
如果你在两次运行之间修改了文件,旧的完成记录不会盖过当前事实。宿主重新验收失败,这时应核对外部变化,再建立新的任务会话,而不是把旧日志手工改成另一个成功故事。
20.4 观察拒绝路径
请使用另一个新目录:
python3 lab/demo.py --workspace /tmp/harness-book-readonly --read-only读取可以执行,写入策略会拒绝,后续检查不满足目标,程序输出 stopped 并以状态码 2 退出。原文件保留错误拼写。这里的“停止”包含可解释原因,不会被模型最后一段文字转换成成功。
20.5 文件地图与限制
harness.py 定义消息、流解码、工具、日志和 Engine;demo.py 负责实验工作区与验收;tests/test_harness.py 定义二十四项行为测试。完整代码随 EPUB 附录收录,下载仓库后可直接运行。
这不是生产级代理。它顺序执行工具,流会先完整缓冲,取消是合作式的,没有通用 Shell、操作系统沙箱或网络模型适配器。正因为范围明确,我们可以逐项实验关键保证,再讨论升级需要付出什么成本。