Skip to main content
Open In ColabOpen on GitHub

如何通过迭代改进来总结文本

大型语言模型(LLM)可以总结文本并从中提取所需信息,包括大量的文本。在许多情况下,特别是当文本量相对于模型的上下文窗口大小而言很大时,将总结任务分解成更小的部分会很有帮助(或有必要)。

迭代改进代表了一种总结长文本的策略。该策略如下:

  • 将文本分成更小的文档;
  • 总结第一个文档;
  • 根据下一个文档改进或更新结果;
  • 按文档顺序重复此过程,直到完成。

请注意,此策略不是并行化的。当子文档的理解依赖于先前的上下文时,它尤其有效——例如,在总结小说或具有内在序列的文本时。

LangGraph 构建在 langchain-core 之上,非常适合解决这个问题:

  • LangGraph 允许对单个步骤(例如连续的总结)进行流式处理,从而更好地控制执行;
  • LangGraph 的 持久化 支持错误恢复、扩展人工干预工作流以及更轻松地集成到对话应用程序中。
  • 由于它是从模块化组件组装而成的,因此也很容易扩展或修改(例如,集成 工具调用 或其他行为)。

下面,我们将演示如何通过迭代改进来总结文本。

加载聊天模型

首先,我们来加载一个聊天模型:

pip install -qU "langchain[google-genai]"
import getpass
import os

if not os.environ.get("GOOGLE_API_KEY"):
os.environ["GOOGLE_API_KEY"] = getpass.getpass("Enter API key for Google Gemini: ")

from langchain.chat_models import init_chat_model

llm = init_chat_model("gemini-2.0-flash", model_provider="google_genai")

加载文档

接下来,我们需要一些文档来总结。下面,我们生成一些示例性的玩具文档。请参阅文档加载器 操作指南集成页面 以获取其他数据源。 总结教程 还包含一个总结博客文章的示例。

from langchain_core.documents import Document

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 yelow", metadata={"title": "banana_book"}),
]
API Reference:Document

创建图表

下面我们展示了此过程的 LangGraph 实现:

  • 我们生成一个简单的链来生成初始摘要,该链提取第一个文档,将其格式化为提示,然后使用我们的 LLM 运行推理。
  • 我们生成第二个 refine_summary_chain,它在我们处理的每个后续文档上操作,以改进初始摘要。

我们需要安装 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 langgraph.constants import Send
from langgraph.graph import END, START, StateGraph

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

# Refining the summary with new docs
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()


# We will define the state of the graph to hold the document
# contents and summary. We also include an index to keep track
# of our position in the sequence of documents.
class State(TypedDict):
contents: List[str]
index: int
summary: str


# We define functions for each node, including a node that generates
# the initial summary:
async def generate_initial_summary(state: State, config: RunnableConfig):
summary = await initial_summary_chain.ainvoke(
state["contents"][0],
config,
)
return {"summary": summary, "index": 1}


# And a node that refines the summary based on the next document
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}


# Here we implement logic to either exit the application or refine
# the summary.
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()

LangGraph 允许绘制图结构以帮助可视化其功能:

from IPython.display import Image

Image(app.get_graph().draw_mermaid_png())

调用图

我们可以按如下方式逐步执行,并在摘要完善过程中打印出来:

async for step in app.astream(
{"contents": [doc.page_content for doc in documents]},
stream_mode="values",
):
if summary := step.get("summary"):
print(summary)
Apples are characterized by their red color.
Apples are characterized by their red color, while blueberries are known for their blue hue.
Apples are characterized by their red color, blueberries are known for their blue hue, and bananas are recognized for their yellow color.

最后一个 step 包含整个文档集所合成的摘要。

后续步骤

查看 如何进行摘要操作的分步指南 了解额外的摘要策略,包括针对大量文本的策略。

请参阅 本教程 了解摘要的更多详细信息。

另请参阅 LangGraph 文档,了解有关使用 LangGraph 进行构建的详细信息。