Skip to content
预计 1 分钟右侧目录可快速定位

Runtime 数据库怎样设计 Key 和 Index:Schema、Key 与 Index ​

前置:Idempotency / Side-effect Semantics;Runtime Execution Identity
核心问题:Run/Node/Attempt 这些 Runtime 事实应该用什么稳定 Key,哪些查询值得建 Index,怎样避免恢复时找不到唯一执行记录?

一个 Harness 往往同时需要保存 Run 当前态、Node attempt、Checkpoint、EventLog 和外部副作用记录。这些数据的生命周期与查询方式不同,因此不能靠一张“大 JSON 状态表”解决全部持久化问题。

Mental Model ​

text
Runtime intent → DB transaction → durable facts/outbox → commit → async external effect → acknowledgement/reconciliation

Durable Agent Runtime 的关键是把 Run/Node/Tool/Checkpoint/Approval/Outbox 等事实建模成可恢复记录,并在并发更新时保护版本。

Schema Design ​

Schema 要从 Runtime 的执行事实、生命周期和查询路径反推,而不是先建一张“大 JSON 状态表”。高频 mutable state、append-only event、Checkpoint、Approval 和大 payload/artifact 应按更新模式分开,使恢复、claim、审计和归档都能有明确约束与索引。

Primary / Unique Key ​

Primary Key 提供稳定实体 identity;Unique constraint 则可以直接保护 idempotency_key、(run_id,node_id,attempt) 等业务不变量。分布式并发下,“先查再插”存在竞态,不能替代数据库唯一约束。

Index ​

Index 只为明确查询路径付费:从 WHERE / JOIN / ORDER BY、cardinality 和访问频率决定复合索引顺序,例如 run_id/status、approval/pending。更多索引意味着更高写放大和存储成本,尤其不要因为字段存在就逐列建索引或随意索引大 JSON。

最小实现 / 数据结构 ​

sql
UPDATE runs
SET status = :status, version = version + 1
WHERE run_id = :run_id AND version = :expected_version;

从访问路径反推 Runtime Schema ​

不要先画十几张表再找用途。以最小 Harness 为例,先列真实访问路径:

text
按 run_id 读取当前 Run
按 tenant + status 找待处理 Run
按 run_id + node_id 找 NodeExecution
按 operation_id 判断 Tool 副作用是否已记录
按 run_id + seq 顺序读取 Event

然后再设计 key/index。例如:

text
runs(run_id PK, tenant_id, status, updated_at, version)
node_executions(run_id, node_id, attempt, status, ...)
events(run_id, seq, event_id UNIQUE, ...)
operations(operation_id UNIQUE, run_id, node_id, status, ...)

索引应该服务查询而不是“字段重要就建”。events(run_id, seq) 对按 Run 重放很有价值;而给一个低基数 status 单列索引未必有用,可能更适合 (tenant_id, status, updated_at) 这样的实际 worker 查询路径。

Failure Modes ​

索引/主键与真实查询模式不匹配 ​

症状: 没有为 run_id/status/checkpoint lookup 等访问路径设计索引。

为什么危险: 数据量增长后恢复/列表/claim 全表扫描。

处理: 从 query plan 和唯一性语义反推 PK/unique/index。

如何验证 ​

Case断言
索引/主键与真实查询模式不匹配百万级数据下关键查询仍命中预期索引。

自测 ​

  1. 你最常按 run_id + status 查询 pending node,但表只有自增主键。什么索引/Key 设计更贴近 Runtime 的访问路径?
  2. 为什么“给每个字段都建索引”不是解决查询慢的可靠办法?索引还会增加哪些写入成本?

Sources ​

AI Engineering · Agent · Harness · Backend Systems