Appearance
External Tool Call 与 Compensation
1. 为什么这组知识要一起学
把数据库用于保存 Runtime 事实和恢复状态,并正确处理事务边界与外部 Tool 副作用之间的一致性。
这几个知识点处在同一条工程链上。如果只记单个名词,很容易在真实系统里把责任放错层:例如让模型管理程序事实、让数据库 transaction 承担外部 API 原子性,或把一个 provider SDK 的行为误认为 Agent 的通用规律。
2. Mental Model
数据库负责 durable facts 与并发一致性;本地 transaction 不能神奇地包住外部 Tool 副作用。
text
Runtime State → Transaction → Run/Node/Tool/Checkpoint tables → Commit; 外部副作用通过 idempotency/outbox/reconcile 衔接3. 核心机制
Transactional Boundary vs External Tool Call
transaction 提供原子性/隔离,但只覆盖同一数据库资源。隔离级别决定并发可见性与冲突,不要长期持锁等待 LLM/HTTP。
Compensation / Reconciliation 基础
跨系统调用只能通过 saga/compensation/reconciliation 等显式策略处理不一致;“先 DB 再 HTTP”或相反都会存在 crash window。
4. 最小实现 / 伪代码
下面代码只表达边界和生命周期,不要求照抄到项目中:
sql
UPDATE runs
SET status = :status, version = version + 1
WHERE run_id = :run_id AND version = :expected_version;真正实现时应把 I/O、状态持久化、错误翻译和策略注入拆成可测试组件,而不是把示例扩成一个巨型函数。
5. 在 Shadow Harness 中怎么落地
设计 run/node/tool_execution/checkpoint/approval 表;用 unique/version 列帮助幂等与 optimistic concurrency。
建议为本章涉及的行为留下明确的 domain object、interface 和 trace event;只要一个关键行为只能通过读日志猜测,就说明 Runtime contract 仍不够清晰。
6. Production Engineering 检查项
- 索引由查询模式驱动
- pool 是容量上限
- transaction 边界尽量短
- 外部调用与 DB 之间设计 outbox/reconciliation
7. Failure Modes
7.1 事务中等待长 LLM/HTTP
当出现「事务中等待长 LLM/HTTP」时,重放 transaction/crash window,核对 version/unique constraint/execution record/outbox,特别关注外部调用是否可能已成功。 这类问题通常需要修改 contract、policy、state 或 adapter,而不是只追加 Prompt。
7.2 connection pool 被 async task 打满
当出现「connection pool 被 async task 打满」时,重放 transaction/crash window,核对 version/unique constraint/execution record/outbox,特别关注外部调用是否可能已成功。 这类问题通常需要修改 contract、policy、state 或 adapter,而不是只追加 Prompt。
7.3 把 exactly-once 当默认事实
当出现「把 exactly-once 当默认事实」时,重放 transaction/crash window,核对 version/unique constraint/execution record/outbox,特别关注外部调用是否可能已成功。 这类问题通常需要修改 contract、policy、state 或 adapter,而不是只追加 Prompt。
7.4 resume 重复副作用
当出现「resume 重复副作用」时,重放 transaction/crash window,核对 version/unique constraint/execution record/outbox,特别关注外部调用是否可能已成功。 这类问题通常需要修改 contract、policy、state 或 adapter,而不是只追加 Prompt。
8. Trade-offs
event log 审计强但读模型复杂;snapshot 读快;关系库对核心 run state 通常比过早引入多种存储更稳。
设计记录最好明确:当前约束是什么、备选方案有哪些、为什么现在选这个、未来什么条件出现时需要重构。 这样 ADR 才能随着模型和基础设施变化被重新审视。
9. Experiment / Evaluation
并发更新同一 run、进程 crash、tool 已成功但 DB 未记账等故障注入,验证幂等与 reconciliation。
实验应固定数据集、版本和环境,至少记录 success、latency、token/cost、attempt/step 数以及失败类型;涉及随机模型时需要重复运行而不是只看一次结果。
10. 常见问题
基础:Transactional Boundary vs External Tool Call 最容易被误解的点是什么?
transaction 提供原子性/隔离,但只覆盖同一数据库资源。隔离级别决定并发可见性与冲突,不要长期持锁等待 LLM/HTTP。
机制:这些能力在一次 Run 的哪个生命周期阶段生效?
沿着 Runtime State → Transaction → Run/Node/Tool/Checkpoint tables → Commit; 外部副作用通过 idempotency/outbox/reconcile 衔接 找位置,并明确它的输入、输出、持久化事实和失败传播。
工程:如果这一层失败,应该由谁恢复?
先区分 transient failure、invalid input、permission、semantic failure 与 irreversible side effect。恢复策略属于拥有该状态与副作用的 Runtime/adapter,而不是交给模型自由决定。
设计:规模扩大 10 倍后,哪个假设最先失效?
优先检查 context/token、并发/连接池、catalog 大小、持久化吞吐、trace 体积、身份与租户隔离。不要默认“多加机器”能解决语义和一致性问题。
11. Sources
12. 本文结论
掌握本文的标准不是能背定义,而是能画出数据流、写出最小 contract、解释失败恢复,并用测试或 benchmark 证明设计没有只停留在概念层。