Excel知识库与LLM结合的解决方案详细分析

Excel知识库与LLM结合的解决方案详细分析

在数据分析和智能问答系统的构建过程中,如何有效地结合结构化数据(如Excel表格)与非结构化数据(如文本文档)成为一个关键挑战。近期接触到的pandas+pandasql解决方案为此提供了一种优雅的处理方式,下面我将对这一方案进行深入分析和详细说明。

一、知识库构建的详细设计

1. Excel元数据构建

知识库中关于Excel的元数据需要包含以下详细信息:

json 复制代码
{
  "excel_files": [
    {
      "file_path": "/path/to/sales_data.xlsx",
      "description": "销售数据统计表,包含2020-2024年各季度销售情况",
      "sheets": [
        {
          "sheet_name": "2023销售数据",
          "description": "2023年各产品线销售数据",
          "columns": [
            {
              "column_name": "日期",
              "description": "销售记录日期,格式为YYYY-MM-DD",
              "data_type": "datetime",
              "sample_values": ["2023-01-15", "2023-02-28"]
            },
            {
              "column_name": "产品ID",
              "description": "产品唯一标识符",
              "data_type": "string",
              "sample_values": ["P001", "P002"]
            },
            {
              "column_name": "销售额",
              "description": "单次销售金额,单位为元",
              "data_type": "float",
              "sample_values": [1500.00, 2400.50]
            },
            {
              "column_name": "销售区域",
              "description": "销售发生的地理区域",
              "data_type": "string",
              "sample_values": ["华东", "华北", "华南"]
            }
          ],
          "relationships": [
            {
              "description": "可通过产品ID关联产品信息表"
            }
          ]
        }
      ]
    }
  ]
}

2. 向量化存储设计

为提高检索效率,可将Excel元数据转化为向量并存储在向量数据库中:

  • 使用sentence-transformer模型将每个sheet的描述、列名及其描述转化为向量
  • 为不同粒度的信息(文件级、sheet级、列级)分别建立索引
  • 在存储向量的同时保留原始JSON结构以便检索后使用

二、查询处理流程详解

1. 用户问题解析

当用户提出问题如"2023年第一季度华东地区销售额最高的产品是什么?"时,系统进行以下处理:

python 复制代码
# 伪代码示例
def process_user_query(query):
    # 1. 问题理解与意图分类
    query_embedding = embedding_model.encode(query)
    
    # 2. 分别查询两个知识分支
    excel_info = query_excel_metadata(query_embedding)
    text_info = query_text_knowledge(query_embedding)
    
    # 3. 路由决策
    if excel_info['relevance_score'] > THRESHOLD:
        # 需要查询Excel数据
        sql_query = generate_sql_query(query, excel_info)
        excel_result = execute_sql_query(sql_query, excel_info)
        
    # 4. 结果综合
    final_answer = generate_combined_answer(query, excel_result, text_info)
    
    return final_answer

2. Excel元数据检索细节

检索相关Excel文件的过程包含以下步骤:

  1. 使用向量相似度搜索找出与问题最相关的Excel文件及sheet
  2. 提取相关度分数超过阈值的候选项
  3. 构建包含完整元信息的上下文,供LLM使用
python 复制代码
def query_excel_metadata(query_embedding):
    # 使用向量检索找出最相关的Excel元数据
    results = vector_db.search(
        collection_name="excel_metadata",
        query_vector=query_embedding,
        top_k=3
    )
    
    # 提取并整合相关元数据
    relevant_metadata = []
    for item in results:
        if item.score > 0.75:  # 相关度阈值
            metadata = item.metadata
            relevant_metadata.append({
                "file_path": metadata["file_path"],
                "sheet_name": metadata["sheet_name"],
                "columns": metadata["columns"],
                "description": metadata["description"],
                "relevance_score": item.score
            })
    
    return {
        "relevant_items": relevant_metadata,
        "relevance_score": max([item.score for item in results]) if results else 0
    }

