AI数据助手从文档问答到智能数据分析前面 9 篇我们把 RAG 问答系统从零搭到了生产级。但一个真正的AI 数据助手不能只会翻文档回答问题。它应该能帮你做数据分析、生成报表、甚至从一堆数据里挖出你不知道的信息。今天这篇我们把 RAG 从问答机器人升级到数据助手。大家好我是黒漂技术佬。一、RAG 只能做问答格局小了先对齐认知当前大火的 AI 数据助手本质上是在 RAG 基础之上叠加了新的能力传统 RAG文档问答 用户问 → 搜文档 → LLM 生成答案 → 返回文字 AI 数据助手增强版 用户问 → 理解意图 → ├── 搜文档RAG ├── 查数据库Text-to-SQL ├── 调APIFunction Calling / Tool Use └── 汇总分析 → 生成结构化答案 图表举个真实的场景用户上个月技术部的加班情况怎么样 传统 RAG 回答从《考勤制度》里搜出加班规则毫无意义 AI 数据助手回答 1. 通过 Text-to-SQL 查数据库 → 技术部30人上月人均加班12.3小时 2. 通过 RAG 查找相关制度 → 加班费计算标准 3. 综合生成 → 技术部30人中近两周加班总时长368小时 其中王工累计42小时最高。按公司制度加班费预计…附图表看出区别了吗数据助手不只是复读文档而是能理解数据、分析数据、呈现结论。二、核心技术一Text-to-SQL —— 让 AI 帮你查数据库这是数据助手的第一个杀手级能力用户用大白话问AI 自动生成 SQL 去数据库查结果。实现原理deftext_to_sql(user_question:str,db_schema:str)-dict:将自然语言问题转为 SQL 并执行promptf 你是一个 SQL 专家。请根据用户问题生成对应数据库查询 SQL。 【数据库 Schema】{db_schema}【注意事项】 1. 只生成 SELECT 语句不要 INSERT/UPDATE/DELETE 2. 查询必须加 LIMIT 限制防止返回海量数据 3. 涉及时间的查询注意时区 4. 表名和字段名用反引号包裹 【用户问题】{user_question}请生成 SQL sqlllm.invoke(prompt)# ⚠️ 安全检查只允许 SELECTifnotsql.strip().upper().startswith(SELECT):return{error:只允许查询操作}# ⚠️ 安全检查禁止危险关键词dangerous[DROP,ALTER,TRUNCATE,EXEC,--,;--]forkeywordindangerous:ifkeywordinsql.upper():return{error:fSQL 包含禁止的关键词:{keyword}}# 执行查询try:resultdb.execute(sql,timeout10)# 超时控制return{sql:sql,data:result}exceptExceptionase:return{error:str(e),sql:sql}为什么还需要 Schema 描述LLM 不知道你数据库里有什么表、什么字段。Schema 描述就是告诉它【表attendance考勤记录】-employee_id:INT,员工ID-date:DATE,日期-overtime_hours:FLOAT,加班时长小时-department:VARCHAR,部门 【表employees员工信息】-id:INT,员工ID-name:VARCHAR,姓名-department:VARCHAR,部门-hire_date:DATE,入职日期有了 SchemaLLM 就能把技术部映射到WHERE department 技术部。Text-to-SQL 的两个关键优化优化 1Few-shot 示例给 Prompt 加几个示例能显著提升 SQL 准确率examples 示例1 用户技术部有多少人 SQLSELECT COUNT(*) FROM employees WHERE department 技术部 示例2 用户上个月加班最多的是谁 SQLSELECT e.name, SUM(a.overtime_hours) as total_ot FROM attendance a JOIN employees e ON a.employee_id e.id WHERE a.date 2024-05-01 AND a.date 2024-06-01 GROUP BY e.name ORDER BY total_ot DESC LIMIT 5 优化 2SQL 纠错重试LLM 生成的 SQL 可能语法错误字段名写错、JOIN 条件漏了。加一个纠错循环max_retries3forattemptinrange(max_retries):sqlllm.invoke(prompt)try:resultdb.execute(sql)returnresultexceptExceptionase:promptf\n上一版 SQL 报错{e}\n请修正后重新生成 SQL三、核心技术二结构化输出 —— 不只是聊天传统 RAG 返回一段文本就完了。但数据助手常常需要返回结构化数据表格、图表数据、JSON。让 LLM 输出 JSONfromlangchain_core.output_parsersimportJsonOutputParserfrompydanticimportBaseModelclassOvertimeReport(BaseModel):department:strtotal_employees:inttotal_overtime_hours:floatavg_overtime_per_person:floattop_overtime_person:strtop_overtime_hours:floattrend:str# 上升 / 下降 / 持平parserJsonOutputParser(pydantic_objectOvertimeReport)promptChatPromptTemplate.from_template( 根据以下数据生成加班分析报告。 {data} {format_instructions} )chainprompt|llm|parser# 调用后得到的是 Python dict可以直接渲染前端图表reportchain.invoke({data:sql_result,format_instructions:parser.get_format_instructions()})# report {# department: 技术部,# total_employees: 30,# total_overtime_hours: 368.5,# avg_overtime_per_person: 12.28,# ...# }有了结构化输出前端就能直接渲染折线图、柱状图、饼图——而不只是展示一段文字。四、核心技术三多轮对话 上下文记忆数据助手不是一问一答就结束的工具。用户经常会在对话中逐步细化问题用户技术部加班情况 AI返回加班总览表 用户王工的呢 ← 王工是从上文继承的上下文 AI返回王工个人的加班明细 用户帮我把他的数据导出成 Excel ← 他指的也是王工 AI生成 Excel 下载链接这需要上下文记忆fromlangchain.memoryimportConversationBufferWindowMemory# 只保留最近 5 轮对话的历史防止上下文过长memoryConversationBufferWindowMemory(k5,return_messagesTrue)defchat_with_memory(user_input:str,user_id:str):# 1. 获取历史消息historymemory.load_memory_variables({})[history]# 2. 如果用户用了代词他/她/它/这个/那个用 LLM 做指代消解ifhas_pronouns(user_input):user_inputresolve_pronouns(user_input,history)# 他的数据 → 王工的数据# 3. 正常的 RAG Text-to-SQL 流程answerpipeline(user_input)# 4. 保存本轮对话到记忆memory.save_context({input:user_input},{output:answer})returnanswer五、AI 数据助手的完整技术架构把文档问答 数据库查询 对话记忆串起来就是一个完整的 AI 数据助手用户输入 │ ▼ ┌─────────────────────┐ │ 意图识别Router │ ← 判断用户想干什么 └──────┬──────────────┘ │ ┌───┼───────────┐ │ │ │ ▼ ▼ ▼ 查文档 查数据库 执行操作 (RAG) (Text2SQL) (Tool Call) │ │ │ │ │ ┌──────┘ ▼ ▼ ▼ ┌──────────────┐ │ 结果聚合分析 │ ← LLM综合所有结果 └──────┬───────┘ ▼ ┌──────────────┐ │ 结构化输出 │ ← JSON 图表 下载链接 └──────────────┘意图识别Router用一个轻量的分类 Prompt 判断用户意图defclassify_intent(question:str)-str:识别用户意图promptf 判断用户意图只输出一个词 - document查文档、制度、流程 - data查数据、统计、分析 - action执行操作导出、发送、下载 用户{question}意图 returnllm.invoke(prompt).strip()然后根据意图走不同的处理链路。 你的 AI 数据助手最想解决公司里的什么数据分析问题是想查日报、看报表、还是做预测评论区聊聊