AI大模型应用开发入门-LangChain开发RAG增强检索生成
检索增强生成(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增强检索生成的更多相关文章
- AI大模型学习了解
# 百度文心 上线时间:2019年3月 官方介绍:https://wenxin.baidu.com/ 发布地点: 参考资料: 2600亿!全球最大中文单体模型鹏城-百度·文心发布 # 华为盘古 上线时 ...
- [嵌入式开发入门]4412开发板从零建立Linux最小系统
本文转自iTOP-4412开发板实战教程书籍 http://www.topeetboard.com iTOP-4412开发板不仅可以运行Android,还可以运行简单的Linux最小文件系统. 最小L ...
- spring boot + vue + element-ui全栈开发入门——windows开发环境
一.node.js开发环境 windows系统,去网站https://nodejs.org/en/download/,下载对应的安装程序,并安装Windows Installer (.msi) 接下 ...
- 【Electron】Electron开发入门(六):项目生成setup安装程序
把electron发布的exe打包成setup安装程序,需要使用nsis软件, nsis打包的详细教程,可以参考我的这篇文章: win7下nsis打包exe安装程序教程
- 华为高级研究员谢凌曦:下一代AI将走向何方?盘古大模型探路之旅
摘要:为了更深入理解千亿参数的盘古大模型,华为云社区采访到了华为云EI盘古团队高级研究员谢凌曦.谢博士以非常通俗的方式为我们娓娓道来了盘古大模型研发的"前世今生",以及它背后的艰难 ...
- 【Electron】Electron开发入门
Electron简介: Electron提供了丰富的本地(操作系统)的API,使你能够使用纯JavaScript来创建桌面应用程序,并且跨平台(win,mac,linux等各种PC端平台).与其它各种 ...
- 【转载】Servlet Filter(过滤器)、Filter是如何实现拦截的、Filter开发入门
Servlet Filter(过滤器).Filter是如何实现拦截的.Filter开发入门 Filter简介 Filter也称之为过滤器,它是Servlet技术中最激动人心的技术,WEB开发人员通过F ...
- spring boot + vue + element-ui全栈开发入门——开篇
最近经常看到很多java程序员朋友还在使用Spring 3.x,Spring MVC(struts),JSP.jQuery等这样传统技术.其实,我并不认为这些传统技术不好,而我想表达的是,技术的新旧程 ...
- spring boot + vue + element-ui全栈开发入门——基于Electron桌面应用开发
前言 Electron是由Github开发,用HTML,CSS和JavaScript来构建跨平台桌面应用程序的一个开源库. Electron通过将Chromium和Node.js合并到同一个运行时环 ...
- spring boot + vue + element-ui全栈开发入门
今天想弄弄element-ui 然后就在网上找了个例子 感觉还是可以用的 第一步是完成了 果断 拿过来 放到我这里这 下面直接是连接 点进去 就可以用啊 本想着不用vue 直接导入连接 ...
随机推荐
- JavaScript 图片弹窗
html <!-- 触发弹窗 - 图片改为你的图片地址 --> <img loading="lazy" id="myImg" src=&quo ...
- 几个技巧,教你去除文章的 AI 味!
最近有不少朋友在利用 AI 写毕业设计论文,几秒钟一篇文章就刷出来的,爽的飞起. 结果万万没想到,人家论文查重服务也升级了,是不是用 AI 写的论文大概率都能被查出来... 这可如何是好啊?救救我救救 ...
- 2D小游戏--猜对应卡牌(unity)
博客地址:https://www.cnblogs.com/zylyehuo/ 项目名称 guess_card_game 参考源码链接: https://www.manning.com/books/un ...
- Linux 下如何修改密码有效期?
有时我们连接远程服务器的时候,提示密码过期,需要修改密码才能登录,这时可以用chage命令来调整下用户密码的有效期,使用户可以继续使用. chage命令 chage命令用于查看以及修改用户密码的有效期 ...
- Hack The Box-Chemistry靶机渗透
通过信息收集访问5000端口,cif历史cve漏洞反弹shell,获取数据库,利用低权限用户登录,监听端口,开放8080端口,aihttp服务漏洞文件包含,获取root密码hash值,ssh指定登录 ...
- 泛型--java进阶day10
1.泛型 2.泛型--统一数据类型 如下图,当我们在泛型中添加不同的数据类型,add方法需要的数据类型也随之改变 [1] [2] 泛型--默认类型object 当我们不指定泛型时,泛型的默认类型为ob ...
- 【Python】Flask API 登录
Flask API 登录 零.起因 最近要写uniapp客户端,服务器使用的是Python的Flask框架,为了实现用户登录,在网上查到了一些Flask的扩展,其中比较简单的就是flask_httpa ...
- JMeter用例数据分离
1.编写接口用例文件 新建csv文件,以查询用户财富值和时长接口为例 参数说明: ${caseSeq}:用例编号 ${apiType}:api类型 ${apiSeq}:api版本号 ${apiName ...
- CyclicBarrier的await()方法底层原理
一.定义 CyclicBarrier 的 await() 方法是其核心功能之一,用于让线程在屏障点等待,直到所有参与的线程都到达屏障后,才能继续执行. 其底层实现依赖于 AQS(AbstractQue ...
- Mybatis的关联关系的配置
例子1. <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC &qu ...