3. SQL生成的精确实现

LLM生成SQL的过程需要特别注意以下细节:

python 复制代码
def generate_sql_query(query, excel_info):
    # 构建提示模板
    prompt = f"""
    基于用户问题:"{query}"
    
    可用的Excel表格信息如下:
    文件路径:{excel_info['relevant_items'][0]['file_path']}
    表格名称:{excel_info['relevant_items'][0]['sheet_name']}
    表格描述:{excel_info['relevant_items'][0]['description']}
    
    可用列信息:
    {format_columns_info(excel_info['relevant_items'][0]['columns'])}
    
    请生成一个SQL查询语句,使用pandasql语法,查询表名应使用sheet名称。
    仅返回SQL语句,不要包含任何额外说明。
    """
    
    # 调用LLM生成SQL
    sql_query = llm.generate(prompt).strip()
    
    # SQL语法验证
    validate_sql_syntax(sql_query)
    
    return sql_query

4. SQL执行与数据获取

使用pandas和pandasql执行生成的SQL查询:

python 复制代码
def execute_sql_query(sql_query, excel_info):
    file_path = excel_info['relevant_items'][0]['file_path']
    sheet_name = excel_info['relevant_items'][0]['sheet_name']
    
    # 加载Excel数据
    df = pd.read_excel(file_path, sheet_name=sheet_name)
    
    try:
        # 执行SQL查询
        result = sqldf(sql_query, locals())
        return {
            "success": True,
            "data": result.to_dict('records'),
            "sql": sql_query
        }
    except Exception as e:
        # 错误处理
        return {
            "success": False,
            "error": str(e),
            "sql": sql_query
        }

三、系统集成与优化

1. 缓存机制

为提高性能,实现多级缓存:

  • Excel文件数据缓存:避免重复读取同一文件
  • SQL查询结果缓存:相似问题可复用查询结果
  • 向量检索结果缓存:加速频繁查询的响应时间
python 复制代码
# Excel数据缓存实现示例
excel_cache = {}

def get_excel_dataframe(file_path, sheet_name):
    cache_key = f"{file_path}:{sheet_name}"
    
    if cache_key in excel_cache:
        # 检查文件是否被修改
        file_mtime = os.path.getmtime(file_path)
        if file_mtime <= excel_cache[cache_key]['timestamp']:
            return excel_cache[cache_key]['data']
    
    # 加载Excel并缓存
    df = pd.read_excel(file_path, sheet_name=sheet_name)
    excel_cache[cache_key] = {
        'data': df,
        'timestamp': time.time()
    }
    
    return df

2. 错误处理与回退策略

实现完善的错误处理机制:

  1. SQL语法错误:使用正则表达式预检查常见语法错误
  2. Excel文件不可访问:提供明确错误信息并从文本知识库获取相关信息
  3. 数据类型不匹配:在SQL生成时确保类型兼容性
  4. 多种回退策略:如SQL失败时尝试直接pandas操作,或降级为纯文本回答
python 复制代码
def fallback_strategy(query, excel_info, error):
    # 记录错误日志
    log_error(query, excel_info, error)
    
    if "syntax error" in str(error).lower():
        # 尝试修复SQL语法
        corrected_sql = try_correct_sql(error.sql)
        if corrected_sql:
            return execute_sql_query(corrected_sql, excel_info)
    
    # 降级为直接DataFrame操作
    try:
        df = get_excel_dataframe(excel_info['file_path'], excel_info['sheet_name'])
        # 基于问题特征执行过滤和聚合
        result = direct_dataframe_operation(df, query)
        return result
    except:
        # 最终降级为纯文本回答
        return {"success": False, "fallback": "text_only"}

3. 结果呈现优化

根据查询结果类型优化呈现方式:

  • 表格数据:格式化为Markdown表格
  • 聚合结果:生成简洁的自然语言描述
  • 时间序列数据:推荐加入可视化描述
  • 异常值检测:突出显示异常数据点
