LangChain 实战:搭建 SQL 数据库自然语言问答系统(Chain + Agent 双方案)

在数据分析、业务运营等场景中,非技术人员往往需要通过 SQL 查询数据库,但编写 SQL 对他们来说门槛极高。LangChain 提供了一套完整的解决方案,能将自然语言问题自动转为 SQL 查询、执行并返回自然语言答案。本文将手把手教你搭建两种 SQL 问答方案:SQL Chain(固定流程链)SQL Agent(智能决策代理),满足不同复杂度的查询需求。

一、核心原理:SQL 问答的三步法

无论是 Chain 还是 Agent,LangChain 处理 SQL 问答的核心逻辑都遵循三步原则:

2. 数据准备

本文使用经典的 Chinook.db 示例数据库(包含音乐商店的艺术家、专辑、订单等表),可直接从 LangChain 示例库 下载,放在项目根目录即可。

3. API Key 配置

创建 .env 文件,填入 OpenAI API Key(需在官网申请):

env

复制代码
OPENAI_API_KEY=你的OpenAI API密钥

三、第一步:连接 SQL 数据库

首先建立 LangChain 与数据库的连接,验证数据库可访问:

python

运行

复制代码
from langchain_community.utilities import SQLDatabase
from dotenv import load_dotenv
import os

# 加载环境变量
load_dotenv()
openai_api_key = os.getenv("OPENAI_API_KEY")

# 连接 SQLite 数据库(替换为你的数据库 URI)
# MySQL 示例:mysql+pymysql://user:password@host:port/dbname
# PostgreSQL 示例:postgresql+psycopg2://user:password@host:port/dbname
db = SQLDatabase.from_uri("sqlite:///Chinook.db")

# 验证连接
print("数据库方言:", db.dialect)  # 输出:sqlite
print("可用表名:", db.get_usable_table_names())  # 输出数据库中的表列表
print("测试查询结果:")
print(db.run("SELECT * FROM Artist LIMIT 10;"))  # 执行测试 SQL

关键说明

四、方案一:搭建 SQL Chain(固定流程问答链)

SQL Chain 是 "固定流程" 的问答方案,适合简单、标准化的查询场景,步骤清晰且可控。

步骤 1:生成 SQL 查询语句

先用大模型将自然语言问题转为 SQL:

python

运行

复制代码
from langchain.chains import create_sql_query_chain
from langchain_openai import ChatOpenAI

# 初始化大模型(GPT-3.5-turbo 性价比最高)
llm = ChatOpenAI(
    model="gpt-3.5-turbo",
    temperature=0,  # 温度设为0,保证 SQL 生成稳定
    api_key=openai_api_key
)

# 创建 SQL 查询生成链
write_query = create_sql_query_chain(llm, db)

# 测试生成 SQL
response = write_query.invoke({"question": "How many employees are there"})
print("生成的 SQL:", response)
# 输出示例:SELECT COUNT(*) FROM Employee;

步骤 2:添加 SQL 执行能力

仅生成 SQL 还不够,需结合 QuerySQLDataBaseTool 执行 SQL:

python

运行

复制代码
from langchain_community.tools.sql_database.tool import QuerySQLDataBaseTool

# 初始化 SQL 执行工具
execute_query = QuerySQLDataBaseTool(db=db)

# 串联"生成 SQL + 执行 SQL"的链
sql_chain = write_query | execute_query

# 测试执行结果
result = sql_chain.invoke({"question": "How many employees are there"})
print("SQL 执行结果:", result)
# 输出示例:[(8,)](表示有8名员工)

步骤 3:生成自然语言回答

最后将 "问题 + SQL + 执行结果" 传给大模型,生成易懂的自然语言答案:

python

运行

复制代码
from operator import itemgetter
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_core.runnables import RunnablePassthrough

