LangChain-v0.2文档翻译:2.14、教程-总结文本

  1. 介绍
  2. 教程
    2.1. 构建一个简单的 LLM 应用程序
    2.2. 构建一个聊天机器人
    2.3. 构建向量存储库和检索器
    2.4. 构建一个代理
    2.5. 构建检索增强生成 (RAG) 应用程序
    2.6. 构建一个会话式RAG应用程序
    2.7. 在SQL数据上构建一个问答系统
    2.8. 构建查询分析系统
    2.9. 基于查询分析系统构建一个本地RAG应用程序
    2.10. 基于图形数据库构建问答应用程序
    2.11. 构建一个提取链
    2.12. 生成合成数据
    2.13. 将文本分类为标签
    2.14. 文本摘要(点击查看原文

总结文本

假设您有一组文档(PDF、Notion页面、客户问题等),并且您想要总结这些内容。

鉴于它们在理解和综合文本方面的熟练程度,大型语言模型(LLMs)是完成这项任务的绝佳工具。

在增强型检索生成的背景下,总结文本可以帮助提炼大量检索到的文档中的信息,为LLM提供上下文。

在本教程中,我们将介绍如何使用LLMs从多个文档中总结内容。
在这里插入图片描述

概念 ​

我们将涵盖以下概念:

  • 使用语言模型。
  • 使用文档加载器,特别是WebBaseLoader,从HTML网页加载内容。
  • 总结或以其他方式组合文档的三种方式。
    1. 填充(Stuff),它简单地将文档连接成一个提示;
    2. 映射-归约(Map-reduce),将文档分成批次,总结这些批次,然后总结总结;
    3. 细化(Refine),通过顺序迭代文档来更新滚动摘要。

这是一个相当多的内容!让我们开始吧。

设置 ​

Jupyter Notebook ​

本指南(以及文档中的大多数其他指南)使用Jupyter笔记本,并假定读者也是如此。Jupyter笔记本非常适合学习如何使用LLM系统,因为事情有时会出错(意外输出、API故障等),在交互式环境中进行指南学习是更好地理解它们的好方法。

这些和其他教程可能最方便地在Jupyter笔记本中运行。请参阅此处以获取安装说明。

安装 ​

要安装LangChain,请运行:

  • Pip
pip install langchain
  • Conda
conda install langchain -c conda-forge

有关更多详细信息,请参阅我们的安装指南。

LangSmith ​

您使用LangChain构建的许多应用程序将包含多个步骤,涉及多次调用LLM。
随着这些应用程序变得越来越复杂,能够检查链或代理内部的确切情况变得至关重要。
实现这一点的最佳方式是使用LangSmith。

在上述链接注册后,请确保设置环境变量以开始记录跟踪:

export LANGCHAIN_TRACING_V2="true"
export LANGCHAIN_API_KEY="..."

或者,如果在笔记本中,您可以使用以下方式设置它们:

import getpass
import os

os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = getpass.getpass()

概述 ​

构建摘要器的一个核心问题是如何在LLM的上下文窗口中传递您的文档。对于此,有三种常见的方法:

  1. Stuff:简单地将所有文档“塞入”单个提示中。这是最简单的方法(请参阅此处,了解用于此方法的create_stuff_documents_chain构造函数的更多信息)。
  2. Map-reduce:在“映射”步骤中独立总结每个文档,然后“归约”这些摘要为最终摘要(请参阅此处,了解用于此方法的MapReduceDocumentsChain的更多信息)。
  3. Refine:通过顺序迭代文档来更新滚动摘要。

在这里插入图片描述

快速开始 ​

为了让您先睹为快,任何一种管道都可以被封装在一个单独的对象中:load_summarize_chain

假设我们想要总结一篇博客文章。我们可以在几行代码中创建这个。

首先设置环境变量并安装包:

%pip install --upgrade --quiet langchain-openai tiktoken chromadb langchain

# 设置环境变量 OPENAI_API_KEY 或从 .env 文件加载
# import dotenv

# dotenv.load_dotenv()

我们可以使用 chain_type="stuff",特别是如果使用像:

  • 128k 令牌 OpenAI gpt-4-turbo-2024-04-09
  • 200k 令牌 Anthropic claude-3-sonnet-20240229

我们也可以使用 chain_type="map_reduce"chain_type="refine"

首先我们加载我们的文档。我们将使用 WebBaseLoader 来加载博客文章:

import os

os.environ["LANGCHAIN_TRACING_V2"] = "True"
from langchain.chains.summarize import load_summarize_chain
from langchain_community.document_loaders import WebBaseLoader
from langchain_openai import ChatOpenAI

loader = WebBaseLoader("https://lilianweng.github.io/posts/2023-06-23-agent/")
docs = loader.load()

llm = ChatOpenAI(temperature=0, model_name="gpt-3.5-turbo-1106")
chain = load_summarize_chain(llm, chain_type="stuff")

result = chain.invoke(docs)

print(result["output_text"])
文章讨论了由大型语言模型(LLMs)驱动的自治代理的概念,重点关注了规划、记忆和工具使用等组成部分。它包括案例研究和概念验证示例,以及挑战和对相关研究的引用。作者强调了LLMs在创建强大的问题解决代理方面的潜力,同时也强调了自然语言接口的可靠性等限制。

选项 1. 填充(Stuff)​

当我们使用 load_summarize_chainchain_type="stuff" 时,我们将使用 StuffDocumentsChain。

该链将获取一个文档列表,将它们全部插入到一个提示中,并将该提示传递给一个LLM:

from langchain.chains.combine_documents.stuff import StuffDocumentsChain
from langchain.chains.llm import LLMChain
from langchain_core.prompts import PromptTemplate

# 定义提示
prompt_template = """Write a concise summary of the following:
"{text}"
CONCISE SUMMARY:"""
prompt = PromptTemplate.from_template(prompt_template)

# 定义 LLM 链
llm = ChatOpenAI(temperature=0, model_name="gpt-3.5-turbo-16k")
llm_chain = LLMChain(llm=llm, prompt=prompt)

# 定义 StuffDocumentsChain
stuff_chain = StuffDocumentsChain(llm_chain=llm_chain, document_variable_name="text")

docs = loader.load()
print(stuff_chain.invoke(docs)["output_text"])
文章讨论了构建由大型语言模型(LLMs)驱动的自治代理的概念。它探讨了这些代理的组成部分,包括规划、记忆和工具使用。文章提供了概念验证演示和示例,突出了LLM驱动代理的挑战和限制。它还包括对相关研究论文和项目的引用。

太好了!我们可以看到我们使用 load_summarize_chain 重现了之前的结果。

更深入 ​

  • 您可以轻松自定义提示。
  • 您可以通过 llm 参数轻松尝试不同的 LLMs(例如,Claude)。

选项 2. 映射-归约(Map-Reduce)​

让我们深入探讨映射归约方法。为此,我们首先使用 LLMChain 将每个文档映射到单独的摘要。然后,我们将使用 ReduceDocumentsChain 将这些摘要合并成一个全局摘要。

首先,我们指定用于将每个文档映射到单独摘要的 LLMChain:

from langchain.chains import MapReduceDocumentsChain, ReduceDocumentsChain
from langchain_text_splitters import CharacterTextSplitter

llm = ChatOpenAI(temperature=0)

# 映射
map_template = """The following is a set of documents
{docs}
Based on this list of docs, please identify the main themes
Helpful Answer:"""
map_prompt = PromptTemplate.from_template(map_template)
map_chain = LLMChain(llm=llm, prompt=map_prompt)

我们还可以使用 Prompt Hub 存储和获取提示。

这将与您的 LangSmith API 密钥一起工作。

例如,请参阅这里的映射提示。

from langchain import hub

map_prompt = hub.pull("rlm/map-prompt")
map_chain = LLMChain(llm=llm, prompt=map_prompt)

ReduceDocumentsChain 处理将文档映射结果归约为单个输出。它包装了一个通用的 CombineDocumentsChain(如 StuffDocumentsChain),但如果它们累积的大小超过了 token_max,则增加了在将其传递给 CombineDocumentsChain 之前折叠文档的能力。在这个例子中,我们实际上可以重用我们的链来合并文档,也可以折叠文档。

所以,如果我们映射文档的累积令牌数超过了 4000 个令牌,那么我们将递归地将文档以小于 4000 个令牌的批次传递给我们的 StuffDocumentsChain 来创建批量摘要。一旦这些批量摘要的累积大小小于 4000 个令牌,我们将它们全部传递给 StuffDocumentsChain 最后一次,以创建最终摘要。

# 归约
reduce_template = """The following is a set of summaries:
{docs}
Take these and distill it into a final, consolidated summary of the main themes.
Helpful Answer:"""
reduce_prompt = PromptTemplate.from_template(reduce_template)

# 注意我们也可以从上面的提示中心获取,如上所述
reduce_prompt = hub.pull("rlm/reduce-prompt")

reduce_prompt

ChatPromptTemplate(input_variables=[‘docs’], metadata={‘lc_hub_owner’: ‘rlm’, ‘lc_hub_repo’: ‘map-prompt’, ‘lc_hub_commit_hash’: ‘de4fba345f211a462584fc25b7077e69c1ba6cdcf4e21b7ec9abe457ddb16c87’}, messages=[HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=[‘docs’], template=‘The following is a set of documents:\n{docs}\nBased on this list of docs, please identify the main themes \nHelpful Answer:’))])

