问数Agent基础设施搭建:从元数据到语义层的完整实践
2026/9/12 23:17:16 网站建设 项目流程

直接开场说重点。我之前写过LCODER系列的AI Agent开发第一篇,把问数项目的整体架构和Agent能力边界划清楚了,这篇接着往里走,把基础设施层的每一块地基填实。问数项目说到底就是让业务人员用大白话查数,但“大白话”这三个字背后,链路比你想象的长得多。从自然语言到SQL,从SQL到数据结果,从结果到可读回答,每一步都依赖下面这层基础设施撑住。

基础设施搭建这个词听起来不性感,但往往是项目后面返工率最高的地方。我见过太多团队一上来就冲LLM和Agent编排,先跑通一条demo再说,结果模型一换、数据源一加、权限一变,整个链路重新翻修。这篇就把我踩过的坑、验证过的方案、以及最终稳定跑起来的一套底座设计全部摊开讲,项目还没开工的可以先当checklist用,已经在做Agent项目的对照着查漏补缺。

1. 问数Agent到底是什么:先对齐认知再动手

1.1 “问数”的本质是把口语翻译成可执行的查询链路

问数项目里很多人把重点放反了,以为核心是“让Agent学会写SQL”。实际上问数的核心是:让自然语言和企业数据之间建立一条语义对齐的通道。业务人员说的“上个月华东区的退货率怎么样”,这句话能不能被准确映射到某个事实表、某些维度字段、某种聚合逻辑,这才是成败关键。

我在设计中把问数Agent定位成三层结构。最上层是交互层,负责理解用户意图、澄清歧义;中间层是语义层,负责把意图映射到指标、维度和表;最底层是执行层,负责生成SQL、调度执行、返回结果。基础设施搭建就是把中间层和最底层的“路”先修好。

很多人会觉得语义层用大模型做就行,RAG召回一下相关表结构,丢给LLM生成SQL,这部分确实能跑通demo。但真实场景里,用户不会说“从orders表里按region字段等于华东、date字段在2024年1月1日到1月31日之间,对returned_flag等于1的记录计数,再除以总订单数”。用户只会说“退货率”,你指望模型自己脑补出这一整套映射逻辑,基本等于赌命。

1.2 基础设施不等于装几个组件

基础设施搭建这个阶段容易犯的错误,是把“基础设施”理解成“把Mysql、Redis、向量库、LLM API都部署好就算完了”。这不叫基础设施,这只是环境初始化。

在我理解里,问数项目的基础设施应该包含四层能力:

  • 数据连接层:统一管理各类数据源连接、元数据采集、数据字典维护,让Agent有一个稳定、可理解的数据视图。
  • 语义映射层:把业务术语、指标定义、维度取值统一沉淀下来,形成一套机器可读的语义层配置,这是Agent理解业务的关键知识库。
  • 模型与提示词管理:统一管理大模型接入、prompt模板、Few-shot样本、模型切换策略,避免prompt写在代码里散落各处。
  • 执行与安全层:负责SQL生成后的校验、权限管控、查询超时、结果集大小限制等保护机制,确保Agent不会把生产库拖垮。

这四层就是这篇要搭建的主体。没有这四层,Agent只会在玩具demo里打转,一旦接到真实业务数据就直接失控。我在LCODER系列第一篇聊过“Agent不是模型而是系统”这件事,基础设施搭建就是把这个系统骨架立起来。

2. 基础设施选型:为什么我放弃了一站式框架

2.1 现成框架的问题不止是定制化难

市面上做Agent基础设施的框架不少,从LangChain、LlamaIndex到各类Data+AI一体化的平台都有。说实话,问数项目用现成框架起步确实快,但一旦进入生产环境,问题就会排队出现。

第一个问题是语义层的缺失。通用Agent框架默认你喂给模型的上下文就是模型需要的上下文,但问数场景中“字段注释写得稀烂”、“同一个指标在两张表里口径不一致”才是常态。你丢一堆表结构给LLM,它生成SQL的时候根本不知道应该引用哪张表、哪个字段,更别说默认过滤条件、权限控制这些隐含约束。