python 复制代码
def format_query_result(excel_result, text_info, query_type):
    if not excel_result['success']:
        return format_text_only_result(text_info)
    
    data = excel_result['data']
    
    if query_type == 'comparison':
        # 创建比较分析
        return format_comparison_result(data)
    elif query_type == 'trend':
        # 创建趋势分析
        return format_trend_result(data)
    elif query_type == 'ranking':
        # 创建排名结果
        return format_ranking_result(data)
    else:
        # 默认格式化
        return format_default_result(data, text_info)

四、实际应用案例与代码示例

1. 完整处理流程示例

假设用户问题:"2023年第一季度销售额最高的是哪个产品,具体销售了多少?"

python 复制代码
# 示例实现流程
def process_example_query():
    query = "2023年第一季度销售额最高的是哪个产品,具体销售了多少?"
    
    # 1. 知识库检索阶段
    query_embedding = embedding_model.encode(query)
    excel_info = query_excel_metadata(query_embedding)
    text_info = query_text_knowledge(query_embedding)
    
    # 2. SQL生成阶段
    sql = """
    SELECT 产品ID, 产品名称, SUM(销售额) as 总销售额
    FROM `2023销售数据`
    WHERE 日期 BETWEEN '2023-01-01' AND '2023-03-31'
    GROUP BY 产品ID, 产品名称
    ORDER BY 总销售额 DESC
    LIMIT 1
    """
    
    # 3. 数据获取阶段
    df = pd.read_excel("/path/to/sales_data.xlsx", sheet_name="2023销售数据")
    result = sqldf(sql, locals())
    
    # 4. 结果整合阶段
    product_id = result['产品ID'].iloc[0]
    product_name = result['产品名称'].iloc[0]
    total_sales = result['总销售额'].iloc[0]
    
    # 5. 从文本知识库获取产品补充信息
    product_info = get_product_info_from_text_kb(product_id)
    
    # 6. 生成最终答复
    answer = f"""
    2023年第一季度销售额最高的产品是{product_name}(产品ID:{product_id}),
    总销售额达到了{total_sales:,.2f}元。
    
    {product_info['description'] if product_info else ''}
    """
    
    return answer

2. pandasql语法细节

使用pandasql时需要注意以下特殊语法:

python 复制代码
# pandasql使用细节
from pandasql import sqldf

# 表名需要使用反引号括起来,尤其是带空格或特殊字符的sheet名
sql = """
SELECT *
FROM `2023销售数据`
WHERE `销售区域` = '华东'
"""

# 表别名使用
sql = """
SELECT a.`产品ID`, a.`销售额`, b.`产品名称`
FROM `2023销售数据` a
JOIN `产品信息` b ON a.`产品ID` = b.`产品ID`
"""

# 日期处理(使用字符串比较)
sql = """
SELECT *
FROM `2023销售数据`
WHERE `日期` >= '2023-01-01' AND `日期` <= '2023-03-31'
"""

# 聚合函数
sql = """
SELECT `销售区域`, SUM(`销售额`) as 区域总销售额,
       AVG(`销售额`) as 平均单次销售额,
       COUNT(*) as 销售次数
FROM `2023销售数据`
GROUP BY `销售区域`
"""

# 结果限制
result = sqldf(sql, locals())

五、性能优化与扩展性

1. 大型Excel文件处理

对于超大型Excel文件(>100MB),采用以下优化策略:

  • 使用pd.read_excel(..., usecols=[])仅加载需要的列
  • 实现分块读取:pd.read_excel(..., chunksize=10000)
  • 考虑将常用Excel预先转换为SQLite数据库提高查询性能
python 复制代码
def optimize_large_excel_loading(file_path, sheet_name, needed_columns, sql_query):
    # 分析SQL确定所需列
    required_columns = extract_columns_from_sql(sql_query)
    
    # 仅加载必要的列
    df = pd.read_excel(
        file_path,
        sheet_name=sheet_name,
        usecols=required_columns
    )
    
    return df