# 运行链
reduce_chain = LLMChain(llm=llm, prompt=reduce_prompt)

# 将文档列表组合成单个字符串,并将其传递给LLMChain
combine_documents_chain = StuffDocumentsChain(
    llm_chain=reduce_chain, document_variable_name="docs"
)

# 组合并迭代归约映射文档
reduce_documents_chain = ReduceDocumentsChain(
    # 这是最终调用的链。
    combine_documents_chain=combine_documents_chain,
    # 如果文档超出了`StuffDocumentsChain`的上下文
    collapse_documents_chain=combine_documents_chain,
    # 将文档分组的最大令牌数。
    token_max=4000,
)

将映射和归约链合并为一个:

map_reduce_chain = MapReduceDocumentsChain(
    # 映射链
    llm_chain=map_chain,
    # 归约链
    reduce_documents_chain=reduce_documents_chain,
    # 在llm_chain中放置文档的变量名称
    document_variable_name="docs",
    # 在输出中返回映射步骤的结果
    return_intermediate_steps=False,
)

text_splitter = CharacterTextSplitter.from_tiktoken_encoder(
    chunk_size=1000, chunk_overlap=0
)
split_docs = text_splitter.split_documents(docs)

# 创建了一个大小为1003的块,比指定的1000长

result = map_reduce_chain.invoke(split_docs)