第二个问题是生命周期管理。问数项目跑起来之后,表结构会变、指标口径会调、权限策略会改。如果你把语义层散落在prompt里、把连接串写在代码里、把权限逻辑挂在应用层,后期每一次变更都是一次小规模重构。基础设施搭建要解决的恰恰是这个“变”的问题。

所以我最终选了轻量化自研路线。底层用LangGraph做Agent编排(这个库对流程控制的支持比LangChain更灵活),语义层完全自建,数据层通过统一元数据服务管理。当时还有个备选方案是直接用开源的语义层项目,但评估下来,那些项目大多面向BI工具,对Agent场景的适配度不够,与其改别人的轮子不如自己造一个更贴合需求的窄轮子。

2.2 核心组件清单与选型理由

基础设施层我用到的核心组件如下,每个组件选择的理由我都会备注清楚:

组件选型选型理由
Agent编排框架LangGraph支持有向图编排,能精细控制多轮追问、分支判断、异常恢复,比链式调用更贴近真实问答场景
大模型接入OpenAI兼容接口+本地部署备用生产环境用云API效果最稳,本地模型做降级和敏感数据处理
向量存储Milvus元数据量大、需支持过滤查询和混合检索,Milvus在工程成熟度上更靠谱
关系型元数据库MySQL存语义配置、指标定义、权限策略等结构化数据,够用且团队熟悉
数据源连接层自研轻量连接器 + JDBC/HTTP适配不同数据源类型差异化处理,同时保证连接池和超时控制统一管理
Embedding服务BGE-M3系列中文语义理解效果好、向量维度适中,综合性价比高于OpenAI的Embedding
任务队列Redis + 自研异步任务SQL执行可能很慢,不能让请求一直占着HTTP连接,必须走异步化

这套选型不是一步到位的。第一版我甚至试过用FastAPI直接接LLM,把表结构塞进system prompt里就开干,效果也能看,但每张表字段一多上下文就爆。后来从第二版才开始引入元数据服务和语义层,整个稳定性才上来。选基础设施组件,永远是“先跑通再重构成熟”,但同时要有预判意识,别把路走死。

2.3 关于向量库的执念与反例

在建基础设施的时候我在向量库选择上纠结了很久。第一次搭建用的方案是把所有表结构、字段注释、历史问答对全部塞进向量库,然后靠相似度检索召回——这个思路在demo里表现非常好,演示的时候领导眼睛都亮了。

但一接真实数据就露馅了。我们有个业务库有800多张表、几千个字段,注释质量参差不齐,很多字段名是拼音缩写。向量检索召回的top10看起来“语义相近”,实际完全不是业务想要的“表A.字段B”。后来我调整了思路:向量检索只用来召回“候选集”,真正的精准匹配靠语义层的规则映射和指标字典。两者是个协作关系,不是替代关系。

这个经验直接影响基础设施搭建方案。所以我在设计上把“用于检索的知识”和“用于生成的语义配置”分开存储——向量库里存的是文档碎片和历史问答样本,MySQL里存的是严谨的指标定义和表关系。两条腿走路,比单靠向量库一条腿稳很多。

3. 数据链路与元数据服务搭建

3.1 元数据服务是整个问数Agent的“眼”

如果把问数Agent拟人化,元数据服务就是它的视力。业务人员问“这个月的销售额”,Agent能不能找到正确的表、正确的字段、正确的聚合逻辑,全靠元数据服务供数。

我搭建元数据服务的时候分了三个层次:

  • 数据源元数据:自动采集表结构、字段类型、注释、主外键关系、行数估算。这是最原始的一层,跟业务无关,纯粹描述“数据库里有什么”。
  • 业务元数据:在原始表结构之上,增加业务语义描述。比如“orders表.status字段”,要补充“status=1表示已支付,status=2表示已退款,status=3表示已取消”这类业务含义。
  • 指标层元数据:把常用指标抽象出来,每个指标绑定计算公式和可用维度。比如“销售额=SUM(amount) WHERE status=1”,并且允许按日期、区域、渠道维度拆分。

这三层元数据一层比一层接近业务语言,也正是从“数据库物理结构”到“Agent需要的逻辑模型”的必经之路。

3.2 自动采集还是人工维护:两条腿走路

