AI数据助手:从文档问答到智能数据分析

AI数据助手:从文档问答到智能数据分析

前面 9 篇我们把 RAG 问答系统从零搭到了生产级。但一个真正的"AI 数据助手",不能只会翻文档回答问题。它应该能帮你做数据分析、生成报表、甚至从一堆数据里挖出你不知道的信息。

今天这篇,我们把 RAG 从"问答机器人"升级到"数据助手"。

大家好,我是黒漂技术佬。


一、RAG 只能做问答?格局小了

先对齐认知:当前大火的 AI 数据助手,本质上是在 RAG 基础之上叠加了新的能力:

复制代码
传统 RAG(文档问答):
  用户问 → 搜文档 → LLM 生成答案 → 返回文字

AI 数据助手(增强版):
  用户问 → 理解意图 → 
    ├── 搜文档(RAG)
    ├── 查数据库(Text-to-SQL)
    ├── 调API(Function Calling / Tool Use)
    └── 汇总分析 → 生成结构化答案 + 图表

举个真实的场景:

复制代码
用户:"上个月技术部的加班情况怎么样?"

传统 RAG 回答:从《考勤制度》里搜出加班规则(毫无意义)

AI 数据助手回答:
  1. 通过 Text-to-SQL 查数据库 → 技术部30人,上月人均加班12.3小时
  2. 通过 RAG 查找相关制度 → 加班费计算标准
  3. 综合生成 → "技术部30人中,近两周加班总时长368小时,
     其中王工累计42小时最高。按公司制度,加班费预计...(附图表)"

看出区别了吗?数据助手不只是"复读文档",而是能"理解数据、分析数据、呈现结论"。


二、核心技术一:Text-to-SQL ------ 让 AI 帮你查数据库

这是数据助手的第一个杀手级能力:用户用大白话问,AI 自动生成 SQL 去数据库查结果。

实现原理

python 复制代码
def text_to_sql(user_question: str, db_schema: str) -> dict:
    """将自然语言问题转为 SQL 并执行"""
    
    prompt = f"""
你是一个 SQL 专家。请根据用户问题,生成对应数据库查询 SQL。

【数据库 Schema】
{db_schema}

【注意事项】
1. 只生成 SELECT 语句,不要 INSERT/UPDATE/DELETE
2. 查询必须加 LIMIT 限制,防止返回海量数据
3. 涉及时间的查询注意时区
4. 表名和字段名用反引号包裹

【用户问题】
{user_question}

请生成 SQL:
"""
    
    sql = llm.invoke(prompt)
    
    # ⚠️ 安全检查:只允许 SELECT
    if not sql.strip().upper().startswith("SELECT"):
        return {"error": "只允许查询操作"}
    
    # ⚠️ 安全检查:禁止危险关键词
    dangerous = ["DROP", "ALTER", "TRUNCATE", "EXEC", "--", ";--"]
    for keyword in dangerous:
        if keyword in sql.upper():
            return {"error": f"SQL 包含禁止的关键词: {keyword}"}
    
    # 执行查询
    try:
        result = db.execute(sql, timeout=10)  # 超时控制
        return {"sql": sql, "data": result}
    except Exception as e:
        return {"error": str(e), "sql": sql}

为什么还需要 Schema 描述?

LLM 不知道你数据库里有什么表、什么字段。Schema 描述就是告诉它:

sql 复制代码
【表:attendance(考勤记录)】
- employee_id: INT, 员工ID
- date: DATE, 日期
- overtime_hours: FLOAT, 加班时长(小时)
- department: VARCHAR, 部门

【表:employees(员工信息)】
- id: INT, 员工ID
- name: VARCHAR, 姓名
- department: VARCHAR, 部门
- hire_date: DATE, 入职日期

有了 Schema,LLM 就能把"技术部"映射到 WHERE department = '技术部'

Text-to-SQL 的两个关键优化

优化 1:Few-shot 示例

给 Prompt 加几个示例,能显著提升 SQL 准确率:

python 复制代码
examples = """
示例1:
用户:技术部有多少人?
SQL:SELECT COUNT(*) FROM employees WHERE department = '技术部'

示例2:
用户:上个月加班最多的是谁?
SQL:SELECT 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
"""

优化 2:SQL 纠错重试

LLM 生成的 SQL 可能语法错误(字段名写错、JOIN 条件漏了)。加一个纠错循环:

python 复制代码
max_retries = 3
for attempt in range(max_retries):
    sql = llm.invoke(prompt)
    try:
        result = db.execute(sql)
        return result
    except Exception as e:
        prompt += f"\n上一版 SQL 报错:{e}\n请修正后重新生成 SQL:"