print(result["output_text"])
在提供文档列表中识别出的主要主题与大型语言模型(LLMs)、自治代理、提示、引导语言模型、自然语言处理(NLP)、使用工具增强语言模型、强化学习、推理、行动、自我反思以及将语言模型与外部知识源整合有关。

如果我们遵循Langsmith Trace,我们可以看到个别LLM摘要,包括最终调用,该调用总结了摘要。

更深入 ​

自定义

  • 如上所示,您可以为映射和归约阶段自定义LLMs和提示。

现实世界用例

  • 请参阅这篇博客文章案例研究,分析用户交互(有关LangChain文档的问题)!
  • 博客文章和相关存储库还引入了聚类作为摘要的一种手段。
  • 这开辟了除了stuffmap-reduce方法之外值得考虑的另一条路径。

在这里插入图片描述

选项 3. 细化(Refine)​

RefineDocumentsChain 类似于映射-归约:

细化文档链通过循环遍历输入文档并逐步更新其答案来构建响应。对于每个文档,它将所有非文档输入、当前文档和最新的中间答案传递给LLM链,以获得新的答案。

这可以很容易地使用指定的 chain_type="refine" 来运行。

chain = load_summarize_chain(llm, chain_type="refine")
result = chain.invoke(split_docs)

print(result["output_text"])
现有摘要为通过代码实现项目架构提供了详细的指导,重点关注在不同文件中创建核心类、函数和方法,遵循所选语言和框架的最佳实践。还概述了对模型、视图和控制器组件的假设。额外的上下文突出了长期规划和任务分解的挑战,以及LLM驱动的自治代理中自然语言接口的可靠性问题。这些见解揭示了在代理系统中使用LLM的限制和潜在陷阱,引用了关于LLM驱动的自治代理和相关技术的最新研究。