元数据采集如果全自动,会被脏数据坑哭。生产库里的字段注释经常是空的,或者写了“备注1”“备注2”这种废信息。但如果全人工维护,几百张表能维护到崩溃。

我的方案是自动采集+人工校准结合。自动采集负责把表结构、索引、行数、外键这些物理信息抓全,业务含义部分用规则引擎自动打标,比如字段名包含“amount”“price”“fee”自动标记为金额类,包含“time”“date”“day”自动标记为时间类。初步标记完之后,业务人员只需在管理界面上做二次确认和补充,这能节省大量人力。

还有个细节容易被忽略:元数据采集要支持定时增量更新。因为数据库表结构不是一成不变的,业务迭代会加字段、改注释。我当时做了一个每日凌晨跑一次的同步任务,把结构变更记录到变更日志里,再推送给管理员确认。没有这个机制,后面Agent生成SQL的准确率会随着表结构漂移越来越差。

3.3 连接层该做和不该做的事

连接层负责按需从各个数据源拉取真实数据执行SQL。这里最容易踩的坑是:连接层要不要顺便做SQL校验、做过滤、做权限限制?

我的答案是:不要在连接层做业务限制。连接层只做三件事——获取连接、执行SQL、返回结果集。至于SQL是否安全、是否越权、是否超时,这些应该由上层Agent编排层来决策和拦截。原因很简单:连接层做太多事,会导致不同租户、不同场景的差异化逻辑互相纠缠,后期没法维护。

连接层真正需要做扎实的是连接池治理和超时控制。我们的生产环境同时接了MySQL、ClickHouse和几个HTTP数据API,每种数据源的超时表现完全不一样。MySQL超过30秒的查询就该杀,ClickHouse可以放长到60秒,HTTP接口需要单独配置重试策略。还有一个很关键的点:所有通过Agent生成并执行的SQL,必须强制开启只读事务,禁止任何写操作。这是安全底线,哪怕内部系统也不例外。

4. 语义层构建:让Agent真正“看懂”业务

4.1 语义层不是一个prompt,是一套配置体系

很多问数项目失败在把语义层等同于“写一个详细的system prompt”。Prompt确实能承载一部分语义信息,比如告诉模型“用户说的销售额指SUM(amount)字段”,但这种方式存在两个致命问题。

第一,prompt的长度有限,你不可能把几百个指标定义全部塞进去。第二,不同用户、不同场景对同一个业务词的语义可能是不同的。销售部说“成交额”和财务部说“成交额”可能是两个口径,一个prompt怎么兼顾?

所以我把语义层做成了一套可配置、可路由、可动态加载的体系。底层是MySQL存的指标字典,每个指标记录包含指标名称、口径描述、计算公式、有效期、关联表、默认维度、授权角色等字段。当用户提问时,Agent先通过LLM做意图识别,粗粗判断用户在问哪个主题域,再去加载对应主题域下的指标配置,合并成context再调用生成SQL。

这样做的好处是每个指标配置短小精悍,上下文占用很小;查询时只加载相关指标,既省token又减少干扰。代价是需要花人力梳理指标字典——但这件事一旦做完,后续Agent准确率提升非常明显,属于投入产出比极高的基础设施投资。

4.2 维度与指标的抽象策略

维度是另一个容易失控的地方。同一个“区域”,在不同表里可能叫region、area_code、zone_name,值也可能是“华东”“EAST”“01”这种五花八门的编码。如果语义层不做维度归一化,LLM生成SQL的时候就会随机选一个字段,结果自然对不齐。

我的抽象策略是定义一套逻辑维度和物理字段的映射关系。逻辑维度由业务部门定义,比如“区域”就是一个逻辑维度;物理字段是各个表中与逻辑维度存在映射关系的具体字段。在Agent生成SQL时,优先匹配当前表中有映射的物理字段,匹配不到再寻求人工澄清。

维度归一化建议配合字典表做。比如区域字段的编码对照关系维护一张映射表,Agent生成SQL时会自动关联翻译,把用户说的“华东”翻译成数据库里的区域编码。这个能力非常值得投入,因为维度是问数里最高频的限定条件,也是出错率最高的环节。

4.3 指标冲突检测:一个容易被低估的环节

