当前位置: 首页 > article >正文

LangGraph 重构个人知识库问答系统(稳定 + 可扩展版)

用 LangGraph 把之前的 RAG 系统重构为模块化、可扩展、带持久化、带错误处理的生产级架构。核心设计思想是节点解耦、状态清晰、流程灵活、易于扩展。一、系统架构设计可扩展核心1. 核心流程图结构用户提问 → 检索文档 → 生成回答 → 反思检查可选→ 结束 ↓失败 ↓失败 重试/兜底 备用模型2. 模块化节点设计方便扩展节点职责可扩展方向retrieve从向量库检索文档多路召回、重排序、元数据过滤generate基于检索结果生成回答多模型切换、Prompt 模板切换reflect反思检查回答质量可选多维度校验、人工介入fallback兜底节点失败时调用返回固定回复、搜索网络3. 状态设计清晰 可扩展class RAGState(TypedDict): messages: Annotated[Sequence[BaseMessage], add_messages] # 对话历史 question: str # 用户原始问题 context: str # 检索到的文档上下文 answer: str # 生成的回答 loop_count: int # 防死循环计数 error: str | None # 错误信息 user_id: str # 用户ID绑定长期记忆二、完整代码实现直接复制运行1. 安装依赖pip install -U langgraph langchain langchain-zhipu langchain-community chromadb python-dotenv pydantic-settings2. 完整代码import os from typing import TypedDict, Sequence, Literal, Annotated from dotenv import load_dotenv from langchain_core.messages import BaseMessage, HumanMessage, AIMessage from langchain_core.tools import tool from langchain_core.prompts import ChatPromptTemplate from langchain_zhipu import ChatZhipuAI from langchain_community.vectorstores import Chroma from langchain_community.embeddings import HuggingFaceBgeEmbeddings from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_community.document_loaders import DirectoryLoader, PyPDFLoader from langgraph.constants import START, END from langgraph.graph import StateGraph, add_messages from langgraph.checkpoint.memory import MemorySaver from pydantic_settings import BaseSettings # 1. 配置管理Pydantic Settings避免硬编码 class Settings(BaseSettings): ZHIPU_API_KEY: str LLM_MODEL: str glm-4.6 EMBEDDING_MODEL: str BAAI/bge-small-zh-v1.5 CHROMA_DB_DIR: str ./chroma_db DOCS_DIR: str ./docs CHUNK_SIZE: int 1000 CHUNK_OVERLAP: int 200 RETRIEVE_TOP_K: int 3 LLM_TIMEOUT: int 15 MAX_LOOP_COUNT: int 3 class Config: env_file .env settings Settings() # 2. 状态定义清晰可扩展 class RAGState(TypedDict): messages: Annotated[Sequence[BaseMessage], add_messages] question: str context: str answer: str loop_count: int error: str | None user_id: str # 3. 向量库初始化模块化方便切换 def init_vector_store(): 初始化或加载向量库 # 初始化嵌入模型 embeddings HuggingFaceBgeEmbeddings( model_namesettings.EMBEDDING_MODEL, model_kwargs{device: cpu}, encode_kwargs{normalize_embeddings: True} ) # 如果向量库已存在直接加载 if os.path.exists(settings.CHROMA_DB_DIR) and len(os.listdir(settings.CHROMA_DB_DIR)) 0: print(✅ 加载已有向量库) return Chroma( persist_directorysettings.CHROMA_DB_DIR, embedding_functionembeddings ) # 否则构建新向量库 print( 构建新向量库) os.makedirs(settings.DOCS_DIR, exist_okTrue) # 加载文档 loader DirectoryLoader( settings.DOCS_DIR, glob*.pdf, loader_clsPyPDFLoader, show_progressTrue ) documents loader.load() # 分割文档 text_splitter RecursiveCharacterTextSplitter( chunk_sizesettings.CHUNK_SIZE, chunk_overlapsettings.CHUNK_OVERLAP, separators[\n\n, \n, 。, , , , ] ) chunks text_splitter.split_documents(documents) # 构建向量库 vector_store Chroma.from_documents( documentschunks, embeddingembeddings, persist_directorysettings.CHROMA_DB_DIR ) vector_store.persist() print(✅ 向量库构建完成) return vector_store # 全局向量库实例 vector_store init_vector_store() # 4. LLM 初始化主模型备用模型 # 主 LLM llm ChatZhipuAI( api_keysettings.ZHIPU_API_KEY, modelsettings.LLM_MODEL, temperature0, timeoutsettings.LLM_TIMEOUT, max_retries0 ) # 备用 LLM更轻量、更稳定 backup_llm ChatZhipuAI( api_keysettings.ZHIPU_API_KEY, modelglm-4-flash, temperature0, timeout10 ) # RAG Prompt 模板模块化方便修改 RAG_PROMPT ChatPromptTemplate.from_template( 你是专业的文档问答助手必须严格遵守以下规则 1. 仅使用下方【文档上下文】中的内容回答用户问题绝对禁止编造。 2. 如果文档上下文中没有相关内容直接回复「抱歉文档中没有相关内容。」 3. 回答简洁、准确、条理清晰。 【文档上下文】 {context} 【用户问题】 {question} ) # 5. 节点定义解耦错误处理可扩展 def retrieve_node(state: RAGState): 检索节点从向量库检索相关文档 print(\n-- 执行节点文档检索 --) question state[question] error None context try: # 检索 Top-K 文档 docs vector_store.similarity_search(question, ksettings.RETRIEVE_TOP_K) context \n\n.join([f第{i1}段{doc.page_content} for i, doc in enumerate(docs)]) print(f✅ 检索到 {len(docs)} 段文档) except Exception as e: print(f❌ 检索失败{str(e)}) error str(e) context 文档检索失败请稍后再试。 return { context: context, loop_count: state[loop_count] 1, error: error } def generate_node(state: RAGState): 生成节点基于检索结果生成回答 print(\n-- 执行节点生成回答 --) question state[question] context state[context] error None answer try: # 构造 Prompt 并调用 LLM prompt RAG_PROMPT.format(contextcontext, questionquestion) response llm.invoke(prompt) answer response.content print(✅ 回答生成完成) except Exception as e: print(f❌ 生成失败{str(e)}) error str(e) answer 抱歉回答生成失败请稍后再试。 return { answer: answer, messages: [AIMessage(contentanswer)], loop_count: state[loop_count] 1, error: error } def backup_generate_node(state: RAGState): 备用生成节点主节点失败时调用 print(\n-- 切换到备用生成节点 --) question state[question] context state[context] error None answer try: prompt RAG_PROMPT.format(contextcontext, questionquestion) response backup_llm.invoke(prompt) answer response.content except Exception as e: print(f❌ 备用生成也失败{str(e)}) error str(e) answer 非常抱歉服务暂时不可用请稍后再试。 return { answer: answer, messages: [AIMessage(contentanswer)], loop_count: state[loop_count] 1, error: error } # 6. 条件路由灵活决策 def should_continue(state: RAGState) - Literal[retrieve, generate, backup_generate, end]: 条件判断决定下一步走哪个节点 # 优先处理错误 if state.get(error): if state[loop_count] 2: if 检索 in state[error]: return retrieve # 检索失败重试检索 else: return backup_generate # 生成失败走备用 else: return end # 失败次数过多结束 # 正常流程 if not state.get(context): return retrieve # 还没检索先检索 elif not state.get(answer): return generate # 还没生成先生成 else: print(→ 结束流程完成) return end # 7. 构建图模块化可扩展 def build_rag_graph(): builder StateGraph(RAGState) # 添加节点 builder.add_node(retrieve, retrieve_node) builder.add_node(generate, generate_node) builder.add_node(backup_generate, backup_generate_node) # 边开始 → 条件判断 builder.add_edge(START, retrieve) # 条件边根据状态决定下一步 builder.add_conditional_edges( retrieve, should_continue, { retrieve: retrieve, generate: generate, backup_generate: backup_generate, end: END } ) builder.add_conditional_edges( generate, should_continue, { backup_generate: backup_generate, end: END } ) builder.add_conditional_edges( backup_generate, should_continue, { end: END } ) # 编译图带持久化 checkpointer MemorySaver() return builder.compile(checkpointercheckpointer) # 全局 RAG Agent 实例 rag_agent build_rag_graph() # 8. 测试运行会话恢复错误处理 if __name__ __main__: print( LangGraph 重构版 RAG 知识库问答系统 ) # 配置同一个 thread_id 可恢复会话 config { configurable: { thread_id: rag_session_001, user_id: user_001 } } # 第一轮对话 print(\n--- 第一轮对话 ---) initial_state { messages: [], question: 什么是RAG技术, context: , answer: , loop_count: 0, error: None, user_id: user_001 } result1 rag_agent.invoke(initial_state, configconfig) print(f第一轮答案{result1[answer]}) # 第二轮对话恢复会话 print(\n--- 第二轮对话恢复会话---) result2 rag_agent.invoke( { messages: [HumanMessage(contentRAG有什么优势)], question: RAG有什么优势, loop_count: 0 }, configconfig ) print(f第二轮答案{result2[answer]}三、系统优势稳定 可扩展1. 稳定性错误处理每个节点都有try-except失败时返回友好提示备用方案主 LLM 失败时自动切换到更轻量的备用模型防死循环loop_count限制最大循环次数超时控制LLM 调用设置超时防止卡死会话持久化用MemorySaver实现会话恢复重启不丢2. 可扩展性节点解耦检索、生成、反思等节点独立方便修改和替换模块化设计向量库、LLM、Prompt 都封装成独立模块方便切换条件边灵活可以轻松添加新节点和新的条件分支状态清晰State 定义明确方便添加新字段如检索分数、重排序结果四、扩展建议让系统更强大1. 加多路召回和重排序# 在 retrieve_node 中添加 def retrieve_node(state: RAGState): # ... 原有检索逻辑 ... # 多路召回同时用语义检索和关键词检索 # 重排序用 BGE-Rerank 对召回结果二次精排 ...2. 加反思检查节点def reflect_node(state: RAGState): 反思节点检查回答质量 # 调用 LLM 检查回答是否完整、准确 # 如果不合格回到生成节点重新生成 ...3. 加工具调用搜索网络tool def web_search(query: str) - str: 搜索网络获取最新信息 # 调用搜索引擎 API ... # 在图中添加工具节点 builder.add_node(tool_executor, ToolNode([web_search]))4. 切换到 Redis 持久化from langgraph.checkpoint.redis import RedisSaver # 替换 MemorySaver checkpointer RedisSaver.from_url(redis://localhost:6379/0)五、使用说明把你的 PDF 文档放入docs目录运行代码第一次会自动构建向量库后续运行会直接加载已有向量库用同一个thread_id可以恢复之前的会话

