一、整体思路

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

  1. 加载网页内容

  2. 拆分成可控大小的 chunk

  3. 对每个 chunk 做初步总结 (map)

  4. 汇总所有初步总结 (reduce)

  5. 如有需要递归 reduce 直到满足 token 限制

  6. 输出最终总结

接下来我们用代码实现!

二、准备工作

1. 初始化 LLM

首先我们通过 init_chat_model 加载 LLM:

# llm_env.py
from langchain.chat_models import init_chat_model llm = init_chat_model("gpt-4o-mini", model_provider="openai")

三、主程序 main.py

1. 导入依赖 & 初始化
import os
import sys sys.path.append(os.getcwd()) from langchain_community.document_loaders import WebBaseLoader
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain.chains.llm import LLMChain
from langchain_core.prompts import ChatPromptTemplate
from langchain_text_splitters import CharacterTextSplitter
import operator
from typing import Annotated, List, Literal, TypedDict
from langchain.chains.combine_documents.reduce import collapse_docs, split_list_of_docs
from langchain_core.documents import Document
from langgraph.constants import Send
from langgraph.graph import END, START, StateGraph from llm_set import llm_env llm = llm_env.llm
2. 加载网页
loader = WebBaseLoader("https://en.wikipedia.org/wiki/Artificial_intelligence")
docs = loader.load()

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

3. 定义 Prompt 模板

- Map 阶段 Prompt

map_prompt = ChatPromptTemplate.from_messages(
[("system", "Write a concise summary of the following: \\n\\n{context}")]
)

- Reduce 阶段 Prompt