同时加载多个指标配置时,可能发生冲突。举个例子,用户问“华东区销售额和华北区销售额的差”,系统需要识别出“销售额”指标被用了两次,只是维度值不同。如果语义层不做去重合并,Agent可能会把两个指标当成不同实体,生成出的SQL靠外连接把数据关联起来,结果就是笛卡尔积爆炸。

我的解决方案是在指标配置里记录指标的“身份指纹”,即指标名+聚合方式+金额单位+默认业务时段维度。同一个指纹的指标不管出现几次,都只生成一份SQL片段,然后按不同维度值做条件拆分。这个小设计看起来不起眼,但能避免大量生成SQL时的逻辑紊乱。

指标冲突检测我建议做成单独的服务接口,Agent在组织SQL前先做一次预检查。虽然会增加一次调用链路,但换来的是SQL生成质量的稳定性,这个延迟值得花。

5. 知识库与动态Schema构建

5.1 为什么需要动态Schema而不是静态表结构

普通的数据应用连数据库,通常直接查information_schema或者硬编码表结构。问数Agent做不到这点,因为Agent面对的是一堆“看似能查但不知道上下文”的数据表。直接把所有表结构塞给LLM,上下文窗口会爆炸;只塞部分表结构,又可能缺失关键关联信息。

动态Schema解决的是“按需加载,按场景组装Schema”的问题。具体做法是,在解析完用户问题之后,先做一次路由判断,缩小到可能涉及的主题域和物理表范围,然后只把这些表的Schema加载出来,再结合字段注释、样例值生成“可用的Schema描述”。

我当时为这个环节设计了一个多级路由:先由LLM根据用户问题判断主题域(比如“订单域”“用户域”“商品域”),再通过向量检索在主题域内召回相关表和字段,最后用规则过滤掉敏感字段和无效字段,再交给生成SQL的环节。

这套流程跑通后,生成SQL的准确率提升了一大截。原因并不神秘——LLM在少数高度相关字段里选字段,远比在几百张表的全量字段里瞎猜更靠谱。

5.2 样例值驱动的Schema增强

Schema增强是让生成SQL更准确的一个实用技巧。把字段注释丢给模型,模型只能知道这是“金额”“日期”,但不知道金额字段里存的是“元”还是“万元”,日期字段是“下单时间”还是“支付时间”。

我的做法是在Schema描述中注入样例值。比如Region字段,样例值会显示“华东、华北、华南”;OrderDate字段样例值显示“2024-03-15 14:22:10”。这些样例值不占用太多token,但对消除模型误解有奇效。

抽取样例值需要小心两个点:一是抽取值要覆盖常见场景,不能是极端的脏数据;二是敏感字段不能随便抽样例。比如用户的手机号、身份证号这类字段,要么脱敏后展示,要么直接禁止作为样例。我们当时是在元数据服务里为每个字段配置了“是否可用于样例展示”的标记位,建表时人工确认一遍,从源头挡住敏感信息泄漏。

5.3 上下文压缩:让LLM只看到该看的

另一个实践中很重要的问题是上下文浪费。每次查询都把表结构、指标定义、历史样本全部带上,调用成本高不说,信息过多还会干扰判断。后来我引入了一个上下文压缩层,在真正调用生成SQL的LLM之前,把元数据、语义配置、路由结果、历史相似问答全部整理成一页精炼的指令页。

这个“指令页”包含五块内容:

  • 当前用户在问什么(重写后的标准问句)。
  • 候选物理表的精简Schema(字段名、类型、关键注释、样例值)。
  • 相关指标定义的简述(名称、口径、计算公式)。
  • 统一过滤条件(比如默认只查最近一年、默认排除测试数据)。
  • Few-shot示例(在相似问题中选1-3条历史问答对)。

这个东西直接决定生成SQL的质量。一开始我嫌麻烦没做,结果LLM每次生成SQL都要“猜”用户的隐藏约束,后来花费大量时间在SQL纠错上。把上下文做精之后,这个情况显著改善,我强烈建议你在基础设施阶段就预留这个组件的位子。

6. 权限模型与安全执行设计

6.1 数据权限不能只靠“提示词约束”

