ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

企业级问数智能体架构设计:从AI Agent到Text2SQL落地实践

企业级问数智能体架构设计:从AI Agent到Text2SQL落地实践 做企业级数据平台的都知道最耗人力的往往不是复杂的报表开发而是业务方随时抛过来的临时取数需求。“帮我拉一下华东大区上个月的退货率”“客单价环比下降了拆一下渠道和品类”“双十一大促各时段成交趋势要一份”……需求像流水一样进来数据工程师手里永远排着队业务方还嫌响应慢。我今年在推进的 LCODER 实践体系里第一个落地的实战项目就是这类“问数项目智能体”——用 AI Agent 把自然语言变成 SQL、执行查询、再把结果组织成人话返回。这篇是这个系列的第一篇先不写代码专心把项目架构讲透这个项目到底要解决什么问题、架构应该分成几层、Agent 编排内核怎么设计、数据层怎么打通、以及从架构到落地有哪些容易被低估的坑。如果你正在规划企业级问数助手或者想用 LangGraph、Spring AI 这类框架落地一个真正的 AI Agent 项目这篇应该能给你一张完整的架构地图。1. 问数场景的痛点拆解取数需求为什么积压成山动手设计架构之前我花了很长时间观察整个“取数-用数”的链路。这个环节想清楚了后面所有技术决策都顺理成章。很多人一上来就聊大模型、聊 Text2SQL 准确率但其实问数项目的本质不是“把自然语言翻译成 SQL”而是“把业务人员从漫长的取数链路里解放出来”。1.1 一条普通取数需求的完整生命周期一个典型取数需求在传统流程里的路径大概是这样的业务方提需求通常是用文字描述夹杂着业务术语和默认前提数据工程师收到后先要确认指标口径比如“销售额”到底是按订单支付时间算还是按发货时间算“退货率”分母是什么然后才是写 SQL、查数、核对数据、导出或做成图表最后发给业务方业务方看了之后大概率还会追问“能不能再拆个省份维度”。整个过程少则半天多则两三天其中真正写 SQL 的时间可能只有半小时其余时间全耗在沟通、理解需求、对齐口径上。这个结果就是数据团队永远在救火。每周开需求评审会需求池里永远躺着七八十条待办加急的、催单的、插队的一个接一个。而当你看清楚这个链路之后会发现重复沟通和口径对齐才是最大的成本写 SQL 反而是最容易自动化、也最适合交给模型去做的部分。1.2 为什么直接调大模型 API 远远不够很多人第一反应是直接接一个大模型 API让它根据数据库 Schema 生成 SQL这确实能在演示 Demo 时跑通但距离真正可用差得很远。一个朴素的大模型调用方案有几个硬伤第一模型对业务语言一无所知。业务方说的是“高价值客户”“动销率”“自然流量”但数据库表结构里只有customer_level、sales_qty、channel_source这种字段名模型不知道“高价值”对应哪个枚举值“动销率”应该怎么算。第二数据安全无法保证。模型一旦直连生产库意味着所有表结构、字段名对模型全量暴露这本身就有数据合规风险更别说权限控制、行级数据隔离这类问题。第三没有多轮追问机制。业务方说“看下销售情况”模型并不知道他想要的是哪个时间范围、哪个粒度、哪个指标组合必须有一个追问澄清的过程而这需要对话管理不是一个简单的 API 请求能做到的。第四出错了没人知道。模型生成的 SQL 逻辑上跑通了但统计口径错了或者表 join 错了业务方拿到错误数据还信以为真这种信任透支一次就够了。问数项目之所以必须用 Agent 而不是普通接口拼装核心原因就是它天然是一个需要“理解-规划-执行-校验-兜底”的复杂工作流而这些正是 Agent 的用武之地。1.3 问数项目的目标边界先做什么不做什么架构设计最怕一开始就想做一个“万能数据问答系统”。我给自己定的边界很明确第一版只做“结构化的查询类问题”比如指标查询、趋势对比、维度下钻不做复杂的预测性分析、归因分析也不做图表自动生成图表通过前端渲染不让 Agent 直接产图。支持的数据源先控制在一个主流数仓或 OLAP 引擎上把架构里的数据接入层留好扩展位但第一版不追求“什么都接”。整个系统定位是“业务自助查数的助理”不是“取代数据分析师”。它把查数环节自动化把异常解读、深度分析这些还有难度的部分留给人。想清楚这三点后续的技术选型和架构设计就有了解题约束。这个边界不是不思进取而是让自己聚焦在“问数准确率”和“流程稳定性”这两个核心指标上否则项目很容易做成一个演示很酷、用起来很虚的玩具。2. 问数智能体的四层架构入口、编排、执行、知识问数项目的架构设计我的核心思路是把它拆成四个逻辑层次交互层负责跟人对话编排层负责“思考”和“调度”执行层负责真正操作数据和生成查询知识层负责给 Agent 喂业务上下文。四层各司其职层与层之间通过标准接口通信这样才能让后续的维护和演进变得可控。2.1 交互层入口形态决定体验交互层在架构里看着最不起眼但往往决定了用户愿不愿意用。我把交互层的核心职责定义为理解用户输入、管理多轮上下文、格式化输出。问数场景里最常见的入口有三种Web 对话框、IM 机器人比如飞书、钉钉、以及嵌入式组件比如在 BI 看板里嵌入一个“问一问”输入框。第一版我建议直接从 Web 对话框开始实现成本低调试方便等流程稳定了再往 IM 上搬。交互层要做的事包括把用户问题拼接进系统提示词维护会话历史处理追问澄清的展示以及把最终结果按照“结论摘要 数据表格 可下钻建议”的结构化格式返回。这里有一个容易被忽略的小细节交互层还要负责把用户的原始问题做一个轻量级预处理比如判断是否空话、是否跟数据无关、是否包含明显的敏感词这些在进入 Agent 主流程之前就拦截掉能省不少 token也能避免一些不必要的安全风险。2.2 编排层Agent 的大脑编排层是整个问数项目的核心。它负责做意图识别、任务规划、工具调度、状态流转以及多轮场景下的上下文管理。用一句通俗的话说用户的问题进来之后编排层要回答四件事用户要做什么、需要分几步做、每一步调什么工具、中间出错怎么办。意图识别在这个项目里不一定要用复杂的意图分类模型基于大模型 提示词就能完成大部分工作。关键是提前定义清楚项目支持的意图类型我首版定义了这么几类指标查询型“上个月销售额多少”核心是确定指标、时间范围、维度。对比分析型“华东和华北哪个增长快”核心是确定对比对象和指标。趋势分析型“最近三个月每天的订单量变化”核心是确定时间序列和粒度。下钻明细型“看一下华南区销售额 TOP10 的客户”核心是排序和限定。每一类意图对应不同的 Agent 执行路径。比如指标查询型只需走“解析指标→查数→返回”的链路对比分析型需要额外生成对比模板下钻明细型需要在编排层就把排序、截断的指令规划好。这比让 Agent 每回都从头推理要稳定得多。另外我强烈建议在编排层定义好“任务节点”和“状态机”。比如一个完整的问数任务节点可以设计为问题理解 → 指标解析 → SQL 生成 → 查询校验 → 执行查询 → 结果解读 → 输出。每个节点成功、失败、需要人工介入的状态都要有明确去向这样链路可观测、可 debug否则 Agent 一旦跑偏你真不知道它在哪个环节出的事。2.3 执行层真正干活的手执行层是问数 Agent 跟底层数据交互的地方它把编排层下达的意图翻译成实际的数据操作。常见的执行单元包括Text2SQL 引擎根据自然语言生成 SQL这是问到准确率的关键战场下一节细说。查询执行器连接到数据源执行 SQL处理超时和异常返回结构化查询结果。校验器对生成的 SQL 和返回的数据做合法性和合理性检查比如 SQL 里是否出现了不该出现的DROP、DELETE等危险操作查询结果是否为空、是否明显超出预期。格式化器把原始查询结果按照指标、维度、时间轴组织成适合展示的结构。执行层的设计有一个重要的原则Agent 不应该直接拿到数据的全量访问权。执行器层要做一次“隔离”所有 SQL 都由执行器统一接管执行器里强制加只读开关、超时控制、返回行数上限、敏感表拦截这样才能把 Agent 对大模型生成结果的信任风险控制在一个可接受的范围内。2.4 知识层让 Agent 懂业务的关键知识层是问数项目真正拉开差距的地方。大模型参数里存的是泛化知识它不知道你公司里“事业部”和“产品线”有什么区别也不知道你数据库里的flag字段存的是什么业务含义。知识层的核心价值就是把“数据资产的业务语义”喂给 Agent让它从“会写 SQL”变成“懂业务的会写 SQL”。知识层一般包含三部分内容。第一部分是数据字典和元数据库表结构、字段注释、枚举值含义、主外键关系。第二部分是业务口径和指标定义比如“毛利率”的计算公式、“新客”的定义窗口“自然流量”的判定标准这些是问数准确率最容易翻车的地方后面第 4 节会展开讲。第三部分是常用查询模板和问答样例前人验证过的正确查询可以沉淀成 few-shot 示例模型生成时照着骨骼填肉稳定性会好很多。知识层的存在还让 Agent 的推理路径变得可解释当用户问“高价值客户有多少”时Agent 先到知识层查找“高价值客户”的定义拿到customer_level in (S, A)这个口径再生成 SQL。这一步如果出错你能够清晰地定位到是口径缺失还是语义理解错了而不是甩锅给“模型能力不够”。3. Agent 编排内核单 Agent 与多 Agent 怎么选状态流转怎么设计问数项目里最核心的架构决策就是编排内核怎么设计。这个决策直接决定后续功能的扩展成本和系统的稳定性。做这个决策前我花了不少时间对比 LangGraph 和 Spring AI 这类框架里的 multi-agent 方案最后才敲定现在的技术路线。3.1 三种编排模式的差异对比现在主流的 Agent 编排方式可以归纳成三类单 Agent 全流程、多 Agent 协作、单主控 子 Agent 模式。单 Agent 全流程是最简单的方式一个 Agent 从头到尾接管用户问题内部用工具调用完成各种操作。优点是实现直接、好理解缺点是所有逻辑集中在一大段提示词里一旦业务流程复杂提示词会膨胀得没法维护而且任何环节改逻辑都得改这个 Agent牵一发动全身。多 Agent 协作是社区讨论热度最高的方案几个 Agent 各管一块比如一个管理解、一个管 SQL、一个管解读它们之间通过消息传递协作。优点是职责清晰、扩展性好缺点是调度复杂Agent 之间容易互相踢皮球对话收敛性差工程上调试链路长。如果你的团队刚接触 Agent我不建议一上来就走这条路。单主控 子 Agent 模式是折中一个主控 Agent 作为总调度负责意图识别和任务路由底下挂若干个专门的子 Agent —— 指标解析 Agent、SQL 生成 Agent、数据解读 Agent。子 Agent 各自只干一件事能力边界非常清晰互不越权。3.2 问数项目为什么选“单主控 子 Agent”我最后敲定的是“单主控 子 Agent”模式这么选有一个核心逻辑问数流程虽然环节多但每个环节的职责边界是清晰的天然适合“总控分派”的架构。主控 Agent 更像一个项目经理它不做具体执行的细节只判断当前该把任务交给谁真正干活的子 Agent 只关心自己这一亩三分地。举个例子用户问“上个月华东区退货率环比变化”主控 Agent 先判定这是一个“对比分析型”意图然后路由给指标解析子 Agent解析出指标是“退货率”时间是“上个月”对比基准是“环比”再把解析结果交给 SQL 生成子 Agent让它结合知识层拿到退货率口径生成 SQL调用执行器跑数跑完结果之后数据解读子 Agent 负责把数据组织成结论。每一条链路都是短的、可预期的调试的时候你能非常清楚地知道问题出在哪个子 Agent。这种模式还有一个隐藏优势容错隔离。SQL 生成这个环节是准确率洼地它不稳定的概率最高。把它隔离成一个独立子 Agent 后我可以单独给它配置更强的模型、更精细的 prompt、更严格的校验规则而不影响其他环节。如果某天想升级 Text2SQL 能力只需要替换这一个子 Agent不用动整个编排链路。3.3 图状态机LangGraph 在对话流程里的应用有了“单主控 子 Agent”这个架构理念落地实现时我选择用 LangGraph 来搭建编排层。LangGraph 的核心思想是把 Agent 的决策流程建模成一张有向图每个节点是一个处理单元边是节点之间的状态转移条件。这和问数项目的流程非常契合。实际实现时我问数项目的图结构大致是这样的入口节点接收用户消息并做基础校验然后进入意图路由节点这个节点根据解析结果决定走哪条子链路不同的意图链路各自包含若干子节点比如指标解析、SQL 生成、查询校验所有链路最终汇聚到输出节点统一组织返回结果。LangGraph 天然支持状态管理整个对话过程中的 session、上下文、中间解析结果都放在共享状态里任意节点都能读取和更新这样避免了很多框架里“参数到处传、传着传着丢了”的问题。同时它支持 checkpoint 持久化允许你保存对话中间状态万一某一步出错可以考虑从最近的成功节点恢复而不是整个重来。3.4 工程上的兜底超时、重试与人工接管Agent 架构和普通微服务最大的区别在于Agent 的每次推理都有不确定性所以编排层必须设计一套完整的兜底机制。超时控制是第一道防线。大模型推理本身耗时不定SQL 执行也可能因为数据量大而卡住所以每个环节都要有独立的超时时间。我实践下来的经验是模型单次调用超时给 30-60 秒SQL 执行超时给 15-30 秒整体链路控制在 60-90 秒内必须返回结果超时就触发降级策略比如提示用户“当前请求复杂度过高请缩小时间范围”。重试策略要区分场景。模型调用超时可以重试一次因为可能是瞬时抖动SQL 校验不通过也可以让模型基于报错信息重试一次把数据库返回的错误当工具结果喂回去往往能自愈。但 SQL 执行结果超时就不要无限重试了多半是查询本身太重应该建议用户降粒度。最重要的是人工接管机制。如果 Agent 连续两次生成校验不通过或者检测到用户明显不满意的语气系统要能礼貌地表示“这个问题我需要确认一下口径”并转给人工处理通道。问数项目归根结底是生产力工具宁可让用户偶尔遇到“暂时答不了”也不能让用户拿到错误答案还毫不自知。4. 数据接入和语义层问数准确率的真正命脉架构里的四大层次是骨架但如果把整个问数项目比作一个人数据接入和语义层就是血液。我见过太多团队把全部精力放在 Agent 框架和 prompt 调优上结果上线后发现用户问十句有八句的指标口径对不上问题不在模型而在数据层根本没打通。4.1 单纯靠 Schema 元数据远远不够大模型生成 SQL 需要理解表结构所以很多人第一反应是把数据库的information_schema里的表注释、字段注释一股脑全塞进上下文。但这个做法在真实业务场景里远远不够。真实情况是什么数据库的注释往往是开发人员写的充满技术黑话比如cust_tag_1这种字段注释可能写的是“客户标签一”但业务方根本不知道“标签一”代表什么。更麻烦的是同一个字段在不同团队语义可能完全不一样order_status里的1在 A 业务代表已支付在 B 业务代表已取消。模型拿到的 Schema 越详细反而越容易产生误导性的 SQL。所以我的做法是Schema 元数据只是最低层的基础真正决定准确率的是在这个之上的一层——经过人工审核和关系建模的“语义层”。4.2 指标口径层的设计思路语义层里最重要的是一张“指标口径表”。我会为每个核心业务指标单独建一条记录字段包含指标名称业务叫什么、指标定义口径描述、计算公式怎么算的、依赖字段对应哪张表的哪些字段、默认维度通常按什么维度和时间粒度查询。举例来说“销售额”这个指标的口径应该是“按订单支付完成时间统计的实付金额剔除退款订单含运费不含促销优惠券本身的面额”。当 Agent 拿到“上个月销售额”这个查询时它会先到指标口径表查到“销售额”的定义然后用这个定义去指导 SQL 生成而不是自行理解“销售额”这个词。口径层还需要处理一词多义和同义不同词的问题。比如“销售额”和“GMV”在某些业务上下文里是同一个指标但在另外的上下文里又有区别。我建议在口径表里给指标加上了“同义词”和“所属业务域”两个字段让 Agent 在路由时根据业务域去匹配避免张冠李戴。4.3 多数据源适配与 MCP 的角色问数项目第一版通常只接一个数仓但架构上一定要提前为多数据源留好位。数据源接入层我抽象了一个统一的“查询服务接口”所有数据源的差异都被封装在这个接口之下上层 Agent 完全不需要感知自己查询的是 ClickHouse、StarRocks 还是 MySQL 仓库。这个设计思路和现在社区里讨论度很高的 MCP 协议理念是一致的。MCP 做的事情就是把 Agent 连接外部工具和数据源的协议标准化让 Agent 不用为每个数据源写一套定制化的对接代码而是通过统一的协议去调用。我在问数项目里虽然没有一步到位接 MCP但把查询服务抽象成类似风格的工具接口为后续升级留好了通道。多数据源接入另一个看似细碎但很容易翻车的点SQL 方言差异。同一个连表查询逻辑在 MySQL 和 ClickHouse 里的写法可能完全不同分页、日期函数、类型转换更是各有各的坑。所以我在查询服务接口里增加了“方言适配器”的抽象每种数据源配一个方言模板SQL 生成子 Agent 在生成 SQL 之前先通过路由拿到当前数据源的方言规范再推导 SQL。4.4 数据权限如何嵌进 Agent 链路数据权限是问数项目绕不开的一个问题处理不好就是安全事故。传统报表系统的权限往往通过后端 SQL 动态拼接实现比如“销售只能看自己负责的客户”这层逻辑在 Agent 场景里同样需要但实现方式得想清楚。我的方案是把权限约束加在 SQL 生成阶段而不是查询结果阶段。具体做法是在执行层之前增加一个“权限注入器”它根据当前登录用户、角色、数据权限范围生成一段固定的 SQL 条件片段。比如用户是华东销售总监权限注入器会自动生成and region east and level in (director, manager)这样的限定条件强拼到 Agent 生成的 SQL 里。这个方式的优点是权限模型跟业务对齐不会出现“把数据查出来再在应用层偷偷删掉”这种既浪费资源又容易漏的笨办法。缺点是 SQL 注入需要非常小心拼接位置和逻辑必须经过严密测试所以我在执行层配了一份“白名单表”只有通过了权限模板校验的 SQL 才会真正发到数据库。5. 工程落地清单模块划分、会话记忆、可观测性与演进节奏架构设计得再漂亮最终还是要落到工程代码上。这个章节我把自己在问数项目里实际落地的模块清单和几个工程要点完整过一遍按这个清单一步步来能少走很多弯路。5.1 一个最小可运行的模块清单问数项目虽然听着高大上但第一版的最小可运行模块其实可以拆得很收敛。我建议按下面这个模块清单来切分工程agent-orchestrator编排层核心服务内置 LangGraph 图定义、状态管理、意图路由。agent-sub-executor子 Agent 执行模块这里重点先实现指标解析和 SQL 生成这两个子 Agent。query-executor查询执行服务负责 SQL 下发、超时控制、结果缓存。security-filter权限注入和 SQL 安全校验服务。semantic-server语义层服务管理指标口径、数据字典、查询模板对外提供口径查询 API。session-store会话和记忆存储。web-frontend对话界面和结果展示前端。如果你用 Java 技术栈上面每个模块都可以对应一个 Spring Boot 服务服务间用轻量级 RPC 或 HTTP 调用打通如果你更习惯 Python可以在一个进程内模块化拆分用 FastAPI 暴露接口。我的建议是第一版不要搞微服务用模块化单体的方式把上面这些逻辑边界物理隔离好等业务量大到需要独立部署了再拆也不迟。5.2 会话记忆与追问状态怎么保存问数项目是个多轮对话系统会话管理做得不好用户体验会非常割裂。“上个月销售额多少”“上个季度呢”——这种省略主语的问题没有会话记忆的加持Agent 根本答不了。我把会话记忆分成了两层。第一层是短时上下文存当前会话最近 N 轮的对话记录、已经解析出的指标、时间范围、维度等关键信息用于回答省略式追问。第二层是长期偏好存用户的常用指标偏好、常用数据源、默认时间粒度等。这层不是必须的但做了之后很多高频问题可以免去重复澄清。会话存储我用了 Rediskey 是 session_idvalue 是上下文结构体。LangGraph 的 checkpoint 也支持持久化到 Redis这正好把图执行状态和会话上下文统一管理起来。有一点必须提醒会话信息里可能含有业务敏感数据存入 Redis 前要对其中涉及具体业务数据的部分做脱敏处理不要整段对话原样落库。5.3 链路追踪与效果评估体系Agent 的可观测性问题比传统服务难得多因为 AI 环节的“黑盒”属性很强。如果用户反馈答案不对你得能回溯出“问题是没理解清楚、口径解析错了、SQL 写错了、还是数据本身的问题”。我的做法是对问数全链路强制打结构化日志。每个子 Agent 执行完都会生成一个 trace 记录内容包括输入消息、输出结果、消耗 token 数、耗时、命中的指标口径版本、生成的 SQL脱敏后、查询结果的行数和校验状态。这些信息统一汇入日志平台并提供按 session 维度一键查看链路的能力。效果评估体系要建两级。第一级是自动化离线评测准备一批已经标注了正确 SQL 和正确答案的测试问句每次修改 Agent 代码后跑一遍回归看准确率变化。没有这级评测你迭代 prompt 就是在盲人摸象。第二级是线上反馈在对话界面做一个“答案是否有帮助”的反馈按钮用户反馈数据回流之后定期人工复盘找出问题集中在哪个环节定向去优化。5.4 架构的演进节奏先跑通链路再优化准确率最后再说说演进节奏。问数项目的架构设计要留扩展位但落地节奏一定要克制。我踩过最大的坑就是一开始想把所有设计一步到位结果项目拖了两个月还没上线。后来我换了一种推进节奏效果好了很多。第一个里程碑先实现“单指标单维度查询”用户明确说出指标、时间范围、维度Agent 能返回正确数据就算赢。第二个里程碑加上“对比和趋势”类意图以及多轮追问澄清。第三个里程碑再去做复杂口径处理、多数据源接入、知识层的自动化沉淀。每个里程碑结束都主动拉业务方做一次“真实问题盲测”让业务方直接问他们平时真正关心的问题不要用自己预先想好的测试集。这个环节极其残酷但也是收获最大的因为你会第一次意识到“模型觉得回答得很好”和“业务觉得答得对”之间差距有多大。我个人的感受是问数项目的架构真正重要的是把 Agent 的能力边界画清楚把数据语义层做扎实把编排状态机设计得可观测、可控制。模型的能力迭代很快但工程架构的稳定性和业务口径的准确性才是这类项目能不能长期跑下去的根本。这也是 LCODER 系列里我一直坚持的准则——先让工程结构立得住再让模型智能走得远。后面几篇我会继续拆指标解析子 Agent 的具体实现、Text2SQL 的优化实战和 LangGraph 状态流的代码细节到时候再聊。
返回列表