相关文章:

LangGraph 重构个人知识库问答系统(稳定 + 可扩展版)

用 LangGraph 把之前的 RAG 系统重构为模块化、可扩展、带持久化、带错误处理的生产级架构。核心设计思想是:节点解耦、状态清晰、流程灵活、易于扩展。一、系统架构设计(可扩展核心)1. 核心流程(图结构)用户提问 → 检…...

3个简单步骤:使用OpenCore Legacy Patcher让旧Mac免费升级最新macOS

3个简单步骤:使用OpenCore Legacy Patcher让旧Mac免费升级最新macOS 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 你是否有一台性能尚可但已被A…...

红色沙漠代码 镜像

《红色沙漠》(Crimson Desert)是一款于 2026 年 3 月 19 日正式发行的开放世界动作冒险游戏。以下是关于该作作者、功能核心及竞品对比的简要介绍: 从夸克下载 正文内容 一、 开发者背景:Pearl Abyss 的技术野心 《红色沙漠》…...

LangGraph 错误处理与超时控制全指南

这是生产级 Agent 必不可少的能力!我会从原理→方法→完整代码,一次性讲透如何给 Agent 加上超时控制、工具调用失败重试、模型调用异常兜底,让你的 Agent 更健壮、不会轻易崩溃。一、核心概念与方法总览LangGraph 的错误处理与超时控制主要分…...

