RAG处理Eecel表格的正确姿势

别再把Excel硬塞进向量库了!这才是RAG处理表格的正确姿势

做RAG的开发者们,你们是不是也遇到过这样的情况:PDF和Word文件处理得好好的,一遇到Excel就翻车?明明按照标准流程解析、切块、向量化、入库,但Agent回答出来的结果总是错漏百出,不是数据对不上,就是统计结果完全不对。

今天我要告诉大家一个扎心的事实:你做RAG最容易踩坑的文件,不是PDF,也不是Word,而是Excel。很多人一看到Excel就直接走老套路,听起来像是完成了RAG,实际上只是把表格拍扁了而已。

为什么直接把Excel扔进向量库会翻车?

很多开发者习惯了处理文本文件的思维,认为只要把Excel转成文本,然后切成块,就万事大吉了。但这种做法在处理Excel时会暴露出三个致命问题:

  1. 只能检索到相关行,无法获取全局信息
    当用户问"哪个产品销售额最高"时,Agent可能只找回几行看起来相关的数据,而不会去遍历整个表格找到真正的最大值。
  2. 没有全局计算能力
    最高、最低、总数、增长率这些问题,需要对全表进行筛选和统计,而不是简单的语义相似匹配。向量库天生擅长"找相关",但不擅长"算正确"。
  3. 结果只能靠猜
    当用户问"3月华东区为什么下降"时,Agent可能检索到了"3月"、"华东区"、"下降"这些关键词,但并不代表它真正算出了下降幅度,更无法准确关联到对应的原因说明。

核心原则:Excel不能原样进向量库

那么Excel到底该不该进向量库?答案不是不能进,而是不能原样进

我们需要把Excel中的信息明确分为两类,区别对待:

  • 语义信息:适合进向量库,用于找解释、找口径、找备注。
  • 结构化数据:适合进DataFrame或数据库(如SQL DB),用于筛选、统计、排序、计算。

关键不是"能不能进",而是"怎么进"。如果不加区分地把所有内容都塞进向量库,Agent就只能靠猜来回答问题。

Excel的本质:信息在结构里

很多人没有意识到,Excel不是普通文本,它的信息在结构里。如果粗暴地把Excel转成纯文本,我们丢掉的不只是格式,还有大量至关重要的结构信息:

  • 行列关系
  • sheet名称
  • 合计行
  • 合并单元格
  • 表头、单位、公式、备注说明

举一个典型的误判例子:如果表格上方有一个大标题"华东区",下面是表头"销售额"。人能看懂这是"华东区销售额",但简单的文本解析会丢掉上下文,只剩"销售额"三个字。这样一来,Agent就分不清这个销售额到底是华东的、华南的,还是全国的汇总。

正确处理Excel的四步流程

既然知道了问题所在,那我们应该如何正确处理Excel文件呢?下面是经过验证的四步标准流程:

第一步:先解析Excel,而不是直接切chunk

一个Excel文件里经常不止一张表。我们首先要做的就是核心判断:这个sheet里的内容是说明型还是数据型?

  • 说明型内容 → 进入向量库
  • 数据型内容 → 进入数据库或DataFrame

💻 代码辅助理解:分类读取 Sheet

python 复制代码
import pandas as pd

# 读取 Excel 中的所有 Sheet
excel_file = pd.ExcelFile("sales_report.xlsx")

for sheet_name in excel_file.sheet_names:
    df = excel_file.parse(sheet_name)
    
    # 简单启发式:如果包含大量文本或列数很少,可能是说明型
    if df.shape[1] < 3 or df.astype(str).apply(lambda x: x.str.len().mean()).mean() > 50:
        print(f"Sheet '{sheet_name}' 可能是说明型 -> 存入向量库")
        # process_for_vector_db(df)
    else:
        print(f"Sheet '{sheet_name}' 可能是数据型 -> 存入 SQL 或保留 DataFrame")
        # process_for_sql_db(df)

第二步:识别表格区域,先找对表头和数据边界

业务用的Excel往往不是标准的数据库表,前几行可能根本不是数据,而是大标题或统计周期。所以我们必须分清楚边界:

  1. 哪几行是说明?哪一行是表头?
  2. 从哪一行开始才是数据?

💻 代码辅助理解:跳过非数据行,精准定位表头

