LangChain RAG Chain Types 详解

文章目录

  • [LangChain RAG Chain Types 详解](#LangChain RAG Chain Types 详解)
    • [1. 为什么需要不同的 Chain Type?](#1. 为什么需要不同的 Chain Type?)
    • [2. 三种 Chain Type 详解](#2. 三种 Chain Type 详解)
      • [2.1 Stuff(填充式)](#2.1 Stuff(填充式))
      • [2.2 Map Reduce(映射归纳式)](#2.2 Map Reduce(映射归纳式))
      • [2.3 Refine(精炼式)](#2.3 Refine(精炼式))
    • [3. 对比总结](#3. 对比总结)
      • [3.1 如何选择?](#3.1 如何选择?)
    • [4. 代码示例](#4. 代码示例)
      • [4.1 测试三种 Chain Type](#4.1 测试三种 Chain Type)
      • [4.2 带上下文的连续对话](#4.2 带上下文的连续对话)
      • [4.3 查看对话历史](#4.3 查看对话历史)
    • [5. 进阶:自定义 Chain](#5. 进阶:自定义 Chain)
      • [5.1 自定义 combine_docs_chain](#5.1 自定义 combine_docs_chain)
      • [5.2 自定义 map 阶段的 prompt](#5.2 自定义 map 阶段的 prompt)
    • [6. 常见问题](#6. 常见问题)
      • [Q1: `stuff` 超过上下文限制怎么办?](#Q1: stuff 超过上下文限制怎么办?)
      • [Q2: `refine` 会累积错误吗?](#Q2: refine 会累积错误吗?)
      • [Q3: 连续对话中 chain_type 怎么选?](#Q3: 连续对话中 chain_type 怎么选?)
      • [Q4: 如何查看 chain 执行的中间结果?](#Q4: 如何查看 chain 执行的中间结果?)
      • [Q5: 文档数量少但答案不完整,用哪个?](#Q5: 文档数量少但答案不完整,用哪个?)

LangChain RAG Chain Types 详解

本文介绍 ConversationalRetrievalChain 的三种文档处理策略:stuffmap_reducerefine

1. 为什么需要不同的 Chain Type?

将文档塞给 LLM 时,有不同的策略:

策略 适用场景 优缺点
Stuff 文档较少 简单快速,但超过上下文限制会失败
Map Reduce 文档多、文档大 可处理大量文档,但可能丢失跨文档关联
Refine 需要连贯上下文 答案更连贯,但速度较慢

2. 三种 Chain Type 详解

2.1 Stuff(填充式)

原理 :将所有检索到的文档拼接到一个 prompt 中,一次性发给 LLM。

复制代码
[文档1] + [文档2] + [文档3] + [问题] → LLM → 答案

代码

python 复制代码
qa = ConversationalRetrievalChain.from_llm(
    llm=model,
    retriever=retriever,
    memory=memory,
    chain_type="stuff"  # 默认方式
)
优点 缺点
简单快速 受上下文窗口限制
保留完整上下文 文档过多时会失败

2.2 Map Reduce(映射归纳式)

原理

  1. Map :每个文档单独调用 LLM 生成答案

  2. Reduce :所有单独答案合并后再调用 LLM 总结

    [文档1] → LLM → 答案1
    [文档2] → LLM → 答案2 → LLM(合并) → 最终答案
    [文档3] → LLM → 答案3

代码

python 复制代码
qa = ConversationalRetrievalChain.from_llm(
    llm=model,
    retriever=retriever,
    memory=memory,
    chain_type="map_reduce"
)
优点 缺点
可处理大量文档 可能丢失文档间关联
每个文档并行处理 多次 API 调用,成本较高

2.3 Refine(精炼式)

原理 :逐个文档迭代精炼答案,后一个文档基于前一个答案继续优化。

复制代码
[文档1] → LLM → 答案1
              ↓
[文档2] + 答案1 → LLM → 答案2
                            ↓
[文档3] + 答案2 → LLM → 最终答案

代码

python 复制代码
qa = ConversationalRetrievalChain.from_llm(
    llm=model,
    retriever=retriever,
    memory=memory,
    chain_type="refine"
)
优点 缺点
答案连贯一致 速度最慢
保留上下文顺序 错误可能累积

3. 对比总结

特性 stuff map_reduce refine
处理方式 一次性塞入 分开处理再合并 迭代精炼
文档数量
上下文保留 完整 部分丢失 较好
速度 中等
成本 较高 最高

3.1 如何选择?

场景 推荐
检索文档 < 3 个 stuff
检索文档 3-10 个 map_reducerefine
检索文档 > 10 个 map_reduce
需要连贯答案/长文 refine

4. 代码示例

4.1 测试三种 Chain Type

python 复制代码
chain_types = ["stuff", "map_reduce", "refine"]

for chain_type in chain_types:
    memory = ConversationBufferMemory(
        memory_key="chat_history",
        return_messages=True,
        output_key="answer"
    )

    qa = ConversationalRetrievalChain.from_llm(
        llm=model,
        retriever=retriever,
        memory=memory,
        chain_type=chain_type,
        verbose=False
    )

    result = qa.invoke({"question": "卢浮宫这个名字怎么来的?"})
    print(f"chain_type={chain_type}: {result['answer']}")

结果:

4.2 带上下文的连续对话

python 复制代码
memory = ConversationBufferMemory(
    memory_key="chat_history",
    return_messages=True,
    output_key="answer"
)

qa = ConversationalRetrievalChain.from_llm(
    llm=model,
    retriever=retriever,
    memory=memory,
    chain_type="stuff",
    verbose=False
)

# 第一轮
result1 = qa.invoke({"question": "卢浮宫是什么时候建的?"})
print(f"Q1: 卢浮宫是什么时候建的?")
print(f"A1: {result1['answer']}")

# 第二轮 - "它"指代上文中的"卢浮宫"
result2 = qa.invoke({"question": "它在哪里?"})
print(f"Q2: 它在哪里?")
print(f"A2: {result2['answer']}")

结果:

4.3 查看对话历史

python 复制代码
print("=== 对话历史 ===")
for msg in memory.chat_memory.messages:
    print(f"{msg.type}: {msg.content}")

结果:


5. 进阶:自定义 Chain

5.1 自定义 combine_docs_chain

python 复制代码
from langchain.chains import LLMChain, StuffDocumentsChain

# 自定义 stuff chain
llm_chain = LLMChain(llm=model, prompt=custom_prompt)
combine_docs_chain = StuffDocumentsChain(llm_chain=llm_chain)

qa = ConversationalRetrievalChain(
    llm=model,
    retriever=retriever,
    memory=memory,
    combine_docs_chain=combine_docs_chain
)

5.2 自定义 map 阶段的 prompt

python 复制代码
from langchain.chains import AnalyzeDocumentChain

qa_chain = AnalyzeDocumentChain(
    combine_docs_chain=custom_combine,
    vectorstore=db
)

6. 常见问题

Q1: stuff 超过上下文限制怎么办?

使用 map_reducerefine,它们会将文档分批处理。

Q2: refine 会累积错误吗?

有可能。如果某个文档答案错误,可能影响后续迭代结果。重要场景建议用 map_reduce 验证。

Q3: 连续对话中 chain_type 怎么选?

连续对话建议用 stuff,因为每次只检索少量相关文档,内存占用可控。

Q4: 如何查看 chain 执行的中间结果?

python 复制代码
qa = ConversationalRetrievalChain.from_llm(
    ...
    verbose=True  # 开启后会打印详细执行过程
)

Q5: 文档数量少但答案不完整,用哪个?

refine,它会基于前一个答案和下一个文档迭代优化。

相关推荐
yanghuashuiyue27 分钟前
LangGraph框架研究-开发测试
python·langgraph
禹凕29 分钟前
PyTorch——安装(有无 NVIDIA 显卡的完整配置方案)
人工智能·pytorch·python
卷心菜狗33 分钟前
Python进阶--迭代器
开发语言·python
dragen_light34 分钟前
5.ROS2-Topics-Publisher-Subscriber
python
jr-create(•̀⌄•́)36 分钟前
LeakyRelu链式法则
开发语言·python·深度学习
vx_biyesheji00012 小时前
计算机毕业设计:Python股价预测与可视化系统 Flask框架 数据分析 可视化 机器学习 随机森林 大数据(建议收藏)✅
python·机器学习·信息可视化·数据分析·flask·课程设计
极客老王说Agent7 小时前
2026实战指南:如何用智能体实现药品不良反应报告的自动录入?
人工智能·ai·chatgpt
lulu12165440787 小时前
Claude Code项目大了响应慢怎么办?Subagents、Agent Teams、Git Worktree、工作流编排四种方案深度解析
java·人工智能·python·ai编程
deephub7 小时前
LangChain 还是 LangGraph?一个是编排一个是工具包
人工智能·langchain·大语言模型·langgraph
kishu_iOS&AI7 小时前
Openclaw -> Hermes —— 初体验
ai·openclaw·hermes