跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
PythonAI

基于大模型的自然语言数据库查询实现指南

使用大模型通过自然语言查询数据库的技术实现方案。内容涵盖环境搭建、SQLAlchemy 数据建模、LlamaIndex 配置、基础查询与流式输出实现、模糊查询的提示词优化以及安全与性能考量。通过具体代码示例展示了如何集成本地 Ollama 模型或云端 API,解决了上下文限制、SQL 生成准确性等问题,并为实际生产环境提供了完整的参考架构和安全建议。

佛系玩家发布于 2025/2/6更新于 2026/8/2251 浏览
基于大模型的自然语言数据库查询实现指南

基于大模型的自然语言数据库查询实现指南

使用大模型(LLM)通过自然语言生成 SQL 语句,从结构化数据库中获取结果,是目前大模型与数据交互的主流形式之一。这种技术通常被称为 Text-to-SQL 或 NL2SQL(Natural Language to SQL)。它极大地降低了非技术人员访问数据的门槛,使得业务人员可以直接通过对话方式查询数据。

本文将详细介绍如何使用 Python 生态中的 LlamaIndex、SQLAlchemy 以及本地或云端大模型,构建一个支持自然语言查询数据库的系统。我们将涵盖环境搭建、数据准备、基础查询、流式输出、模糊查询优化以及安全注意事项等完整流程。

一、核心原理概述

Text-to-SQL 的基本流程如下:

  1. 上下文注入:将数据库的 DDL(建表语句)作为上下文信息提供给大模型,使其理解表结构、字段含义及关系。
  2. 意图识别与 SQL 生成:大模型接收用户的自然语言问题,结合表结构,生成对应的 SQL 查询语句。
  3. 执行与反馈:系统执行生成的 SQL,获取结果集,并将结果再次输入大模型,由大模型将数据转换为自然语言回答。

以下是一个简单的示例场景:存储朝阳区高中学校招生信息的数据库,用户提问 陈经纶招多少人?,系统大致处理步骤为:

  • 数据库 DDL 加入对话上下文,主要是建表语句,让大模型感知表结构。
  • 大模型将提示词转化为 SQL 查询语句,例如 select * from school_info where school_name like '%陈经纶%'。
  • 大模型根据 SQL 查询结果,生成自然语言的回答,例如 北京市陈经纶中学招收的学生人数为 279 名。

二、环境准备与依赖安装

在开始之前,需要准备好开发环境。推荐使用 Jupyter Notebook 或 JupyterLab 进行交互式开发。

1. 基础依赖

我们需要安装以下核心库:

pip install llama-index sqlalchemy pandas ollama openai
  • llama-index: 用于连接 LLM 和外部数据源的核心框架。
  • sqlalchemy: ORM 工具,用于定义数据库结构和操作记录。
  • pandas: 用于数据处理和展示。
  • ollama: 用于运行本地大模型。
  • openai: 兼容 OpenAI API 格式的客户端,用于调用云端或本地兼容接口。

2. 模型配置

本文演示同时支持本地模型(通过 Ollama)和云端模型(通过 One-API 或类似网关)。

  • 本地模型:需确保 Ollama 服务已启动,并拉取相应模型(如 qwen2, llama3 等)。
  • 云端模型:需配置 API Key 和 Base URL。

三、数据准备与建模

我们使用 SQLAlchemy 在内存 SQLite 数据库中创建示例表和相关记录。SQLite 轻量且无需额外服务器,适合演示。

1. 建立连接和表结构

from sqlalchemy import (
    create_engine,
    MetaData,
    Table,
    Column,
    String,
    Integer,
    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)

2. 插入测试数据

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)

3. 数据验证

可以使用 Pandas 查看数据是否正确写入:

import pandas as pd
with engine.connect() as conn:
    df = pd.read_sql("SELECT * FROM school_info", conn)
    print(df)

四、LlamaIndex 基础配置

在使用 LlamaIndex 进行查询前,需要设置全局的 LLM 和 Embedding 模型。这样后续方法调用时无需重复传递参数。

1. 配置 LLM

这里以 Qwen2 为例,通过 Ollama 本地部署或兼容接口调用。

from llama_index.llms.openai_like import OpenAILike
from llama_index.embeddings.ollama import OllamaEmbedding
from llama_index.core import Settings

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
)

Settings.embed_model = OllamaEmbedding(
    model_name="quentinz/bge-large-zh-v1.5",
    base_url="http://localhost:11434",
    ollama_additional_kwargs={"mirostat": 0}
)

