源头语义 — 把「是什么意思」写进契约
这一章讲三件事: schema(表结构)和语义(含义)的区别——以及为什么弄混它 会让后面所有工程白做;语义为什么必须在数据进门的那一刻就写下来; 书给出的具体工件:一份事件源协议(ESA)长什么样、七个部分各管什么。 承上:03 章建了实体内核,内核要求「每个属性有书面语义」——这一章讲语义从哪来。
1. 顶层全景:数据进门时,把话说清
数据源(变更流/外部供应商/应用遥测)
│
▼
┌──────────────────────────────┐
│ 数据契约(进门时签) │ SLA · 表结构 · 就绪信号 ← 传统契约只有这三样
│ + 每个事件的语义 │ ← 本书要求补上的部分
└──────────────────────────────┘
│
▼
管道加工 → 实体内核 → RAG 应用取数
图说:契约是数据源和平台之间的约定。传统契约管「货什么时候到、包装什么样」;
本书要求它同时管「这批货到底是什么」。
2. schema 不是语义:一个事件,两份说明
这一节讲清全书最容易混的一对词。混了它,后面每一步都会跑偏。
先说来源。平台的数据来自三类地方1:系统记录的变更流(订单改了、合同续了, 一条条流出来)、外部数据供应商、以及遥测——应用把「用户做了什么」自动上报回来的 一条条使用记录。
这些数据进来,首先要有一份契约(数据提供方与平台之间的书面约定)。传统契约写的是 保底交付三件套:服务水平承诺(何时到货)、表结构(schema,数据有哪些列、 各是什么类型、格式有什么约束)、以及「源头已就绪」的信号机制2。书说这些都重要, 但有一整类信息被漏掉了——而它恰恰决定 RAG 应用能不能用2。
漏掉的就是语义。书的对照值得原样记住3:
| schema(结构) | 语义(含义) | |
|---|---|---|
| 回答的问题 | 数据长什么形状 | 每一行每一列该作何理解 |
| 例子 | 「Action.Type 是一串字符」 | 「Action.Type=OpenSurface 表示用户主动打开了输入面板」 |
| 谁能从里面读出来 | 任何人看字段列表就行 | 没人能从字段列表里读出来,只能问当初定规则的人 |
然后是走查。书用了一个真实事件做例子:CreateCopilot_Intent——
「用户起了用 Copilot 的念头」这个事件。它的 schema 长这样4:
Event.Id: "b123-456" ← 这次事件的唯一编号
Session.Id: "s789" ← 用户这次会话的编号
Module.Name: "Create" ← 哪个产品模块
Feature.Name: "Copilot.QuickCompose"
Action.Type: "OpenSurface" ← 动作类型
Client.Type: "Web" ← 从哪个端
Device.Name: "SurfacePro"
只看这七行,一个字都不用改就能讲出完全不同的故事。语义文档补上的正是 schema 说不出的那两句5:
- 只有当登录用户主动发起(点了「Try Copilot」按钮,或按了快捷键)、 并且输入面板真的加载出来,两个条件同时成立,这个事件才发;
- 鼠标悬停、气泡浮现这类被动曝光,不发。
这两句话就是语义。它不改变任何字段类型,却决定了一个关键指标怎么数: 「今天有多少人对 Copilot 产生了兴趣」——按第一句,悬停不算数;没有这两句话, 两个团队可以各自合理地数出两个不同的数。02 章三个「用户」的事故, 在字段级别重演了一遍。