reduce_template = """
The following is a set of summaries:
{docs}
Take these and distill it into a final, consolidated summary
of 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 = 1000

def 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 逻辑

- 内部 reduce 函数

def _reduce(input: dict) -> str:
prompt = reduce_prompt.invoke(input)
response = llm.invoke(prompt)
return response.content

- Collapse summaries

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 灵活编排流程、

AI大模型应用开发入门-LangChain实现文档总结的更多相关文章

  1. 【分享】iTOP4412开发板-Bluetooth移植文档

    [分享]iTOP4412开发板-Bluetooth移植文档 最近须要把Bluetooth移植到iTOP-4412 开发平台.查阅了相关资料,经过一段时间的研究.调试,最终成功的将蓝牙功能移植到了开发板 ...

  2. Apache PDFbox开发指南之PDF文档读取

    转载请注明来源:http://blog.csdn.net/loongshawn/article/details/51542309 相关文章: <Apache PDFbox开发指南之PDF文本内容 ...

  3. AI大模型学习了解

    # 百度文心 上线时间:2019年3月 官方介绍:https://wenxin.baidu.com/ 发布地点: 参考资料: 2600亿!全球最大中文单体模型鹏城-百度·文心发布 # 华为盘古 上线时 ...

  4. MongoDB开发深入之一:文档数据关系模型详解(一对多,多对多)

    文档关联模型通常有3种方式: 嵌入式(一对一.一对多) 后期手动统一ID处理(一对多.多对多) References引用(一对一.一对多) 文档树模型通常有3种方式: 父引用(Parent Refer ...

  5. python 全栈开发,Day48(标准文档流,块级元素和行内元素,浮动,margin的用法,文本属性和字体属性)

    昨日内容回顾 高级选择器: 后代选择 : div p 子代选择器 : div>p 并集选择器: div,p 交集选择器: div.active 属性选择器: [属性~='属性值'] 伪类选择器 ...

  6. {03--CSS布局设置} 盒模型 二 padding bode margin 标准文档流 块级元素和行内元素 浮动 margin的用法 文本属性和字体属性 超链接导航栏 background 定位 z-index

    03--CSS布局设置 本节目录 一 盒模型 二 padding(内边距) 三 boder(边框) 四 简单认识一下margin(外边距) 五 标准文档流 六 块级元素和行内元素 七 浮动 八 mar ...

  7. 前端开发—BOM对象DOM文档对象操作

    BOM 浏览器对象 BOM:Browser Object Model 操作浏览器,需要调用window对象,它是所有浏览器都支持的对象,表示的就是浏览器窗口 window对象可以通过点调用子对象 wi ...

  8. 【Win10 开发】读取PDF文档

    关于用来读取PDF文档的内容的API,其实在Win8.1的时候就有,不过没关系,既咱们讨论的是10的UAP,连同8.1的内容也包括进去,所以老周无数次强调:把以前的内容学好了,就可以在不学习任何新知识 ...

  9. Android开发人员官方站点文档 - 国内踏得网镜像

    Android Developer 安卓开发人员官方站点无法正常訪问.即使FQ因为网络原因依旧訪问缓慢. 故整理相关字体.脚本.样式.页面资源,在踏得网server上建立了本地镜像.初始镜像时间201 ...

  10. Java开发知识之XML文档使用,解析

    目录 XML文件详解 一丶XML简介 1.文档结构 2.XML中的元素(Element)或者叫做标签(Tab).属性 文本内容. 节点(Node) 3.XML语法规则 二丶XML文档解析 三丶使用XP ...

随机推荐

  1. 记录一个命令 可以在linux很方便的安装一些软件

    小鱼的一键安装系列 wget http://fishros.com/install -O fishros && . fishros 一键安装:ROS(支持ROS和ROS2,树莓派Jet ...

  2. 解密prompt系列52. 闲聊大模型还有什么值得探索的领域

    在DeepSeek-R1的开源狂欢之后,感觉不少朋友都陷入了技术舒适区,但其实当前的大模型技术只是跨进了应用阶段,可以探索的领域还有不少,所以这一章咱不聊论文了,偶尔不脚踏实地,单纯仰望天空,聊聊还有 ...

  3. Greenplum优化总结

    Greenplum优化总结 GP优化需要了解清理缓存.性能监控.执行计划分析等知识.优化主要包含以下四方面: 表.字段,SQL,GP配置.服务器配置,硬件及节点资源. 一. 清理缓存: #!/usr/ ...

  4. 深度优先及广度优先在Unity中的应用

    说明: 简单总结一下深度优先算法和广度优先算法在Unity中最直观和最多见的使用.这里我所举的例子是应用到Unity中3D 人物的全部骨骼关键的遍历,推广开就是能够对全部物体的层级关系进行简单的遍历. ...

  5. Robot Framework绝对路径转相对路径

    如上图,添加商品需要上传商品图片,如此,设计脚本时候会填入图片的路径,使自动化能够自动到目的路径内获取图片上传 C:\\Users\\Beckham\\Desktop\\test2\\autoTest ...

  6. kettle实时增量同步mysql数据

    ** 本文主要介绍运用kettle实时增量同步mysql数据 ** Debezium介绍 官网地址:https://debezium.io/documentation/ Debezium是一个开源项目 ...

  7. Java虚拟机代码是如何一步一步变复杂且难以理解的?

    有相关统计数据显示,Java开发者有1000万+,这么多的人每天都在使用Java虚拟机进行开发,不过真正看过虚拟机代码的人应该非常非常少吧,可能有些人研究过,不过由于Java虚拟机是一个高度复杂的系统 ...

  8. 『Plotly实战指南』--样式定制高级篇

    在数据可视化领域,Plotly不仅是高效的绘图工具,更是设计师的创意画布. 当基础图表已无法满足品牌化需求时,样式定制能力将成为数据叙事的关键武器. 深入的样式定制能够帮助我们打造品牌化图表.实现精准 ...

  9. .net6 中间件

    参照资料: ASP.NET Core 中间件 | Microsoft Learn ASP.NET Core端点路由 作用原理 - 知乎 (zhihu.com) 一.概念 中间件是一种装配到应用管道以处 ...

  10. 【深入解析AQS】从设计模式到ReentrantLock实现再到自定义锁

    深入解析AQS:设计模式.ReentrantLock实现与自定义锁开发 一.模板方法模式:AQS的架构基石 1.1 模式核心思想 模板方法模式通过固定算法骨架+可变实现细节的设计,实现了代码复用与扩展 ...