*注意:如果网络不通,请确保 Ollama 服务地址正确,且防火墙允许访问。

五、基本查询实现

LlamaIndex 提供了 NLSQLTableQueryEngine,这是最基础的文本转 SQL 查询引擎。

1. 初始化查询引擎

from llama_index.core.sql_database.interface 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.response)
# 预期输出:'招生最多的是北京工业大学附属中学,共有 418 名学生。'

2. 局限性分析

这种方式虽然简单,但存在明显不足:

  • 不支持流式输出:用户必须等待整个响应生成完毕才能看到结果,体验较差。
  • 上下文限制:当数据库表很多时,DDL 信息可能超出 LLM 的上下文窗口,导致性能下降或错误。
  • 缺乏灵活性:难以针对特定业务逻辑定制提示词。

六、支持流式输出回答

为了提升用户体验,需要使用 LlamaIndex 底层的检索 API (Retriever) 来构建支持流式的查询引擎。

1. 配置 NLSQLRetriever

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()

2. 效果说明

启用流式后,用户可以看到文字逐字生成,大大减少了等待焦虑感。这对于长文本回答尤为重要。

七、高级功能:模糊查询与提示词工程

默认情况下,Text-to-SQL 对模糊匹配的支持较弱,往往要求精确匹配。如果需要支持模糊查询(如 LIKE '%关键词%'),需要调整 Prompt 模板。

1. 默认行为问题

直接询问 陈经纶招多少? 可能会失败,因为模型倾向于生成精确匹配条件,而表中是 北京市陈经纶中学。

2. 自定义 Prompt 模板

我们可以通过修改 text_to_sql_prompt 来强制模型使用模糊查询。

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://your-api-gateway:3000/v1", 
        api_key="sk-your-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}\n查询关键字使用模糊查询,并且查询结果应包含关键字所属的列"
)

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 名学生。

3. 定制化回答格式

除了生成 SQL,我们还可以控制最终的回答格式。例如要求显示学校全名。

my_qa_prompt_template = (
    "回答中要求使用学校的完整名称 (school_name)\n"
    "不用再计算,给出的就是答案\n"
    "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()

八、性能优化与安全考量

在实际生产环境中,仅靠上述代码是不够的,还需要考虑性能和安全性。

1. 上下文窗口管理

当数据库 schema 非常复杂时,直接将所有 DDL 放入 Prompt 会导致 Token 耗尽。建议采取以下策略:

  • Schema Linking:只将与当前问题相关的表和字段加入上下文。
  • 摘要化:对表注释进行压缩,保留关键语义。
  • 分层检索:先检索元数据,再决定加载哪些 DDL。

2. 模型选择策略

  • 本地模型:成本低,隐私性好,但能力有限。Qwen2-7B 等模型在简单查询上表现尚可,但在复杂多表关联上容易出错。
  • 云端模型:GPT-4、Qwen-Turbo 等高级模型在 SQL 生成准确率上显著优于小参数模型。建议混合使用:简单查询用本地,复杂查询路由到云端。

3. 安全性防护

Text-to-SQL 最大的风险在于 SQL 注入。虽然 LlamaIndex 会生成 SQL,但必须确保:

  • 只读权限:数据库账号仅授予 SELECT 权限,严禁 DELETE/UPDATE/DROP。
  • 参数化查询:尽量使用 ORM 或参数化接口,避免字符串拼接。
  • 异常捕获:对 SQL 执行过程中的语法错误或超时进行捕获,防止服务崩溃。

九、完整代码示例整合

为了方便复用,以下是一个整合了上述功能的简化版脚本结构:

import os
from sqlalchemy import create_engine, MetaData, Table, Column, String, Integer, insert
from llama_index.core import Settings
from llama_index.llms.openai_like import OpenAILike
from llama_index.embeddings.ollama import OllamaEmbedding
from llama_index.core.sql_database.interface import SQLDatabase
from llama_index.core.retrievers import NLSQLRetriever
from llama_index.core.query_engine import RetrieverQueryEngine
from llama_index.core.prompts import PromptTemplate

def setup_environment():
    # 配置 LLM
    Settings.llm = OpenAILike(
        model="qwen2",
        api_base="http://localhost:11434/v1",
        api_key="ollama",
        is_chat_model=True,
        temperature=0.1
    )
    Settings.embed_model = OllamaEmbedding(
        model_name="bge-large-zh-v1.5",
        base_url="http://localhost:11434"
    )

def init_db():
    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},
    ]
    for row in rows:
        stmt = insert(school_info_table).values(**row)
        with engine.begin() as connection:
            connection.execute(stmt)
    return SQLDatabase(engine)