问数Agent最危险的地方在于:一旦用户绕过UI直接调API,他就可以让Agent执行任意SQL。如果底层不做强制校验,仅靠提示词里写的“你是一个数据助手,只能查询有权限的数据”,在真实攻击者面前就是一层纸。

我的权限模型设计分三层:应用层权限、数据源层权限和数据粒度权限。

  • 应用层权限决定“谁能用问数功能”,简单说就是登录用户角色判断。
  • 数据源层权限决定“这个用户连哪个数据源”,我们通过数据源标签和用户组映射来控制。
  • 数据粒度权限是最关键的,它控制“用户查询哪些行、哪些列”。比如普通销售只能看自己负责区域的订单数据,不能看全公司数据;某些敏感字段如成本价、毛利,普通员工查询时会被直接脱敏或拒绝返回。

这三层权限的校验,第一层在Controller层做,第二层在连接层做,第三层在生成SQL阶段由Agent结合用户上下文自动注入行级过滤条件。

6.2 强制“只读+行级过滤”的落实方式

强制只读在基础设施层面落实很简单,就是给连接层使用的数据库账号设置只读权限,这是数据库账号层面的事,代码里不用写逻辑。但行级过滤要复杂很多,因为不同用户的数据范围是动态的。

我的方案是在Agent生成SQL之后、执行之前加一个“SQL改写/校验”环节。这个环节会根据当前用户的数据权限范围,自动往SQL上追加WHERE条件。比如用户A的可见区域是“华东区”,那么SQL会被自动加一条region IN ('EAST', 'EAST_CN')的子句。

这里有三个注意事项:

  • 用户权限范围的数据必须从权限服务动态获取,不能缓存太久,权限变动要实时生效。
  • 注入的过滤条件命名要跟数据库实际字段对齐,这个映射关系放在元数据服务里统一维护。
  • 如果SQL里已经包含同字段的过滤条件,要自动合并而不是叠加,否则可能产生逻辑错误甚至查不到数据。

行级过滤如果用得不好,会造成两种后果:一种是不生效,形同虚设;另一种是过滤得过严,把用户本来有权限看的数据也挡掉了。建议在测试阶段多准备几个不同权限角色的账号,逐一验证。

6.3 执行保护机制:超时、限流、结果集截断

数据查询是对生产库的直接访问,必须做好保护。我们在基础设施建设阶段就预置了三道防线:

  • 超时控制:可配置的查询超时时间,默认30秒,超过自动取消。对于大查询,我们做了异步化处理,任务进入队列,执行完成后通过WebSocket推送给前端。
  • 并发控制:同一个用户同时最多只能跑3个查询,防止用户用脚本疯狂刷接口。同时对每个数据源设置了全局并发上限,避免Agent查询把生产库连接池打爆。
  • 结果集截断:SQL返回的结果集行数和列数都做上限控制,默认最大返回500行。超过上限时,Agent会收到提示,并尝试通过聚合方式缩减数据量。

这三道防线不复杂,但一定要在基础设施阶段就做进架构,不能等上线后出事故再补。我见过不止一个团队把Agent直接挂在生产库上跑,结果业务方点一下报表,数据库CPU直接飙到100%。这种事故一旦发生,领导层对AI项目的信任度就会大打折扣。

7. 常见问题与排查技巧实录

7.1 元数据采集到了但Agent仍然“看不懂”表

现象:明明元数据服务里表结构已经采集全了,字段注释也有,但是Agent生成SQL时还是选择了错误的表或字段。

排查思路:先看动态Schema是否真的把正确的表信息加载出来了。很多时候问题出在路由环节——用户问题里的表达方式跟元数据里的主题域标签不匹配,导致该召回的没召回。可以在日志里把“路由结果”“召回表清单”完整打出来,人工确认是路由问题还是生成问题。

另外要重点检查Sample Value是否干净。脏样例值对模型的误导非常严重,比如一个“status”字段,样例值全是“1”“2”“3”,模型根本不知道含义,这时候需要在元数据注释里补充“1=待支付,2=已支付”这类说明。

7.2 SQL生成正确但执行结果与业务认知不符

现象:Agent生成的SQL逻辑上完全正确,表、字段、聚合方式都对,但跑出来的结果跟业务方人工统计的数字对不上。

