用LangGraph写一个小RAG
最小RAG的链式写法大致这样用户问题 - 检索资料 - 拼Prompt - 调模型回答用LangGraph把最小RAG拆成一张小图START ↓ retrieve_docs ├─ 有足够相关资料 - build_context - answer - END └─ 无足够相关资料 - fallback - END图结构接下里主要是看下graph里一般怎么接入rag实现不复杂。准备知识库和测试问题先准备一份很小的客服知识库包含退款、发票、会员续费、商品质量问题等内容然后测试三个问题1、未发货订单能退款吗 2、电子发票在哪里下载 3、积分可以提现吗预期效果应该是前两个问题应该能检索到资料并回答第三个问题不在知识库范围内应该走fallback。定义State和Runtime ContextState保存这次问答过程中产生的数据class RagDocument(TypedDict): source: str chunk_index: int start_index: int content: str similarity: float class RagState(TypedDict, totalFalse): question: str retrieved_docs: list[RagDocument] context: str route: Literal[answer, fallback] answer: str稍微解释下question是用户问题retrieved_docs是结构化检索结果context是给模型看的上下文这里后续会包含从向量哭里检索出来的文档片段route记录走了正常回答还是fallbackanswer保存最终回答。Runtime Context保存运行配置和外部依赖内容包括class RagContext(TypedDict): knowledge_base_path: str top_k: int min_similarity: float embedding_model: str answer_model: str ollama_base_url: str vectorstore: InMemoryVectorStoretop_k是每次检索最多返回几个相关片段min_similarity是最低相似度阈值低于这个分数的资料不进入回答流程embedding_model使用的Embedding模型vectorstore已经构建好的向量库对象用它根据用户问题检索相关资料两份存储的区别1、问答过程中产生的东西放State2、运行时需要的配置和依赖放Runtime Context启动时先建向量库启动时建一次向量库后面多个问题都可以复用写入到内存暂时不用本地存储def build_vectorstore( knowledge_base_path: str, embedding_model: str, ollama_base_url: str, ) - InMemoryVectorStore: docs load_support_docs(knowledge_base_path) embeddings OllamaEmbeddings( modelembedding_model, base_urlollama_base_url, ) return InMemoryVectorStore.from_documents(docs, embeddings)文本切分用RecursiveCharacterTextSplittersplitter RecursiveCharacterTextSplitter( chunk_size160, chunk_overlap30, separators[\n\n, \n, 。, , , ], add_start_indexTrue, ) docs splitter.split_documents(raw_docs)add_start_indexTrue能保留chunk在原文里的起始位置后面展示参考资料时有用。写检索节点retrieve_docs检索节点做的四件事读取问题、查询向量库、过滤低相关资料、写回State。def retrieve_docs(state: RagState, runtime: Runtime[RagContext]) - RagState: context runtime.context question get_question(state) results context[vectorstore].similarity_search_with_score( question, kcontext[top_k], ) retrieved_docs: list[RagDocument] [] for doc, similarity in results: if similarity context[min_similarity]: continue retrieved_docs.append( { source: Path(str(doc.metadata.get(source, unknown))).name, chunk_index: int(doc.metadata.get(chunk_index, -1)), start_index: int(doc.metadata.get(start_index, -1)), content: doc.page_content, similarity: similarity, } ) return {retrieved_docs: retrieved_docs}这里的min_similarity0.60只是当前知识库和embedding模型下的实验阈值不是通用标准。换知识库或模型后要重新观察和选择你要使用啥分数写条件边有资料才回答检索后不要直接回答先判断有没有足够相关资料def route_after_retrieve(state): if state.get(retrieved_docs): return build_context return fallback有资料才回答没资料就fallback这里也体现了langchain与langgraph环境下使用rag的实现区别。写build_context、answer和fallbackbuild_context把结构化检索结果整理成模型可读的上下文def build_context(state: RagState) - RagState: context_parts [] for index, doc in enumerate(state.get(retrieved_docs, []), start1): context_parts.append( f资料 {index}{doc[source]}#chunk-{doc[chunk_index]}\n f相似度{doc[similarity]:.3f}\n f起始位置{doc[start_index]}\n f正文{doc[content]} ) return {context: \n\n.join(context_parts), route: answer}answer只根据用户问题和检索上下文回答model ChatOllama( modelcontext[answer_model], base_urlcontext[ollama_base_url], temperature0, )但是Prompt里要写清楚只根据给定资料回答不要编造资料中没有的信息这个约束还是挺重要的不然模型会放飞自己。fallback不调用模型直接兜底就行。def fallback(state: RagState) - RagState: return { route: fallback, context: , answer: 当前知识库里没有找到足够相关的资料建议转人工客服或补充更多问题信息。, }RAG的底线没有依据时不要不懂装懂。把节点连成图图本身不大graph_builder StateGraph(RagState, context_schemaRagContext) graph_builder.add_node(retrieve_docs, retrieve_docs) graph_builder.add_node(build_context, build_context) graph_builder.add_node(answer, answer) graph_builder.add_node(fallback, fallback) graph_builder.add_edge(START, retrieve_docs) graph_builder.add_conditional_edges( retrieve_docs, route_after_retrieve, { build_context: build_context, fallback: fallback, }, ) graph_builder.add_edge(build_context, answer) graph_builder.add_edge(answer, END) graph_builder.add_edge(fallback, END) graph graph_builder.compile()到这里一个最小LangGraph RAG就搭好了。运行并观察三条路径启动时配置知识库、模型和向量库knowledge_base_path support_policy_retriever.txt embedding_model qwen3-embedding:latest answer_model qwen3-coder:30b ollama_base_url http://localhost:11434 vectorstore build_vectorstore( knowledge_base_pathknowledge_base_path, embedding_modelembedding_model, ollama_base_urlollama_base_url, ) runtime_context { knowledge_base_path: knowledge_base_path, top_k: 2, min_similarity: 0.60, embedding_model: embedding_model, answer_model: answer_model, ollama_base_url: ollama_base_url, vectorstore: vectorstore, }每次调用时初始State只放问题initial_state {”question”: question} final_state graph.invoke(initial_state, contextruntime_context)看下关键输出的效果问题 1未发货订单能退款吗 路径answer 最终回答未发货订单可以申请退款系统会自动拦截发货流程退款通常在1-3个工作日内原路退回。 参考资料[1] support_policy_retriever.txt#chunk-10(0.730); [2] support_policy_retriever.txt#chunk-2109(0.626) 问题 2电子发票在哪里下载 路径answer 最终回答电子发票可在订单详情页下载。进入”我的订单 - 订单详情 - 发票信息”查找发票入口。 参考资料[1] support_policy_retriever.txt#chunk-3208(0.732) 问题 3积分可以提现吗 路径fallback 最终回答当前知识库里没有找到足够相关的资料建议转人工客服或补充更多问题信息。 参考资料无基本符合预期。‘9. 五条核心边界1、State保存用户问题、检索结果、上下文和最终回答。2、Runtime Context保存知识库、模型、检索参数和向量库。3、向量库启动时构建一次不要每个问题重复建索引。4、检索节点只负责找资料。5、没有足够相关资料就fallback不让模型硬答。实验细节GitHub 仓库 https://github.com/yauld/ai-forge 完整实验文章 labs/langgraph/foundations/24 | LangGraph RAG把最小问答链路接入图.md 实验代码 labs/langgraph/foundations/experiments/24_minimal_rag_graph/学AI大模型的正确顺序千万不要搞错了2026年AI风口已来各行各业的AI渗透肉眼可见超多公司要么转型做AI相关产品要么高薪挖AI技术人才机遇直接摆在眼前有往AI方向发展或者本身有后端编程基础的朋友直接冲AI大模型应用开发转岗超合适就算暂时不打算转岗了解大模型、RAG、Prompt、Agent这些热门概念能上手做简单项目也绝对是求职加分王给大家整理了超全最新的AI大模型应用开发学习清单和资料手把手帮你快速入门学习路线:✅大模型基础认知—大模型核心原理、发展历程、主流模型GPT、文心一言等特点解析✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑✅开发基础能力—Python进阶、API接口调用、大模型开发框架LangChain等实操✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经以上6大模块看似清晰好上手实则每个部分都有扎实的核心内容需要吃透我把大模型的学习全流程已经整理好了抓住AI时代风口轻松解锁职业新可能希望大家都能把握机遇实现薪资/职业跃迁这份完整版的大模型 AI 学习资料已经上传CSDN朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】

相关新闻

LangGraph 状态快照与回滚|Agent 故障自愈、流程回溯

LangGraph 状态快照与回滚|Agent 故障自愈、流程回溯

每执行完一个图节点,LangGraph 自动保存一份当前完整状态,就是快照。每条快照包含:全量状态、父快照 ID、时间戳、自定义业务元数据。 Checkpointer(存储器) 快照存放载体,分三类: MemorySav…

2026/10/20 1:34:23 阅读更多 →
HDMI视频寄存器配置实战:从同步时序到色彩空间转换详解

HDMI视频寄存器配置实战:从同步时序到色彩空间转换详解

1. 项目概述与核心价值在嵌入式视频系统开发,尤其是涉及HDMI、DisplayPort这类高速数字接口的领域,工程师们常常会遇到一个看似简单实则棘手的问题:如何让一块屏幕准确地、稳定地显示出我们想要的图像?这背后远不止是发送像素数据…

2026/10/19 11:48:58 阅读更多 →
TMS320C28x FPU64软件流水线优化:从延迟槽到指令级并行实战

TMS320C28x FPU64软件流水线优化:从延迟槽到指令级并行实战

1. 项目概述与核心价值在嵌入式数字信号处理器(DSP)的开发中,尤其是面向电机控制、数字电源、新能源逆变器等对实时性要求极高的领域,每一纳秒的指令执行时间都至关重要。TMS320C28x系列DSP,凭借其强大的定点运算能力和…

2026/10/17 23:09:34 阅读更多 →

最新新闻

Keras 实现 CycleGAN:非配对图像风格迁移实战

Keras 实现 CycleGAN:非配对图像风格迁移实战

简介:这份资源是CycleGAN的Keras实现代码包,面向具备一定深度学习基础、希望动手实践无监督图像到图像转换的开发者与研究者。它围绕生成对抗网络展开,重点解决无配对样本条件下的跨域图像转换问题,可应用于风格迁移、季节转换等场…

2026/10/20 1:34:02 阅读更多 →
高斯伪谱法求解最优控制:GPOPS II使用与避坑指南

高斯伪谱法求解最优控制:GPOPS II使用与避坑指南

简介:GPOPS II(高斯伪谱法优化程序)是面向最优控制问题的高效MATLAB工具,适用于航空航天轨迹优化、机械与能源系统控制等场景,可帮助工程师和研究人员处理含多状态变量、控制输入及约束条件的复杂动态系统优化。压缩包…

2026/10/20 1:34:02 阅读更多 →
GenomeQA:大模型与RAG驱动的基因组学通才问答系统

GenomeQA:大模型与RAG驱动的基因组学通才问答系统

如果你做过一段时间遗传解读或生信分析,大概率会遇到过类似的场景:手里攥着一个基因变异位点,数据库一个个翻过去——病理注释说可能致病,人群频率数据说在特定人群中很常见,药物基因组学资料又提到它影响某个代谢酶的…

2026/10/20 1:34:02 阅读更多 →
储能EMS社招面试核心:从功能实现到系统守门人的能力跃迁

储能EMS社招面试核心:从功能实现到系统守门人的能力跃迁

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:34:02 阅读更多 →
RAG落地关键:Embedding与Reranker的配合及长文本向量模型解析

RAG落地关键:Embedding与Reranker的配合及长文本向量模型解析

简介:面向大语言模型幻觉、知识更新滞后及私域数据利用难等核心痛点,这份PDF系统讲解了RAG(检索增强生成)的技术链路,从Embedding向量模型到Reranker重排模型,内容涵盖Jina-embeddings-v2 8K模型的ALiBi注意…

2026/10/20 1:34:02 阅读更多 →
Bonsai-demo 完整指南:两条命令跑起 27B 级 2-bit 本地推理

Bonsai-demo 完整指南:两条命令跑起 27B 级 2-bit 本地推理

Bonsai-demo 完整指南:两条命令跑起 27B 级 2-bit 本地推理 【免费下载链接】Bonsai-demo Bonsai Demo 项目地址: https://gitcode.com/GitHub_Trending/bo/Bonsai-demo 如果你想在自家电脑或笔记本上跑 27B 级的推理模型,Bonsai-demo 是目前最省…

2026/10/20 1:33:02 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →