检索增强生成(RAG)是一种结合“向量检索”与“大语言模型”的技术路线,能在问答、摘要、文档分析等场景中大幅提升准确性与上下文利用率。

本文将基于 LangChain 构建一个完整的 RAG 流程,结合 PGVector 作为向量数据库,并用 LangGraph 构建状态图控制流程。

大语言模型初始化(llm_env.py)

我们首先使用 LangChain 提供的模型初始化器加载 gpt-4o-mini 模型,供后续问答使用。

# llm_env.py
from langchain.chat_models import init_chat_model llm = init_chat_model("gpt-4o-mini", model_provider="openai")

RAG 主体流程(rag.py)

以下是整个 RAG 系统的主流程代码,主要包括:文档加载与切分、向量存储、状态图建模(analyze→retrieve→generate)、交互式问答。

# rag.py
import os
import sys
import time sys.path.append(os.getcwd()) from llm_set import llm_env
from langchain_openai import OpenAIEmbeddings
from langchain_postgres import PGVector
from langchain_community.document_loaders import WebBaseLoader
from langchain_core.documents import Document
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langgraph.graph import START, StateGraph
from typing_extensions import List, TypedDict, Annotated
from typing import Literal
from langgraph.checkpoint.postgres import PostgresSaver
from langgraph.graph.message import add_messages
from langchain_core.messages import HumanMessage, BaseMessage
from langchain_core.prompts import ChatPromptTemplate # 初始化 LLM
llm = llm_env.llm # 嵌入模型
embeddings = OpenAIEmbeddings(model="text-embedding-3-large") # 向量数据库初始化
vector_store = PGVector(
embeddings=embeddings,
collection_name="my_rag_docs",
connection="postgresql+psycopg2://postgres:123456@localhost:5433/langchainvector",
) # 加载网页内容
url = "https://python.langchain.com/docs/tutorials/qa_chat_history/"
loader = WebBaseLoader(web_paths=(url,))
docs = loader.load()
for doc in docs:
doc.metadata["source"] = url # 文本分割
text_splitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=50)
all_splits = text_splitter.split_documents(docs) # 添加 section 元数据
total_documents = len(all_splits)
third = total_documents // 3
for i, document in enumerate(all_splits):
if i < third:
document.metadata["section"] = "beginning"
elif i < 2 * third:
document.metadata["section"] = "middle"
else:
document.metadata["section"] = "end" # 检查是否已存在向量
existing = vector_store.similarity_search(url, k=1, filter={"source": url})
if not existing:
_ = vector_store.add_documents(documents=all_splits)
print("文档向量化完成")

分析、检索与生成模块

接下来,我们定义三个函数构成 LangGraph 的流程:analyze → retrieve → generate。

class Search(TypedDict):
query: Annotated[str, "The question to be answered"]
section: Annotated[
Literal["beginning", "middle", "end"],
...,
"Section to query.",
] class State(TypedDict):
messages: Annotated[list[BaseMessage], add_messages]
query: Search
context: List[Document]
answer: set # 分析意图 → 获取 query 与 section
def analyze(state: State):
structtured_llm = llm.with_structured_output(Search)
query = structtured_llm.invoke(state["messages"])
return {"query": query} # 相似度检索
def retrieve(state: State):
query = state["query"]
if hasattr(query, 'section'):
filter = {"section": query["section"]}
else:
filter = None
retrieved_docs = vector_store.similarity_search(query["query"], filter=filter)
return {"context": retrieved_docs}

生成模块基于 ChatPromptTemplate 和当前上下文生成回答:

prompt_template = ChatPromptTemplate.from_messages(
[
("system", "尽你所能按照上下文:{context},回答问题:{question}。"),
]
) def generate(state: State):
docs_content = "\n\n".join(doc.page_content for doc in state["context"])
messages = prompt_template.invoke({
"question": state["query"]["query"],
"context": docs_content,
})
response = llm.invoke(messages)
return {"answer": response.content, "messages": [response]}

构建 LangGraph 流程图

定义好状态结构后,我们构建 LangGraph

graph_builder = StateGraph(State).add_sequence([analyze, retrieve, generate])
graph_builder.add_edge(START, "analyze")

PG 数据库中保存中间状态(Checkpoint)

我们通过 PostgresSaver 记录每次对话的中间状态:

DB_URI = "postgresql://postgres:123456@localhost:5433/langchaindemo?sslmode=disable"

with PostgresSaver.from_conn_string(DB_URI) as checkpointer:
checkpointer.setup()
graph = graph_builder.compile(checkpointer=checkpointer)
input_thread_id = input("输入thread_id:")
time_str = time.strftime("%Y%m%d", time.localtime())
config = {"configurable": {"thread_id": f"rag-{time_str}-demo-{input_thread_id}"}} print("输入问题,输入 exit 退出。")
while True:
query = input("你: ")
if query.strip().lower() == "exit":
break
input_messages = [HumanMessage(query)]
response = graph.invoke({"messages": input_messages}, config=config)
print(response["answer"])

效果

总结

本文通过 LangChain 的模块式能力,结合 PGVector 向量库与 LangGraph 有状态控制系统,实现了一个可交互、可持久化、支持多文档结构的 RAG 系统。其优势包括:

  • 支持结构化提问理解(分区查询)

  • 自动化分段与元数据标记

  • 状态流追踪与恢复

  • 可拓展支持文档上传、缓存优化、多用户配置

AI大模型应用开发入门-LangChain开发RAG增强检索生成的更多相关文章

  1. AI大模型学习了解

    # 百度文心 上线时间:2019年3月 官方介绍:https://wenxin.baidu.com/ 发布地点: 参考资料: 2600亿!全球最大中文单体模型鹏城-百度·文心发布 # 华为盘古 上线时 ...

  2. [嵌入式开发入门]4412开发板从零建立Linux最小系统

    本文转自iTOP-4412开发板实战教程书籍 http://www.topeetboard.com iTOP-4412开发板不仅可以运行Android,还可以运行简单的Linux最小文件系统. 最小L ...

  3. spring boot + vue + element-ui全栈开发入门——windows开发环境

     一.node.js开发环境 windows系统,去网站https://nodejs.org/en/download/,下载对应的安装程序,并安装Windows Installer (.msi) 接下 ...

  4. 【Electron】Electron开发入门(六):项目生成setup安装程序

    把electron发布的exe打包成setup安装程序,需要使用nsis软件, nsis打包的详细教程,可以参考我的这篇文章: win7下nsis打包exe安装程序教程

  5. 华为高级研究员谢凌曦:下一代AI将走向何方?盘古大模型探路之旅

    摘要:为了更深入理解千亿参数的盘古大模型,华为云社区采访到了华为云EI盘古团队高级研究员谢凌曦.谢博士以非常通俗的方式为我们娓娓道来了盘古大模型研发的"前世今生",以及它背后的艰难 ...

  6. 【Electron】Electron开发入门

    Electron简介: Electron提供了丰富的本地(操作系统)的API,使你能够使用纯JavaScript来创建桌面应用程序,并且跨平台(win,mac,linux等各种PC端平台).与其它各种 ...

  7. 【转载】Servlet Filter(过滤器)、Filter是如何实现拦截的、Filter开发入门

    Servlet Filter(过滤器).Filter是如何实现拦截的.Filter开发入门 Filter简介 Filter也称之为过滤器,它是Servlet技术中最激动人心的技术,WEB开发人员通过F ...

  8. spring boot + vue + element-ui全栈开发入门——开篇

    最近经常看到很多java程序员朋友还在使用Spring 3.x,Spring MVC(struts),JSP.jQuery等这样传统技术.其实,我并不认为这些传统技术不好,而我想表达的是,技术的新旧程 ...

  9. spring boot + vue + element-ui全栈开发入门——基于Electron桌面应用开发

     前言 Electron是由Github开发,用HTML,CSS和JavaScript来构建跨平台桌面应用程序的一个开源库. Electron通过将Chromium和Node.js合并到同一个运行时环 ...

  10. spring boot + vue + element-ui全栈开发入门

    今天想弄弄element-ui  然后就在网上找了个例子 感觉还是可以用的  第一步是完成了  果断 拿过来  放到我这里这  下面直接是连接  点进去 就可以用啊 本想着不用vue   直接导入连接 ...

随机推荐

  1. Qt Creator下使用Qt Console Application打印中文

    Qt对中文的支持一直不好,本人研究了其在控制台下显示中文的方法,直接上步骤: 1.首先创建Qt Console Application工程(本人用的是Qt5.10版本),然后点击 菜单栏->编辑 ...

  2. 归并排序(递归)(NB)

    博客地址:https://www.cnblogs.com/zylyehuo/ 递归思路 # _*_coding:utf-8_*_ import random def merge(li, low, mi ...

  3. oracle服务 linux启动命令

    一.Linux下启动Oracle Linux下启动Oracle分为两步: 1)启动监听: 2)启动数据库实例: 1.登录服务器,切换到oracle用户,或者以oracle用户登录 [admin@dat ...

  4. 网络编程-关闭连接(1)-C/C++相关系统调用

    背景 在linux网络编程中,经常需要编写关闭socket的代码,比如心跳检测失败需要关闭重连:网络报异常需要关闭重连.但究竟关闭操作做了什么,却不太清楚.目前项目使用Netty框架来实现的网络编程, ...

  5. 阿里云ECS下安装的MySQL无法远程连接?

    场景重现 在阿里云ECS下, Ubuntu系统上通过以下命令安装的MySQL数据库, 本地连接正常, 但远程死活连接不上. # 安装MySQL apt-get install mysql-server ...

  6. ASP.NET Core 项目归档

    把一些基于 ASP.NET Core 的实用项目找个地方记录下... 项目列表: IdentityServer

  7. cannot resolve unit......

    Just disable Error Insight (Tools -> Options -> Editor Options -> Code Insight, uncheck Err ...

  8. mybatis的输入参数类型

    一.传递简单数据类型 二.传入一个bean对象 三.传入一个包装对象(对象中存放对象)

  9. MySQL 中的索引数量是否越多越好?为什么?

    MySQL 中的索引数量是否越多越好?为什么? 虽然索引能够提高查询性能,但并不是索引越多越好.索引数量过多会带来一定的负面影响,尤其是在写操作频繁的场景下.需要根据实际的查询需求来合理设计索引,以平 ...

  10. 使用Tortoise-ORM和FastAPI构建评论系统

    title: 使用Tortoise-ORM和FastAPI构建评论系统 date: 2025/04/25 21:37:36 updated: 2025/04/25 21:37:36 author: c ...