# 定义答案生成的提示词模板
answer_prompt = PromptTemplate.from_template(
    """Given the following user question, corresponding SQL query, and SQL result, answer the user question in natural language.

Question: {question}
SQL Query: {query}
SQL Result: {result}
Answer: """
)

# 构建答案生成链
answer_chain = answer_prompt | llm | StrOutputParser()

# 整合完整链:生成 SQL → 执行 SQL → 生成答案
full_chain = (
    RunnablePassthrough.assign(query=write_query).assign(
        result=itemgetter("query") | execute_query
    )
    | answer_chain
)

# 测试完整链
final_answer = full_chain.invoke({"question": "How many employees are there"})
print("最终回答:", final_answer)
# 输出示例:There are 8 employees in total.

关键说明

五、方案二:搭建 SQL Agent(智能决策代理)

SQL Chain 适合固定流程的简单查询,但面对复杂问题(如多表关联、分步查询、需要解释表结构)时,Agent 更灵活 ------ 它能自主决策是否需要多轮查询、是否需要查看表结构,甚至修正错误的 SQL。

步骤 1:初始化 SQL 代理

python

运行

复制代码
from langchain_community.agent_toolkits import create_sql_agent

# 创建 SQL 代理
agent_executor = create_sql_agent(
    llm=llm,
    db=db,
    agent_type="openai-tools",  # 适配 OpenAI 函数调用的代理类型
    verbose=True  # 开启详细日志,查看代理的思考过程
)

步骤 2:测试复杂查询

python

运行

复制代码
# 测试1:多表关联查询(总销售额按国家统计,找出消费最多的国家)
result1 = agent_executor.invoke(
    {
        "input": "List the total sales per country. Which country's customers spent the most?"
    }
)
print("代理回答1:", result1["output"])

# 测试2:查询表结构(无需手动写 SQL,代理自动判断需要执行 DESC 语句)
result2 = agent_executor.invoke({"input": "Describe the playlisttrack table"})
print("代理回答2:", result2["output"])

执行日志示例 (开启 verbose=True 后可见):

plaintext

复制代码
> Entering new AgentExecutor chain...
Invoking: `sql_db_list_tables` with `{}`
Got tables: Artist, Album, Track, Playlist, PlaylistTrack, Customer, Invoice, InvoiceLine, Employee, Genre, MediaType
Invoking: `sql_db_schema` with `{'table_names': ['Invoice', 'Customer']}`
Got schema: ...(表结构)
Invoking: `sql_db_query` with `{'query': 'SELECT c.Country, SUM(i.Total) AS TotalSales FROM Customer c JOIN Invoice i ON c.CustomerId = i.CustomerId GROUP BY c.Country ORDER BY TotalSales DESC LIMIT 1;'}`
SQL 执行结果:[('USA', 523.06)]
> Finished chain.
代理回答1:The United States has the highest customer spending with a total of 523.06 in sales.

关键说明

六、Chain vs Agent:该怎么选?

特性 SQL Chain SQL Agent
适用场景 简单、标准化的单步查询 复杂、多步、需要决策的查询
灵活性 低(固定流程) 高(自主决策)
可解释性 高(流程透明) 中(需查看日志)
性能 快(少轮次) 稍慢(多轮思考)
学习成本 低(代码简单) 中(需理解代理逻辑)

选型建议

七、常见问题排查

