如何在SQL问答中处理大型数据库的挑战

65 阅读3分钟

引言

在处理SQL问答任务时,面对大型数据库,我们经常会遇到难题。例如,当数据表过多或列的基数过高时,我们无法在每个提示中导入数据库的完整信息。在这篇文章中,我们将探讨如何动态地选择并在提示中仅插入最相关的信息,从而生成有效的SQL查询。

主要内容

识别相关的表子集

第一步是识别与用户问题相关的表。通常我们无法在一个提示中包含所有表的架构,因此我们需要提取与用户输入相关的表名,并仅包含这些表的架构。

使用工具调用

通过工具调用,我们可以从数据库中提取相关表名,并将其绑定到模型中。这可以通过以下方式实现:

from langchain_community.utilities import SQLDatabase
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers.openai_tools import PydanticToolsParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.pydantic_v1 import BaseModel, Field

class Table(BaseModel):
    """Table in SQL database."""

    name: str = Field(description="Name of table in SQL database.")

db = SQLDatabase.from_uri("sqlite:///Chinook.db")

table_names = "\n".join(db.get_usable_table_names())
system = f"""Return the names of ALL the SQL tables that MIGHT be relevant to the user question.
The tables are:

{table_names}

Remember to include ALL POTENTIALLY RELEVANT tables, even if you're not sure that they're needed."""

prompt = ChatPromptTemplate.from_messages(
    [
        ("system", system),
        ("human", "{input}"),
    ]
)

llm_with_tools = ChatOpenAI(model="gpt-4").bind_tools([Table])
output_parser = PydanticToolsParser(tools=[Table])

table_chain = prompt | llm_with_tools | output_parser

识别相关的列值

当处理高基数列时,如包含地址、歌曲名称或艺术家名称的列,为了正确过滤数据,我们需要确保拼写准确。可以通过创建向量存储来管理这些列:

import ast
import re

def query_as_list(db, query):
    res = db.run(query)
    res = [el for sub in ast.literal_eval(res) for el in sub if el]
    res = [re.sub(r"\b\d+\b", "", string).strip() for string in res]
    return res

proper_nouns = query_as_list(db, "SELECT Name FROM Artist")

然后,我们将这些唯一值嵌入并存储在一个向量数据库中,以便在查询时使用:

from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings

vector_db = FAISS.from_texts(proper_nouns, OpenAIEmbeddings())
retriever = vector_db.as_retriever(search_kwargs={"k": 15})

代码示例

下面是一个示例,展示如何结合上述步骤动态生成适合的SQL查询:

from langchain.chains import create_sql_query_chain

query_chain = create_sql_query_chain(llm_with_tools, db)
query = query_chain.invoke(
    {"question": "What are all the genres of Alanis Morissette songs"}
)
print(query)

常见问题和解决方案

  • 问题:当表的数量过多时,如何确保仅选择相关表?

    • 解决方案:通过先根据用户的输入筛选出可能相关的表,再只传递这些表的架构信息。
  • 问题:如何处理拼写错误的情况?

    • 解决方案:利用向量数据库进行拼写校正,将最相关的值注入提示中。

总结和进一步学习资源

通过动态选择相关的信息,我们可以在处理大型数据库的SQL问答任务中实现更高效的查询。如果你想进一步了解相关技术,推荐阅读LangChain社区的SQL: Agents指南

参考资料

  1. LangChain Documentation
  2. SQLAlchemy Documentation

结束语:如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!

---END---