文档版本:v1.3 final
契约版本:contract_version = 2.0(frozen;序列化载荷中的取值,与文档版本独立,见第 1.2 节)
更新日期:2026-09-20
配套主文档:《Metric、Log、Trace、Profiling 联合分析研究报告(图解与案例版)》v1.6.1
适用对象:联合分析平台实现者、查询适配器开发者、诊断智能体接入方、POC 验收评审人
1. 定位与使用方式
1.1 与主报告的分工
主报告负责方法论与决策依据,本分册负责实现口径。两者的分工:
| 主报告 | 本分册 | |
|---|---|---|
| 回答 | 为什么这样设计、有哪些边界和陷阱 | 字段叫什么、取什么值、怎么算 |
| 读者 | 架构评审、立项决策、跨团队沟通 | 实现者、接入方、验收人 |
| 变更节奏 | 随方法论认知更新 | 随实现细节迭代,通常更频繁 |
两份文档独立版本迭代。本分册中任何与主报告方法论冲突之处,以主报告为准,并应反向修订本分册。
**本分册给出的是字段与口径的建议基线,不是行业标准。**所有阈值均为首轮 POC 的讨论起点,冻结前须结合目标服务、数据规模、故障风险和现有基线调整。
1.2 契约版本与兼容策略
一旦工作台、查询适配器和诊断智能体围绕本契约开发,契约本身就必须可版本化演进。
**文档版本与契约版本相互独立。**本文档为 v1.3 final,其定义的载荷契约为 2.0。文档可因措辞、示例、验收阈值等原因单独修订而不改变契约;契约的 major 变化也不要求文档跟随同号。二者不得混用同一个版本号。
本次升至 2.0 的原因即在于此:Evidence Contract 由单层结构改为 QueryResult + EvidenceBundle 两层,关联状态由记录级下沉至关联边级,来源标识由二元组改为三元组,均属下表中的“层级调整”与“字段改名”,按本节规则必须升 major。
每个顶层序列化载荷必须携带 contract_version(语义化版本,如 "2.0")。嵌套在 EvidenceBundle 内的 QueryResult 继承外层版本,不重复携带;若 QueryResult 独立传输(例如适配器直接返回单源结果),其自身必须携带 contract_version。实现方内部若另有存储结构版本,用 schema_version 单独标识,两者不得混用。
变更分级:
| 变更类型 | 版本位 | 说明 |
|---|---|---|
| 新增可选字段 | minor | 向后兼容。消费方须忽略未知字段,不得因此报错 |
| 新增枚举取值 | minor | 条件性兼容,见下 |
| 字段改名、删除、类型变更 | major | breaking change |
| 字段语义变更(名称不变但含义变) | major | 比改名更危险,须强制升 major |
| 必填性变更(可选转必填) | major | — |
| 层级调整(字段在结构中移位) | major | 见上文关于 2.0 的说明 |
枚举扩展的强制约束:新增枚举取值只有在消费方遵守“未知取值一律降级为该枚举的安全兜底值”时才是向后兼容的。因此所有消费方实现必须对下列枚举设置默认分支,不得使用穷尽匹配。未遵守此约束的消费方,任何枚举扩展对它都是 breaking change。
**并非所有枚举都适用同一条兼容规则。**判定标准只有一条:
消费方在不理解某个取值含义的前提下,能否仍然做出安全且不误导的处理?
能,则该枚举可降级,新增取值属 minor;不能,则新增取值本身就是 breaking change。据此分为两类。
**第一类:可降级枚举。**必须定义安全兜底值,消费方必须实现默认分支。新增取值为 minor。
| 枚举 | 兜底值 | 说明 |
|---|---|---|
query_status |
UNKNOWN |
与 ERROR 严格区分:ERROR 是“查询确实失败了,原因归入其他”;UNKNOWN 是“无法判断这次查询处于什么状态”,典型来源是收到更高版本生产端的未知取值 |
data_status |
UNKNOWN |
— |
completeness |
UNKNOWN |
消费方不得把 UNKNOWN 当作 COMPLETE |
correlation_status |
UNKNOWN |
— |
evidence_level |
UNASSESSED |
哨兵状态,不是第六级 |
hypothesis.status |
UNVERIFIED |
未知取值按“尚未验证”处理,不得按“已验证”处理 |
truncation_reason |
UNKNOWN |
可降级:completeness = PARTIAL 已承载可行动信息,不理解具体原因也不会误判 |
truncation_dimension |
UNKNOWN |
同上,QUERY_BUDGET 已说明截断性质 |
validation.method |
OTHER |
不理解具体方法仍可如实展示,不影响 status 的判读 |
generated_by |
UNKNOWN |
未知来源按“血缘不明”处理,属保守方向 |
第二类:结构性枚举。取值决定了其他字段如何解释,因此不理解取值就无法安全处理。新增取值默认视为 breaking change,须升 major;除非该枚举在定义处明确写明“未知值可安全忽略”的策略。
| 枚举 | 为什么不可降级 |
|---|---|
source_type |
决定该记录属于哪类数据、走哪条核验路径与展示逻辑 |
correlations[].type |
直接决定 target 的 Schema;不理解 type 就不知道 target 里的字段该如何解释 |
target.entity_type |
决定 entity_id 指向什么 |
target.resource_type |
决定 resource_id 指向什么 |
因此不建议机械地给所有枚举都加 UNKNOWN:给 correlations[].type 加兜底值毫无意义,消费方拿到未知 type 时连 target 都无法解析,此时正确行为是拒绝该条边并按 breaking 处理,而不是假装能理解。
兜底方向始终取保守一侧:不确定时降级,不得升级。
兼容窗口建议:major 版本发布后,生产端应在约定期限内同时支持新旧两个 major 版本,消费方完成迁移后再下线旧版本。跨 major 版本的历史诊断快照须保留其原始 contract_version,不得按新契约重新解释(参见主报告附录 A.4 的可复查要求)。
2. 查询结果状态契约
对应主报告 6.2 节。四个维度彼此正交,必须分别返回,不得合并为单一枚举。
归属层级(决定第 4 章的结构分层):
| 维度 | 归属对象 | 出现位置 |
|---|---|---|
query_status |
一次对某个数据源的查询 | QueryResult |
data_status |
一次对某个数据源的查询 | QueryResult |
completeness |
一次对某个数据源的查询 | QueryResult |
correlation_status |
一条关联边(一条证据与某个目标之间的一条关系) | Evidence.correlations[] |
一次跨源诊断会产生多条 QueryResult、多条 Evidence 和更多条关联边,三者数量互不相等:一次查询可能产出多条证据也可能一条都没有;一条证据通常同时参与多条关联边。
**确定性属于关系,不属于记录。**同一条日志可以精确绑定到某个 Span(EXACT),而该 Span 归属哪个部署仍然只是候选(CANDIDATE)。给整条记录贴一个 correlation_status 无法表达这种情况,详见 2.4 节。
2.1 query_status:这次查询本身成功了吗
| 取值 | 含义 | 使用约束 |
|---|---|---|
OK |
查询正常完成 | — |
TIMEOUT |
超出该源的超时预算 | completeness 置为 PARTIAL;若已获得结果则一并返回,若超时发生在首条结果之前则 data_status = UNKNOWN |
UNAVAILABLE |
数据源不可达或拒绝服务 | 不得降级表达为“无记录” |
PERMISSION_DENIED |
使用方对该源或该范围无权限 | 必须与 NO_MATCH 严格区分,否则使用方无法判断是系统没有还是自己看不到 |
ERROR |
其他查询失败 | 须附带来源侧错误标识,便于排查 |
UNKNOWN |
无法判断查询状态 | 兜底值。与 ERROR 区分:ERROR 表示确定失败,UNKNOWN 表示状态不可判定。消费方不得视为 OK |
2.2 data_status:目标数据存在吗
| 取值 | 含义 | 使用约束 |
|---|---|---|
FOUND |
查到目标记录 | — |
NO_MATCH |
查询成功且范围完整,确实无匹配记录 | 表示“查到了,没有”;仍不能推出“系统没问题” |
EXPIRED |
目标已超出保留期 | 须有保留策略或保留审计作为依据,不得由查不到推断 |
SAMPLED_OUT |
目标在采样阶段被丢弃 | 仅当来源提供明确采样决策审计证据时才可填写,否则返回 UNKNOWN |
NOT_COLLECTED |
该字段/信号在该对象上未采集 | 仅当来源提供采集配置审计证据时才可填写,否则返回 UNKNOWN |
UNKNOWN |
无法区分上述情况 | 默认值。不确定时必须落在此项 |
硬约束:绝大多数数据源不记录“这条我采样丢弃了”“这个字段我没采集”。
SAMPLED_OUT与NOT_COLLECTED若无审计证据支撑,就是带确定性外观的猜测。实现方在接入每一个数据源时,须先确认该源是否具备提供这两类证据的能力,并在适配器配置中显式声明;未声明的源一律只能返回UNKNOWN。
2.3 completeness:拿到的是全部吗
| 取值 | 含义 |
|---|---|
COMPLETE |
查询范围内结果完整 |
PARTIAL |
因分页、预算、超时或源侧限制被截断 |
UNKNOWN |
无法判断结果是否完整(兜底值) |
消费方不得把 UNKNOWN 当作 COMPLETE:在诊断语境下,“不知道是否完整”必须与“确认完整”分开处理,否则会退化为“没查到异常即无异常”。
PARTIAL 必须附带截断原因。由于一次查询可能同时触发多个限制(例如既超时又触及扫描预算),truncation_reason 定义为数组:
| 取值 | 含义 |
|---|---|
PAGE_LIMIT |
分页上限 |
TIMEOUT |
超时预算 |
SOURCE_LIMIT |
源侧自身限制 |
QUERY_BUDGET |
触及第 7 章定义的查询预算 |
UNKNOWN |
已截断但原因不明,或消费方对未知取值的降级结果(1.2 节) |
出现 QUERY_BUDGET 时必须同时给出 truncation_dimension,取值为触顶的预算参数名:max_time_range / max_entities / max_sources / max_scan_bytes / max_results / max_recursive_depth / UNKNOWN;多个维度同时触顶时该字段亦为数组。
两处的 UNKNOWN 是 1.2 节兜底规则的合法落点:消费方执行降级后写回的值必须仍然符合本 Schema,否则就会出现“规范允许降级,Schema 不接受降级结果”的自相矛盾。生成端不应主动使用 UNKNOWN,除非确实无法判定截断原因。
这样设计是因为预算参数会随实现演进增减。把每个参数都做成一个 truncation_reason 取值会导致枚举频繁扩张,而 QUERY_BUDGET 加维度名的组合可以扩展而不破坏兼容。
2.4 correlation_status:这条关联关系确定吗
对应主报告 6.2、6.3 节与附录 B.1 的验收口径。
**该状态标注在关联边上,不标注在证据记录上。**一条证据同时参与多条关联,各边的确定性可以不同:
证据 trace-span-S2 → T7 / S2 (REQUEST_SPAN) EXACT
证据 trace-span-S2 → 实例 I17 (ENTITY_RELATION) CANDIDATE
若只给这条证据一个状态,EXACT 和 CANDIDATE 都是错的。因此 Schema 中采用 correlations[] 数组,逐边标注(见 4.3 节)。
边的 source 语义
一条边的 source 恒为其所属的父 Evidence,不在边内显式声明。target 只允许一个明确目标。这条规则必须定死,否则实现者会在两种理解之间分裂:一种认为 source 永远是父 Evidence,另一种认为 source 可以是前一条边的 target(即把 correlations[] 当成链式关系包)。
由此得出一条推论:**边不可传递复合。**若要表达跨多跳的关系(例如“该日志所属实例的部署版本”),必须显式生成新的关联边,且:
复合边的
status不得高于链路上最弱的一环。链路最弱环节是确定性的上限,而不是充分条件。
具体说:EXACT 加 CANDIDATE 的上限只能是 CANDIDATE;即使上游各边均为 EXACT,仍须确认该关系具备可传递语义、各跳处于一致的事件时间与有效期区间,并由明确规则重新判定后,复合边才可标记为 EXACT。不得仅以“上游边都是 EXACT”为由自动推导出复合边为 EXACT。
type 与 target Schema
type 是结构性枚举(见 1.2 节),它直接决定 target 的字段结构:
| type | 含义 | target 必填字段 |
典型判定依据 |
|---|---|---|---|
REQUEST_SPAN |
请求/执行关联:该记录属于某一次执行 | trace_id 必填;span_id 条件必填(关联到整条 Trace 而非具体 Span 时可省略) |
Trace/Span 绑定或其他确定性执行键 |
ENTITY_RELATION |
实体历史关系:该记录归属哪个逻辑实体 | entity_type + entity_id |
带有效期的历史关系 + 可信事件时间 |
RESOURCE_CONTEXT |
资源上下文关联:该记录产生于哪个承载资源 | resource_type + resource_id |
进程身份、容器与主机关系 |
两个 target 枚举同样是结构性枚举:
| 枚举 | 取值 | 边界 |
|---|---|---|
entity_type |
SERVICE / DEPLOYMENT / INSTANCE |
指向逻辑实体 |
resource_type |
POD / CONTAINER / HOST / PROCESS |
指向承载资源 |
ENTITY_RELATION 与 RESOURCE_CONTEXT 的分界即在于此:前者回答“属于哪个服务/部署/实例”,后者回答“跑在哪个 Pod/容器/主机/进程上”。二者不重叠,也不可互相替代。
RESOURCE_CONTEXT 对应 OTel Profiles 概念页区分的 resource-context correlation,使 Profile 到进程、容器、Pod、主机等承载资源的关联纳入同一模型,不必另设字段。注意逻辑实例 INSTANCE 属于 entity_type,不得放入 resource_type。
| 取值 | 含义 | 判定要求 |
|---|---|---|
EXACT |
确定性关联 | 依据请求上下文或唯一身份键直接命中;不确定时必须降级,不得凑数 |
CANDIDATE |
启发式候选 | 由时间窗口、实体范围、耗时特征等推出;界面与契约中必须标明为候选 |
AMBIGUOUS |
存在多个候选且无法区分 | 例如误差窗口内有两个 Pod 候选、新旧身份空间无法判等 |
UNKNOWN |
不具备判定依据 | 默认值 |
核心取舍:对诊断系统而言,错误地声称
EXACT比返回UNKNOWN危险得多。宁可不知道,也不能精确地关联错。
不同 type 的误判后果不同,验收时须分别统计(第 11.1 节):REQUEST_SPAN 误判会把不相干的日志或样本塞进本次诊断;ENTITY_RELATION 误判会把证据归到错误的版本或实例上,进而误导版本对照。
2.5 典型组合
字段名使用第 4 章的扁平形式。注意 correlation_status 归属于关联边而非查询记录,此处并列仅为便于对照;实际载荷中它出现在 Evidence.correlations[] 内。
| 场景 | query_status | data_status | completeness | correlation_status |
|---|---|---|---|---|
| 查询成功,范围完整,确实无记录 | OK |
NO_MATCH |
COMPLETE |
— |
| Trace 保留审计确认已过期 | OK |
EXPIRED |
COMPLETE |
— |
| 日志源超时,返回部分结果 | TIMEOUT |
UNKNOWN |
PARTIAL |
— |
| 误差窗口内两个 Pod 候选 | OK |
FOUND |
COMPLETE |
AMBIGUOUS |
| 扫描预算触顶 | OK |
FOUND |
PARTIAL |
EXACT |
| 使用方无权限 | PERMISSION_DENIED |
UNKNOWN |
— | — |
| Exemplar 环形缓冲已覆盖 | OK |
UNKNOWN |
COMPLETE |
UNKNOWN |
3. 证据等级
对应主报告 4.4 节。与 correlation_status 是两个不同维度:后者描述一条关联边的身份与关系确定性,前者描述整组证据的支撑程度。
| 取值 | 含义 | 上升到下一级所需的额外证据 |
|---|---|---|
ENTITY_RELATED |
同属一个实体 | 事件时间 + 历史生命周期与资源关系(该实例当时运行在哪台主机、属于哪个部署) |
WINDOW_RELATED |
同一时间窗口及相关资源 | 请求上下文:Trace/Span 绑定,或其他确定性执行键 |
EXECUTION_RELATED |
同一次执行 | 代码与版本差异分析 |
MECHANISM_HYPOTHESIS |
形成可解释观测的机制假设 | 对照实验 |
MECHANISM_VERIFIED |
控制条件下复现并验证 | — |
UNASSESSED |
哨兵值,不是第六级:尚无法评估证据等级 | 兜底值。证据包不含任何证据、或收到未知取值降级时使用 |
**每一级都不能由前一级自动推导。**输出诊断结论时必须标注当前等级;停在 MECHANISM_HYPOTHESIS 并说明还缺什么,优于直接输出 MECHANISM_VERIFIED。
注意前两级跃迁所需的证据类型不同,容易混淆:从 ENTITY_RELATED 到 WINDOW_RELATED,靠的是时间与历史资源关系;请求上下文属于再下一级的跃迁条件。在尚无请求身份时以“有 Trace 在同一窗口”为由标注 EXECUTION_RELATED,是本模型最常见的误用。
另有一条强制规则:
evidence_level不得高于该证据包实际携带的证据所能支撑的等级。
也就是说,若 evidence[] 为空,evidence_level 只能是 UNASSESSED。如果窗口级判断来自 K8s 历史关系、实体注册表或其他上下文事实,那么这些事实本身就是证据,必须作为条目进入 evidence[],而不是以“背景信息”的名义支撑一个更高的等级。
4. 证据契约 Evidence Contract
统一的机器可读结构,人机双接口共用(主报告 7.4 节)。三条核心设计:
- 分两层:
QueryResult描述“对某个源的一次查询发生了什么”,EvidenceBundle描述“这次诊断收集到的跨源证据整体”。 - 确定性属于关系:关联状态标注在
Evidence.correlations[]的每条边上,不标注在证据记录上。 - 事实与推断分离:
evidence只承载观测到的记录,hypothesis承载推断且带独立验证状态。
4.1 序列化约定
| 约定 | 规则 |
|---|---|
| 契约版本 | 顶层载荷必须带 contract_version;嵌套的 QueryResult 继承外层版本,独立传输时自身必须携带 |
| 字段命名 | 统一使用扁平字段名(query_status、data_status、completeness、correlation_status),与第 2 章一致;不使用 query.status 这类嵌套形式 |
| 时间戳 | RFC 3339,含时区,如 2026-09-20T10:04:00+08:00。主报告的教学案例可继续显示短时间,实现必须用完整格式 |
| 记录标识 | 统一为 source_type + source_system + source_record_id 三元组(第 5 章),不使用跨源拼接的裸字符串 |
| 空值语义 | 数组字段无内容时返回空数组,不得省略;省略表示“未检查”,空数组表示“已检查且无内容” |
| 未知字段 | 消费方必须忽略并继续处理 |
| 未知枚举值 | 消费方必须降级为该枚举的兜底值(见 1.2 节),不得升级 |
4.2 QueryResult:单源查询结果
query_id: q-20260920-100501-log-01 # 指向 9.3 节审计记录中的实际查询条件
source_type: LOG
source_system: es-prod-cluster-a
query_status: OK
data_status: FOUND
completeness: COMPLETE
truncation_reason: []
effective_time_range: # 该源实际使用的窗口,可能因时钟偏差宽于 bundle 级 time_range
start: "2026-09-20T10:03:30+08:00"
end: "2026-09-20T10:06:30+08:00"
time_quality:
clock_offset_estimate: "+120ms"
result_count: 3
effective_time_range 与 bundle 级 time_range 并存且可以不同。第 6 章规定“不得在扩大窗口后直接宣称精确关联”,若实际使用的窗口不落到 QueryResult 上,该规则事后无法审计——审计者看不到当时用的是哪个窗口。
4.3 EvidenceBundle:一次诊断的跨源证据包
contract_version: "2.0"
subject:
service_id: svc-042
deployment_id: dep-240
instance_id: I17
time_range:
start: "2026-09-20T10:04:00+08:00"
end: "2026-09-20T10:06:00+08:00"
query_results:
- query_id: q-...-log-01
source_type: LOG
source_system: es-prod-cluster-a
query_status: OK
data_status: FOUND
completeness: COMPLETE
- query_id: q-...-trace-01
source_type: TRACE
source_system: apm-new-prod
query_status: OK
data_status: FOUND
completeness: COMPLETE
- query_id: q-...-profile-01
source_type: PROFILE
source_system: pyroscope-prod
query_status: OK
data_status: UNKNOWN
completeness: COMPLETE
evidence:
- source_type: LOG
source_system: es-prod-cluster-a
source_record_id: log-123
correlations:
- type: REQUEST_SPAN
target:
trace_id: T7
span_id: S2
status: EXACT
rule_version: correlation-v3
- type: RESOURCE_CONTEXT
target:
resource_type: CONTAINER
resource_id: C17
status: EXACT
rule_version: entity-v7
- source_type: TRACE
source_system: apm-new-prod
source_record_id: trace-span-S2
correlations:
- type: REQUEST_SPAN
target:
trace_id: T7
span_id: S2
status: EXACT
rule_version: correlation-v3
- type: ENTITY_RELATION
target:
entity_type: INSTANCE
entity_id: I17
status: CANDIDATE
rule_version: entity-v7
time_quality:
time_uncertainty: "±300ms"
evidence_level: EXECUTION_RELATED
limitations: []
hypothesis:
statement: "请求执行期间发生规则重新解析"
status: UNVERIFIED
要点说明:
query_results中出现PROFILE且data_status = UNKNOWN,而evidence中没有对应条目——这正是“查了但没拿到”与“拿到了证据”的区分,两者必须能分别表达。- 每条边的 source 都是它所属的那条证据:
log-123的两条边分别断言“这条日志属于 T7/S2”和“这条日志产生于容器 C17”;trace-span-S2的两条边分别断言“它就是 T7/S2”和“它当时归属实例 I17”。没有任何一条边以另一条边的 target 为起点。 trace-span-S2的两条边状态不同:请求身份是EXACT,实体归属只到CANDIDATE。这正是 2.4 节要解决的情况。- 若要表达“这条日志归属哪个部署”,必须显式建一条
log-123 → DEPLOYMENT dep-240的边,其状态按最弱环节取CANDIDATE,不得由前两条边复合推出EXACT。 time_quality出现在关联边上而非证据记录上,因为时间误差影响的是具体某条关系的判定(第 6 章)。evidence_level与hypothesis属于整个包,描述这组证据整体支撑到了哪一级。
4.4 hypothesis.status 与状态迁移
hypothesis.status 为四值枚举:
| 取值 | 含义 | 允许的 evidence_level |
|---|---|---|
UNVERIFIED |
尚未做对照验证 | 最高 MECHANISM_HYPOTHESIS |
VERIFIED |
对照验证通过 | MECHANISM_VERIFIED |
REFUTED |
对照验证做了,假设被推翻 | 不得为 MECHANISM_VERIFIED,应回落至 EXECUTION_RELATED |
INCONCLUSIVE |
验证做了但结果不确定 | 保持 MECHANISM_HYPOTHESIS,并在 limitations 中说明缺口 |
只有 UNVERIFIED 与 VERIFIED 两个值时,对照实验失败后契约只能停在 UNVERIFIED,无法区分“还没验证”和“验证后被否定”——两者对下一步排查的指导完全相反。
**REFUTED 是有诊断价值的结论,不是失败。**它排除了一条机制假设,与 11.2 节“拒答不计为错误”属同一逻辑:REFUTED 不得计入错误结论分子。若不明确这一点,实现方会倾向于把被推翻的假设留在 UNVERIFIED 以免“显得做错了”,这恰好是该枚举要消除的行为。
状态迁移时,hypothesis.status 与 evidence_level 必须同时更新。单独出现 VERIFIED 而证据等级未升,或 REFUTED 而等级仍为 MECHANISM_VERIFIED,均视为契约违例。
validation:验证过程与结论范围
仅有 status 无法满足主报告附录 A.4 的可复查要求——该节要求每份判断保存机制假设、支持与反证、缺口、验证结果及结论范围。若只记录 VERIFIED,系统可以声称已验证,却无法复现为什么已验证。因此 hypothesis 下增加 validation:
evidence:
# ...前述证据条目...
- source_type: METRIC # 验证实验本身也是证据,必须在包内
source_system: prom-prod
source_record_id: exp-run-01
correlations: []
hypothesis:
statement: "请求执行期间发生规则重新解析"
status: VERIFIED
validation:
method: CONTROLLED_COMPARISON
conditions: "同一输入、同一流量、同一资源规格;对比 v2.3 / v2.4 / 修复版"
evidence_refs:
- source_type: METRIC
source_system: prom-prod
source_record_id: exp-run-01
result_summary: "仅 v2.4 复现,修复版恢复至基线"
conclusion_scope: "订单服务 v2.4 优惠计算路径;未覆盖其他调用路径与其他服务"
引用闭环是强制的:
validation.evidence_refs中的每一项,必须引用同一EvidenceBundle.evidence[]中存在的记录。
若验证所依据的实验记录不在证据包内,就会出现“status = VERIFIED,但支撑它的实验记录不可访问甚至已过期”的情况,这正好抵消了 validation 要解决的可复查问题。因此验证实验本身必须作为证据条目进入 evidence[](如上例的 exp-run-01),即使它没有任何关联边。
若将来确需引用包外证据,应单独定义 external_evidence_refs 字段,并强制携带快照、内容哈希与保留期约定;不得让 evidence_refs 同时承担包内引用和包外引用两种语义。该字段不在 2.0 范围内。
必填性规则:
hypothesis.status |
validation |
|---|---|
UNVERIFIED |
可为空 |
VERIFIED |
必填 |
REFUTED |
必填 |
INCONCLUSIVE |
必填 |
validation.method 为可降级枚举(1.2 节),兜底值 OTHER:CONTROLLED_COMPARISON / ROLLBACK / FIX_VERIFICATION / LOAD_REPLAY / CONFIG_TOGGLE / OTHER。
只要 validation 存在,conditions 一律必填,不区分 method 取值。原因是兼容性:未来 2.x 生产端若新增 CHAOS_EXPERIMENT,旧消费方会把它降级为 OTHER;若 conditions 仅在 OTHER 时必填,生产端并不知道自己会被降级,自然可能不发送该字段,于是一个声称 minor 兼容的枚举扩展经 fallback 后反而违反旧 Schema。统一必填既消除这个冲突,也让 VERIFIED / REFUTED / INCONCLUSIVE 三种结果都带有可复现的实验条件。
conclusion_scope 是其中最容易被省略、也最容易被误用的字段:它划定结论的适用边界。上例中验证只覆盖了优惠计算路径,不能据此断言该服务其他路径无同类问题。缺少这一字段时,一次局部验证很容易在传播中被当作全局结论。
REFUTED 同样必须填写 validation——被推翻的假设需要记录“用什么方法、在什么条件下推翻的”,否则下一次排查会重复同样的实验。
4.5 异常返回示例
contract_version: "2.0"
query_results:
- query_id: q-...-log-02
source_type: LOG
source_system: es-prod-cluster-a
query_status: TIMEOUT
data_status: UNKNOWN
completeness: PARTIAL
truncation_reason: [TIMEOUT, QUERY_BUDGET]
truncation_dimension: [max_scan_bytes]
evidence: []
evidence_level: UNASSESSED
limitations:
- "日志源超时且触及扫描预算,仅返回部分结果"
- "时间误差窗口内存在两个 Pod 候选"
- "Exemplar 留存窗口已过,无法反查指标样本"
hypothesis: null
此例中 evidence[] 为空,因此 evidence_level 只能是 UNASSESSED(第 3 章的等级上限规则)。若要声称已达 WINDOW_RELATED,支撑它的 K8s 历史关系或注册表事实必须作为证据条目出现在 evidence[] 中。
limitations 为空数组与不返回该字段含义不同:前者表示已检查且无限制,后者表示未检查。evidence 同理。
4.6 字段必填性
QueryResult:
| 字段 | 必填性 | 说明 |
|---|---|---|
query_id |
必填 | 审计与复查的锚点 |
source_type / source_system |
必填 | — |
query_status / data_status / completeness |
必填 | — |
truncation_reason |
条件必填 | completeness = PARTIAL 时必填,否则返回空数组 |
truncation_dimension |
条件必填 | truncation_reason 含 QUERY_BUDGET 时必填 |
effective_time_range |
条件必填 | 与 bundle 级 time_range 不同时必填;相同时可省略 |
time_quality |
可选 | 源端能提供时钟偏差估计时填写 |
result_count |
可选 | — |
contract_version |
条件必填 | 独立传输时必填;嵌套于 bundle 时省略 |
EvidenceBundle:
| 字段 | 必填性 | 说明 |
|---|---|---|
contract_version |
必填 | — |
subject / time_range |
必填 | — |
query_results |
必填 | 无查询时返回空数组 |
evidence |
必填 | 无证据时返回空数组 |
evidence_level |
必填 | 无证据时为 UNASSESSED |
limitations |
必填 | 无限制时返回空数组 |
hypothesis |
可选 | 未形成假设时为 null |
Evidence 条目:
| 字段 | 必填性 | 说明 |
|---|---|---|
source_type / source_system / source_record_id |
必填 | 三元组缺一不可 |
correlations |
必填 | 无关联边时返回空数组(此时该证据只能支撑 ENTITY_RELATED) |
correlations[].type / target / status |
必填 | target 的字段结构由 type 决定,见 2.4 节 |
correlations[].rule_version |
必填 | 诊断可复现的前提 |
correlations[].time_quality |
条件必填 | 该边的判定依赖时间时必填(典型为 ENTITY_RELATION) |
hypothesis:
| 字段 | 必填性 | 说明 |
|---|---|---|
statement / status |
必填 | hypothesis 非 null 时 |
validation |
条件必填 | status 为 VERIFIED / REFUTED / INCONCLUSIVE 时必填 |
validation.method / result_summary / conclusion_scope |
必填 | validation 存在时 |
validation.conditions |
必填 | 不区分 method 取值,见 4.4 节的兼容性说明 |
validation.evidence_refs |
必填 | 每项必须命中同一 bundle 的 evidence[];无支撑证据时返回空数组,但此时 status 不应为 VERIFIED |
4.7 智能体输出的强制字段
诊断智能体基于上述证据包形成结论时,输出必须包含:
conclusion 结论陈述
evidence_refs 引用的证据(source_type + source_system + source_record_id 三元组列表)
evidence_level 当前证据等级(第 3 章)
completeness 数据完整性汇总
counter_evidence 反证(观察到但与结论不符的证据)
missing_evidence 缺失证据及其影响
next_verification 下一步验证动作
evidence_refs 中的每一项必须能在同一证据包的 evidence 数组中找到对应记录;引用不存在的记录,计入主报告附录 B.1 的“智能体错误证据引用率”。
并强制区分四类陈述,不得混用:
| 类别 | 说明 | 反例 |
|---|---|---|
| 事实 | 直接观测到的数据 | — |
| 关联 | 某条关联边所断言的关系,须带该边的 status |
把 CANDIDATE 的实体归属陈述为确定 |
| 假设 | 能解释观测的机制推断 | 把“同一窗口观察到 CPU 热点”写成“CPU 热点导致请求变慢” |
| 验证结论 | 经对照实验确认的机制 | 把未做对照的假设标为已验证 |
5. 血缘与来源字段
对应主报告附录 A.1。实体关系、别名映射和精确关联均须携带:
记录的全局引用由三元组 source_type + source_system + source_record_id 承担。拆分的原因是:log、trace 这类值描述的是数据类型而非来源系统;企业同时运行两个日志集群时,log + log-123 并不唯一。
| 字段 | 说明 | 取值约束 |
|---|---|---|
source_type |
数据类型 | 封闭枚举(结构性,新增即 breaking):METRIC / LOG / TRACE / PROFILE / CHANGE / SERVICE_CATALOG / CMDB / K8S / RELEASE / CONFIG / RUNTIME / REGISTRY |
source_system |
提供该记录的具体系统实例 | 开放取值,填企业注册的稳定系统标识(如 es-prod-cluster-a、apm-new-prod);不是封闭枚举,新增系统不构成契约变更 |
source_record_id |
在该系统中的原始记录标识 | 须可回溯查询;仅在同一 source_system 内保证唯一 |
observed_at |
该事实被观察到的时间 | 与 valid_from 区分,观察时间可晚于生效时间 |
valid_from |
关系生效时间 | 必填 |
valid_to |
关系失效时间 | 未失效为空;不得用当前时间填充 |
rule_version |
产生该关系的规则或映射版本 | 诊断可复现的前提 |
confidence |
确定性等级 | 复用 correlation_status 取值 |
generated_by |
生成方式 | auto_rule / manual_fix / source_direct / UNKNOWN(血缘不明,亦为 1.2 节降级的合法落点) |
**关于变更事件的归类。**主报告 4.2 节把变更事件列为一级诊断维度,其来源涵盖发布、配置、扩缩容、路由流量调整、数据库与中间件变更、基础设施迁移等。这些记录必须有确定归属,否则各适配器会各自发明分类。规则如下,按优先级从上到下:
| 变更来源 | source_type |
|---|---|
| 应用发布、依赖升级(制品变更随发布记录) | RELEASE |
| 配置项变更、灰度配置调整 | CONFIG |
| 扩缩容、编排控制面内的路由与流量调整 | K8S |
| 其余变更记录:数据库与中间件变更单、基础设施迁移、网关或网格平台的独立变更单 | CHANGE |
即:若变更由发布、配置或编排平台直接产生,用对应的具体类型;其余变更记录统一归入 CHANGE,具体领域由开放取值的 source_system 区分。
这里没有采用"全部映射到已有类型、不设 CHANGE"的方案,原因是数据库变更单、基础设施迁移等确实在现有类型中无自然归属,强行映射到 CMDB 会把"资产登记"与"变更记录"混为一谈,反而制造新的语义争议。由于 source_type 是结构性枚举,此项必须在 2.0 冻结前定下——冻结后再加就是 breaking change。
关于人工修订:旧版本把 manual 放在来源枚举中并不合适——人工修订是生成方式而非数据源系统。正确表达是 source_type = REGISTRY(实体注册表自身)、source_system 填治理入口的系统标识,由 generated_by = manual_fix 承担“人工”语义。两个字段各司其职,不重叠。
6. 时间质量与误差模型
对应主报告附录 C.1。仅靠扩大查询窗口不足以支撑精确关联。
| 字段 | 说明 |
|---|---|
event_time |
事件实际发生时间 |
observed_time |
采集端观察到的时间(对应 OTel ObservedTimestamp) |
ingest_time |
入库时间 |
clock_offset_estimate |
该来源相对基准时钟的偏差估计 |
time_uncertainty |
综合误差边界 |
判定规则建议:
需要区分两类关联,它们对时间质量的依赖完全不同:
| 关联类型 | 回答的问题 | 对时间的依赖 |
|---|---|---|
| 请求/Span 身份关联 | 这条日志是不是属于这个 Span | 有请求上下文直接绑定时不依赖时间 |
| 实体关系关联 | 这个 Span 当时属于哪个部署、哪个 Pod、哪个版本 | 始终依赖时间,因为实体关系带有效期 |
| 条件 | correlation_status 上限 |
|---|---|
| 有请求上下文直接绑定(仅限请求/Span 身份关联) | 可为 EXACT,不因时钟误差降级 |
无请求上下文,time_uncertainty 小于目标 Span 时长的约定比例 |
最高 CANDIDATE |
| 无请求上下文,误差窗口内存在多个候选 | AMBIGUOUS |
| 时间源不可信或偏差未知 | UNKNOWN |
误差边界必须随结果返回,不得在扩大窗口后直接宣称精确关联。
即使请求身份关联已达 EXACT,涉及部署、实例生命周期和历史拓扑的实体关系仍须独立考虑时间质量:请求上下文能证明“这条日志属于 T7/S2”,但不能证明“S2 当时跑在 dep-240 的 I17 上”——后者只能由带有效期的历史关系加上可信的事件时间共同确定。两类关联应分别标注 correlation_status,不得用前者的确定性覆盖后者。
7. 查询预算 Query Budget
对应主报告附录 C.1 与 7.4 节。应作为统一契约而非各适配器内部参数。
| 参数 | 说明 | 智能体额外约束 |
|---|---|---|
max_time_range |
单次查询的最大时间跨度 | 自主模式下应显著收紧 |
max_entities |
单次查询涉及的最大实体数 | 未获对应策略授权时禁止自动横向扩展;获得目的绑定的授权后,仅允许在本预算范围内扩展 |
max_sources |
单次查询涉及的最大数据源数 | — |
max_scan_bytes |
各源扫描量上限 | 触顶即 PARTIAL,不得静默继续 |
max_results |
返回记录数上限 | — |
timeout |
各源超时预算 | — |
max_recursive_depth |
自动下钻/展开的递归深度 | 必填,防止一次告警触发跨四平台的大范围扫描 |
预算触顶必须体现在 completeness 与 truncation_reason 中(QUERY_BUDGET 加 truncation_dimension,见 2.3 节),不得以静默截断的方式返回看似完整的结果。
智能体的横向扩展遵循主报告 9.2 节的原则:默认禁止,按需开通,目的绑定,范围受控。这里的“受控”不等于“绝对禁止”——跨多应用巡检的诊断账号本就可能需要更大的横向范围,关键是该范围必须来自显式授权策略,并落在本章预算之内。
8. 权威源与冲突裁决
对应主报告 7.3 节。治理形态为统一治理入口 + 多权威事实源:注册表负责模型、规则版本、冲突裁决、历史快照与查询输出,不负责生产所有事实。
8.1 按字段划分权威
**不使用“业务归属”这类笼统说法,一律拆到字段。**笼统表述是跨文档矛盾的主要来源。
| 字段 | 权威源 | 说明 |
|---|---|---|
service_identity |
服务目录 | 逻辑服务身份 |
business_service_owner |
服务目录 | 业务服务责任人 |
asset_owner |
CMDB | 资产责任人 |
cost_center |
CMDB | 成本中心 |
physical_location |
CMDB | 机房与网络位置 |
| Pod/容器/节点生命周期与有效期 | 编排控制面 | 时序信息,多数 CMDB 不保存 |
| 部署批次、版本、灰度范围 | 发布平台 | — |
| 配置项版本与生效时间 | 配置中心 | — |
process_identity |
运行时 | 进程身份与启动时间 |
running_artifact |
运行时 | 实际加载的制品,对“实际运行什么”强于登记信息 |
8.2 冲突裁决
**冲突不一定意味着数据错误。**它可能来自权威级别差异、数据新鲜度、迟到数据、配置偏差,也可能确实是真实的数据错误。裁决规则只负责给出当前应采信的值,不代表其余来源都无需修复。
需要先区分两类,处理方式完全不同。
**第一类:表面冲突。**看起来矛盾,拆到字段后自然消失。
CMDB: 该实例的资产责任人属于 A 团队 (asset_owner)
运行时: 该进程实际加载 service-A 的构建产物 (running_artifact)
这两条根本没有冲突,只是回答了不同字段。大量所谓的“数据不一致”属于这一类,根因是用了“业务归属”这种笼统说法而非字段名。8.1 节把权威性拆到字段,正是为了消除这类伪冲突。
**第二类:真实冲突。**同一字段,两个来源给出不同值。
service_catalog.service_identity = service-A
k8s.annotation.service_identity = service-B
这才需要裁决。裁决规则按以下顺序应用:
- 按字段确定权威源(8.1 节表)——
service_identity的权威源是服务目录,服务目录胜出;K8s annotation 在此属于登记信息,对该字段不具权威性。 - 同权威级别时按发生时间——较新的事实优先,但须检查是否为迟到数据。
- 仍无法裁决时置为
AMBIGUOUS,不得任选其一。此项仅适用于两个同等权威级别来源相持不下的情形,权威级别明确时不得以AMBIGUOUS回避。 - 无论裁决结果如何,保留冲突记录,包含各来源取值、裁决依据与规则版本,供事后复查。
上例中虽然服务目录胜出,但 annotation 与服务目录长期不一致本身就是一个需要修复的配置问题,冲突记录是发现它的唯一途径。
禁止“谁先写谁赢”。
9. 数据新鲜度
实体映射不仅要正确,还要及时。“映射逻辑正确但事实已过时”是一类不易察觉的误诊来源。
各权威源须定义:
| 字段 | 说明 |
|---|---|
freshness_sla |
约定的最大同步延迟 |
max_acceptable_lag |
超过即触发告警并在查询结果中提示的阈值 |
last_updated_at |
该源最近一次成功同步时间 |
超出 max_acceptable_lag 时,基于该源的关联结果应降级(correlation_status 不高于 CANDIDATE),并在 limitations 中说明。
10. 联合分析平台自身的可观测性
对应主报告附录 B.1。平台本身必须可观测,不能只依赖被它查询的四类系统。
| 指标 | 说明 |
|---|---|
| 查询成功率 | 按源、按使用方类型分别统计 |
| 查询时延 P95 / P99 | 按查询类型和负载分别统计 |
| 实体服务可用性 | 不可用时下游应按设计降级而非整体失败 |
| 映射同步延迟 | 按权威源分别统计,对应第 9 章 |
PARTIAL 返回率 |
持续升高通常意味着预算设置不合理或源侧劣化 |
AMBIGUOUS 比例 |
持续升高通常意味着实体模型或时间质量出现问题 |
| 错误关联数量 | 经事后核验发现的 EXACT 误判,应为零容忍项 |
| 查询超时率 | 按源统计 |
| 权威源数据新鲜度 | 对应 last_updated_at |
| 智能体错误证据引用率 | 引用了不存在或不相关证据的结论占比 |
11. POC 验收指标清单
拆为两组分别统计。两组不得混合报告,技术质量达标不等于运维价值实现。
11.1 技术质量组
| 指标 | 计算方法 | 讨论起点 |
|---|---|---|
| 实体映射覆盖率 | 正确且唯一映射对象数 / 应覆盖对象数;另报流量加权 | ≥95%,关键对象单列 |
| EXACT 准确率 | 核验正确的 EXACT 关联边数 / 已核验 EXACT 关联边总数,按 type 分别统计 |
任一 false positive 为阻断项;须报样本量与统计不确定性 |
| CANDIDATE 质量 | Precision、Recall、Top-K 命中率,同样按 type 分别统计 |
单独统计,不与 EXACT 混合 |
| 请求上下文覆盖率 | 具备可用关联上下文的适用请求日志 / 适用请求日志 | ≥95%,不把系统日志混入分母 |
| 关联实际命中率 | 成功取得目标证据的关联尝试 / 全部合法关联尝试 | 原始与条件命中率须一起报告;Exemplar 留存作为独立变量 |
| Completeness | COMPLETE 返回占比 |
按源统计 |
| 查询时延 | 代表性并发与窗口下的 P95、超时率 | P95 ≤5 秒,须限定查询类型与负载 |
| 可用性 | 平台自身可用性与降级表现 | 与既有告警主路径解耦 |
| 采集与平台开销 | 应用 CPU/RSS/延迟、网络、存储、扫描量、运维工时 | 必须实测,不得引用宣传值 |
统计单位必须是关联边而非证据记录,且按 type 分开:REQUEST_SPAN 误判会把不相干的日志或样本塞进本次诊断,ENTITY_RELATION 误判会把证据归到错误的版本或实例上并误导版本对照。两者的后果、排查路径和阻断条件不同,混在一个比率里等于抹掉了 2.4 节建立的区分。
11.2 运维价值组
| 指标 | 说明 | 归因要求 |
|---|---|---|
| MTTD | 故障发现时间 | — |
| MTTI | 定位时间中位数与 P90 | 必须同案例集对照,控制人员熟练度与案例记忆 |
| MTTR | 恢复时间 | 受修复方案影响大,不可单独归因本平台 |
| 跨平台跳转次数 | 单次排障中的平台切换次数 | 仅减少跳转不构成价值证明 |
| 人工查询次数 | 单次排障中的手工查询次数 | — |
| 错误结论率 | 错误根因结论占比 | 在已知真值且不向诊断者泄露的案例上评估 |
| 无法判断率(abstention rate) | 明确拒答占比 | 不计入“错误根因”分子,但必须单独统计并与有效回答覆盖率同时验收;不得通过扩大拒答比例换取表面准确率 |
| 假设推翻率 | hypothesis.status = REFUTED 的占比 |
不计入错误结论分子(4.4 节)。推翻一条假设是有效的排除结论,不是诊断失败 |
| 有效回答覆盖率 | 给出明确结论(无论对错)的案例占比 | 与无法判断率互补,两者须成对报告 |
归因约束:定位与恢复时间受人员熟练度、故障类型、当班经验影响很大。若未采用同案例集对照设计,改善不得归因于本平台。
12. 必测反例
实现方须对下列情形逐条执行并记录结果。用例表齐全不构成通过依据,执行记录与回归结果才是。
| 用例 | 期望表现 |
|---|---|
| 不同租户/环境同名服务 | 不串联、不泄露 |
| Pod 重建、IP 复用、PID 复用 | 旧数据仍关联原对象 |
| 服务改名、滚动发布、新旧版本并存 | 服务历史连续,部署与进程正确区分 |
| CMDB 与运行时冲突或迟到 | 按第 8 章裁决并保留冲突记录 |
| 日志乱序、时钟偏差、采集延迟 | 返回误差边界,不用到达顺序伪造执行顺序 |
| 消息重试、批处理、异步跨线程 | 不混淆尝试,不强拼单父链 |
| Trace 采样但日志保留 | 有 ID 无 Trace 时返回有依据的状态 |
| Exemplar 存在但 Trace 过期 | EXPIRED,不跳到其他 Trace |
| Exemplar 环形缓冲被覆盖 | 区分“无 Exemplar”与“有 Exemplar 但目标不可得” |
| 新旧 APM 身份空间无法判等 | AMBIGUOUS,不做截断或补零匹配 |
| 跨 Canonical Trace Context 切换点 | 提示关联降级,不把旧身份空间记录当 canonical 命中 |
| 使用方无权限 | PERMISSION_DENIED,不与无记录合并 |
| 数据源无采样审计能力 | UNKNOWN,不得推断为 SAMPLED_OUT |
| 同一条证据的两类关联状态不同 | correlations[] 中 REQUEST_SPAN 为 EXACT、ENTITY_RELATION 为 CANDIDATE 时可分别表达,界面与智能体输出不得取其一代表整条证据 |
| 消费方收到未知枚举值 | 按 1.2 节兜底表降级(query_status/completeness→UNKNOWN,evidence_level→UNASSESSED),不得报错中断,也不得升级为确定状态 |
| 证据包不含任何证据 | evidence_level 只能为 UNASSESSED,不得声称已达窗口级或更高 |
| 对照实验推翻假设 | hypothesis.status = REFUTED,validation 必填,evidence_level 回落至 EXECUTION_RELATED,且不计入错误结论 |
声称 VERIFIED 但未提供 validation |
拒绝该载荷为契约违例,不得接受 |
validation.evidence_refs 指向包外记录 |
拒绝该载荷为契约违例;验证实验记录必须作为证据条目进入 evidence[] |
validation 存在但缺 conditions |
拒绝该载荷为契约违例,不区分 method 取值 |
消费方降级后写回 truncation_reason / generated_by |
写回 UNKNOWN 必须仍通过 Schema 校验 |
上游各边均为 EXACT 的多跳复合 |
不得自动判为 EXACT;须确认可传递语义与时间区间一致后由明确规则重新判定 |
| 跨两跳的关联需求(日志→实例→部署) | 必须显式建边,状态按最弱环节取值;不得由两条边复合推出 EXACT |
收到未知的 correlations[].type 或 source_type |
按结构性枚举处理:拒绝该条边或该条证据并上报版本不兼容,不得降级为 UNKNOWN 后继续解析 target |
| 两个同等权威来源对同一字段给出不同值 | 置 AMBIGUOUS 并保留冲突记录;权威级别明确时不得以 AMBIGUOUS 回避 |
| 某源实际查询窗口宽于 bundle 级窗口 | QueryResult.effective_time_range 如实记录,不得仅上报 bundle 级 time_range |
| 智能体自主模式跨应用查询 | 无对应授权策略时拒绝或转人工确认;有目的绑定授权时仅在 Query Budget 范围内执行 |
| 递归深度触顶 | 停止下钻并返回 PARTIAL |
| Profile 有标记无样本、符号不全 | 显示限制,不输出虚假 Span 级归因 |
| 指标重置、单位差异、P99 跨实例聚合 | 正确处理或拒绝无效比较 |
| Collector 或实体服务不可用 | 原有监控继续运行,新增能力按设计降级 |
13. 与主报告的对应关系
| 本分册章节 | 主报告出处 |
|---|---|
| 第 1.2 节 契约版本 | 本分册独有,主报告不涉及 |
| 第 2 章 状态契约 | 6.2 节 |
| 第 3 章 证据等级 | 4.4 节、图 6 |
| 第 4 章 证据契约 | 6.2 节、7.4 节、附录 A.4 |
| 第 5 章 血缘字段 | 附录 A.1 |
| 第 6 章 时间质量 | 附录 C.1 |
| 第 7 章 查询预算 | 附录 C.1、7.4 节 |
| 第 8 章 权威源与冲突 | 7.3 节、2.3 节 |
| 第 9 章 数据新鲜度 | 7.3 节 |
| 第 10 章 平台自观测 | 附录 B.1 |
| 第 11 章 验收清单 | 附录 B.1 |
| 第 12 章 必测反例 | 附录 B.2 |
涉及 Canonical Trace Context 的迁移策略见主报告 6.3 节与图 9,本分册不重复。安全、权限与审计要求见主报告第 9 章。