python 复制代码
# 假设前 3 行是标题和部门名称,第 4 行才是真正的表头
# skiprows=3 会跳过前 3 行,将第 4 行作为列名 (Header)
df_data = pd.read_excel("sales_report.xlsx", sheet_name="明细数据", skiprows=3)

# 清理底部的"合计行"或空行
df_data = df_data.dropna(subset=['核心字段']) # 过滤空数据
df_data = df_data[~df_data['核心字段'].str.contains('合计', na=False)]

print("清洗后的干净数据:\n", df_data.head())

第三步:向量块要带上上下文,不是拼单元格

很多人处理Excel的语义信息时,只是简单地把单元格内容拼接起来,这样生成的向量块是没有价值的。

不要这样写

  • "销售额:支付金额。"
  • "3月异常。"

应该这样写

  • "在《2025年华东区销售明细》这个sheet中,字段'销售额'表示用户实际支付金额,单位为元,不包含退款金额。"
  • "在《区域销售月报》中,3月份华东区销售额下降,备注说明主要原因是核心产品A缺货,导致订单转化下降。"

💻 代码辅助理解:构建带上下文的语义块

python 复制代码
def build_contextual_chunk(sheet_name, field_name, description, unit):
    return f"在《{sheet_name}》这个sheet中,字段'{field_name}'表示{description},单位为{unit}。"

# 示例:生成高质量的语义块
chunk = build_contextual_chunk("2025年华东区销售明细", "销售额", "用户实际支付金额,不包含退款金额", "元")
print(chunk)
# 输出: 在《2025年华东区销售明细》这个sheet中,字段'销售额'表示用户实际支付金额,不包含退款金额,单位为元。

第四步:给每个向量块加 metadata

除了文本内容本身,我们还需要给每个向量块添加丰富的元数据(metadata),至少应该包含:

  • 文件名、sheet名、表格名称
  • 行列范围、字段名、数据类型、时间范围

需要明确的是,真正进入向量库的不是整张表,而是字段说明、业务规则、异常说明、表格摘要和少量代表性样例。千万不要把十万行订单全部切成chunk塞进向量库。

最终架构:提问时 Agent 先做问题路由

有了前面的准备工作,我们就可以构建真正可用的Excel RAG架构了。核心在于提问时Agent先做问题路由

text 复制代码
用户问题 → 问题路由 → 向量库 (找解释)
                 ↘ 表格计算/SQL (算数据)
                   ↘ 合并回答

具体来说:

  • 问"销售额字段是什么意思?" → 走向量库
  • 问"哪个产品销售额最高?" → 走表格计算
  • 问"3月华东区为什么下降?" → 先算下降幅度,再查备注原因

💻 代码辅助理解:Agent 路由逻辑伪代码

python 复制代码
def agent_router(user_question):
    # 1. 意图识别 (可以使用 LLM 来判断意图)
    intent = llm_classify_intent(user_question) 
    
    if intent == "explain_concept":
        # 语义解释,查向量库
        context = vector_db.similarity_search(user_question)
        return llm_generate_answer(user_question, context)
        
    elif intent == "data_calculation":
        # 数据计算,Text2SQL 或 Pandas Agent
        sql_query = text_to_sql(user_question)
        result = execute_sql(sql_query)
        return f"计算结果为:{result}"
        
    elif intent == "hybrid_analysis":
        # 混合分析:先计算,再找原因
        calc_result = execute_sql(text_to_sql(user_question))
        context = vector_db.similarity_search(f"{user_question} 的原因")
        return llm_generate_hybrid_answer(calc_result, context)

真正可用的Excel RAG = 语义检索 + 结构化计算 + Agent路由。向量库不负责全表扫描,那是数据库的工作。

核心总结:Excel不是文档,是数据资产

最后,让我们用五点来总结今天的内容:

  1. 该进向量库的是解释性信息:字段说明、口径、备注、异常原因。
  2. 该进数据库的是明细数据:金额、日期、地区、产品、订单流水。
  3. 该交给Agent的是:判断这次问题到底查说明还是算结果。
  4. 遇到"为什么下降"这类问题:要先算清楚,再去寻找原因说明。
  5. 不要整表硬塞:要保留结构、上下文和metadata。

没有拆分,RAG就会猜;拆对结构,Agent才能稳定回答。

最后记住一句话:Excel不是一篇文档,它是一个数据资产。用处理文档的思维去处理数据资产,注定会翻车。