离线 Agent 工具循环实验¶
用固定脚本替代模型决策,观察「决定下一步 → 运行时校验与执行 → 记录观察 → 停止」的边界。只需要 Python 3.10+ 标准库,没有安装步骤、API Key 或网络调用。
在仓库根目录运行:
python3 examples/agent_lab/lab.py --scenario all
python3 -m unittest discover -s tests -p 'test_agent_lab.py' -v
可以单独选择 happy、retry、approval、denied 或 loop:
输出是 JSON Lines:每行一条 decision、observation、错误、stop 或 summary。所有场景都会核对停止原因、实际工具尝试次数与工单创建数;任一核对失败,进程返回非零。all 每个场景使用独立 Runtime,不共享工单。
五条可观察路径¶
| 场景 | 注入条件 | 预期停止原因 | 预期结果 |
|---|---|---|---|
| happy | 检索一次后结束 | final_answer |
实际检索 1 次、创建 0 个工单 |
| retry | 首次检索临时失败 | final_answer |
最多 2 次尝试,本例第二次成功 |
| approval | 运行时已明确批准的同一请求调用两次 | final_answer |
写工具执行 2 次、工单只创建 1 个,第二次返回 replayed=true |
| denied | 无对应运行时批准 | approval_required |
写工具执行 0 次、创建 0 个工单 |
| loop | 策略持续要求检索 | step_budget_exhausted |
第 3 步之后停止,不再索取下一项决策 |
steps 计算策略决策次数,最终回答也占一步;读工具重试计入独立的 search_attempts。每次读调用的尝试上限包含首次调用。这个实验没有总时限、取消、token 预算、退避调度或并发执行,不能由步数上限推断已经覆盖这些限制。
代码中的边界¶
scripted()或固定 lambda 是决策器。run()拥有循环和停止预算,Runtime.invoke()拥有执行前的工具白名单、参数与批准检查。search在 4 条合成文本上按关键词交集排序,结果可为空。- 参数校验拒绝未知字段、缺失字段、非法取值和把
true当整数的情况。未知工具不会分发到其他函数,也没有 shell 或任意代码执行入口。 - 只有
search的TransientReadFailure会自动重试;参数错误、未知工具、未批准操作、幂等冲突和写结果不确定都会停止。 Approval(request_id, title)由可信运行时配置传入,绑定请求 ID 与完整标题。approval场景模拟“执行前批准已完成”,没有交互式批准 UI。决策参数中的approved=true会被拒绝,不能产生批准。create_ticket只修改当前 Python 进程里的字典。重复请求 ID 与相同标题返回已有工单;重复 ID 对应不同内容会拒绝。输出的创建数是字典终态计数,不是根据返回文字猜测。
write_attempts 表示通过参数与批准检查后进入模拟写路径的次数,包含幂等重放;它不等于新建对象数。被拒绝的请求会出现在 trace 中,但不会增加该计数。
写成功但响应丢失¶
测试 test_lost_write_response_stops_then_reconciles_without_duplicate 会:
- 在模拟后端创建工单,再注入
WriteOutcomeUnknown,替代“提交成功但调用方没收到响应”。 - 检查执行器已经停止,没有自动重试写操作。
- 由可信测试代码调用
lookup_ticket(request_id)查看同一模拟后端终态。 - 对同一 Runtime 再提交同一批准操作,确认返回原工单且数量仍为 1。
本例使用同一进程中的同一个 Runtime 实例顺序调用。进程重启、多个服务实例和并发请求需要额外的持久幂等记录、唯一性约束及外部系统对账设计。
用它准备面试¶
先猜测每个场景的终态,再运行确认。选一个失败场景,按这四句解释:
- 谁做决定,谁真正执行,谁拥有批准权?
- 哪个输入触发了失败,执行前后的状态分别是什么?
- 哪条限制使它停止,有没有已发生的副作用?
- 哪项输出或测试能证明自己的结论,哪部分仍未覆盖?
继续完成 7 天个人项目实验。接入真实 LLM、真实检索和持久存储是后续工作,需要另写适配器、测试集和评测记录。
测试覆盖与扩展¶
当前测试覆盖正常与空检索、工具白名单、参数拒绝、批准绑定、幂等重放与冲突、临时读错误恢复和耗尽、循环上限、写响应丢失及 CLI 场景自检。
决策器与工具在同一进程内运行,工单存储使用内存字典。扩展到真实服务时,可依次增加模型适配器、持久存储、并发控制、身份与租户隔离、执行沙箱、日志脱敏及调用费用统计。
合成文本及代码适用仓库根目录 LICENSE。