这类问题十有八九出在口径定义上。比如“销售额”在语义层被定义成了“订单金额总和”,但业务方心里的销售额是不含退款、不含取消订单的。这时候光看SQL发现不了问题,要看指标口径描述是否和业务预期一致。

排查时需要让业务方提供一份“标杆报表”,把Agent查出来的结果和标杆报表逐行对比。一般来说,对不上的原因集中在三个地方:是否过滤了无效状态、是否排除了测试数据、是否处理了跨天/跨月边界。把这几个维度逐一比对,就能定位到口径偏差点。

7.3 查询性能太慢,页面转圈圈

现象:Agent已经生成了SQL,执行也没报错,但查询耗时动辄一两分钟,体验很差。

处理办法分两步。第一,确认慢是否来自SQL本身——看看是否少了必要的时间范围限制、是否做了大表全扫、是否JOIN了过多表。很多情况下,Agent生成的SQL没有带默认时间过滤,我们通过校验阶段自动追加“最近365天”这类默认条件来兜底。第二,如果SQL本身没问题但数据量实在大,就要考虑走数仓或OLAP引擎,不能指望业务MySQL扛得住。

有一个小技巧:在SQL执行前先做一个“预估扫描行数”的检查。MySQL下可以用EXPLAIN估算扫描行数,超过阈值就直接提示用户收窄条件,不要等查询跑了几十秒才反馈“超时”。这个体验细节非常加分。

7.4 多轮对话中的上下文污染

现象:用户先问“华东区的销售额”,然后接着问“那退货率呢?”,Agent需要理解“那”指的是华东区。但如果Agent把上一轮的所有字段、SQL、结果都塞进上下文,很容易生成出跟“退货率”无关的奇怪SQL。

解决思路是在多轮对话管理中引入“槽位记忆”机制,只保留上一轮中的关键约束条件(维度值、时间范围、过滤条件),丢掉其它过程信息。我们把每一轮对话的结构化信息(用户意图、SQL模板、约束条件、指标清单)单独保存一份,下一轮开始时只组装这些结构化数据作为上下文,而不是把上一轮的整段对话文本直接灌给LLM。

8. 实践经验与后续规划

8.1 搭建过程中的几个关键心得

第一个心得:基础设施永远要先于Agent逻辑落地。我踩过最大的坑就是把Agent的业务逻辑(生成SQL、追问澄清)先写完了,回过头再补元数据和语义层,结果业务逻辑里到处是临时写死的表名和字段名,补基础设施时要反推重构,成本极高。正确顺序应该是先把元数据采集、语义配置、权限服务搭好,Agent逻辑只是这些基础设施的“调用方”。

第二个心得:不要把打通demo当作完成基础设施。上一个demo只需跑通一条线,但生产环境要经得起“随便什么业务问题都能问”的考验。基础设施阶段要把异常分支都盖住:查不到数据怎么办、用户输入含敏感词怎么办、业务词存在歧义怎么办、数据源抖动怎么办。这些才是基础设施价值的体现。

第三个心得:多准备几个“验收型问题”。在基础设施搭建完成后,我会准备20个覆盖常见业务场景的验收问题,包括简单查询、维度对比、趋势分析、多表关联、含歧义问题等。每次改完基础设施都拿这批问题回归一遍,能快速暴露各种隐藏问题。

8.2 下一步:Agent编排层和模型调优

基础设施搭建完成之后,下一步就是Agent编排层的开发。到时候会在LangGraph里把“意图识别—语义映射—SQL生成—SQL校验—执行反馈—答案生成”整条链路串起来,同时加入多轮追问和主动澄清能力。

模型调优方面,我计划积累足量的真实问答对数据,做Few-shot样本库和SFT微调数据准备。问数项目这类场景,通用模型虽然能用,但要做到稳定的准确率,还是需要在业务数据上做针对性优化。Few-shot方式启动成本最低,先跑起来收集bad case,再迭代成微调数据。

还有一块后续值得做的是主动数据洞察。当基础设施稳定之后,可以训练Agent从历史查询日志里挖掘高频问题,主动生成数据周报、异常提醒——那是把问数Agent从“被动问答”升级为“主动运营”的方向,也是下一篇文章重点探索的内容。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询