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

相关推荐
Access开发易登软件8 分钟前
Access 怎么做前后端分离?用 Web API 读写 SQL Server
前端·数据库·人工智能·microsoft·excel·access
红莲凪是1 天前
使用二次封装的Excel COM 组件操作Excel\WPS ET IExcelRange 高级应用
python·excel·wps
用户298698530141 天前
如何使用免费工具在线将 Excel 转换为 XML 格式
人工智能·后端·excel
开开心心就好1 天前
内存清理工具定时自动清理开机自启动
java·开发语言·elasticsearch·ocr·excel·音视频·big data
开开心心就好1 天前
电脑内存优化工具一键释放内存超简单
java·开发语言·macos·arcgis·ocr·excel·音视频
随手工具-Excel, pdf, SQL1 天前
没有 SSMS 导入向导?Excel/CSV 一键生成 SQL Server INSERT 脚本
excel·sql server·在线工具·insert·测试数据·ssms·t-sql
SunnyDays10112 天前
Python 将 Excel(XLS/XLSX)转换为 JSON:导出工作簿、工作表、单元格区域与自定义 JSON 结构
python·json·excel·excel 转 json·导出 excel 到 json·xlsx 转 json·xls 转 json
chatexcel2 天前
ChatExcel AI Word 升级:多模态读资料、按模板生成、智能排版配图,还能批注修订和联动Excel 复核
人工智能·ai·word·excel·ai写作
北极糊的狐2 天前
Excel快速拆分一列数据为两列(领养例子)该摘要描述了如何将包含姓名和电话的混合数据列拆分为单独的两列
excel
搭贝低代码2 天前
财务管控系统架构设计:从Excel到数字化管控平台的技术跃迁
低代码·系统架构·excel