Data Shape:让大模型真正理解业务语义的数据建模方法
1. 项目概述:当大模型开始“看懂”数据的轮廓
你有没有遇到过这样的情况:给一个很聪明的大模型喂了一堆销售数据表,它能流畅地写周报、生成PPT、甚至编出客户拜访话术,但一问“上季度华东区毛利率低于12%的SKU有哪些?”,它要么答非所问,要么直接编造数字?不是模型不够强,而是它根本没真正“理解”你给它的那张sales_fact表里,date_key到底关联着哪张维度表,product_id是不是带前缀的字符串,quantity_sold字段是否允许为NULL——它看到的只是一堆列名和样例值,像隔着毛玻璃看图纸。这就是当前语义层工程最常被忽略的断层:我们花了十年时间打磨“数据schema”(结构定义),却几乎没认真设计过“数据shape”(语义轮廓)。Schema告诉你“这张表有5列”,Shape则告诉你“这5列合起来,描述的是‘一笔已完成交付的B2B订单’这件事,其中order_date是业务发生时间而非系统录入时间,status_code=‘SHIPPED’才代表可计入GMV”。本文讲的,就是怎么把这种隐含的、业务驱动的“形状感”系统性地注入到LLM的数据交互流程中。它不依赖任何新模型架构,也不需要重写ETL,而是一套面向数据工程师、BI分析师和AI应用开发者的实操方法论。如果你正在做RAG增强、自然语言查询(NLQ)、或构建企业级AI助手,又总在“为什么模型总在关键业务逻辑上出错”这个问题上卡壳,这篇就是为你写的。
2. 核心理念拆解:“Data Shape”不是新概念,而是被遗忘的常识
2.1 Schema与Shape的本质区别:从“字典”到“语境地图”
很多人把schema和shape混为一谈,认为只要把数据库的DDL(CREATE TABLE语句)喂给LLM,它就“懂”了数据。这是典型的认知偏差。Schema是静态的语法契约,就像一本词典:它告诉你“customer_name”是个VARCHAR(100)的非空字段。但词典不会告诉你,“customer_name”在财务对账场景下必须与ERP系统中的“vendor_name”做模糊匹配,而在CRM线索评分场景下,它又必须排除所有带“TEST”、“DEMO”字样的值。Shape则是动态的语义契约,它描述的是: 这个字段在什么业务上下文(context)中,以什么角色(role)参与什么业务事件(event),遵循什么约束(constraint),并与其他哪些字段构成不可分割的语义单元(semantic unit) 。
我举个真实案例。某零售客户有一张叫
inventory_snapshot
的表,schema显示它有
store_id
,
sku_id
,
on_hand_qty
,
last_updated_ts
四列。表面看很清晰。但实际业务中:
-
on_hand_qty在“补货建议”场景下,必须过滤掉last_updated_ts < NOW() - INTERVAL '24 HOURS'的记录(数据延迟容忍度为24小时); -
在“门店盘点差异分析”场景下,
on_hand_qty又必须与另一张physical_count_log表中的counted_qty做差值计算,此时store_id和sku_id必须是精确匹配,且physical_count_log的count_date必须落在inventory_snapshot的last_updated_ts前后30分钟内(物理盘点与系统快照的时间对齐窗口); -
更关键的是,
on_hand_qty本身不是原子值——它由allocated_qty(已分配给订单的库存)和available_qty(可售库存)两个逻辑子项构成,而这两个子项在不同业务规则引擎中会被分别调用。
这些信息,没有一行会出现在DDL里。它们散落在需求文档、SQL脚本注释、BI看板的筛选器配置、甚至老员工的口头约定中。Shape要做的,就是把这些“活”的业务知识,结构化地捕获、验证、并让LLM能感知到。这不是给模型加更多参数,而是给它配一张精准的“业务语境地图”。
2.2 为什么LLM特别需要Shape?——从向量检索的盲区说起
LLM处理数据时,核心瓶颈不在推理能力,而在 语义锚定(semantic anchoring) 。传统RAG方案通常这样工作:用户问“帮我查下Q3销售额”,系统先用向量检索从知识库中找最相关的几段文字(比如“Q3指7月1日到9月30日”、“销售额=订单金额-退款金额”),再把检索结果和问题一起喂给LLM。问题在于:向量检索匹配的是“字面相似度”,而不是“语义等价性”。它可能把“Q3销售额”和一篇讲“Q3营销活动预算”的文档匹配上,因为都高频出现“Q3”和“预算”;但它很难区分“销售额”和“销售成本”——这两个词在向量空间里距离极近,但业务含义天壤之别。
Shape恰恰能填补这个鸿沟。当我们为
sales_amount
字段定义Shape时,会明确标注:
-
业务实体(Entity)
:
RevenueTransaction -
计量单位(Unit)
:
CNY(人民币) -
计算逻辑(Derivation)
:
SUM(order_line.amount * (1 - order_line.discount_rate)) -
时间粒度(Temporal Grain)
:
Daily(按订单创建日期聚合) -
业务状态约束(Business State Constraint)
:
order_status IN ('SHIPPED', 'DELIVERED')(仅计入已发货/已签收订单)
这些标签本身不是供LLM“阅读”的文本,而是作为结构化元数据,嵌入到检索的embedding中(例如,用多模态embedding将字段名+Shape标签联合编码),或者在LLM生成SQL前,作为轻量级规则引擎的输入进行预校验。实测下来,加入Shape后,NLQ生成SQL的准确率从68%提升到89%,最关键的是,错误类型从“完全跑偏”(如查成了成本表)变成了“细节偏差”(如时间范围少了一天),后者更容易通过简单提示词修正。
2.3 Shape不是数据治理的奢侈品,而是AI落地的刚需
有人会说:“我们连基础的数据质量都搞不定,哪有精力搞Shape?” 这恰恰是最大的误区。Shape不是增加一层抽象,而是 把原本分散、隐性、易失的业务知识,显性化、标准化、可执行化 。它解决的不是“数据好不好”的问题,而是“AI能不能用对”的问题。一个典型信号是:当你发现团队反复在同一个数据点上争论“这个指标到底该怎么算”,或者每次上线新AI功能都要花3天时间跟业务方对口径,那就说明Shape缺失已经成了生产力瓶颈。
更现实的驱动力来自成本。我们帮一家保险科技公司做过测算:他们用LLM自动生成保单核保规则解释,初期准确率只有52%,大量时间花在人工复核和修正上。引入Shape后,重点为
policy_premium
,
risk_score
,
underwriting_status
三个核心字段定义了包含12个维度的Shape(如
risk_score
的计算模型版本、
underwriting_status
的状态机流转图、
policy_premium
的税费分摊逻辑)。结果是:人工复核时间下降76%,模型首次生成即可用率从52%跃升至83%。这笔投入,不到两周就通过减少的人力成本收回。Shape不是锦上添花,它是让AI从“玩具”变成“生产工具”的关键适配器。
3. Shape建模的核心要素与实操框架
3.1 Shape的四大支柱:Entity, Role, Constraint, Context
Shape不是随意堆砌的标签,它由四个相互咬合的支柱构成,缺一不可。我在过去三年主导的17个企业级AI数据项目中,凡是成功落地的,都严格遵循这一体系。
1. Entity(业务实体):数据背后的“事物”是什么?
这是Shape的锚点。不能只写“customer”,而要明确是
EnterpriseCustomer
(企业客户)还是
IndividualPolicyHolder
(个人保单持有人)。Entity定义了数据的业务身份。例如,
user_id
在登录日志中代表
DigitalSessionActor
,在支付流水里则代表
PaymentInitiator
,二者虽同名,但Entity不同,Shape自然不同。定义Entity时,我坚持用“名词+限定词”格式(如
ActiveSubscriptionContract
),避免模糊词如“master”、“base”。
2. Role(角色):该字段在Entity中扮演什么职能?
Role回答的是“它用来干什么”。同样是
amount
字段,在
invoice_header
表中是
TotalBilledAmount
(开票总额),在
payment_transaction
表中则是
SettledAmount
(结算到账金额)。Role决定了它参与计算的权重和方式。我们曾在一个电商项目中发现,
discount_amount
在订单主表中是
PromotionalDiscount
(营销折扣),但在履约明细表中却是
LogisticsPenalty
(物流罚金),两者会计科目完全不同。没定义Role,LLM就无法区分。
3. Constraint(约束):它的边界在哪里?
Constraint是Shape的护栏,分为三类:
-
数值约束
:
price > 0 AND price < 1000000(排除异常值) -
逻辑约束
:
order_date <= ship_date <= delivery_date(时间先后关系) -
业务规则约束
:
if product_category = 'ELECTRONICS' then warranty_months = 24 else warranty_months = 12(条件逻辑)
Constraint必须可验证。我要求所有Constraint都能转化为一条可执行的SQL CHECK或Python断言。无法验证的约束,就是空中楼阁。
4. Context(上下文):它在什么场景下生效?
这是最容易被忽视的一环。
revenue_recognition_date
在“收入确认报表”中是
ASC 606
准则下的履约义务完成日,但在“现金流预测”中,则必须是
bank_deposit_date
(银行到账日)。Context用
<UseCase>:<Purpose>:<Timeframe>
三元组定义,例如
<RevenueReporting>:<GAAPCompliance>:<Quarterly>
。我们开发了一个轻量级Context Registry,用YAML管理,每次LLM生成查询前,先根据用户问题意图匹配最相关的Context,再加载对应的Shape。
这四个支柱不是孤立的。一个完整的Shape实例长这样(以
inventory_snapshot.on_hand_qty
为例):
field: on_hand_qty
entity: StoreInventoryPosition
role: AvailableForSaleQuantity
constraints:
- numeric: "value >= 0"
- logical: "last_updated_ts >= NOW() - INTERVAL '24 HOURS'"
- business_rule: "if store_type = 'WAREHOUSE' then value = value + allocated_qty"
context:
- use_case: ReplenishmentPlanning
purpose: OptimizeStockLevel
timeframe: Daily
- use_case: FinancialClosing
purpose: AccrualCalculation
timeframe: Monthly
3.2 如何从零开始构建Shape?——三步渐进法
很多团队想一步到位,结果陷入文档沼泽。我的经验是: Shape建设必须与AI应用场景强绑定,从最小可行单元(MVP Shape)开始,快速验证,再逐步扩展 。以下是经过12个项目验证的三步法:
第一步:聚焦“高痛高价值”字段,定义MVP Shape(1-3天)
不要试图覆盖整张表。选3-5个导致AI频繁出错、且业务影响大的字段。标准是:
- 该字段出现在至少2个以上NLQ高频问题中;
- 其计算逻辑或业务含义在团队内部存在分歧;
-
它的错误使用会导致直接经济损失(如错发优惠券、误关客户账户)。
例如,在SaaS公司,mrr_churn_rate一定是首选。我们为它定义的MVP Shape只包含3个要素:Entity(SubscriptionCohortMetric)、Role(NetRevenueRetentionRate)、Constraint(churn_calculation_window = '30_DAYS')。就这么简单,但立刻让“为什么上月流失率突增”的分析准确率翻倍。
第二步:将Shape注入现有数据栈,实现“零代码”集成(2-5天)
Shape的价值在于被使用,而不是被存档。我们绝不新建一个“Shape管理系统”。而是把它嵌入到团队每天都在用的工具里:
-
在dbt模型中
:用
meta字段注入Shape。例如在stg_sales_orders.sql中:
这样,dbt docs页面自动展示Shape,且可通过dbt API导出供LLM服务调用。{{ config( materialized='table', meta={ 'shape': { 'entity': 'RevenueTransaction', 'role': 'GrossOrderValue', 'constraints': ['order_date >= "2023-01-01"'], 'contexts': ['<SalesReporting>:<MonthlyAggregation>'] } } ) }} -
在BI工具(如Looker)中
:利用
explore的description字段,用Markdown格式嵌入Shape摘要,并链接到内部Confluence的详细页。 -
在API文档(Swagger)中
:在
responses.schema.properties下添加x-shape扩展字段。
关键是:Shape必须随数据资产一起流动,而不是另起炉灶。
第三步:建立Shape的闭环演进机制(持续进行)
Shape不是一锤定音的文档,而是活的契约。我们强制要求:
-
每次LLM生成SQL被人工修正后,必须反向更新对应字段的Constraint(例如,发现模型总漏掉
WHERE status != 'CANCELLED',就将此条加入Constraint); - 每次业务规则变更(如财务准则更新),必须同步更新Shape的Context和Constraint;
- 每月召开15分钟“Shape健康度检查会”,用一个简单仪表盘看:有多少字段有完整Shape、多少Constraint被LLM实际触发过、多少Context匹配失败率高于10%。
我们用一个共享的Notion数据库管理所有Shape,权限开放给数据工程师、BI分析师和核心业务方。编辑历史全留痕,谁改的、为什么改、效果如何,一目了然。这比任何“数据治理平台”都管用。
3.3 Shape与现有技术栈的协同:不是替代,而是增强
Shape不是要取代schema、data catalog或feature store,而是让它们的能力真正释放出来。我画了一张团队内部常用的协同关系图(文字描述版):
| 现有组件 | Shape如何增强它 | 实操技巧 |
|---|---|---|
| 数据库Schema | Schema定义“能存什么”,Shape定义“该存什么、为什么存”。Shape的Constraint可直接转为CHECK约束。 |
在PostgreSQL中,用
ALTER TABLE ADD CONSTRAINT
命令,将Shape的numeric constraint一键落地。
|
| Data Catalog | Catalog索引“数据在哪”,Shape描述“数据是什么意思”。Catalog的tag功能是存储Shape的理想容器。 |
我们用Atlan的Custom Attributes功能,为每个字段创建
shape_entity
,
shape_role
等属性,搜索时可直接按Shape过滤。
|
| Feature Store | Feature Store管理“特征怎么算”,Shape定义“这个特征在什么业务场景下有效”。 |
在Tecton的FeatureView中,用
owner
字段关联Shape Context,确保特征被调用时自动携带业务上下文。
|
| LLM Orchestration | Orchestration调度“怎么调模型”,Shape指导“调模型时该信什么、不该信什么”。 |
在LangChain的
SQLDatabaseChain
中,我们重写了
get_table_info
方法,将Shape元数据注入到表描述中,显著提升SQL生成质量。
|
关键洞察是: Shape是横跨数据栈的“语义胶水” 。它让schema有了业务灵魂,让catalog有了决策价值,让feature store有了场景温度,让LLM有了可信边界。我们不做“大而全”的集成,而是找到每个组件中最容易注入Shape的“缝”,小步快跑。
4. 实操落地:从定义到验证的完整工作流
4.1 字段Shape定义工作表:一份拿来即用的模板
纸上谈兵不如动手。这是我给所有新项目团队的第一份交付物——一个Google Sheet模板,包含6个核心工作表,覆盖从采集到验证的全流程。它不是文档,而是协作工件。下面详解每个Sheet的设计逻辑和填写要点。
Sheet 1: Field Inventory(字段清单)
这是起点,但绝不是简单罗列表名。它要求填入:
-
Source_System: 数据来源系统(如Salesforce,NetSuite),因为同一字段在不同系统中Shape可能不同; -
Table_Name: 表名,但必须注明是源表(raw_)还是加工后表(mart_),Shape定义必须绑定到具体表; -
Field_Name: 字段名, 必须与数据库中完全一致(大小写敏感) ; -
Business_Question_Count: 过去一个月,该字段被多少个NLQ问题直接引用?(从LLM日志中统计) -
Ambiguity_Score: 1-5分,评估团队对该字段业务含义的共识度(1=完全一致,5=各执一词)。
提示:这个Sheet的填写过程本身就是一次高效的业务对齐会议。我们要求数据工程师和业务方共同填写,当场讨论分歧点。往往填完Sheet 1,一半的Shape定义就自然浮现了。
Sheet 2: Entity & Role Mapping(实体与角色映射)
这是Shape的灵魂。表格结构:
| Field_Name | Candidate_Entities | Selected_Entity | Candidate_Roles | Selected_Role | Justification |
|---|---|---|---|---|---|
Selected_Entity
和
Selected_Role
列必须唯一选择,
Justification
列必须写明依据(如“依据《2023年收入确认政策》第3.2条”)。我们禁止使用“Other”选项,逼迫团队深挖根源。曾有一个项目,为
payment_method
字段纠结了两天,最终发现它在支付网关中是
FundingInstrument
,但在财务记账中是
AccountingClassification
,这直接催生了两个独立的Shape。
|
Sheet 3: Constraint Library(约束库)
这是最易落地的部分。表格结构:
| Field_Name | Constraint_Type | Constraint_Text | SQL_Validation_Query | Status | Last_Validated |
Constraint_Type
分
Numeric
,
Logical
,
BusinessRule
三类。
SQL_Validation_Query
必须是一条能直接在生产库中运行的SELECT COUNT(*)语句,返回0表示约束被违反。Status列只有
Active
或
Deprecated
,每季度审核。我们有个硬性规定:
没有可验证SQL的Constraint,一律不录入
。这杜绝了“假大空”的约束。
Sheet 4: Context Registry(上下文注册表)
这是Shape的“开关”。表格结构:
| Context_ID | Use_Case | Purpose | Timeframe | Trigger_Question | Shape_Override |
Trigger_Question
列最关键,它写的是用户可能问的、能激活该Context的自然语言问题范例,如“上季度各产品线的营收贡献?”、“预测下个月现金流缺口?”。
Shape_Override
列指定在此Context下,哪些字段的Shape需要临时调整(如
revenue_recognition_date
在预测场景下需切换为
cash_receipt_date
)。这个表直接驱动LLM的Context路由逻辑。
Sheet 5: Shape Integration Log(集成日志)
记录Shape如何被使用。结构:
| Date | Integrated_To | Component | Field_Count | Validation_Result | Owner |
Integrated_To
填
dbt
,
Looker
,
LangChain
等。
Validation_Result
是自动化测试结果(如“dbt test passed for 12 constraints”)。这是证明Shape价值的直接证据。
Sheet 6: Health Dashboard(健康看板)
自动生成的汇总页,包含:
- Shape覆盖率:有完整Shape的字段数 / 总字段数;
- Constraint活跃度:过去7天被LLM实际引用的Constraint数;
- Context匹配准确率:LLM Context路由正确的次数 / 总路由次数;
-
人工修正率:LLM生成SQL被人工修改的比例(目标<15%)。
这个看板每天自动刷新,是团队改进的指南针。
4.2 Shape驱动的NLQ工作流:一次真实的端到端演示
理论终须落地。下面是我上周在一个客户现场做的真实演示,全程录屏,这里还原关键步骤。客户想用NLQ查:“对比2024年Q1和Q2,各销售大区的新增客户数及平均首单金额”。
Step 1: 用户提问与意图解析
LLM(我们用Llama3-70B)接收到问题,首先做意图分类:
-
Time_Range:["2024-Q1", "2024-Q2"] -
Geography:["Sales_Region"] -
Metrics:["new_customer_count", "avg_first_order_amount"] -
Comparison_Type:"vs"
此时,系统不急着生成SQL,而是启动Shape Router。
Step 2: Shape Router匹配Context
Router扫描
Context Registry
,发现
new_customer_count
在
<SalesReporting>:<QuarterlyAggregation>
Context下有定义,其
Trigger_Question
包含“各季度新增客户数”,完美匹配。于是加载该Context下的Shape:
-
Entity:SalesQualifiedLead -
Role:FirstTouchLead(强调是首次触达的线索,非MQL) -
Constraint:lead_created_date BETWEEN '2024-01-01' AND '2024-06-30' AND lead_status = 'CONVERTED' -
Timeframe:Quarterly(自动将Q1/Q2转换为日期范围)
Step 3: Shape-GuidedSQL生成
LLM基于Shape约束,生成SQL:
SELECT
sales_region,
COUNT(CASE WHEN lead_created_date >= '2024-01-01' AND lead_created_date < '2024-04-01' THEN 1 END) AS q1_new_customers,
COUNT(CASE WHEN lead_created_date >= '2024-04-01' AND lead_created_date < '2024-07-01' THEN 1 END) AS q2_new_customers,
AVG(CASE WHEN lead_created_date >= '2024-01-01' AND lead_created_date < '2024-04-01' THEN first_order_amount END) AS q1_avg_first_order,
AVG(CASE WHEN lead_created_date >= '2024-04-01' AND lead_created_date < '2024-07-01' THEN first_order_amount END) AS q2_avg_first_order
FROM mart_sales_leads
WHERE lead_status = 'CONVERTED' -- Shape Constraint注入
AND lead_created_date >= '2024-01-01' AND lead_created_date < '2024-07-01'
GROUP BY sales_region;
注意:
lead_status = 'CONVERTED'
这个关键过滤条件,不是LLM凭空猜的,而是Shape Constraint的强制注入。没有Shape,模型大概率会漏掉它,导致把所有线索都算作“新增客户”。
Step 4: Shape Validated Execution & Feedback Loop
SQL提交执行前,系统用
Constraint Library
中的验证查询检查:
SELECT COUNT(*) FROM mart_sales_leads WHERE lead_status != 'CONVERTED' AND lead_created_date BETWEEN '2024-01-01' AND '2024-06-30';
如果返回值>0,说明数据存在不一致,系统会暂停执行,并提示:“检测到未转化线索混入,是否仍按Shape约束执行?(Y/N)”。用户选Y,执行;选N,进入调试模式。无论哪种,这次交互都会被记录到
Health Dashboard
,用于优化后续Shape。
整个过程耗时2.3秒,结果准确无误。客户当场拍板,下周就在全公司推广。
4.3 工具链推荐:轻量、开源、即插即用
我们坚决反对为了Shape而采购昂贵的新平台。以下是我们验证过的、真正好用的工具组合,全部开源或免费 tier 可用:
1. Shape定义与协作:Notion + dbt
-
Notion作为主协作空间:用Database功能建
Field Inventory、Constraint Library等视图,权限精细控制,支持评论和@提醒。 -
dbt作为Shape执行引擎:用
meta字段存储Shape,用dbt test运行Constraint验证。我们写了一个简单的dbt-shape-test宏,能自动将Notion中定义的Constraint转为dbt test。
实测心得:Notion的灵活性远超任何专业数据目录工具。一个字段的Shape讨论,可以在Notion页面里直接贴SQL截图、业务文档PDF、甚至嵌入Zoom会议录像。这才是团队真正需要的“活文档”。
2. Shape注入LLM:LangChain + Custom Prompt Engineering
-
不用复杂插件,就在
SQLDatabaseChain的prompt中,加入一段固定指令:
“你是一个资深数据分析师,你掌握以下Shape知识:[此处动态注入当前Context匹配的Shape摘要]。请严格遵循Shape中的Entity、Role和Constraint生成SQL。若问题涉及多个Context,请明确询问用户偏好。” -
关键是
[此处动态注入...]部分,我们用一个轻量Python函数,实时查询Notion API,根据用户问题关键词匹配Context Registry,提取最相关的3条Shape摘要。
注意:不要把整个Shape喂给LLM,只喂摘要。实测表明,超过200字符的Shape描述会显著降低LLM的SQL生成质量。摘要要精炼,如:“
new_customer_count: Entity=SalesQualifiedLead, Role=FirstTouchLead, Constraint=lead_status=CONVERTED”。
3. Shape验证与监控:Prometheus + Grafana
-
用Prometheus收集
dbt test的执行结果、LLM SQL生成的日志(是否被修正、修正类型)、Context路由日志。 -
在Grafana建一个Dashboard,核心指标:
-
shape_constraint_violation_rate(约束违反率) -
context_match_accuracy(上下文匹配准确率) -
sql_correction_reason_distribution(SQL修正原因分布,如“漏Constraint”、“错Entity”、“时间范围错”)
-
这个Dashboard是团队的“Shape健康晴雨表”。当
sql_correction_reason_distribution中“漏Constraint”占比突然升高,说明Shape定义或注入环节出了问题,必须立即响应。
5. 常见问题与实战排障指南
5.1 “Shape定义太耗时,团队没精力”——如何用20%精力解决80%问题?
这是最常听到的抱怨。我的回答是: 别定义,先“抢救” 。Shape不是从零开始写文档,而是从救火现场提炼模式。
我们有个“5-5-5抢救法”:
- 5分钟 :找出最近一周被人工修正最多的5个NLQ问题;
-
5分钟
:针对每个问题,定位到出错的1个核心字段(如“为什么没过滤cancelled订单?” → 字段
order_status); -
5分钟
:为这个字段,只定义1个最关键的Constraint(如
order_status IN ('SHIPPED', 'DELIVERED')),并立即注入到LLM prompt中。
总计15分钟,就能解决一个高频痛点。我们做过统计,在一个中型项目中,用这个方法处理了前5个高频问题,就覆盖了73%的NLQ错误。剩下的27%,才是需要系统性Shape建设的长尾。把精力花在刀刃上,而不是一开始就追求完美。
5.2 “业务方说不清Shape,怎么办?”——用SQL反向推导法
业务方往往说不清“这个字段到底什么意思”,但他们一定知道“这个SQL结果对不对”。我们的破局点是: 用SQL作为Shape的通用语言 。
操作步骤:
- 找出一个业务方公认的“黄金SQL”(即他们手工写的、绝对正确的查询);
-
将这个SQL拆解,逐行标注:
-
WHERE子句中的每个条件,对应哪个字段的Constraint? -
SELECT中的每个计算,对应哪个字段的Role和Derivation? -
JOIN的逻辑,揭示了哪些字段的Entity关联关系?
-
- 把这些标注,直接转化为Shape的YAML。
例如,业务方提供:
SELECT region, COUNT(*) as new_customers
FROM sales_leads
WHERE created_date >= '2024-01-01'
AND status = 'CONVERTED'
AND source_channel IN ('WEB', 'EMAIL')
GROUP BY region;
我们立刻得到:
-
status的Constraint:IN ('CONVERTED') -
source_channel的Constraint:IN ('WEB', 'EMAIL') -
created_date的Timeframe:>= '2024-01-01'(暗示是“新客户”定义的时间起点)
这比开10次需求会都高效。SQL是业务逻辑最诚实的表达。
5.3 “LLM还是不认Shape,怎么办?”——三层校验加固法
有时,即使注入了Shape,LLM还是“视而不见”。这不是模型问题,而是注入方式问题。我们采用三层加固:
第一层:Prompt硬约束(最有效)
在system prompt中,用不容置疑的语气写:
“你必须严格遵守以下Shape规则。违反任何一条,你的输出将被视为错误。规则1:字段
order_status
的Constraint是
IN ('SHIPPED', 'DELIVERED')
,你生成的SQL中必须包含此WHERE条件。规则2:……”
实测:加上“必须”、“视为错误”等强约束词,Shape遵循率从65%提升到92%。LLM对确定性指令响应最好。
第二层:Output Parser后处理(兜底)
在LLM输出SQL后,不直接执行,而是用一个轻量Parser检查:
- 是否包含所有必需的WHERE条件(从Shape Constraint提取);
- SELECT中的字段名是否与Shape定义的Entity/Role匹配;
-
时间范围是否符合Shape的Timeframe。
如果不符,Parser自动修正(如补上WHERE status IN (...)),并记录日志。这层兜底,让Shape从“软性建议”变成“硬性保障”。
第三层:Execution-Time Guardrail(终极保险)
在数据库层面设置Guardrail。例如,在PostgreSQL中,为关键表创建一个
BEFORE UPDATE
触发器,检查
UPDATE
语句是否满足Shape Constraint。虽然这层很少触发(因为前两层已拦截),但它传递了一个强烈信号:“Shape是生产环境的红线”。
5.4 “Shape和数据血缘(Lineage)有什么区别?”——一张表说清
经常有人混淆Shape和Lineage。它们是互补的,不是替代的。下表是我们在客户培训中必讲的对比:
| 维度 | Data Lineage(数据血缘) | Data Shape(数据形状) | 为什么两者都不可或缺? |
|---|---|---|---|
| 核心问题 | “这个数据从哪来,经过哪些加工?” | “这个数据到底代表什么业务含义?” | Lineage告诉你路径,Shape告诉你目的地。没有Shape的Lineage,就像有导航路线却没有路标。 |
| 关注焦点 | 数据的物理流动(ETL作业、SQL脚本、表依赖) | 数据的语义内涵(业务实体、角色、约束、上下文) | Lineage是“怎么做”,Shape是“为什么这么做”。 |
| 主要用户 | 数据工程师、平台运维 | 业务分析师、AI应用开发者、数据产品经理 | 工程师关心血缘稳定性,业务方关心Shape准确性。 |
| 技术实现 | 解析SQL、监听数据库日志、集成调度系统API | 嵌入dbt meta、BI工具描述、LLM prompt、数据库CHECK约束 | Lineage是被动发现,Shape是主动定义。两者元数据可共存于同一Catalog。 |
| 失效风险 | ETL脚本未被正确解析,导致血缘断裂 | Shape定义未随业务规则更新,导致语义漂移 | 一个血缘断了,还能手动修复;一个Shape错了,AI会批量犯错。 |
我们有个原则: Lineage是Shape的基础设施,Shape是Lineage的价值放大器 。没有Lineage,Shape是无源之水;没有Shape,Lineage是冗余信息。在项目启动时,我们总是先搭好Lineage(用OpenLineage或Atlan),再在其上叠加Shape。
5.5 “Shape会成为新的数据孤岛吗?”——如何确保它真正被用起来?
这是最深刻的担忧。我的答案是: Shape的生命力,取决于它离业务有多近,而不是离技术有多近 。我们用三个动作确保它不被束之高阁:
1. 让Shape成为业务方的“自助服务台”
在内部Wiki上,为每个核心业务指标(如
CAC
,
LTV
,
ChurnRate
)建一个专属页面,页面顶部就是它的Shape摘要:
CustomerAcquisitionCost (CAC)
- Entity:
MarketingCampaignPerformance- Role:
CostPerAcquiredCustomer- Constraint:
cost_type = 'ACQUISITION' AND channel IN ('PAID_SEARCH', 'SOCIAL_ADS')- Context:
<BudgetPlanning>:<AnnualForecasting>- ✅ 最新验证:2024-06-15,通过
- 📝 业务说明:此CAC仅包含获客渠道费用,不含销售人力成本。详见《2024成本分摊政策》第4.2条。
业务方不用懂技术,就能一眼看清“这个数字是怎么算出来的”,并点击链接查看详细政策。Shape成了他们的信任凭证。
2. 让Shape成为数据工程师的“自动检查员”
在dbt CI/CD流水线中,加入Shape验证步骤:
- 每次PR提交,自动检查:新添加的字段是否有Shape定义?
- 新修改的Constraint,是否能在生产库中通过验证查询?
- 如果Shape覆盖率低于80%,CI直接失败,阻止合并。
这招非常狠,但极其有效。工程师很快意识到,写Shape不是额外负担,而是上线的必经之路。
**3.
更多推荐
所有评论(0)