在大模型应用落地过程中,"幻觉""知识过时""无法对接业务数据"是三大核心痛点------大模型虽具备强大的自然语言理解与生成能力,但自身知识库固定(无法实时更新)、缺乏逻辑推理能力(尤其多跳关系)、无法直接操作结构化数据(如数据库)。而检索增强技术(Retrieval-Augmented Generation, RAG),正是解决这些痛点的关键方案。
普通RAG、GraphRAG、NL2SQL 作为检索增强领域的三大核心技术,虽本质都是"让大模型结合外部数据生成回答",但针对的数据源、检索方式、适用场景截然不同。本文将进行全方位、超详细讲解,从技术原理到实操示例,从场景适配到对比选型,帮你彻底掌握这三大技术,无论是学习、开发还是面试,都能直接复用。
第一章:基础铺垫------什么是检索增强(RAG)?
在深入讲解三大技术前,先明确检索增强的核心逻辑:检索增强 = 检索(从外部数据源获取相关信息)+ 生成(大模型基于检索到的信息生成回答),核心目标是"让大模型的回答更准确、更实时、更贴合业务",本质是"给大模型装一个可更新、可扩展的'外部大脑'"。
检索增强的核心价值的三点:
-
解决幻觉:让大模型"有据可依",基于外部真实数据回答,避免一本正经地胡说八道;
-
解决知识过时:外部数据源可实时更新(如文档、数据库),让大模型掌握最新知识;
-
解决业务适配:对接企业自有文档、业务数据库,让大模型能回答与企业相关的具体问题(如"我们公司2025年1月的销售额是多少")。
普通RAG、GraphRAG、NL2SQL 都是检索增强的具体实现方式,区别在于"外部数据源的类型"和"检索的方式"------普通RAG对接非结构化文本,GraphRAG对接知识图谱(结构化关系数据),NL2SQL对接结构化数据库,三者覆盖了绝大多数企业的数据源类型,可单独使用,也可组合构建完整的检索增强体系。
第二章:普通RAG(向量RAG)------最通用、最基础的检索增强方案
2.1 核心定义
普通RAG,又称"向量RAG",是最基础、最通用的检索增强技术,核心是基于"文本相似度"从非结构化文本中检索相关片段,再让大模型基于这些片段生成回答。这里的"非结构化文本"包括:企业文档、PDF、Word、网页、聊天记录等,也是企业中最常见的数据源类型。
一句话总结:普通RAG = 文本分块 + 向量向量化 + 向量检索 + 大模型生成,核心是"找相似的文本片段"。
2.2 核心技术原理(超详细拆解)
普通RAG的完整实现流程分为"构建阶段"和"检索生成阶段",每个阶段的细节如下,确保新手也能理解:
2.2.1 构建阶段(离线准备,一次性操作)
核心目标:将非结构化文本转换成"可检索的向量形式",存储到向量数据库中,为后续检索做准备。
-
文档加载(Document Loading):将非结构化文本(PDF、Word、TXT等)加载到系统中,常用工具包括LangChain的DocumentLoader、LlamaIndex的Reader等。例如,用PyPDFLoader加载PDF文档,将其转换成可处理的文本格式。
-
文本分块(Text Splitting):这是普通RAG的关键步骤之一。由于大模型有上下文窗口限制(如GPT-3.5的上下文窗口为4096 Token),无法直接处理长文本,因此需要将加载后的文本分割成"小片段"(Chunk)。
-
分块原则:片段长度适中(通常500-1000 Token),保留文本的完整性(如一句话、一个段落不拆分),同时设置"重叠部分"(如50-100 Token),避免因拆分导致上下文断裂。
-
常用工具:LangChain的RecursiveCharacterTextSplitter、LlamaIndex的SentenceSplitter等。
-
-
文本向量化(Embedding):将每个文本片段转换成"向量"(一串数字)------因为计算机无法直接理解文本,只能处理数字,而Embedding模型能将文本的语义信息转换成向量,语义越相似的文本,向量距离越近。
-
常用Embedding模型:OpenAI的text-embedding-ada-002、开源的BGE、Sentence-BERT等。
-
核心逻辑:每个文本片段对应一个向量,向量的维度通常为768、1024等(维度越高,语义表示越精准,但存储和计算成本越高)。
-
-
向量存储(Vector Storage):将转换后的文本向量存储到"向量数据库"中,向量数据库能高效地进行"相似性检索"(根据用户问题的向量,快速找到最相似的文本向量对应的片段)。
- 常用向量数据库:Chroma(轻量、易上手,适合开发测试)、Pinecone(云端托管,适合生产环境)、Milvus(开源、高性能,适合大规模数据)。
2.2.2 检索生成阶段(在线响应,用户提问时执行)
核心目标:接收用户问题,从向量数据库中检索相关文本片段,再让大模型基于这些片段生成准确回答。
-
用户问题向量化:将用户的自然语言问题,通过和"文本分块向量化"相同的Embedding模型,转换成向量。
-
相似性检索:将用户问题的向量传入向量数据库,数据库会计算该向量与所有存储的文本向量的"相似度"(常用余弦相似度),返回相似度最高的N个文本片段(通常N=3-5,可调整)。
-
提示词构建:将检索到的N个文本片段,作为"上下文",结合用户问题,构建提示词(Prompt),引导大模型"仅基于上下文信息回答问题",避免幻觉。
-
大模型生成:将构建好的提示词传入大模型,大模型基于上下文信息,生成自然、准确的回答。
2.3 实操示例(基于LangChain+Chroma,可直接运行)
本次示例实现"企业文档问答"功能,步骤:加载PDF文档→分块→向量化→存储→检索→生成回答,全程可复用。
前提:安装依赖包 pip install langchain langchain-openai langchain-community chromadb pypdf,配置OpenAI API Key(用于Embedding和大模型调用)。
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.document_loaders import PyPDFLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.prompts import ChatPromptTemplate
# 1. 配置模型(Embedding模型+大模型)
embeddings = OpenAIEmbeddings(api_key="你的API_KEY")
llm = ChatOpenAI(
model="gpt-3.5-turbo",
temperature=0.1, # 低温度,保证回答准确
api_key="你的API_KEY"
)
# 2. 文档加载(加载企业PDF文档,替换为你的文档路径)
loader = PyPDFLoader("企业产品手册.pdf")
documents = loader.load() # 加载文档,返回Document对象列表
# 3. 文本分块
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 每个片段500 Token
chunk_overlap=50, # 重叠50 Token,避免上下文断裂
length_function=len # 按字符长度计算
)
splits = text_splitter.split_documents(documents) # 分块后的文本片段列表
# 4. 向量存储(将分块后的文本向量化,存入Chroma向量库)
vectorstore = Chroma.from_documents(
documents=splits,
embedding=embeddings,
persist_directory="./chroma_db" # 向量库存储路径,可持久化
)
vectorstore.persist() # 持久化向量库,避免每次重新生成
# 5. 构建检索器(用于相似性检索)
retriever = vectorstore.as_retriever(
search_kwargs={"k": 3} # 检索相似度最高的3个片段
)
# 6. 构建提示词模板(引导模型基于检索到的上下文回答)
prompt = ChatPromptTemplate.from_messages([
("system", "你是企业产品顾问,仅基于以下提供的文档内容回答用户问题,不要添加任何额外信息,若文档中没有相关内容,回复'暂无相关信息'。"),
("user", "用户问题:{input}\n\n参考文档:{context}")
])
# 7. 构建RAG链(检索+生成一体化)
combine_docs_chain = create_stuff_documents_chain(llm, prompt)
rag_chain = create_retrieval_chain(retriever, combine_docs_chain)
# 8. 接收用户问题,执行检索生成
user_question = "我们公司的产品A有哪些核心功能?"
response = rag_chain.invoke({"input": user_question})
# 输出结果
print("用户问题:", user_question)
print("检索到的相关片段:")
for i, doc in enumerate(response["context"]):
print(f"{i+1}. {doc.page_content}")
print("最终回答:", response["answer"])
运行结果说明:
-
程序会加载指定的PDF文档,分块后向量化存入Chroma向量库;
-
接收用户问题"我们公司的产品A有哪些核心功能?",将问题向量化后,从向量库中检索3个最相关的文本片段;
-
大模型基于这3个片段,生成关于产品A核心功能的回答,全程不依赖模型自身知识库,避免幻觉。
2.4 优点与缺点
优点(核心优势)
-
通用型强:适配所有非结构化文本,无需对数据进行特殊处理,落地成本低;
-
实现简单:流程清晰(分块→向量化→存储→检索→生成),有成熟的框架(LangChain、LlamaIndex)支持,新手可快速上手;
-
性价比高:无需复杂的技术架构,轻量部署即可满足大多数文档问答场景;
-
兼容性强:可与任何大模型(闭源+开源)配合使用,灵活度高。
缺点(核心局限)
-
不懂逻辑关系:仅能基于"文本相似度"检索,无法理解文本中实体之间的关系(如"张三和李四在哪些项目有合作");
-
多跳问题表现差:无法处理多跳推理问题(如"张三的上级是谁?该上级负责的项目有哪些?"),只能检索单一段落的信息;
-
易误召回:当文本中存在相似关键词但语义不同时,容易检索到不相关的片段(如"苹果手机"和"苹果水果");
-
无法处理结构化数据:只能对接非结构化文本,无法直接查询数据库、Excel等结构化数据。
2.5 适用场景
普通RAG因其通用性和简单性,是企业最常用的检索增强方案,核心适用场景包括:
-
企业文档问答:如员工查询产品手册、规章制度、操作指南等;
-
客服场景:客服智能体检索FAQ文档,回答用户常见问题(如"如何办理退款");
-
资料查询:如科研人员检索论文、学生检索学习资料、程序员检索技术文档;
-
轻量级知识库:无需复杂推理,仅需基于文本片段回答事实类、描述类问题的场景。
第三章:GraphRAG------懂关系、能推理的高级检索增强方案
3.1 核心定义
GraphRAG(Graph Retrieval-Augmented Generation,图检索增强生成),是在普通RAG基础上的升级方案,核心是将非结构化文本转换为结构化的"知识图谱",再基于知识图谱的"实体关系"进行检索与推理,最后结合大模型生成回答。
普通RAG"查文本片段",而GraphRAG"查实体关系"------知识图谱由"实体"(人、公司、产品、项目等)和"关系"(A就职于B、A和B合作、A属于B等)组成,能清晰地呈现实体之间的逻辑关联,从而解决普通RAG"不懂关系、无法推理"的痛点。
一句话总结:GraphRAG = 文本实体关系抽取 + 知识图谱构建 + 图检索 + 大模型推理生成,核心是"找实体之间的逻辑关系"。
3.2 核心技术原理(超详细拆解)
GraphRAG的实现流程比普通RAG更复杂,增加了"实体关系抽取"和"知识图谱构建"两个核心步骤,整体分为"构建阶段"和"检索推理阶段":
3.2.1 构建阶段(离线准备,核心是构建知识图谱)
-
文档加载与文本分块:与普通RAG一致,加载非结构化文本(PDF、文档等),并分割成合适的文本片段。
-
实体关系抽取(核心步骤):从分块后的文本片段中,提取出"实体"和"实体之间的关系",这是GraphRAG的核心难点。
-
实体:指文本中具有明确含义的对象,如"张三""腾讯公司""产品A""2025年";
-
关系:指实体之间的关联,如"张三-任职于-腾讯公司""产品A-属于-腾讯公司""张三-负责-项目B";
-
抽取方式:
-
基于大模型抽取:用GPT、Qwen等大模型,通过提示词引导,从文本中提取实体和关系(最常用、最灵活);
-
基于规则抽取:针对特定领域(如金融、医疗),制定规则(如"XX公司-收购-XX公司"),提取关系;
-
基于开源模型抽取:用专门的实体关系抽取模型(如BERT-based模型),实现批量抽取。
-
-
-
知识图谱构建:将抽取到的"实体"和"关系",存储到"图数据库"中,构建知识图谱。
-
图数据库:与普通的关系型数据库(MySQL)、向量数据库不同,图数据库专门用于存储"实体-关系-实体"的网络结构,支持高效的关系查询和多跳推理;
-
常用图数据库:Neo4j(最主流、易用,适合企业级落地)、NebulaGraph(开源、高性能)、ArangoDB;
-
知识图谱结构示例:实体(张三)→ 关系(任职于)→ 实体(腾讯公司);实体(腾讯公司)→ 关系(推出)→ 实体(产品A)。
-
-
知识图谱优化:对构建好的知识图谱进行清洗和优化,包括去重(删除重复的实体和关系)、补全(补充缺失的关系)、纠错(修正错误的实体和关系),确保知识图谱的准确性。
3.2.2 检索推理阶段(在线响应,核心是图检索与多跳推理)
-
用户问题解析:将用户的自然语言问题,解析成"实体+关系"的查询意图。例如,用户问"张三负责的项目有哪些?",解析后得到:实体(张三)、关系(负责)、目标实体(项目)。
-
图检索(核心步骤):基于解析后的查询意图,在图数据库中检索相关的"实体-关系"路径,包括单跳关系和多跳关系。
-
单跳检索:如"张三-任职于-腾讯公司"(直接查询两个实体之间的关系);
-
多跳检索:如"张三-负责-项目B"→"项目B-属于-腾讯公司"(查询三个及以上实体之间的关联路径)。
-
-
推理增强:将检索到的"实体-关系"路径,整理成结构化的上下文,结合用户问题,引导大模型进行推理,生成准确的回答。例如,检索到"张三-负责-项目B""项目B-属于-腾讯公司""项目B-启动时间-2025年1月",大模型可推理出"张三负责腾讯公司2025年1月启动的项目B"。
-
大模型生成:基于图检索到的关系路径和推理结果,生成自然、连贯的回答,同时可返回相关的实体关系路径,让回答"可追溯"。
3.3 实操示例(基于LangChain+Neo4j,可直接运行)
本次示例实现"企业人员关系查询"功能,步骤:加载文档→抽取实体关系→构建知识图谱→图检索→推理生成,重点展示GraphRAG的核心流程。
前提:安装依赖包 pip install langchain langchain-openai neo4j python-dotenv,安装Neo4j图数据库(本地或云端),配置OpenAI API Key和Neo4j连接信息。
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.graphs import Neo4jGraph
from dotenv import load_dotenv
import os
# 1. 加载环境变量(API Key + Neo4j连接信息)
load_dotenv()
openai_api_key = os.getenv("OPENAI_API_KEY")
neo4j_uri = os.getenv("NEO4J_URI")
neo4j_user = os.getenv("NEO4J_USER")
neo4j_password = os.getenv("NEO4J_PASSWORD")
# 2. 配置大模型(用于实体关系抽取和生成回答)
llm = ChatOpenAI(
model="gpt-3.5-turbo",
temperature=0.1,
api_key=openai_api_key
)
# 3. 文档加载与分块(加载企业人员介绍文档)
loader = TextLoader("企业人员介绍.txt")
documents = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=300, chunk_overlap=50)
splits = text_splitter.split_documents(documents)
# 4. 实体关系抽取(提示词引导大模型抽取)
# 定义抽取提示词
extract_prompt = ChatPromptTemplate.from_messages([
("system", "你是实体关系抽取专家,从以下文本中提取实体和关系,实体包括人员、公司、项目,关系包括任职于、负责、合作等。输出格式:实体1-关系-实体2,每个关系一行,不要添加额外文本。"),
("user", "文本:{text}")
])
# 构建抽取链
extract_chain = extract_prompt | llm
# 批量抽取实体关系
relations = []
for doc in splits:
response = extract_chain.invoke({"text": doc.page_content})
# 解析输出,提取实体关系对
for line in response.content.strip().split("\n"):
if "-" in line:
relations.append(line.strip())
print("抽取到的实体关系:", relations)
# 5. 连接Neo4j图数据库,构建知识图谱
graph = Neo4jGraph(
url=neo4j_uri,
username=neo4j_user,
password=neo4j_password
)
# 清空现有数据(开发测试用,生产环境注释)
graph.query("MATCH (n) DETACH DELETE n")
# 将实体关系导入Neo4j(创建节点和关系)
for relation in relations:
entity1, rel, entity2 = relation.split("-", 2)
# 创建实体节点(若不存在)
graph.query(f"MERGE (a:Entity {{name: '{entity1}'}})")
graph.query(f"MERGE (b:Entity {{name: '{entity2}'}})")
# 创建实体之间的关系
graph.query(f"MATCH (a:Entity {{name: '{entity1}'}}), (b:Entity {{name: '{entity2}'}}) MERGE (a)-[:{rel.upper()}]->(b)")
print("知识图谱构建完成!")
# 6. 图检索与推理生成
# 定义图检索提示词(引导模型生成Cypher查询语句)
graph_prompt = ChatPromptTemplate.from_messages([
("system", "你是Neo4j Cypher查询专家,根据用户问题,生成对应的Cypher查询语句,用于查询知识图谱中的实体关系。不要添加任何解释,仅输出Cypher语句。"),
("user", "用户问题:{question}\n知识图谱实体类型:人员、公司、项目;关系类型:任职于、负责、合作。")
])
# 构建图检索链
graph_chain = graph_prompt | llm
# 定义生成回答的提示词
answer_prompt = ChatPromptTemplate.from_messages([
("system", "你是企业人员关系顾问,基于以下知识图谱查询结果,用自然语言回答用户问题,确保逻辑清晰、准确。"),
("user", "用户问题:{question}\n查询结果:{context}")
])
# 构建生成链
answer_chain = answer_prompt | llm
# 7. 执行检索推理
user_question = "张三负责哪些项目?"
# 生成Cypher查询语句
cypher = graph_chain.invoke({"question": user_question}).content.strip()
print("生成的Cypher查询:", cypher)
# 执行Cypher查询,获取图检索结果
context = graph.query(cypher)
print("图检索结果:", context)
# 生成最终回答
final_answer = answer_chain.invoke({"question": user_question, "context": context})
print("最终回答:", final_answer.content)
运行结果说明:
-
程序加载企业人员介绍文档,分块后通过大模型抽取实体关系(如"张三-任职于-腾讯公司""张三-负责-项目B");
-
将实体关系导入Neo4j图数据库,构建知识图谱;
-
接收用户问题"张三负责哪些项目?",生成Cypher查询语句,从图数据库中检索相关关系;
-
大模型基于检索到的关系(如"张三-负责-项目B""张三-负责-项目C"),生成最终回答,实现多跳推理和关系查询。
3.4 优点与缺点
优点(核心优势)
-
擅长关系推理:能清晰理解实体之间的关联,完美解决普通RAG无法处理的多跳问题和关系查询问题;
-
回答更准确、可追溯:基于结构化的知识图谱检索,能明确回答"为什么"(如"张三负责项目B,因为张三-负责-项目B"),减少幻觉;
-
适配复杂场景:适合需要深度推理的领域(如金融风控、医疗问诊、企业知识管理);
-
知识结构化:将非结构化文本转换为结构化知识,便于后续的查询、分析和复用。
缺点(核心局限)
-
构建成本高:需要进行实体关系抽取、知识图谱构建和优化,技术门槛高,耗时耗力;
-
维护成本高:知识图谱需要实时更新(如新增员工、新项目),否则会出现知识过时;
-
不适合松散文本:对于无明确实体和关系的松散文本(如散文、随笔),抽取效果差,无法构建有效的知识图谱;
-
技术架构复杂:需要结合文本处理、实体抽取、图数据库、大模型等多种技术,部署和调试难度大。
3.5 适用场景
GraphRAG适合需要深度关系推理、结构化知识管理的场景,核心适用场景包括:
-
企业知识管理:如查询员工之间的协作关系、项目之间的关联、部门与产品的对应关系;
-
金融领域:如风控分析(查询企业的上下游风险主体、关联企业)、投资研究(分析企业之间的合作与竞争关系);
-
医疗领域:如梳理"症状-疾病-药物-医生"的关联关系,辅助问诊和医学研究;
-
科研领域:如梳理学术论文中的"作者-机构-研究方向-成果"关系,辅助科研检索;
-
多跳问答场景:任何需要"多步推理"才能回答的问题,如"张三的上级负责的项目有哪些?"。
第四章:NL2SQL------对接结构化数据库的检索增强方案
4.1 核心定义
NL2SQL(Natural Language to SQL,自然语言转SQL),是专门对接结构化数据库的检索增强技术,核心是"让大模型将用户的自然语言问题,自动转换为可执行的SQL语句,查询数据库后,将结果转换为自然语言回答"。
与普通RAG、GraphRAG不同,NL2SQL的数据源是"结构化数据"------即存储在MySQL、PostgreSQL、ClickHouse等关系型数据库中的数据(如订单数据、用户数据、财务数据),这些数据是企业业务的核心,也是普通RAG和GraphRAG无法直接处理的。
一句话总结:NL2SQL = 自然语言解析 + SQL生成 + SQL执行 + 结果格式化,核心是"让非技术人员用口语查数据库"。
4.2 核心技术原理(超详细拆解)
NL2SQL的核心难点是"将自然语言准确转换为符合数据库表结构的SQL语句",其实现流程分为"准备阶段"和"查询生成阶段":
4.2.1 准备阶段(离线准备,核心是让大模型了解数据库结构)
-
数据库结构梳理:整理数据库的表结构,包括表名、字段名、字段类型、字段含义、表之间的关联关系(如外键)。例如,订单表(order_table)包含字段:订单ID(order_id)、用户ID(user_id)、销售额(amount)、订单日期(order_date)、门店ID(store_id)。
-
表结构信息提供:将梳理好的表结构信息,以清晰的格式提供给大模型,让大模型了解"数据库里有什么表、每个表有什么字段、字段代表什么意思"------这是NL2SQL准确生成SQL的关键。
-
样例数据准备(可选):提供少量样例数据,让大模型更直观地理解字段的取值范围和数据格式(如订单日期的格式是YYYY-MM-DD,销售额是数字类型),提升SQL生成的准确率。
-
SQL语法适配:根据数据库类型(如MySQL、PostgreSQL),明确SQL语法规范(如limit和top的区别),让大模型生成符合对应数据库语法的SQL语句。
4.2.2 查询生成阶段(在线响应,核心是SQL生成与执行)
-
用户问题解析:将用户的自然语言问题,解析成"查询意图"和"查询条件"。例如,用户问"2025年1月销售额超100万的门店有哪些?",解析后得到:查询意图(查询门店)、查询条件(销售额>100万、订单日期在2025年1月)、目标字段(门店ID、门店名称)。
-
SQL生成(核心步骤):大模型结合"用户问题"和"数据库表结构信息",生成可执行的SQL语句。这一步的关键是"准确映射"------将自然语言中的"销售额超100万"映射为"amount > 1000000",将"2025年1月"映射为"order_date BETWEEN '2025-01-01' AND '2025-01-31'"。
-
SQL校验(可选,提升稳定性):对生成的SQL语句进行校验,检查语法是否正确、字段是否存在、表关联是否合理,避免SQL执行报错。若校验失败,让大模型重新生成SQL。
-
SQL执行:将校验通过的SQL语句,传入数据库中执行,获取查询结果(结构化数据,如表格)。
-
结果格式化:将数据库返回的结构化结果(如表格),转换为自然语言,生成流畅、易懂的回答。例如,将查询到的门店列表,整理为"2025年1月销售额超100万的门店有:门店1(销售额120万)、门店2(销售额150万)"。
4.3 实操示例(基于LangChain+MySQL,可直接运行)
本次示例实现"业务数据查询"功能,步骤:梳理数据库表结构→大模型生成SQL→执行SQL→格式化结果,对接MySQL数据库,模拟企业业务查询场景。
前提:安装依赖包 pip install langchain langchain-openai pymysql python-dotenv,安装MySQL数据库(本地或云端),创建订单表并插入测试数据,配置OpenAI API Key和MySQL连接信息。
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_community.utilities import SQLDatabase
from langchain.chains import create_sql_query_chain
from dotenv import load_dotenv
import os
# 1. 加载环境变量(API Key + MySQL连接信息)
load_dotenv()
openai_api_key = os.getenv("OPENAI_API_KEY")
mysql_host = os.getenv("MYSQL_HOST")
mysql_user = os.getenv("MYSQL_USER")
mysql_password = os.getenv("MYSQL_PASSWORD")
mysql_db = os.getenv("MYSQL_DB")
# 2. 连接MySQL数据库
db = SQLDatabase.from_uri(
f"mysql+pymysql://{mysql_user}:{mysql_password}@{mysql_host}:3306/{mysql_db}"
)
# 3. 配置大模型
llm = ChatOpenAI(
model="gpt-3.5-turbo",
temperature=0.1,
api_key=openai_api_key
)
# 4. 定义NL2SQL提示词(引导模型生成正确的SQL)
sql_prompt = ChatPromptTemplate.from_messages([
("system", """你是SQL生成专家,根据以下数据库表结构和用户问题,生成符合MySQL语法的SQL语句,注意:
1. 严格按照表结构中的字段名和表名生成SQL,不要使用不存在的字段或表名;
2. 处理日期格式:订单日期(order_date)格式为YYYY-MM-DD,查询时需正确使用日期范围;
3. 销售额(amount)单位为元,整数类型,查询时注意数值比较;
4. 只输出SQL语句,不要添加任何解释或额外文本;
5. 若用户问题中没有明确的查询条件,合理默认(如最近30天)。
数据库表结构:
表名:order_table(订单表)
字段:
- order_id: 订单ID(INT,主键)
- user_id: 用户ID(INT)
- amount: 销售额(INT,单位:元)
- order_date: 订单日期(DATE)
- store_id: 门店ID(INT)
- store_name: 门店名称(VARCHAR)
表名:user_table(用户表)
字段:
- user_id: 用户ID(INT,主键)
- user_name: 用户姓名(VARCHAR)
- user_phone: 用户电话(VARCHAR)
表关联:order_table.user_id = user_table.user_id
"""),
("user", "用户问题:{question}")
])
# 5. 构建NL2SQL链(生成SQL)
sql_chain = create_sql_query_chain(llm, db, prompt=sql_prompt)
# 6. 构建结果格式化链(将SQL查询结果转换为自然语言)
format_prompt = ChatPromptTemplate.from_messages([
("system", "你是业务数据分析师,将以下SQL查询结果转换为自然语言回答,要求简洁、清晰、易懂,突出关键信息,不要添加额外内容。"),
("user", "用户问题:{question}\nSQL查询结果:{context}")
])
format_chain = format_prompt | llm
# 7. 执行NL2SQL流程
user_question = "查询2025年1月销售额超100万的门店,显示门店名称和销售额"
# 生成SQL语句
sql = sql_chain.invoke({"question": user_question})
print("生成的SQL语句:", sql)
# 执行SQL,获取结果
context = db.run(sql)
print("SQL查询结果:", context)
# 格式化结果,生成最终回答
final_answer = format_chain.invoke({"question": user_question, "context": context})
print("最终回答:", final_answer.content)
运行结果说明:
-
程序连接MySQL数据库,获取订单表和用户表的结构信息;
-
接收用户问题"查询2025年1月销售额超100万的门店,显示门店名称和销售额",大模型生成对应的SQL语句;
-
执行SQL语句,从数据库中查询到符合条件的门店数据;
-
大模型将查询结果(结构化表格)转换为自然语言回答,如"2025年1月销售额超100万的门店有:门店A(销售额1200000元)、门店B(销售额1500000元)"。
4.4 优点与缺点
优点(核心优势)
-
直接对接业务数据:能直接查询企业核心业务数据库,获取实时、准确的业务数据,解决普通RAG无法处理结构化数据的痛点;
-
非技术友好:让非技术人员(如产品、运营、管理层)无需懂SQL,用口语就能查询数据,提升工作效率;
-
支持复杂查询:能生成包含过滤、分组、排序、关联查询等复杂SQL语句,满足数据分析需求(如"查询各门店2025年Q1的销售额增长率");
-
结果精准:基于数据库中的真实数据回答,无幻觉,可追溯(可查看生成的SQL语句和原始数据)。
缺点(核心局限)
-
对表结构依赖高:若表结构复杂(如多表关联、字段名称不直观),大模型容易生成错误的SQL语句;
-
无法处理模糊查询:对于"销售额较高的门店""最近一段时间的订单"等模糊问题,生成SQL的准确率会下降;
-
安全风险:若权限管控不当,可能导致用户查询到敏感数据(如用户手机号、密码);
-
需要领域知识:大模型需要了解业务领域的术语(如"客单价""复购率"),否则无法准确映射为对应的字段。
4.5 适用场景
NL2SQL是企业业务数据分析的核心工具,核心适用场景包括:
-
业务数据分析:产品、运营、管理层查询业务数据(如销售额、订单量、用户数、增长率);
-
智能客服:客服智能体查询用户订单、物流、退款等数据,回答用户问题(如"我的订单什么时候发货?");
-
报表自动生成:自动生成日报、周报、月报(如"生成上周各门店的销售额报表");
-
数据自助查询:企业内部员工自助查询所需数据,无需依赖数据分析师;
-
业务监控:实时查询关键业务指标(如"今天的实时销售额是多少"),辅助决策。
第五章:三大技术深度对比与选型建议(面试/开发重点)
5.1 核心对比表(超详细,面试直接用)
| 对比维度 | 普通RAG(向量RAG) | GraphRAG | NL2SQL |
|---|---|---|---|
| 核心定位 | 非结构化文本检索,找相似片段 | 知识图谱检索,找实体关系,多跳推理 | 结构化数据库检索,自然语言转SQL |
| 数据源类型 | 非结构化文本(PDF、Word、网页等) | 非结构化文本→结构化知识图谱 | 结构化数据库(MySQL、PostgreSQL等) |
| 检索方式 | 向量相似度检索 | 图检索(实体关系路径查询) | SQL查询 |
| 核心优势 | 通用、简单、落地成本低 | 擅长关系推理、多跳问答、可追溯 | 对接业务数据、实时准确、非技术友好 |
| 核心局限 | 不懂关系、多跳差、易误召回 | 构建/维护成本高、技术门槛高 | 依赖表结构、模糊查询差、有安全风险 |
| 常用工具/框架 | LangChain、LlamaIndex、Chroma、Pinecone | LangChain、Neo4j、NebulaGraph、实体关系抽取模型 | LangChain、SQLDatabase、大模型NL2SQL能力 |
| 技术门槛 | 低(新手可快速上手) | 高(需掌握知识图谱、实体抽取) | 中(需梳理表结构,优化SQL生成) |
| 适用场景 | 文档问答、客服FAQ、资料查询 | 企业知识管理、金融风控、医疗推理、多跳问答 | 业务数据分析、智能客服、报表生成、数据自助查询 |
| 工业落地难度 | 低(轻量部署,快速落地) | 高(复杂架构,维护成本高) | 中(需对接数据库,做权限管控) |
5.2 选型建议
三大技术并非对立,而是互补共生,实际项目中通常会组合使用,选型的核心是"匹配数据源类型和业务需求":
-
优先选普通RAG的情况:
-
数据源是非结构化文本(如文档、FAQ);
-
业务需求是事实类、描述类问答,无需复杂推理;
-
追求低成本、快速落地,技术门槛低。
-
-
优先选GraphRAG的情况:
-
业务需求涉及多跳推理、实体关系查询(如"谁和谁合作""某项目的负责人是谁");
-
需要构建结构化的企业知识库,实现知识的可追溯和深度复用;
-
预算充足、有专业的技术团队,能承担知识图谱的构建和维护成本。
-
-
优先选NL2SQL的情况:
-
数据源是结构化数据库(如订单表、用户表);
-
业务需求是业务数据分析、报表生成、实时数据查询;
-
需要让非技术人员自助查询数据,提升工作效率。
-
-
组合使用建议(企业级最佳实践):
-
用普通RAG处理通用文档问答(如产品手册、规章制度);
-
用GraphRAG处理企业知识关系查询(如员工、项目、部门关联);
-
用NL2SQL处理业务数据查询(如销售额、订单量);
-
通过LangChain等框架,将三者整合到一个智能体中,实现"一站式检索"------用户无需区分数据源,智能体自主判断用哪种技术检索。
-
第六章:总结
普通RAG、GraphRAG、NL2SQL 作为检索增强领域的三大核心技术,分别解决了大模型"无法处理非结构化文本""无法处理关系推理""无法处理结构化数据"的三大痛点,覆盖了企业绝大多数的数据源类型和业务需求。