三、核心技术二:结构化输出 ------ 不只是聊天

传统 RAG 返回一段文本就完了。但数据助手常常需要返回结构化数据(表格、图表数据、JSON)。

让 LLM 输出 JSON

python 复制代码
from langchain_core.output_parsers import JsonOutputParser
from pydantic import BaseModel

class OvertimeReport(BaseModel):
    department: str
    total_employees: int
    total_overtime_hours: float
    avg_overtime_per_person: float
    top_overtime_person: str
    top_overtime_hours: float
    trend: str  # "上升" / "下降" / "持平"

parser = JsonOutputParser(pydantic_object=OvertimeReport)

prompt = ChatPromptTemplate.from_template("""
根据以下数据,生成加班分析报告。

{data}

{format_instructions}
""")

chain = prompt | llm | parser

# 调用后得到的是 Python dict,可以直接渲染前端图表
report = chain.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 下载链接)

这需要上下文记忆

python 复制代码
from langchain.memory import ConversationBufferWindowMemory

# 只保留最近 5 轮对话的历史,防止上下文过长
memory = ConversationBufferWindowMemory(k=5, return_messages=True)

def chat_with_memory(user_input: str, user_id: str):
    # 1. 获取历史消息
    history = memory.load_memory_variables({})["history"]
    
    # 2. 如果用户用了代词(他/她/它/这个/那个),用 LLM 做指代消解
    if has_pronouns(user_input):
        user_input = resolve_pronouns(user_input, history)
        # "他的数据" → "王工的数据"
    
    # 3. 正常的 RAG + Text-to-SQL 流程
    answer = pipeline(user_input)
    
    # 4. 保存本轮对话到记忆
    memory.save_context({"input": user_input}, {"output": answer})
    
    return answer

五、AI 数据助手的完整技术架构

把文档问答 + 数据库查询 + 对话记忆串起来,就是一个完整的 AI 数据助手:

复制代码
用户输入
  │
  ▼
┌─────────────────────┐
│ 意图识别(Router)    │ ← 判断用户想干什么
└──────┬──────────────┘
       │
   ┌───┼───────────┐
   │   │           │
   ▼   ▼           ▼
 查文档  查数据库   执行操作
(RAG)  (Text2SQL)  (Tool Call)
   │   │           │
   │   │    ┌──────┘
   ▼   ▼    ▼
┌──────────────┐
│ 结果聚合+分析  │ ← LLM综合所有结果
└──────┬───────┘
       ▼
┌──────────────┐
│ 结构化输出    │ ← JSON + 图表 + 下载链接
└──────────────┘

意图识别(Router)

用一个轻量的分类 Prompt 判断用户意图:

python 复制代码
def classify_intent(question: str) -> str:
    """识别用户意图"""
    prompt = f"""
判断用户意图,只输出一个词:

- "document":查文档、制度、流程
- "data":查数据、统计、分析
- "action":执行操作(导出、发送、下载)

用户:{question}
意图:
"""
    return llm.invoke(prompt).strip()

然后根据意图走不同的处理链路。


💬 你的 AI 数据助手最想解决公司里的什么数据分析问题?是想查日报、看报表、还是做预测?评论区聊聊!

相关推荐
YangYang9YangYan1 小时前
2026大数据专业填报志愿学数据分析的价值
大数据·数据挖掘·数据分析
搬砖柯1 小时前
系列11-测试平台 MCP Server 实践:用 Kimi Code 自然语言查项目、跑 API 回归
人工智能·python·ai·开源·自动化
米小虾1 小时前
2026年7月AI圈大地震:GPT-5.6被政府限制、Claude入驻Slack、Anthropic自研芯片
人工智能·chatgpt·claude
城事漫游Molly1 小时前
文献综述不是“读书笔记堆砌“——三种文献整合策略详解
人工智能·论文写作·ai for science·文献综述·博士生必读
中微极客1 小时前
LangChain 0.3实战:企业级RAG与多Agent架构解析
人工智能·langchain·新人首发
人工智能AI技术2 小时前
抛弃PaddleOCR!RapidOCR速度碾压,本地离线秒识别
人工智能
MartinYeung52 小时前
[论文学习]BackdoorLLM:大语言模型后门攻击与防御的综合性基准——深度解析
人工智能·学习·语言模型
陈天伟教授2 小时前
SolidWorks快速入门
人工智能·工业设计
IVVi0jToe2 小时前
2026年是“多智能体元年”——从单Agent到Agent军团
人工智能
2zcode2 小时前
基于MATLAB图像处理的苹果质量智能分级系统设计与实现
图像处理·人工智能·matlab