2. 多Excel关联查询

实现跨Excel文件的关联查询:

python 复制代码
def cross_excel_query(query, excel_infos):
    # 加载相关Excel文件
    dataframes = {}
    for info in excel_infos:
        df = pd.read_excel(info['file_path'], sheet_name=info['sheet_name'])
        dataframes[info['sheet_name']] = df
    
    # 生成跨表SQL查询
    sql = generate_cross_excel_sql(query, excel_infos)
    
    # 执行查询
    result = sqldf(sql, dataframes)
    return result

3. 动态适应Excel结构变化

实现Excel结构变更的自动检测与适应:

python 复制代码
def verify_excel_structure(file_path, sheet_name, expected_columns):
    # 读取Excel头部
    df_header = pd.read_excel(file_path, sheet_name=sheet_name, nrows=0)
    actual_columns = set(df_header.columns)
    expected_columns_set = set(expected_columns)
    
    # 检查列变化
    missing_columns = expected_columns_set - actual_columns
    new_columns = actual_columns - expected_columns_set
    
    if missing_columns or new_columns:
        # 更新知识库中的Excel元数据
        update_excel_metadata(file_path, sheet_name, actual_columns)
        
        # 记录变更日志
        log_structure_change(file_path, sheet_name, missing_columns, new_columns)
    
    return {
        "structure_changed": bool(missing_columns or new_columns),
        "missing_columns": list(missing_columns),
        "new_columns": list(new_columns)
    }

六、部署与工程实践

1. 系统架构设计

复制代码
┌─────────────────┐         ┌─────────────────┐
│                 │         │                 │
│  用户查询接口    │◄────────┤  前端应用       │
│                 │         │                 │
└────────┬────────┘         └─────────────────┘
         │
         ▼
┌────────────────────────────────────────────┐
│                                            │
│             查询处理服务                    │
│                                            │
│  ┌─────────────┐         ┌─────────────┐   │
│  │             │         │             │   │
│  │  LLM服务    │◄────────┤ 查询路由器   │   │
│  │             │         │             │   │
│  └─────┬───────┘         └──────┬──────┘   │
│        │                        │          │
│        ▼                        ▼          │
│  ┌─────────────┐         ┌─────────────┐   │
│  │             │         │             │   │
│  │ SQL生成器   │         │ 知识检索器   │   │
│  │             │         │             │   │
│  └─────┬───────┘         └──────┬──────┘   │
│        │                        │          │
└────────┼────────────────────────┼──────────┘
         │                        │
         ▼                        ▼
┌────────────────┐      ┌───────────────────┐
│                │      │                   │
│ Excel数据处理器 │      │  向量知识库       │
│                │      │                   │
└────────┬───────┘      └─────────┬─────────┘
         │                        │
         ▼                        ▼
┌────────────────┐      ┌───────────────────┐
│                │      │                   │
│  Excel文件存储  │      │  文本知识库       │
│                │      │                   │
└────────────────┘      └───────────────────┘

2. API设计

python 复制代码
# FastAPI实现示例
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

app = FastAPI()

class QueryRequest(BaseModel):
    query: str
    user_id: str = None
    context_id: str = None

class QueryResponse(BaseModel):
    answer: str
    excel_data: list = None
    confidence: float
    sources: list = None

@app.post("/api/query", response_model=QueryResponse)
async def process_query(request: QueryRequest):
    try:
        # 处理查询
        result = knowledge_engine.process_query(
            request.query,
            user_id=request.user_id,
            context_id=request.context_id
        )
        
        return result
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

3. 错误监控与日志系统

python 复制代码
# 日志系统设计
import logging
from elasticsearch import Elasticsearch

