掘金 人工智能 06月30日 14:03
AI大模型应用开发入门(六)-LangChain实现文档总结
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文介绍了一种使用LangChain和LLM(大型语言模型)构建长网页文本总结的map-reduce流水线的方案。该方案通过将长文本拆分成多个chunk,对每个chunk进行初步总结(map),然后汇总这些初步总结(reduce),并根据需要递归reduce,最终生成最终总结。文章提供了详细的代码实现,包括初始化LLM、加载网页、定义prompt模板、拆分文档、定义token长度计算、定义状态、生成初步总结、map调度逻辑、收集总结、reduce逻辑、判断是否需要继续reduce以及生成最终总结等步骤。通过StateGraph灵活编排流程,实现了长文本的自动总结。

💡 **map-reduce流程设计:** 该方案的核心是利用map-reduce流水线处理长文本。首先将长网页文本拆分成可控大小的chunk,然后对每个chunk进行初步总结(map),再汇总这些初步总结(reduce),如有需要则递归reduce,直至满足token限制,最后输出最终总结。

🌐 **LangChain的应用:** 方案充分利用了LangChain的特性,包括`WebBaseLoader`加载网页内容,`CharacterTextSplitter`拆分文档,以及`ChatPromptTemplate`定义prompt模板。这些工具简化了处理流程,提高了代码的可读性和可维护性。

⚙️ **StateGraph的灵活编排:** 方案使用StateGraph来构建流程图,灵活编排整个流水线。这使得流程的控制更加精细,可以根据实际情况进行调整,例如根据token长度判断是否需要继续reduce。

🔑 **关键代码实现:** 文章提供了详细的代码示例,包括初始化LLM、加载网页、定义prompt模板、拆分文档、定义token长度计算、定义状态、生成初步总结、map调度逻辑、收集总结、reduce逻辑、判断是否需要继续reduce以及生成最终总结等步骤,方便读者理解和实践。

🔄 **递归reduce机制:** 方案支持递归reduce,这使得它可以处理超过LLM单次处理token限制的文本。通过不断reduce,将文本压缩到LLM可以处理的范围内,最终生成最终总结。

一、整体思路

长网页文本往往超过 LLM 单次处理的 token 限制,我们需要设计一个 map-reduce 流水线来拆分、局部总结、归并:

    加载网页内容拆分成可控大小的 chunk对每个 chunk 做初步总结 (map)汇总所有初步总结 (reduce)如有需要递归 reduce 直到满足 token 限制输出最终总结

接下来我们用代码实现!

二、准备工作

1. 初始化 LLM

首先我们通过 init_chat_model 加载 LLM:

# llm_env.pyfrom langchain.chat_models import init_chat_modelllm = init_chat_model("gpt-4o-mini", model_provider="openai")

三、主程序 main.py

1. 导入依赖 & 初始化
import osimport syssys.path.append(os.getcwd())from langchain_community.document_loaders import WebBaseLoaderfrom langchain.chains.combine_documents import create_stuff_documents_chainfrom langchain.chains.llm import LLMChainfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_text_splitters import CharacterTextSplitterimport operatorfrom typing import Annotated, List, Literal, TypedDictfrom langchain.chains.combine_documents.reduce import collapse_docs, split_list_of_docsfrom langchain_core.documents import Documentfrom langgraph.constants import Sendfrom langgraph.graph import END, START, StateGraphfrom llm_set import llm_envllm = llm_env.llm
2. 加载网页
loader = WebBaseLoader("https://en.wikipedia.org/wiki/Artificial_intelligence")docs = loader.load()

通过 WebBaseLoader 可以轻松加载网页文本到 docs 列表中。

3. 定义 Prompt 模板
map_prompt = ChatPromptTemplate.from_messages(    [("system", "Write a concise summary of the following: \n\n{context}")])
reduce_template = """The following is a set of summaries:{docs}Take these and distill it into a final, consolidated summaryof the main themes."""reduce_prompt = ChatPromptTemplate([("human", reduce_template)])
4. 拆分文档 chunk
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)split_docs = text_splitter.split_documents(docs)print(f"Split into {len(split_docs)} chunks")

将网页内容拆分成多个 chunk,chunk 大小设置 1000 tokens,便于单次处理。

5. 定义 Token 长度计算
token_max = 1000def length_function(documents: List[Document]) -> int:    return sum(llm.get_num_tokens(d.page_content) for d in documents)

计算输入文档 token 总量,用于判断是否需要继续 collapse。

6. 定义状态

主状态:

class OverallState(TypedDict):    contents: List[str]    summaries: Annotated[list, operator.add]    collapsed_summaries: List[Document]    final_summary: str

Map 阶段状态:

class SummaryState(TypedDict):    content: str
7. 生成初步 summary (Map 阶段)
def generate_summary(state: SummaryState):    prompt = map_prompt.invoke(state["content"])    response = llm.invoke(prompt)    return {"summaries": [response.content]}
8. Map 调度逻辑
def map_summaries(state: OverallState):    return [        Send("generate_summary", {"content": content}) for content in state["contents"]    ]
9. 收集 summary
def collect_summaries(state: OverallState):    return {        "collapsed_summaries": [Document(summary) for summary in state["summaries"]]    }
10. Reduce 逻辑
def _reduce(input: dict) -> str:    prompt = reduce_prompt.invoke(input)    response = llm.invoke(prompt)    return response.content
def collapse_summaries(state: OverallState):    docs_lists = split_list_of_docs(        state["collapsed_summaries"],        length_function,        token_max,    )    results = []    for doc_list in docs_lists:        combined = collapse_docs(doc_list, _reduce)        results.append(combined)    return {"collapsed_summaries": results}
11. 是否继续 collapse
def should_collapse(state: OverallState):    num_tokens = length_function(state["collapsed_summaries"])    if num_tokens > token_max:        return "collapse_summaries"    else:        return "generate_final_summary"
12. 生成最终 summary
def generate_final_summary(state: OverallState):    response = _reduce(state["collapsed_summaries"])    return {"final_summary": response}

四、构建流程图 (StateGraph)

graph = StateGraph(OverallState)graph.add_node("generate_summary", generate_summary)graph.add_node("collect_summaries", collect_summaries)graph.add_node("collapse_summaries", collapse_summaries)graph.add_node("generate_final_summary", generate_final_summary)graph.add_conditional_edges(START, map_summaries, ["generate_summary"])graph.add_edge("generate_summary", "collect_summaries")graph.add_conditional_edges("collect_summaries", should_collapse)graph.add_conditional_edges("collapse_summaries", should_collapse)graph.add_edge("generate_final_summary", END)app = graph.compile()
五、执行总结流程
for step in app.stream(    {"contents": [doc.page_content for doc in split_docs]},    {"recursion_limit": 10},):    print(list(step.keys()))

通过 .stream() 启动整个流水线,传入切片后的 contents,流式输出每步结果,直到最终汇总完成。

六、总结

通过这个示例,你可以看到: 

✅ 使用 LangChain + LLM 轻松实现 网页总结
✅ 设计了 自动 map-reduce 流程,支持长文本拆分和递归 reduce
✅ 通过 StateGraph 灵活编排流程

原文地址:https://www.cnblogs.com/chenyishi/p/18945790

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

LangChain LLM map-reduce 长文本总结 StateGraph
相关文章