通过Langsmith跟踪,我们可以看到摘要随着新信息的加入而逐步更新。

也可以提供提示并返回中间步骤。

prompt_template = """
Write a concise summary of the following:
{text}
CONCISE SUMMARY:
"""
prompt = PromptTemplate.from_template(prompt_template)

refine_template = (
    "Your job is to produce a final summary\n"
    "We have provided an existing summary up to a certain point: {existing_answer}\n"
    "We have the opportunity to refine the existing summary"
    "(only if needed) with some more context below.\n"
    "------------\n"
    "{text}\n"
    "------------\n"
    "\n"
    "Given the new context, refine the original summary in Italian"
    "If the context isn't useful, return the original summary."
)
refine_prompt = PromptTemplate.from_template(refine_template)

chain = load_summarize_chain(
    llm=llm,
    chain_type="refine",
    question_prompt=prompt,
    refine_prompt=refine_prompt,
    return_intermediate_steps=True,
    input_key="input_documents",
    output_key="output_text",
)
result = chain.invoke({"input_documents": split_docs}, return_only_outputs=True)

print(result["output_text"])
本文讨论了使用大型语言模型(LLM)作为主要控制器构建自治代理的概念。文章探讨了LLM驱动的代理系统的不同组成部分,包括规划、记忆和工具使用。它还提供了概念验证演示的例子,并强调了LLM作为通用问题解决者的潜力。Chain of Thought、Tree of Thoughts、LLM+P、ReAct和Reflexion等方法允许自治代理进行计划、自我反思并逐步改进。然而,需要面对的挑战包括有限的上下文能力,这限制了详细历史信息的包含以及长期规划和任务分解的困难。此外,LLM与外部组件如记忆和工具之间的自然语言界面的可靠性是不确定的,因为LLM可能会犯格式错误并表现出反抗行为。尽管如此,AutoGPT系统被提及为使用LLM作为自治代理主要控制器的概念验证示例。本文引用了多种来源,探讨了LLM在自治代理领域的特定方法和应用。
print("\n\n".join(result["intermediate_steps"][:3]))
本文讨论了使用大型语言模型(LLM)作为核心控制器构建自治代理的概念。文章探讨了LLM驱动的代理系统的不同组成部分,包括规划、记忆和工具使用。它还提供了概念验证演示的例子,并强调了LLM作为通用问题解决者的潜力。
本文讨论了使用大型语言模型(LLM)作为主要控制器构建自治代理的概念。文章探讨了LLM驱动的代理系统的不同组成部分,包括规划、记忆和工具使用。它还提供了概念验证演示的例子,并强调了LLM作为通用问题解决者的潜力。此外,介绍了Chain of Thought、Tree of Thoughts、LLM+P、ReAct和Reflexion等方法,这些方法允许自治代理进行计划、自我反思并逐步改进。新上下文涉及Chain of Hindsight (CoH)方法,允许模型通过监督学习过程自主改进自己的输出。还介绍了Algorithm Distillation (AD)方法,将相同的概念应用于强化学习任务的学习轨迹。

在单个链中拆分和总结 ​

为了方便起见,我们可以将长文档的文本拆分和总结包装在单个 AnalyzeDocumentsChain 中。

from langchain.chains import AnalyzeDocumentChain

summarize_document_chain = AnalyzeDocumentChain(
    combine_docs_chain=chain, text_splitter=text_splitter
)
summarize_document_chain.invoke(docs[0].page_content)

下一步 ​

我们鼓励您查看如何指南,以获取更多详细信息:

  • 内置文档加载器和文本拆分器
  • 将各种合并文档链集成到RAG应用程序中
  • 在聊天机器人中整合检索

以及其他概念。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值