业务故事站
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
背景
陈工导入了 aip_demo_warehouse(orders/customers/products 三表)的元数据后,在 /schema-annotation 页面选择该数据源,点"推断"。他想验证系统能不能自己发现 orders 和 customers、products 之间的外键关联,以及每列的业务语义。
传统做法对比
以前建一张关系/指标字典要数据建模师逐表核对字段、翻建表脚本确认外键,小时级起步;现在规则候选 + 采样 + LLM 批量判定,几分钟产出 suggested 结果,人审确认即达可用状态。
角色
数据工程师(导入元数据 + 触发推断)。
操作步骤
  1. 先 POST /datasources/:id/import-metadata 导入元数据
  2. 在 /schema-annotation 选择该数据源
  3. 点"推断",任务化返回 task_id
  4. 轮询 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 人审确认/驳回 + 幻觉防御:瞎编的表列被拒之门外
背景
王姐在关系表格核对推断结果:确认 orders.customer_id → customers.id(外键没错),驳回 LLM 误判的 orders.quantity → products.stock(订单数量对不上库存,语义牵强)。同时她注意到 LLM 这次还想输出一个不存在的表,被系统拦掉了。
传统做法对比
人工建模是"人肉防幻觉",看一个字段想半天;系统用白名单把 LLM 的瞎编表/列在落库前直接丢弃,confidence 越界自动夹取,人审只需要核对剩下的真实候选。
角色
业务分析师(逐条确认/驳回关系与标注)。
操作步骤
  1. GET /datasources/:id/relationships?status=suggested 拉候选
  2. 确认 orders.customer_id→customers.id:POST /schemaai/relationships/<id>/confirm
  3. 驳回 orders.quantity→products.stock:POST /schemaai/relationships/<id>/reject
  4. 再触发推断,验证人审结果保留、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
背景
某次环境没有配置 LLM key(或 LLM 上游 500),陈工照常触发推断。他没有等来报错——推断正常完成,只是 InferRun 里 source 变成了 rule_only。他要确认这套结果是什么来路、能不能直接给人审。
传统做法对比
很多 AI 功能在 LLM 缺失时直接断链或报 503;Schema AI 定位是"半自动辅助",规则结果可接受,所以降级为纯规则并诚实标注 source=rule_only,链路不断、人审流程照常。
角色
数据工程师(触发推断,识别降级来源)。
操作步骤
  1. 断开/失效 LLM key(或模拟 LLM 500)
  2. 在 /schema-annotation 触发推断
  3. 查看 InferRun 的 source 字段
  4. 确认 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 不断线,但要认得出这个诚实标注。