Trace Index Loop 领域模型
Loop 是 Runtime 启动并持续驱动的一次 Agent 执行生命周期。一次 Loop 可以包含多次模型生成、工具调用、工具输出和运行中的人类调整。loop_id 是当前已发布投影中引用这次执行的不透明 ID,start_record_id 指出它凭哪条物理记录成立。Runtime 如果报告了本轮使用的模型和 token 用量,Loop 还会保存可选的 model 与 usage;缺失表示没有可靠事实,不表示零用量。
Trace Index 领域模型 从程序结构视角定义 Session、Loop 和 Item。本页定义 Loop 的完整字段、身份、成员关系、结束边界和运行结果。
Loop 解决什么领域问题
Runtime 收到一项开启输入后,通常不会只调用模型一次。Agent 可能先解释准备做什么,再调用工具,读取工具输出,继续生成,并在执行期间接收人的补充或纠正。这些活动共同属于一次仍在推进的程序执行。
Loop 回答:哪些 Item 发生在同一次由 Runtime 持续驱动的 Agent 执行中,这次执行从哪里开始,以及是否已经结束并留下明确结果。
没有 Loop,工具往返会被拆成互不相关的消息;运行中的补充输入也可能被误认为下一次独立执行。Loop 的边界来自 Runtime 的程序结构,不来自输入文字包含几个任务,也不来自相邻消息看起来是否相关。
Loop 的完整形状
? 表示字段可以不存在。LoopId、SessionId 和 RecordId 都是不透明引用,调用方只能把它们作为完整标识进行比较和引用。
当前模型不为缺失事实建立额外的 unknown 或 open 值。没有 end 已经准确表示“尚未观察到结束”,end 中没有 outcome 已经准确表示“知道本轮结束,但不知道结果”。
Loop 的身份从明确开始建立
一条 Record 只有在 Runtime 的结构能够证明“这里建立了一次新的外层 Agent 执行”时,才能成为 start_record_id。这条证据可以同时携带 Runtime 的原生外层身份,也可以只声明一次外层生命周期开始。
native_id 不是建立所有 Loop 的前提。有些 Runtime 为外层执行提供稳定身份,有些 Runtime 只持久化能够确认开始的结构信号。两者都可以形成 Loop;区别只是后者省略 native_id。
身份遵守以下规则:
- 同一外层执行继续生成、调用工具、接收工具输出或处理运行中输入时,
loop_id不变。 - Runtime 重复记录同一个原生外层身份时,仍然是同一个 Loop,不因多了一条身份 Record 而新建对象。
- 前一 Loop 已经结束,Runtime 又建立新的独立执行时,形成新的
loop_id。 - 输入句柄、消息 ID、模型调用 ID、工具调用 ID、物理相邻和时间接近都不能单独建立 Loop 身份。
- 没有足够结构证据确认一次新的外层执行时,不创建 Loop。已经发生的 Item 仍然属于 Session,但不强行填写
loop_id。 - 更强证据证明原来的生命周期分区错误时,受影响的 Loop 和 Item 归属按正确边界重建。重建后的 Loop 可以获得新的
loop_id,领域契约不承诺复用旧值。
start_record_id 使用单条 Record,而不是 Record 范围或列表。它指向建立这次外层执行的规范证据。重复观察属于来源事实,不要求领域对象保存全部重复身份记录。
Loop 与 Session、Item
一个 Loop 恰好属于一个 Session,一个 Session 可以包含零到多个 Loop。Session 在第一轮执行开始前可以暂时没有 Loop。
成员关系的规范方向由 Item 的可选 loop_id 表达,Loop 不复制一个需要同步维护的 item_ids 列表。Loop 可以暂时没有 Item:例如 Runtime 已经明确建立执行,但尚未产生可选择为 Item 的活动。
Item 已经发生而 Loop 归属不能可靠确定时,它继续拥有必需的 session_id,并省略 loop_id。Trace Index 不为了让每个 Item 都落入一棵整齐的树而猜测边界。
Item 填写 loop_id 时,它自己的 session_id 必须与该 Loop 的 session_id 相同。Loop 不能包含属于另一个 Session 的 Item。
Loop 内顺序由 Item 的 loop_position 表达。它只表示同一 Loop 中的观察顺序,不表示因果、父子、分支或下一次执行从哪个程序位置继续。
Session 内的 Loop 顺序由 session_position 表达。它从 0 开始,并在同一 Session 中唯一。读取完整对话时间线时,先按 session_position 排列 Loop,再按各 Loop 内的 loop_position 排列 Item。不同 Loop 的 loop_position 都从 0 重新开始,不能直接拿来比较跨 Loop 先后。
模型与用量
model 与 usage 描述整次 Loop 中观察到的模型执行,而不是某一条消息或工具调用。它们留在 Loop 上,Agent 才能直接比较不同执行用了什么模型、上下文容量是多少,以及一轮工作消耗了多少模型 token,而不必从多条 Runtime 原生记录重复恢复并相加。
这些字段只保留 Runtime 确实报告的事实。model.id 不会触发模型名称到容量的推断;effort 也不被强行转换成跨 Runtime 的枚举。某个可选字段没有出现,表示 Runtime 没有报告或当前证据无法可靠建立它。Runtime 明确报告的 0 则仍然是已知的零,两者不能混淆。
不同 Runtime 对缓存 token 的报告方式不一样,usage 统一成下面的计数关系:
cached 和 cache_write 是 input 的组成部分,reasoning 是 output 的组成部分。统计总量时不能把这些子集再次相加。Trace Index 不保存另一项 total,因为它可以无歧义地由 input + output 得到。
usage 是 Loop 内已观察到的模型调用之和,不表示供应商账单、费用或整份 Session 的累计用量。原生计数如何转换成这组共同字段,以及多个原生报告如何避免重复累计,由 Adapter 代码和测试负责。
结束边界与运行结果
end 表示已经确认本轮不再继续,end.outcome 表示 Runtime 对整轮执行给出的结果。两者相关但不相同,形成三种有效状态:
字段是否存在已经完整表达这些状态,不再增加 open、bounded 或 unknown 等同义枚举。
completed 只表示 Runtime 正常结束了这次 Loop,不表示自然语言中的 Task 已经完成、答案正确或用户满意。
end 必须由外层执行边界支持。下一次独立 Loop 的开始可以限定上一 Loop 的 end,但不能单独产生上一 Loop 的 outcome。单次模型生成的停止原因、工具调用前的停止、输出长度耗尽或看起来像最终回答的文字,都不能单独证明外层 Loop 已经结束。
最终回答与运行结果也不能互相推导。agent.final_answer 是属于 Loop 的 Item 语义,end.outcome 是整次外层执行的运行结果。Loop 不增加 final_answer_item_id。读取回答时,应查询属于该 Loop 且语义角色为 agent.final_answer 的 Item。
建立、补全与重建
Loop 根据当前 Record 投影建立:
- 观察到明确的外层开始证据后,以该 Record 建立
loop_id、session_id、session_position和start_record_id,并在存在真实原生外层身份时填写native_id。 - 后续证据可以增加属于同一 Loop 的 Item,而不改变身份。
- 明确结束信号或下一次独立 Loop 的开始可以补全
end。 - Runtime 明确给出整轮结果时,可以补全
end.outcome。 - Runtime 报告模型身份、配置或用量时,可以补全
model与usage,而不改变 Loop 身份。 - 来源或映射规则变化并证明原分区错误时,相关 Loop 与 Item 归属一起按当前证据重建。
共同的证据和当前性约束见 Trace Index 投影模型。本页只定义 Loop 自己特有的成立条件。
不变量
任何合法 Loop 都满足:
loop_id、session_id、session_position和start_record_id同时存在。- 每个 Loop 恰好属于一个 Session。
native_id只表示 Runtime 的外层执行身份,不能由输入、消息、模型调用或工具调用句柄代替。end存在时必须具有一个record_id,且该 Record 必须证明外层执行结束或下一独立 Loop 已经建立。outcome只能出现在end内。outcome只能是completed、interrupted或failed,并且必须来自 Runtime 的整轮执行结构,不能从文字或单次模型停止原因推断。- Item 只有在 Loop 归属得到证据支持时才填写
loop_id。 - Item 填写
loop_id时,Item 与 Loop 必须属于同一个 Session。 loop_id只保证在当前已发布投影中唯一引用一项 Loop。来源或映射变化触发重建后,调用方不能假设旧值仍然有效。model存在时必须包含非空id;context_window只能来自 Runtime 报告,不能按模型名补全。usage存在时必须同时包含input与output;所有计数都是非负整数,且cached <= input、cache_write <= input、reasoning <= output。- 同一 Session 内的
session_position从0开始且不能重复;跨 Loop 顺序只能先按它确定。 - 缺失的
model、usage或其可选成员表示未知,不能按零处理;模型 token 总量只由input + output得出。
页面边界
Loop 不判断自然语言中的 Task 数量,不评价回答质量,也不把单次模型调用或消息句柄提升为外层执行。模型执行身份与归一化用量是可选的 Loop 属性;权限、指令和其他 Runtime 上下文如果形成 Item,仍由 Item 的 Semantic 表达,并以 Record 作为来源证据。它们不组成一份必须存在的 Loop 上下文快照。
具体 Runtime 的原生字段路径、Adapter 算法、数据库表和公共查询列不属于本页。人的输入怎样成为 Request 或 Steering,见 Item 语义契约。