class QueryLogger:
    def __init__(self):
        self.es_client = Elasticsearch()
        self.logger = logging.getLogger("query_processor")
    
    def log_query(self, query, user_id, excel_info, sql, result):
        # 详细日志记录
        log_entry = {
            "timestamp": datetime.now().isoformat(),
            "user_id": user_id,
            "query": query,
            "excel_files": [info["file_path"] for info in excel_info],
            "sql_generated": sql,
            "result_status": "success" if result["success"] else "failure",
            "execution_time_ms": result["execution_time"]
        }
        
        # 记录到Elasticsearch
        self.es_client.index(index="query_logs", document=log_entry)
        
        # 记录到本地日志
        self.logger.info(f"Query processed: {query}")
        
        if not result["success"]:
            self.logger.error(f"Query failed: {query}, Error: {result.get('error')}")

七、最佳实践与注意事项

1. 元数据维护

Excel知识库的元数据维护是整个系统的基础,需要特别注意:

  • 建立自动化工具定期扫描Excel文件变化并更新元数据
  • 提供友好的元数据编辑界面,支持业务人员直接维护
  • 实现元数据质量检查,确保描述准确、完整
  • 设计版本控制机制,跟踪元数据变更历史

2. 安全性考虑

在处理Excel数据时需要注意以下安全事项:

  • 实现严格的访问控制,确保只有授权用户可以查询特定Excel
  • 对SQL注入进行防护,验证和清理LLM生成的SQL
  • 敏感数据脱敏处理,确保返回结果不包含敏感信息
  • 实现完整的操作审计日志

3. 扩展思路

该方案还可以进一步扩展:

  • 支持其他结构化数据源(如CSV、数据库、API等)
  • 添加数据可视化组件,自动生成图表
  • 实现交互式查询精化,允许用户对初始结果进行深入探索
  • 集成数据变更监控,当数据更新时主动推送相关信息

八、总结与展望

pandas+pandasql结合LLM的解决方案为企业知识库构建提供了一种既实用又高效的方法。通过将Excel文件的结构信息纳入知识库,然后利用LLM生成SQL查询并通过pandas执行,最终将结构化数据查询与非结构化文本查询结果相结合,形成了一个强大的智能问答系统。

这种方案的优势在于:

  1. 降低实现门槛:利用现有的pandas和SQL技术栈,降低了开发难度
  2. 提高查询精度:通过结构化查询提高了数据查询的准确性
  3. 减轻LLM负担:避免将大量表格数据直接输入LLM,节省令牌消耗
  4. 增强系统灵活性:易于与现有知识库系统集成
  5. 提升用户体验:能够精确回答涉及结构化数据的复杂问题

随着LLM能力的进一步提升和工具使用能力的增强,这种结合方式有望发展出更加智能化的企业数据应用系统,为数据驱动决策提供更强大的支持。

相关推荐
我是六月生5 小时前
右击没有Word、PPT、Excel功能
word·powerpoint·excel
杜子腾dd6 小时前
4.用 Excel 录入数据
excel
杜子腾dd15 小时前
21.Excel自动化:如何使用 xlwings 进行编程
运维·python·自动化·excel·numpy·pandas
姚瑞南18 小时前
【Excel使用技巧】某列保留固定字段或内容
chatgpt·aigc·excel
Mr.45671 天前
java8循环解压zip文件---实现Excel文件数据追加
excel
杜子腾dd1 天前
4.Matplotlib:基础绘图
大数据·python·excel·matplotlib
inxunoffice2 天前
根据模板将 Excel 明细数据生成 PDF 文档 | PDF实现邮件合并功能
pdf·excel
SunkingYang2 天前
C++中使用CopyFromRecordset将记录集拷贝到excel中时,如果记录集为0个,函数崩溃,是什么原因
c++·excel·崩溃·闪退·copyfrom·recordset·空记录集
geekmice2 天前
问题:md文档转换word,html,图片,excel,csv
html·word·excel
henry_dx2 天前
Excel新增的函数
excel