{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://wanxiang.ai/contracts/trace/tier2-trace-event.schema.json", "title": "Tier2TraceEvent", "description": "tier2 富游戏自治生成线的统一 trace 事件契约(H 族 · A2)。【这是什么】一条 trace 记录 = 一次生成轨迹里的一步,由 tier2/gen-worker/observability/trace.py 的 TraceAdapter 订阅 AgentScope 2.0.2 官方 typed Event System(reply_stream() 吐的 AgentEvent 流)映射而成。tier2 这条线只「订阅 + 映射」,不「埋点 + 采集」——事件流是框架现成件(源码 agentscope/src/agentscope/event/_event.py 已逐条核过)。【为什么独立成约】统一 trace 要让两条异构生成线(tier2 ReAct 多轮 / SAA 16 节点)写进同一张表,靠的是「接口对称、内容不对称」:一个对称的公共核心五字段子集 + 各轨一个不对称的 ext 扩展段——消灭 split-brain 是『每条派发路诚实镜像它真有的字段、没有的绝不编造』,不是强求字段对齐(H1)。本 schema 定义的是 tier2 这一轨写进统一表的记录形状;SAA 那一轨的扩展段由 Java 线另一个 adapter 产、字段各写各的。【字段口径来源】所有字段忠实映射 trace.py 已实现的 TraceStep / to_trace_step,凡代码未产的字段一律不造;代码注释提及为可选、当前未实填的字段(如 cost.tokens.cached、cost.cost_rmb)在各自 description 标注其填充时机。【与图说的对应】公共核心五字段 = H1 对称子集;ext 三段(reasoning/action/observation)= H1/H2 tier2 ReAct 三段扩展段,逐段对到 H2「七类强类型事件」(TextBlock*/ThinkingBlock* → reasoning、ToolCall* → action、ToolResult* → observation;ModelCall* 不单独成段而落 cost.tokens + ext.raw,ReplyStart/End 落 ext.raw 作一步回复边界)。【additive 立位】contracts/trace/ 是契约组新一类 additive 立位,本约不改、不破坏任何现有契约(events / game-package / tier2-verdict 等);随 0号 spike 或控制面 phase-1 才真接代码。状态=建(tier2 待 spike)。详见 docs/architecture/架构/生成引擎/tier2细节图说-H-观测与成本.md 图 H1/H2,以及 tier2/gen-worker/observability/trace.py。", "type": "object", "required": ["traceId", "step", "timestamp", "ext"], "additionalProperties": false, "properties": { "traceId": { "description": "公共核心子集字段(两条生成线同名同义必填)。一次生成的轨迹主键,贯穿整条生成任务链路,是对账 / 成本关联键,对接 tier2-verdict.schema.json 的 evidence.traceId。由 TraceAdapter 在构造时钉定,本次轨迹所有 step 共用同一个 traceId(trace.py TraceAdapter.trace_id)。", "type": "string", "minLength": 1 }, "step": { "description": "公共核心子集字段。第几步(tier2 = TraceAdapter 每 ingest 一个 AgentEvent 递增一次的步序;在 SAA 那一轨语义为第几节点)。从 0 起,由 adapter 内部计数器维护(trace.py TraceAdapter._step)。", "type": "integer", "minimum": 0 }, "cost": { "description": "公共核心子集字段。这一步折成人民币的成本载体;仅在 ModelCallEndEvent 那一步非空(End 事件带 token 用量),其余事件步为 null。本 adapter 只记 token 量,折人民币(cost_rmb)由 cost.py 按 new-api quota 权威口径事后 best-effort 回填(成本权威源是 new-api 计费行,trace 不携金额估算)。", "type": ["object", "null"], "$ref": "#/$defs/cost" }, "verdict": { "description": "公共核心子集字段。这一步 / 这道门的裁决(可空)。tier2 这一轨当前仅在 ToolResultEndEvent 处由工具执行最终状态(ToolResultState)填入(成功 / 失败 / 拒绝 / 中断 / 运行中),其余事件步为 null;门级裁决(九门 / 富游戏三门)由裁决引擎 judge 另行回填,不在 adapter 映射阶段产生(trace.py to_trace_step:verdict = ToolResultEnd 的 state)。", "type": ["string", "null"] }, "timestamp": { "description": "公共核心子集字段。本步对应事件的发生时刻,取 AgentEvent.created_at(ISO8601 字符串,源码 EventBase.created_at = datetime.now().isoformat())。事件缺 created_at 时为兜底空串。", "type": "string" }, "ext": { "description": "tier2 扩展段(不对称段,各轨各写各的,SAA 轨的扩展段字段与此不同名也不要求对齐)。一个 JSON 对象,必含 raw(原始事件类型 + 关键字段,反查用),按当前事件类型可含 reasoning / action / observation 三段之一(ReAct 三段:想一步 reason → 做一个动作 act → 看一次结果 observe)。一个事件步至多落三段中的一段;ModelCall* 与 ReplyStart/End 不落三段、只把关键字段写进 raw(trace.py to_trace_step:ext = {raw, [reasoning|action|observation]?})。", "$ref": "#/$defs/ext" } }, "$defs": { "cost": { "type": ["object", "null"], "description": "成本载体(ModelCallEndEvent 步)。tokens 由 adapter 实填(从 End 事件抓 input_tokens / output_tokens);cost_rmb 与 tokens.cached 是代码注释明确为可选、当前未由 adapter 实填的字段,标注其归属:cost_rmb 由 cost.py 折算回填,cached 预留缓存命中 token(代码 TraceStep 注释 {tokens?:{in,out,cached}, cost_rmb?})。", "additionalProperties": false, "required": ["tokens"], "properties": { "tokens": { "description": "本次模型调用的 token 用量。in / out 由 adapter 从 ModelCallEndEvent.input_tokens / output_tokens 抓取并实填;cached 预留(缓存命中 token,当前 adapter 未填,见 trace.py 注释)。", "type": "object", "additionalProperties": false, "required": ["in", "out"], "properties": { "in": { "description": "输入 token 数(ModelCallEndEvent.input_tokens)。", "type": "integer", "minimum": 0 }, "out": { "description": "输出 token 数(ModelCallEndEvent.output_tokens)。", "type": "integer", "minimum": 0 }, "cached": { "description": "缓存命中 token 数(可选,当前 adapter 未实填,预留;代码注释 {in,out,cached})。", "type": "integer", "minimum": 0 } } }, "cost_rmb": { "description": "本步折算人民币(可选)。adapter 不填,由 cost.py 读 new-api logs.quota 按 traceId 关联后 best-effort 回填(权威口径;trace 阶段不带金额估算)。", "type": "number", "minimum": 0 } } }, "ext": { "type": "object", "description": "tier2 扩展段对象。必含 raw;reasoning / action / observation 三段按事件类型至多落一段(纯函数 to_trace_step 对单事件的映射结果)。additionalProperties:false 锁死段名,防止 adapter 之外注入未约定段。", "additionalProperties": false, "required": ["raw"], "properties": { "raw": { "$ref": "#/$defs/raw" }, "reasoning": { "$ref": "#/$defs/reasoningSeg" }, "action": { "$ref": "#/$defs/actionSeg" }, "observation": { "$ref": "#/$defs/observationSeg" } } }, "raw": { "type": "object", "description": "原始事件类型 + 关键字段(调试 / 反查用,非判定来源)。所有事件步必填 event(原始 AgentEvent 类型名);其余键按事件类型有条件出现:ModelCallStart 带 model_name、ModelCallEnd 带 model_call_end=true(token 已落 cost),ReplyStart/End 带 reply_boundary 与 reply_id(ReplyStart 另带 agent_name)。映射源:to_trace_step 对 ModelCall* / ReplyStart-End / 其余事件(熔断 / HITL / Custom 等)只落 raw 不落三段。", "additionalProperties": true, "required": ["event"], "properties": { "event": { "description": "原始 AgentEvent 类型名(如 ReplyStartEvent / ModelCallEndEvent / ToolCallStartEvent;映射逻辑取 type(event).__name__,序列化 dict 形态取 type 字段)。", "type": "string", "minLength": 1 }, "model_name": { "description": "模型名(仅 ModelCallStartEvent 步;ModelCallStartEvent.model_name)。", "type": ["string", "null"] }, "model_call_end": { "description": "标记本步是 ModelCallEndEvent(token 用量已落 cost.tokens),恒为 true。", "type": "boolean" }, "reply_boundary": { "description": "一轮回复边界事件类型名(ReplyStartEvent / ReplyEndEvent;框住一步完整 reason→act→observe)。", "type": "string" }, "reply_id": { "description": "本轮回复 id(ReplyStart/End 步;AgentEvent.reply_id)。", "type": ["string", "null"] }, "agent_name": { "description": "agent 名(仅 ReplyStartEvent 步;ReplyStartEvent.name)。", "type": ["string", "null"] } } }, "reasoningSeg": { "type": "object", "description": "reason 段(想一步)。映射七类事件中的思考块与文本块:ThinkingBlockStart/Delta/End、TextBlockStart/Delta/End(源码事件类 ThinkingBlock* / TextBlock*)。phase 恒为 reasoning;kind 记具体原始事件类名;delta 仅在 *DeltaEvent 带增量文本 / 思考片段(落 sink 时可截断,此处保真)。", "additionalProperties": false, "required": ["phase", "kind"], "properties": { "phase": { "description": "段标记,恒为 reasoning。", "type": "string", "const": "reasoning" }, "kind": { "description": "具体原始事件类名(thinking / text 块的六类之一)。", "type": "string", "enum": ["ThinkingBlockStartEvent", "ThinkingBlockDeltaEvent", "ThinkingBlockEndEvent", "TextBlockStartEvent", "TextBlockDeltaEvent", "TextBlockEndEvent"] }, "delta": { "description": "增量文本 / 思考片段(仅 Delta 事件带;ThinkingBlockDeltaEvent.delta / TextBlockDeltaEvent.delta)。", "type": "string" } } }, "actionSeg": { "type": "object", "description": "act 段(做一个动作)。映射工具调用三类事件:ToolCallStart/Delta/End(源码 ToolCall* 事件类)。phase 恒为 action;kind 记具体原始事件类名;tool / toolCallId 在事件带对应字段时填(ToolCallStart 带工具名 tool_call_name 与 tool_call_id);argsDelta 仅 ToolCallDeltaEvent 带工具参数 JSON 增量片段。", "additionalProperties": false, "required": ["phase", "kind"], "properties": { "phase": { "description": "段标记,恒为 action。", "type": "string", "const": "action" }, "kind": { "description": "具体原始事件类名(工具调用三类之一)。", "type": "string", "enum": ["ToolCallStartEvent", "ToolCallDeltaEvent", "ToolCallEndEvent"] }, "tool": { "description": "工具名(事件带 tool_call_name 时填;ToolCallStartEvent.tool_call_name)。", "type": "string" }, "toolCallId": { "description": "工具调用 id(事件带 tool_call_id 时填;贯穿同一次调用的 Call 与 Result)。", "type": "string" }, "argsDelta": { "description": "工具参数 JSON 增量片段(仅 ToolCallDeltaEvent 带;ToolCallDeltaEvent.delta)。", "type": "string" } } }, "observationSeg": { "type": "object", "description": "observe 段(看一次结果)。映射工具结果四类事件:ToolResultStart / ToolResultTextDelta / ToolResultDataDelta / ToolResultEnd(源码 ToolResult* 事件类)。phase 恒为 observation;kind 记具体原始事件类名;toolCallId / tool 在事件带对应字段时填;state 仅 ToolResultEndEvent 带(工具执行最终状态 ToolResultState,use_enum_values 故为小写字符串值),同时该 state 被填进顶层 verdict。", "additionalProperties": false, "required": ["phase", "kind"], "properties": { "phase": { "description": "段标记,恒为 observation。", "type": "string", "const": "observation" }, "kind": { "description": "具体原始事件类名(工具结果四类之一)。", "type": "string", "enum": ["ToolResultStartEvent", "ToolResultTextDeltaEvent", "ToolResultDataDeltaEvent", "ToolResultEndEvent"] }, "toolCallId": { "description": "对应工具调用 id(事件带 tool_call_id 时填)。", "type": "string" }, "tool": { "description": "工具名(事件带 tool_call_name 时填;ToolResultStartEvent.tool_call_name)。", "type": "string" }, "state": { "description": "工具执行最终状态(仅 ToolResultEndEvent 带;源码 ToolResultState 枚举,use_enum_values 落为小写字符串值)。该值同时被填进顶层 verdict 作这一步裁决。", "type": "string", "enum": ["success", "error", "interrupted", "denied", "running"] } } } } }