基于大模型的自然语言数据库查询与数据分析
本文介绍了利用大语言模型结合 LlamaIndex 框架,通过自然语言生成 SQL 语句查询数据库的技术方案。内容涵盖环境搭建、基础查询实现、流式输出支持、模糊查询优化及提示词工程调整。文章分析了不同模型在 NL2SQL 任务中的表现差异,探讨了本地模型与云端模型的适用场景,并补充了安全注意事项与最佳实践,为开发者提供从原型验证到生产部署的参考路径。

本文介绍了利用大语言模型结合 LlamaIndex 框架,通过自然语言生成 SQL 语句查询数据库的技术方案。内容涵盖环境搭建、基础查询实现、流式输出支持、模糊查询优化及提示词工程调整。文章分析了不同模型在 NL2SQL 任务中的表现差异,探讨了本地模型与云端模型的适用场景,并补充了安全注意事项与最佳实践,为开发者提供从原型验证到生产部署的参考路径。

利用大语言模型(LLM)通过自然语言生成 SQL 语句,从结构化数据库中获取结果,是目前大模型与数据交互的主流形式之一。这种技术通常被称为 NL2SQL(Natural Language to SQL)。
以查询朝阳区高中学校招生信息为例,当用户提问 陈经纶招多少人? 时,系统处理的大致步骤如下:
select * from school_info where school_name like '%陈经纶%'。北京市陈经纶中学招收的学生人数为 279 名。以下示例基于 Jupyter Notebook 环境实现,主要涉及 SQLAlchemy、LlamaIndex 以及本地或云端模型调用。
首先使用 SQLAlchemy 在 SQLite 内存数据库中创建表结构和记录。
from sqlalchemy import (
create_engine,
MetaData,
Table,
Column,
String,
Integer,
select,
insert,
)
# 建立连接和表
engine = create_engine("sqlite:///:memory:")
metadata_obj = MetaData()
# 创建学校信息表结构
table_name = "school_info"
school_info_table = Table(
table_name,
metadata_obj,
Column("school_name", String(200), primary_key=True),
Column("students_enrolled", Integer, nullable=False),
)
metadata_obj.create_all(engine)
# 插入学校信息记录
rows = [
{"school_name": "北京市第八十中学", "students_enrolled": 260},
{"school_name": "北京市陈经纶中学", "students_enrolled": 279},
{"school_name": "北京市日坛中学", "students_enrolled": 403},
{"school_name": "中国人民大学附属中学朝阳学校", "students_enrolled": 247},
{"school_name": "北京工业大学附属中学", "students_enrolled": 418},
{"school_name": "北京中学", "students_enrolled": 121},
]
for row in rows:
stmt = insert(school_info_table).values(**row)
with engine.begin() as connection:
cursor = connection.execute(stmt)
数据可以通过 pandas 查询显示,确保数据已正确写入。
需要配置 LLM 和嵌入模型,设置到 LlamaIndex 全局 Settings 中,这样后续方法无需重复设置参数。
from llama_index.core import Settings
from llama_index.llms.openai_like import OpenAILike
from llama_index.embeddings.ollama import OllamaEmbedding
# 设置 LLM (以本地 Ollama 为例)
Settings.llm = OpenAILike(
model="qwen2",
api_base="http://localhost:11434/v1",
api_key="ollama",
is_chat_model=True,
temperature=0.1,
request_timeout=60.0
)
# 设置 Embedding 模型
Settings.embed_model = OllamaEmbedding(
model_name="quentinz/bge-large-zh-v1.5",
base_url="http://localhost:11434",
ollama_additional_kwargs={"mirostat": 0}
)
执行基础查询:
from llama_index.core.sql_database import SQLDatabase
from llama_index.core.query_engine import NLSQLTableQueryEngine
sql_database = SQLDatabase(engine)
query_engine = NLSQLTableQueryEngine(
sql_database=sql_database,
tables=["school_info"],
)
query_str = "招生最多的是哪个学校?"
response = query_engine.query(query_str)
print(response)
# 输出示例:'招生最多的是北京工业大学附属中学,共有 418 名学生。'
局限性分析:
为了提升体验,需要使用 LlamaIndex 底层的检索 API 来实现流式响应。
from llama_index.core.retrievers import NLSQLRetriever
from llama_index.core.query_engine import RetrieverQueryEngine
nl_sql_retriever = NLSQLRetriever(
sql_database, tables=["school_info"], return_raw=True
)
query_engine = RetrieverQueryEngine.from_args(
nl_sql_retriever,
streaming=True
)
response = query_engine.query("招生最多的前三个学校?")
response.print_response_stream()
运行效果将逐字打印出答案,显著提升交互流畅度。
默认情况下,NL2SQL 对模糊匹配的支持较弱。直接询问 陈经纶招多少? 可能因无法精确匹配表结构而返回空结果。
需要增加提示词约束,并依赖能力更强的 LLM 模型。本地小模型(如 Qwen 7B/14B)可能难以生成准确的模糊查询 SQL,建议尝试云端高级模型。
from llama_index.core.prompts import PromptTemplate
# 配置云端模型 (示例)
nl_sql_retriever = NLSQLRetriever(
sql_database, tables=["school_info"],
return_raw=False,
llm=OpenAILike(
model='qwen-turbo',
api_base="http://api.example.com/v1",
api_key="<YOUR_API_KEY>", # 请替换为实际密钥
is_chat_model=True,
temperature=0.1,
request_timeout=60.0
)
)
# 修改提示词模板
old_prompt_str = nl_sql_retriever.get_prompts()['text_to_sql_prompt'].template
new_prompt = PromptTemplate(
f"{old_prompt_str}"
"查询关键字使用模糊查询,并且查询结果应包含关键字所属的列"
)
nl_sql_retriever.update_prompts({"text_to_sql_prompt": new_prompt})
query_engine = RetrieverQueryEngine.from_args(
nl_sql_retriever,
streaming=True,
)
response = query_engine.query("陈经纶招多少?")
response.print_response_stream()
# 预期输出:陈经纶招收 279 名学生。
如果需要更严格的输出格式(例如必须显示全名),可以在 QA 阶段进一步定制提示词。
my_qa_prompt_template = (
"回答中要求使用学校的完整名称 (school_name)"
"不用再计算,给出的就是答案"
"Context information is below.\n"
"---------------------\n"
"{context_str}\n"
"---------------------\n"
"Given the context information and not prior knowledge, "
"answer the query.\n"
"Query: {query_str}\n"
"Answer: "
)
my_qa_prompt = PromptTemplate(
my_qa_prompt_template, prompt_type="QUESTION_ANSWER"
)
query_engine = RetrieverQueryEngine.from_args(
nl_sql_retriever,
streaming=True,
text_qa_template=my_qa_prompt,
)
response = query_engine.query("陈经纶招多少?")
response.print_response_stream()
在实际测试中,不同模型的表现差异显著:
初步结论:
在使用大模型查询数据库时,需注意以下安全问题:
本文演示了如何使用大模型将自然语言转换为 SQL,并将查询结果以自然语言形式反馈给用户。关键点包括:
通过合理配置 LlamaIndex 框架及选择合适的模型,开发者可以快速构建具备自然语言交互能力的数据库应用。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online