WrenAI 入门:从零到会用的核心机制指南
这是一篇整理了WrenAI核心工作机制的技术博客,面向刚开始接触AI4BI,AI-Databot的数据工程师,串联起这类项目结构、知识管理、技能编排和 如何保证AI写SQL正确性这几条主线。
一、WrenAI要解决什么问题
给LLM一个原始数据库schema,让它直接写SQL,常见的失败模式是:表名歧义(customers vs customers_v3)、不知道status=4是什么意思、幻觉出不存在的join。
而WrenAI的核心思路是在数据库和agent之间加两样东西:
- 一层显式、可版本控制的语义层——MDL(Modeling Definition
Language,一种用YAML描述Models、Relationships、Views、Cubes的语义契约,规定哪些数据集存在、暴露哪些字段、如何关联、哪些计算逻辑可复用) - 业务知识(knowledge/rules、knowledge/sql)
让agent只能在这层"经过审查的现实"上操作,而不是直接面对原始表 。
二、四个知识载体:MDL如何管理业务背景知识
WrenAI把知识拆成四层显式文件,全部可Git版本控制、审查、回滚:
| 产物 | 内容 | 更新方式 |
|---|---|---|
MDL(models/、views/、relationships.yml) | 结构与语义契约:数据是什么、如何关联、可复用的计算逻辑 | wren context build、手动编辑、agent提议 |
knowledge/rules/ | schema无法表达的业务规则(如软删除默认过滤条件) | 手动编辑或agent提议 |
knowledge/sql/ | 确认过的自然语言→SQL对,一个markdown文件一对 | wren memory store、手动编辑 |
Memory index(.wren/memory/) | 基于前三者派生的检索索引(可选LanceDB,否则grep) | wren memory index |
关键区分:前三者是源文件,memory index是派生产物,随时可从源重建、不是真相来源 3 。
三、Model / View / Cube:MDL中的三种语义对象
| 类比 | 关键字段 | |
|---|---|---|
| Model | SQL表或存储的SELECT | table_reference(物理表)或ref_sql(SQL SELECT)二选一,加columns |
| View | SQL VIEW | 完整statement,schema从语句推断,可递归引用其他view |
| Cube | 预聚合语义对象(借用OLAP/维度建模词汇,不是完整方法论) | base_object(model或view)+ measures/dimensions/time_dimensions |
Cube的价值在于把agent最容易出错的四类问题(join错误、聚合层级错误导致重复计数、日期截断歧义、指标定义不一致)提前声明清楚,agent查询时用结构化命令wren cube query --cube revenue --measures total --dimensions status,不需要手写GROUP BY/DATE_TRUNC 7 。
YAML源 vs JSON编译产物
三者都用YAML写(snake_case字段),编译成target/mdl.json供引擎读取(camelCase字段,wire format) 8 。YAML是给人编辑维护的多文件结构,JSON是给Rust引擎(wren-core)消费的扁平manifest——类似TypeScript源码 vs 编译出的JS,源格式便于协作review,产物格式便于机器消费、随时可重建。
四、六个技能(Skills):agent的操作手册
WrenAI没有把"怎么用WrenAI"写死在prompt里,而是做成CLI内置、按需拉取的技能文档:
| 技能 | 定位 | 触发时机 |
|---|---|---|
| onboarding | 入口技能,编排环境检查→项目脚手架→连接配置→MDL生成→首次查询 | 用户说"set up wren" |
| generate-mdl | 一次性设置:探索数据库schema,生成初始MDL | onboarding的Step 5调用;项目初始化时跑一次 |
| usage | 日常查询主循环:fetch context→recall→写SQL→执行→store | 每次查询 |
| enrich-context | 深挖业务含义(枚举值、单位、canonical表、命名指标) | 用户抱怨/发现新术语时按需触发,非每次查询 |
| dlt-connector | 通过dlt连接SaaS数据源(HubSpot/Stripe等)到DuckDB | 接入新数据源时 |
| genbi | 把context层转成可分享的GenBI web应用 | 需要分享/部署时 |
两拍哲学:Scaffold Fast → Enrich Deep
generate-mdl只覆盖"数据库能自我描述的部分"——表结构、列类型、外键推断的关系 10 。真正的业务含义(哪张表是canonical、status=4是什么意思)活在文档、Slack、分析师的SQL里,需要enrich-context通过Grill模式(逐问题澄清确认)或Auto-pilot模式(批量读取raw/推断)补进MDL或knowledge/ 11 。两种模式都只新增、不覆盖已有字段,冲突留人工处理 12 。
五、usage:每次查询怎么保证准确
usage不是简单地"把问题丢给LLM生成SQL",而是一套多阶段流程:
定向检索而非全量塞schema
两种常见失败模式——把整个schema塞进prompt(模型被无关表干扰)、让模型自己猜哪张表相关(容易选错)——usage都不做。Memory索引MDL + knowledge/rules/ + 确认过的NL-SQL对,只检索匹配当前问题的那一小片 13 。
复杂度判断影响是否要dry-plan验证
- 简单(单表、MDL已定义的简单JOIN)→ 直接执行
- 复杂(非MDL relationships覆盖的JOIN、子查询、多步逻辑)→ 先
wren dry-plan验证展开后的SQL再执行 14
这是个判断而非硬规则:“如果对单条查询有信心,可以直接执行;如果失败后难以调试,就该验证” 15 。
六、dry-plan:给agent一个"编译器"
这是最容易被误解的一点:agent写的SQL和最终跑在数据库上的SQL不是同一句。
agent写的是"模型层SQL"
针对MDL model名字写查询,比如SELECT c_name FROM orders JOIN customer ON ...,这里的orders、customer是MDL声明的逻辑对象,不是必然对应数据库里同名的物理表。
引擎(不是LLM)负责展开
WrenEngine.dry_plan()是纯规则化的转译管道,不涉及任何LLM推理:sqlglot解析 → 识别引用的models/columns → wren-core按MDL语义展开每个model → 注入为CTE → 生成目标方言SQL 16 。
真实展开例子(来自wren-core测试):用户写SELECT c_custkey, count(distinct c_name) FROM customer GROUP BY c_custkey,展开后customer被替换成多层嵌套子查询,最内层才是FROM customer AS __source真实表访问 17 。如果model有跨表计算字段,展开时会自动注入JOIN,即使用户没写;如果MDL定义了row-level policy,展开时会自动加WHERE过滤条件。
为什么"agent检查agent写的SQL"不是空转
因为检查所依据的信息不是LLM自己复述的,而是引擎解析MDL manifest后返回的确定性事实——SQL到底引用了哪些真实存在的model/column,JOIN到底展开成什么样。这类似程序员写代码后跑compiler/linter:代码是自己写的,但编译器的报错是独立于生成过程的外部反馈。如果列名写错了,dry-plan直接返回可用列名列表,agent据此重试而不是靠"自我反思" 18 。
dry-plan vs dry-run vs query
| 连接数据库? | 输出 | 用途 | |
|---|---|---|---|
dry-plan | 否 | 展开后的SQL文本 | 转译预览,MDL层校验 |
dry-run | 是 | OK / Error: <reason> | 验证SQL能否在DB上跑通,不取数据 |
query(真正执行) | 是 | 结果数据 | 内部先跑一次dry-plan再交给connector执行 |
对应两层错误诊断策略:dry-plan失败 = MDL层问题(模型/列名错、缺关系);dry-plan成功但执行失败 = DB层问题(类型不匹配、权限、dialect) 20 。
七、整体心智模型总结
对初学者而言,记住三个分层就够用:
- 知识分层:MDL(结构语义)+
knowledge/rules(业务规则)+knowledge/sql(confirmed范例),全是可审查的文本文件,memory index只是它们的派生检索层。 - 技能分层:
onboarding/generate-mdl是一次性搭台,enrich-context是按需深挖,usage是唯一贯穿每次查询的主循环。 - SQL分层:agent写的是针对MDL对象的"意图SQL",
dry-plan把它展开成数据库能理解的"事实SQL",两者之间的差异就是WrenAI给agent架的一层安全网。

294

被折叠的 条评论
为什么被折叠?