八、总结

  1. 自然语言转 SQL:大模型根据用户问题和数据库结构,生成符合语法的 SQL 查询语句;

  2. 执行 SQL 查询:调用数据库工具执行生成的 SQL,获取查询结果;

  3. 结果转自然语言 :大模型将 SQL 执行结果整理成通俗易懂的自然语言回答。

    二、前置准备

    1. 环境依赖安装

    bash

    运行

    复制代码
    pip install langchain langchain-openai sqlalchemy python-dotenv
  4. langchain:核心框架,提供 SQL 链 / 代理能力;

  5. langchain-openai:对接 OpenAI 大模型(也可替换为开源模型);

  6. sqlalchemy:数据库连接工具,支持 SQLite/MySQL/PostgreSQL 等;

  7. python-dotenv:管理环境变量(如 OpenAI API Key)。

  8. SQLDatabase.from_uri 支持主流数据库,只需替换 URI 即可切换;

  9. get_usable_table_names() 可查看数据库中可访问的表,方便大模型了解表结构;

  10. db.run() 可直接执行 SQL,用于验证数据库连接是否正常。

  11. RunnablePassthrough.assign:用于给链的上下文添加新变量(如 queryresult);

  12. itemgetter("query"):提取上下文里的 query 变量,传给执行工具;

  13. 整个链的执行流程:用户问题 → 生成 SQL → 执行 SQL → 生成自然语言答案,全程自动化。

  14. Agent 会先查看数据库的表列表 → 再查看相关表的结构 → 生成并执行 SQL → 整理答案;

  15. 相比 Chain,Agent 具备 "自主思考" 能力,能处理更复杂的问题,比如:

    • "先找出销量最高的专辑,再查看该专辑的所有曲目";
    • "如果表中没有销售额字段,告诉我有哪些可用字段"。
  16. 日常简单查询(如 "统计某表的行数""查询某类数据的总数"):选 Chain,速度快、稳定;

  17. 复杂业务查询(如多表关联、分步分析、需要动态调整查询逻辑):选 Agent,更智能。

  18. 生成的 SQL 语法错误

    • 原因:大模型不了解数据库方言(如 SQLite/MySQL 语法差异);
    • 解决:确保 db.dialect 正确,或在提示词中指定数据库类型(如 "生成 SQLite 语法的 SQL")。
  19. 代理无法找到相关表

    • 原因:get_usable_table_names() 返回的表名不全;
    • 解决:初始化 SQLDatabase 时,用 include_tables 指定可用表(如 db = SQLDatabase.from_uri(..., include_tables=["Employee", "Customer"]))。
  20. API Key 无效

    • 检查 .env 文件中的密钥是否正确,或是否有足够的余额。
  21. 数据库连接失败

    • 确认数据库 URI 正确,且数据库服务已启动(如 MySQL/PostgreSQL)。
  22. LangChain 搭建 SQL 问答系统的核心是 "自然语言转 SQL → 执行 SQL → 生成答案" 三步;

  23. SQL Chain 适合简单、固定流程的查询,代码简洁、性能快;

  24. SQL Agent 适合复杂、需要自主决策的查询,具备更强的灵活性;

  25. 两种方案都无需手动编写 SQL,非技术人员可通过自然语言直接查询数据库。

相关推荐
weisian1514 分钟前
Java并发编程--45-分布式一致性协议入门:Raft、Paxos与ZAB的核心思想
java·分布式·raft·paxos·zab
木井巳6 分钟前
【递归算法】解数独
java·算法·leetcode·决策树·深度优先·剪枝
t***54412 分钟前
如何在 Dev-C++ 中切换编译器
java·开发语言·c++
Lisonseekpan13 分钟前
Git:如何将一个分支的特定提交合并到另一个分支?
java·大数据·git·后端·elasticsearch
Boop_wu15 分钟前
[Java EE 进阶]Mybatis进阶(动态SQL)
java·数据库·maven·mybatis
Elastic 中国社区官方博客19 分钟前
使用 EDOT Browser 和 Kibana 进行 OpenTelemetry 浏览器端埋点
大数据·服务器·数据库·elasticsearch·搜索引擎·单元测试·可用性测试
星轨zb32 分钟前
为什么Mysql需要索引以及如何应用到项目中
数据库·mysql
BullSmall37 分钟前
Redis 双机部署 完整方案(两种架构,适配两台机器)
java·redis·架构
sdm07042739 分钟前
进程间通信
linux·运维·服务器
蚰蜒螟43 分钟前
Linux内核启动(init)与程序执行(execve)深度解析:从kernel_init到load_elf_binary
linux·运维·服务器