P1 AIP
元数据语义标注:让表结构自动长出关系
导入元数据只是第一步,表与表之间怎么关联、每列是什么语义(金额/时间/枚举/指标),以前要建模师逐表核对。Schema AI 用"FK 命名猜测 → 每表 LIMIT 20 采样 → LLM 批量判定"自动产出候选关系与列语义标注,带幻觉防御白名单,LLM 不在时降级纯规则(诚实标注 rule_only),人审确认/驳回闭环。看完这 3 个故事,你就能把一个数据源"一键长出关系"并读懂每一条证据。
数据工程师
业务分析师
元数据
语义标注
外键
幻觉防御
共 3 个故事
能 / 不能速览
✅ 这个主题能做
- 基于已导入元数据自动推断表间关系(fk / semantic / join_path)与列语义类型(enum/currency/identifier/text/metric/dimension/time)
- FK 命名猜测:列名形如 <表名单数>_id → 0.8;列名与他表单列主键同名 → 0.6
- 每表经连接器 SELECT * LIMIT 20 采样,两端取值求重叠率,零重叠置信度 × 0.5
- LLM 批量判定关系与列标注(坏 JSON 重试 1 次),幻觉防御:表/列必须真实存在、类型白名单、置信度夹取 [0,1]
- 任务化推断(type=schema_infer),任务结果含 InferRun 摘要
- llm 缺失/失败降级纯规则(source=rule_only),链路不断、人审照常
⛔ 这个主题做不了
- 推断前置:数据源必须先导入元数据,否则 404「无已导入元数据」
- 采样依赖连接器:连接器缺失/失败/空表时跳过采样(sampled=false),重叠率证据缺失
- 单数化极简:只处理常见英文复数(ies/ses/xes/s),person/people 这类不规则复数不识别
- 列标注无 reject:asi_column_annotations 仅 suggested/confirmed 两态,拒绝即不确认
- 单次 LLM 关系判定候选上限 40,超长数据源会被截断
适用角色
本主题面向两个角色:
- 数据工程师:核心使用者,导入元数据后触发推断,把"表结构说明书"自动化。
- 业务分析师:审核人,逐条确认/驳回关系与标注;确认后的结果供本体建模半自动消费。
页面在 /schema-annotation,任意登录用户可操作(protected),无 admin-only 端点。
能力速览(能做什么)
触发推断(POST /infer-relationships)
任务化返回 {task_id, task},前端轮询 /tasks/:id 到终态,result 为 InferRun 摘要(tables/sampled_tables/candidates/relationships/annotations/source/llm_retries)。
规则候选
FK 命名猜测:*_id 后缀 + 单数化命中目标表 → 0.8;列名与他表单列主键同名(排除 id/uuid/key/pk 通用名)→ 0.6。
采样重叠率
每表 LIMIT 20 采样,两端取值求重叠率记录进 evidence;采样成功但零重叠 → 置信度 × 0.5。
LLM 判定 + 幻觉防御
表/列真实存在白名单校验(大小写不敏感)、关系/语义类型白名单、confidence 夹取 [0,1] 两位小数;一条不合法整批降级。
列语义标注
每 3 表一批,每列最多 3 个采样值,输出 semantic_type + 中文描述 + 置信度;失败批降级启发式类型映射。
人审闭环 + 审计
confirmed/rejected 人审结果保留不回退;推断全程 refType=ai_decision、stepType=schema_annotation 审计打点。
调整指南(怎么调整)
- 改结果质量:推断前先导入元数据;采样能否成功取决于连接器,连接器不可用时只靠命名与结构,结果会弱一些。
- 改关系证据:关系行的 evidence 字段有 source/rule/reason/confidence/sampled/sample_overlap/sample_size,人审时可点开核对采样重叠率再决定确认/驳回。
- 改降级行为:LLM 缺失/失败/输出全非法时 source=rule_only(诚实标注);配置 LLM key 后重新触发即可升级为 llm。
- 改去重语义:关系去重键含关系类型(from.from_col→to.to_col|type),列标注去重键为 table.column(小写);同键人审结果优先。
- 改消费方向:confirmed 的关系/标注可被本体建模(ontology)消费;要自动生成 ontology 对象/链接属后续扩展。
做得好的场景
语义标注在"单数据源、命名规范、结构清晰"的库上收益最明显:
- 一键长出关系:orders.customer_id 这类 *_id 命名 + 单数化 + 采样重叠率,自动产出 fk 候选 0.8+,建模师不用逐表核对。
- 降级不断线:LLM 不可用时纯规则照常产出(rule_only 诚实标注),人审流程不受影响——这与 entityextract"llm 缺失明确报错"相反,体现"半自动辅助"定位。
- 幻觉防御:LLM 瞎编的表/列被白名单直接丢弃,confidence 越界被夹取,标注产出不会污染元数据。
- 人审结论稳:重跑只更新 suggested,confirmed/rejected 原样保留,人工决策不回退。
限制与不足
以下是明确的边界,使用前先知道:
- 必须先生成元数据:数据源无已导入元数据时触发推断返回 404 明确提示。
- 采样依赖连接器:连接器缺失/失败/空表跳过采样,零重叠才触发置信度 ×0.5;连接器每轮独立开合,不共享缓存句柄。
- 单数化极简:只处理常见英文复数,不规则单复数(person/people、child/children)不识别。
- 表名白名单:safeIdent 校验 ^[A-Za-z_][A-Za-z0-9_.]*$,非法表名跳过采样(防注入)。
- 候选上限:单次关系判定候选上限 40,超长数据源被截断;默认 MetaReader 要求数字数据源 ID。
场景故事
故事 1
演示库一键长出关系:orders 表自动关联 customers 与 products
场景:首次推断
角色:数据工程师
耗时:约 5 分钟
- 背景
- 陈工导入了 aip_demo_warehouse(orders/customers/products 三表)的元数据后,在 /schema-annotation 页面选择该数据源,点"推断"。他想验证系统能不能自己发现 orders 和 customers、products 之间的外键关联,以及每列的业务语义。
- 传统做法对比
- 以前建一张关系/指标字典要数据建模师逐表核对字段、翻建表脚本确认外键,小时级起步;现在规则候选 + 采样 + LLM 批量判定,几分钟产出 suggested 结果,人审确认即达可用状态。
- 角色
- 数据工程师(导入元数据 + 触发推断)。
- 操作步骤
-
- 先 POST /datasources/:id/import-metadata 导入元数据
- 在 /schema-annotation 选择该数据源
- 点"推断",任务化返回 task_id
- 轮询 GET /tasks/:task_id 到终态,查看 InferRun 摘要
- 系统响应
- 触发推断返回任务(任务化模式):
{
"code": 0,
"data": {
"task_id": "<task_id>",
"task": { "id": "<task_id>", "type": "schema_infer", "status": "queued", "created_by": "u1", "created_at": "..." }
}
}
任务终态 result 为 InferRun 摘要:{
"run": {
"run_id": "<uuid>", "datasource_id": "1",
"tables": 3, "sampled_tables": 3, "candidates": 2,
"relationships": 2, "annotations": 12,
"source": "llm", "llm_retries": 0, "duration_ms": 3200
}
}
- 结果洞察
- 规则候选先动手:orders.customer_id(*_id 后缀 + 单数化 customers,0.8)、orders.product_id(→ products,0.8)。随后每表 LIMIT 20 采样,customer_id 取值与 customers.id 重叠率 100%,证据写入 evidence 字段。LLM 批量判定:orders.customer_id → customers.id (fk, 0.95)、orders.product_id → products.id (fk, 0.93)。列标注:orders.sales_amount → currency、orders.order_date → time、customers.customer_name → text、products.category → enum。坏 JSON 重试 1 次,llm_retries=0 表示一次成功。
- 调整建议
- 推断前确认数据源 Active 且元数据是最新的;采样依赖连接器,连接器不可用时 sampled_tables 会变少、只靠命名与结构;每 3 表一批的 LLM 列标注,表多时批次多、耗时相应增加。
- 动手试一试
- 登录:http://127.0.0.1:18080,admin / admin1。前置:对 aip_demo_warehouse 执行元数据导入。页面路径:/schema-annotation → 选择数据源 → 点"推断"。预期结果:关系表格出现 orders.customer_id→customers.id 与 orders.product_id→products.id(relation_type=fk,confidence>0.9);标注表格出现 12 条列语义。
- 限制提示
- 数据源无已导入元数据时返回 404「无已导入元数据,请先执行元数据导入」;单次关系判定候选上限 40;采样成功但零重叠的关系置信度会 × 0.5。
故事 2
人审确认/驳回 + 幻觉防御:瞎编的表列被拒之门外
场景:人审 + 防御
角色:业务分析师
耗时:约 5 分钟
- 背景
- 王姐在关系表格核对推断结果:确认 orders.customer_id → customers.id(外键没错),驳回 LLM 误判的 orders.quantity → products.stock(订单数量对不上库存,语义牵强)。同时她注意到 LLM 这次还想输出一个不存在的表,被系统拦掉了。
- 传统做法对比
- 人工建模是"人肉防幻觉",看一个字段想半天;系统用白名单把 LLM 的瞎编表/列在落库前直接丢弃,confidence 越界自动夹取,人审只需要核对剩下的真实候选。
- 角色
- 业务分析师(逐条确认/驳回关系与标注)。
- 操作步骤
-
- GET /datasources/:id/relationships?status=suggested 拉候选
- 确认 orders.customer_id→customers.id:POST /schemaai/relationships/<id>/confirm
- 驳回 orders.quantity→products.stock:POST /schemaai/relationships/<id>/reject
- 再触发推断,验证人审结果保留、suggested 原位更新
- 系统响应
- 确认与驳回返回更新后的关系记录:
// confirm
{ "code": 0, "data": { "id": "<uuid>", "from_table": "orders", "from_column": "customer_id",
"to_table": "customers", "to_column": "id", "relation_type": "fk", "confidence": 0.95,
"source": "llm", "status": "confirmed", "created_at": "..." } }
// reject
{ "code": 0, "data": { "id": "<uuid>", "from_table": "orders", "from_column": "quantity",
"to_table": "products", "to_column": "stock", "relation_type": "semantic", "confidence": 0.6,
"source": "llm", "status": "rejected", "created_at": "..." } }
幻觉防御示例(LLM 输出不存在的表/列被丢弃):LLM 输出: { "from_table": "fake_table", "from_column": "x", "to_table": "products", "to_column": "id" }
validateRelationships → 表名白名单校验失败,整条丢弃,不落库
- 结果洞察
- 幻觉防御四连:表/列必须真实存在(大小写不敏感白名单校验);关系类型白名单(非法归 semantic);confidence 夹取 [0,1] 两位小数(输出 1.7 会变 1.0);一条都不合法则整批降级 rule_only。人审闭环:落库时同键 confirmed/rejected 跳过、suggested 原位更新——再次触发推断,王姐确认/驳回的结论原样保留,计数只统计新增/更新。确认后的关系可被本体建模消费。
- 调整建议
- 按 confidence 降序核对;evidence 字段里的 reason 与 sample_overlap 帮助判断是否误判;列标注只有 confirmed/suggested 两态,不想要的标注不确认即可。
- 动手试一试
- 登录:admin / admin1。页面路径:/schema-annotation → 关系表格(状态过滤"待确认")。操作:确认 customer_id 外键,驳回 quantity→stock,再触发一次推断。预期结果:confirmed/rejected 原样保留,suggested 更新为新结果。
- 限制提示
- 列标注无 reject 端点(asi_column_annotations 仅 suggested/confirmed 两态);单数化只处理常见英文复数,不规则复数可能猜错目标表;relation_type 非法会被归为 semantic 而非报错。
故事 3
LLM 缺失降级纯规则:演示不断线,诚实标注 rule_only
场景:规则降级
角色:数据工程师
耗时:约 3 分钟
- 背景
- 某次环境没有配置 LLM key(或 LLM 上游 500),陈工照常触发推断。他没有等来报错——推断正常完成,只是 InferRun 里 source 变成了 rule_only。他要确认这套结果是什么来路、能不能直接给人审。
- 传统做法对比
- 很多 AI 功能在 LLM 缺失时直接断链或报 503;Schema AI 定位是"半自动辅助",规则结果可接受,所以降级为纯规则并诚实标注 source=rule_only,链路不断、人审流程照常。
- 角色
- 数据工程师(触发推断,识别降级来源)。
- 操作步骤
-
- 断开/失效 LLM key(或模拟 LLM 500)
- 在 /schema-annotation 触发推断
- 查看 InferRun 的 source 字段
- 确认 rule_only 后按规则来源判断结果可参考性
- 系统响应
- 推断正常完成,source 诚实标注 rule_only:
{
"run": {
"run_id": "<uuid>", "datasource_id": "1",
"tables": 3, "sampled_tables": 0, "candidates": 2,
"relationships": 2, "annotations": 9,
"source": "rule_only", "llm_retries": 0, "duration_ms": 210
}
}
规则候选示例:{ "from_table": "orders", "from_column": "customer_id", "to_table": "customers", "to_column": "id",
"relation_type": "fk", "confidence": 0.8, "source": "rule_only",
"evidence": "{\"source\":\"rule_only\",\"rule\":\"fk_name_suffix\",\"sampled\":false}" }
- 结果洞察
- source=rule_only 时:关系来自 FK 命名猜测(*_id → 0.8、列名==主键 → 0.6),列标注来自类型映射启发式(date/time/timestamp→time 0.9、含金额列名→currency 0.85、bool→enum 0.7、主键或 _id 后缀→identifier 0.8 等)。sampled_tables=0 说明连接器采样也没成功(LLM 缺失 + 采样不可用双重降级),重叠率证据缺失。这是与 entityextract"llm 缺失明确报错 503"相反的降级设计:标注是半自动辅助,规则结果可接受;抽取是核心产出,无 LLM 无法工作。
- 调整建议
- 配置 DashScope key 后重新触发推断即可升级为 llm(suggested 原位更新);rule_only 不代表数据错误,人审流程照常,只是置信度与理由更朴素。
- 动手试一试
- 登录:admin / admin1。操作:临时让 LLM 不可用,在 /schema-annotation 触发推断。预期结果:推断不报错,InferRun.source=rule_only,关系与标注仍产出,来源标注"纯规则"。
- 限制提示
- 降级时仅当至少一个批的 LLM 输出真正生效才标 llm,否则诚实标 rule_only;采样依赖连接器,连接器缺失/失败/空表跳过采样,重叠率证据缺失;非法表名(不匹配 safeIdent)跳过采样防注入。
常见问题
推断结果能直接用吗?
不能直接当生产关系用。产出的是 suggested 候选,需要人审确认(confirmed)后才可被本体建模消费;拒绝的(rejected)保留状态不回退。来源 source 会标注 llm 还是 rule_only,供人审参考可信度。
什么算"幻觉防御"?
LLM 判定输出的表/列必须先通过真实存在白名单校验(大小写不敏感),不存在的直接丢弃;关系类型/语义类型走白名单(非法归 semantic);confidence 夹取到 [0,1] 并保留两位小数。LLM 输出不会污染元数据。
rule_only 和 llm 有什么差别?
source=rule_only 表示 LLM 不可用/失败/输出全非法,结果来自 FK 命名猜测与启发式类型映射(诚实标注);source=llm 表示至少一个批的 LLM 输出真正生效。两者都要人审,只是置信度与理由来源不同。
支持 Foundry 的字符串 ID 数据源吗?
默认 MetaReader 的 ListTables 要求数字数据源 ID(非数字返回 400)。要接入 Foundry 字符串 ID 数据源,需注入自定义 MetaReader 适配实现。
确认后的关系去哪儿了?
confirmed 的关系/标注留在 asi_inferred_relationships / asi_column_annotations,可被本体建模(ontology)半自动消费,自动生成对象/属性/链接属后续扩展方向。
主题小结
一句话:元数据语义标注 = FK 命名猜测 → 每表采样 → LLM 批量判定 → 幻觉防御 → 人审闭环,把"表结构说明书"半自动化。记住边界:必须先导入元数据、采样依赖连接器、单数化极简、列标注无 reject、候选上限 40。LLM 缺失时降级 rule_only 不断线,但要认得出这个诚实标注。