Python 爬虫进阶技巧:网页乱码问题全方位解决办法

前言 在 Python 爬虫项目落地与数据采集过程中,网页乱码是高频出现且极易影响数据解析质量的核心问题。各类网站开发规范不统一、编码格式自定义、响应头标识缺失、压缩传输等多重因素,都会导致爬虫获取的 HTML 文本、接口数据出现问号、方框、异形字符…...

ngx_connection_local_sockaddr

1 定义 ngx_connection_local_sockaddr 函数 定义在 ./nginx-1.24.0/src/core/ngx_connection.cngx_int_t ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s,ngx_uint_t port) {socklen_t len;ngx_uint_t addr;ngx_sockaddr_t …...

如何免费下载Steam创意工坊模组:跨平台玩家的终极解决方案

如何免费下载Steam创意工坊模组:跨平台玩家的终极解决方案 【免费下载链接】WorkshopDL WorkshopDL - The Best Steam Workshop Downloader 项目地址: https://gitcode.com/gh_mirrors/wo/WorkshopDL 你是否在Epic Games Store或GOG平台购买了心仪的游戏&…...

GRETNA开源工具实战指南:从零掌握MATLAB脑网络分析

GRETNA开源工具实战指南:从零掌握MATLAB脑网络分析 【免费下载链接】GRETNA A Graph-theoretical Network Analysis Toolkit in MATLAB 项目地址: https://gitcode.com/gh_mirrors/gr/GRETNA 在神经科学研究中,如何从复杂的大脑影像数据中提取有意…...

5个实战技巧:高效使用WebAssembly进行浏览器端图像处理

5个实战技巧:高效使用WebAssembly进行浏览器端图像处理 【免费下载链接】opencvjs JavaScript Bindings for OpenCV 项目地址: https://gitcode.com/gh_mirrors/op/opencvjs OpenCV.js是OpenCV计算机视觉库的JavaScript绑定版本,通过Emscripten将…...

3个步骤掌握AI Toolkit:从零到一的完整AI开发指南

3个步骤掌握AI Toolkit:从零到一的完整AI开发指南 【免费下载链接】vscode-ai-toolkit 项目地址: https://gitcode.com/GitHub_Trending/vs/vscode-ai-toolkit AI Toolkit for Visual Studio Code是一款专为开发者设计的AI应用开发扩展,它将Azur…...

小龙虾养成记:小龙虾和爱马仕(OpenClaw vs Hermes)源码对比与选型指南

适用人群:第一次接触 OpenClaw / Hermes,想快速看懂差异、做选型、不踩坑。 OpenClaw:偏本地与可控编排 | Hermes:偏在线与持续运营 小龙虾和爱马仕怎么选?是不是很多朋友都有这个疑惑。其实很多朋友第一次看 OpenClaw 和 Hermes,会有同一个感受: “都能接微信/飞书/…...

如何快速配置Lab Streaming Layer:科研数据同步与流式处理的完整指南

如何快速配置Lab Streaming Layer:科研数据同步与流式处理的完整指南 【免费下载链接】labstreaminglayer LabStreamingLayer super repository comprising submodules for LSL and associated apps. 项目地址: https://gitcode.com/gh_mirrors/la/labstreamingla…...

CSS旋转效果在Edge旧版支持_添加-ms-transform前缀与过渡

本文教你如何将 random.randint(100, 999) 生成的三位整数拆解为各位数字,高效判断是否存在重复数字(如 112、333),并量化重复程度(双重复/三重复),从而为游戏逻辑提供可编程的胜率倍数变量。 …...

5分钟搞定小说离线阅读:Novel-Downloader终极使用指南

5分钟搞定小说离线阅读:Novel-Downloader终极使用指南 【免费下载链接】novel-downloader 一个可扩展的通用型小说下载器。 项目地址: https://gitcode.com/gh_mirrors/no/novel-downloader 你是否经常遇到这样的情况:追更到一半的小说突然网站打…...

星露谷农场规划器:专业级农场布局设计与优化方案

星露谷农场规划器:专业级农场布局设计与优化方案 【免费下载链接】stardewplanner Stardew Valley farm planner 项目地址: https://gitcode.com/gh_mirrors/st/stardewplanner 星露谷农场规划器(Stardew Valley Farm Planner)是一款专…...

终极指南:如何用RPFM快速上手《全面战争》模组制作

终极指南:如何用RPFM快速上手《全面战争》模组制作 【免费下载链接】rpfm Rusted PackFile Manager (RPFM) is a... reimplementation in Rust and Qt6 of PackFile Manager (PFM), one of the best modding tools for Total War Games. 项目地址: https://gitcod…...

构建现代化IT资产管理体系:开源CMDB如何解决企业运维核心痛点

构建现代化IT资产管理体系:开源CMDB如何解决企业运维核心痛点 【免费下载链接】open-cmdb 开源资产管理平台 项目地址: https://gitcode.com/gh_mirrors/op/open-cmdb 在数字化转型的浪潮中,企业IT基础设施日益复杂,资产管理混乱、运维…...

零基础入门kohya_ss:在AMD GPU上轻松训练你的专属AI绘画模型

零基础入门kohya_ss:在AMD GPU上轻松训练你的专属AI绘画模型 【免费下载链接】kohya_ss 项目地址: https://gitcode.com/GitHub_Trending/ko/kohya_ss 你是否曾经想过,用自己的AMD显卡就能训练出专属的AI绘画模型?不用羡慕那些拥有昂…...

我开源了一款本地音乐播放器 —— Yeah Music,欢迎大家体验

我开源了一款本地音乐播放器 —— Yeah Music,欢迎大家体验 🎵 大家好,我是一名普通的开发者,也是个重度本地音乐爱好者。 这些年被各种商业音乐App的广告、会员、联网要求搞得很烦,尤其是想好好听自己收藏的无损音乐时…...

【PostgreSQL从零到精通】第48篇:PL/Proxy数据分片——PostgreSQL的水平扩展利器

上一篇【第47篇】Bucardo多主复制——实现真正的双向数据同步 下一篇【第49篇】pgpool-II完全指南——连接池复制负载均衡的三合一方案 单台 PostgreSQL 服务器的读写能力总有一个上限。当数据量达到 TB 级别、并发请求达到数万 QPS 时,再怎么优化硬件也无济于事——…...

看完100个失败私域直播案例,90%的人死在预热前

前年刚开始搞私域直播的时候,我特别自信,觉得产品也好、主播也专业,开播肯定有人看。结果呢?第一场播下来,场观不到两百,卖了不到一千块。我当时完全懵了,不知道问题出在哪。后来我一个做私域的…...

D3.js:数据可视化的终极利器

什么是 D3.js D3.js(Data-Driven Documents)是一个基于 JavaScript 的数据可视化库,用于创建动态、交互式的数据可视化图表。它通过绑定数据到 DOM(文档对象模型),并利用 HTML、SVG 和 CSS 实现数据驱动的…...

从零搭建一个拼多多CPS返利小程序:我的踩坑记录与避坑指南

从零搭建一个拼多多CPS返利小程序:我的踩坑记录与避坑指南 去年夏天,我决定尝试开发一个拼多多CPS返利小程序。作为一个独立开发者,我本以为凭借多年的编程经验,两周就能搞定这个"小项目"。没想到从API对接、用户绑定到…...

从D435i的深度图反推:如何让OpenCV SGBM的输出更接近工业级传感器效果?

从D435i深度图反推:OpenCV SGBM算法优化实战指南 当你在机器人导航或三维重建项目中对比OpenCV SGBM算法生成的深度图与Intel RealSense D435i输出的结果时,是否发现前者总是显得"平面化"且噪声明显?这背后隐藏着工业级深度传感器在…...

RAG进阶:下一代RAG怎么玩?

基础RAG能解决80%的问题,但剩下20%的难题,需要更进阶的技术。一、基础RAG碰到了什么天花板 基础RAG的套路很简单:文档切块 → Embedding → 向量检索 → 拼接Prompt → 大模型生成答案。 简单场景够用,但往深了用,三个…...

用GD32F470的ADC+DMA实现高精度电流采样,附梁山派开发板实测波形

GD32F470高精度电流采样实战:ADC过采样与DMA传输的工程化实现 在电机控制和电源监测领域,电流采样的精度和实时性直接决定了系统性能的上限。传统12位ADC往往难以兼顾噪声抑制和动态响应,而外置高精度ADC又会增加BOM成本和布线复杂度。本文将…...

【Docker 工程实践】AI 服务容器化部署全流程

文章目录Docker 工程实践:AI 服务容器化部署全流程一、引言二、核心挑战:Mac arm64 → Linux amd64 的跨平台陷阱2.1 为什么会出现 exec format error2.2 一个镜像跑两端:统一构建 amd64三、Dockerfile 工程规范3.1 标准生产模板3.2 多阶段构…...

VMware Workstation 虚拟机创建客户端系统,出现此主机不支持64位客户机操作系统问题解决

安装VMware Workstation 虚拟机(版本15.5),选择windows 11 64位是出现此主机不支持64位客户机操作系统.硬件以及系统支持64位。网上找了几个情况1、hyper-v 功能选项是否开启状态,关闭它2、看CPU技术是否支持虚拟技术,打开任务管…...

如何配置Data Guard环境中的应用连接_客户端TAF与服务漂移Service Trigger

TAF配置不生效主因是TNSNAMES.ORA中未正确定义FAILOVER_MODE参数,需显式设置TYPE(SESSION/SELECT)、METHOD(BASIC)、RETRIES、DELAY及ADDRESS_LIST顺序;srvctl服务需配合DB_ROLE_CHANGE触发器或Broker手动启…...

从Claude Code源码泄露事件看AI CLI工具的五层架构与安全设计

1. 项目概述:一次对Claude Code CLI的深度技术考古最近,AI编程助手领域发生了一件颇有意思的技术事件:Anthropic官方推出的命令行工具Claude Code,其完整的TypeScript源代码意外地在npm包中被公开了。这并非一次主动的开源&#x…...