def main():
    setup_environment()
    db = init_db()
    retriever = NLSQLRetriever(db, tables=["school_info"])
    engine = RetrieverQueryEngine.from_args(retriever, streaming=True)
    
    query = "招生最多的是哪个学校?"
    response = engine.query(query)
    print(f"Query: {query}")
    response.print_response_stream()

if __name__ == "__main__":
    main()

十、总结与展望

本文演示了如何使用大模型将自然语言转换为 SQL,并将查询结果以自然语言形式返回。主要结论如下:

  1. 技术可行性:利用 LlamaIndex 可以较快地搭建 Text-to-SQL 原型,支持流式输出和基础模糊查询。
  2. 模型依赖性:得到预期结果高度依赖大模型的能力。GPT-4 或 Qwen 高级模型效果最好,本地小模型(如 7B)在复杂场景下可能需要微调或配合更强的云端模型。
  3. 提示词工程:通过定制 Prompt 模板,可以有效改善模糊查询和输出格式的控制。
  4. 未来方向:随着 Agent 技术的发展,未来的 NL2SQL 系统将具备自我纠错能力,能够自动修正错误的 SQL 并重新执行,进一步提高准确率。

在实际落地时,建议采用混合架构,结合本地模型的隐私优势和云端模型的高智能优势,并严格做好数据库权限隔离,以确保系统的安全稳定运行。

目录

  1. 基于大模型的自然语言数据库查询实现指南
  2. 一、核心原理概述
  3. 二、环境准备与依赖安装
  4. 1. 基础依赖
  5. 2. 模型配置
  6. 三、数据准备与建模
  7. 1. 建立连接和表结构
  8. 创建内存数据库引擎
  9. 创建学校信息表结构
  10. 2. 插入测试数据
  11. 3. 数据验证
  12. 四、LlamaIndex 基础配置
  13. 1. 配置 LLM
  14. 五、基本查询实现
  15. 1. 初始化查询引擎
  16. 封装数据库对象
  17. 预期输出:'招生最多的是北京工业大学附属中学,共有 418 名学生。'
  18. 2. 局限性分析
  19. 六、支持流式输出回答
  20. 1. 配置 NLSQLRetriever
  21. 2. 效果说明
  22. 七、高级功能:模糊查询与提示词工程
  23. 1. 默认行为问题
  24. 2. 自定义 Prompt 模板
  25. 获取原有模板
  26. 添加模糊查询指令
  27. 预期输出:陈经纶招收 279 名学生。
  28. 3. 定制化回答格式
  29. 八、性能优化与安全考量
  30. 1. 上下文窗口管理
  31. 2. 模型选择策略
  32. 3. 安全性防护
  33. 九、完整代码示例整合
  34. 十、总结与展望
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • MySQL 数据类型详解与性能优化实践
  • AI 大模型本地部署指南:使用 Ollama 快速运行
  • 简单的解压缩算法 (多语言实现)
  • 2026年全球AI大模型深度研究报告
  • CSS 渐变详解:线性、径向与锥形渐变的实战应用
  • 3 种方法快速判断 Ubuntu 系统 ARM 或 x86 架构
  • 天然气管道内检测机器人检测节设计
  • MySQL Windows 版安装与验证指南
  • 用 UniApp 和 ThinkPHP 搭的全栈项目基础
  • 2026 大厂前端、后端及算法岗位 AI 技能清单
  • Apache Arrow FFI 接口详解:C 与 Rust 数据零拷贝交互
  • OpenClaw 技术架构详解:构建个人 AI 助手系统
  • Django+Vue3 前后端分离 Web 视觉系统:集成 YOLO 与 LLM 大模型智能分析
  • C++ 测试与调试实战:保障代码质量与稳定性
  • Git SSH 密钥配置指南
  • 从菜鸟到架构师:校招宣讲中的技术展示策略
  • 大模型 RAG 技术详解:架构、优势与实战应用
  • 希水涵 Web 日志分析工具 V0.32 版本更新
  • Java Web 开发入门:基础概念与静态资源解析
  • VSCode 中可视化使用 Git 的完整指南

相关免费在线工具

  • RSA密钥对生成器

    生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online

  • Mermaid 预览与可视化编辑

    基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online

  • 随机西班牙地址生成器

    随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online

  • curl 转代码

    解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online