【LangChain系列】9. 实用技巧:大模型的流式输出在 OpenAI 和 LangChain 中的使用

当大模型的返回文字非常多时,返回完整的结果会耗费比较长的时间。如果等待大模型形成完整的答案再展示给用户,明显会给用户不好的体验。所以,现在市面上大多数的AI应用,在给用户结果时,都是以流式输出的方式展示给用户的。所谓的流式输出,就是类似打字机式的方式,一个字或一个词的输出,给用户一种答案逐渐出现的动画效果。

今天我们来学习下如何流式输出大模型的返回结果。本文将涵盖 LangChain 的流式输出方式和 OpenAI 原生的流式输出方式。
在这里插入图片描述

0. LangChain的流式输出 Streaming

0.1 实现流式输出

我们在 【AI大模型应用开发】【LangChain系列】实战案例4:再战RAG问答,提取在线网页数据,并返回生成答案的来源 代码的基础上,增加流式输出。

原代码:

python代码解读复制代码import bs4
from langchain import hub
from langchain_community.document_loaders import WebBaseLoader
from langchain_community.vectorstores import Chroma
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter

# Load, chunk and index the contents of the blog.
loader = WebBaseLoader(
    web_paths=("https://lilianweng.github.io/posts/2023-06-23-agent/",),
    bs_kwargs=dict(
        parse_only=bs4.SoupStrainer(
            class_=("post-content", "post-title", "post-header")
        )
    ),
)
docs = loader.load()

text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
splits = text_splitter.split_documents(docs)
vectorstore = Chroma.from_documents(documents=splits, embedding=OpenAIEmbeddings())

# Retrieve and generate using the relevant snippets of the blog.
retriever = vectorstore.as_retriever()
prompt = hub.pull("rlm/rag-prompt")
llm = ChatOpenAI(model_name=
<think>好的,我现在需要帮助用户了解如何在LangChain中实现代理的流式输出。首先,我要回想一下LangChain的基本结构,特别是AgentAgentExecutor的运作机制。根据之前学过的知识,Agent通过结合语言模型工具来执行任务,而AgentExecutor负责驱动整个流程。 用户提到流式输出,也就是希望看到逐步的输出结果,而不是等待所有处理完成后一次性返回。这通常涉及将中间步骤的结果实时反馈给用户。我需要考虑如何截获Agent执行过程中的各个步骤,比如工具的选择、输入的处理、模型的响应等,并将这些信息逐步输出。 接下来,查阅相关文档,比如《LangChain Agent 原理解析》中提到,AgentExecutor通过循环处理模型输出,直到生成最终结果。这提示我可以通过回调函数或自定义执行流程来捕获中间步骤。可能需要在调用AgentExecutor时传入一个回调处理器,或者在自定义的循环中逐步执行并输出结果。 然后,我需要一个示例代码。根据《LangChain AgentExecutor究竟是怎样驱动模型工具完成任务的》,标准的Agent执行是同步的,但可以通过异步或生成器的方式实现流式输出。可能需要覆盖部分方法,或者在每一步执行后手动触发输出。 另外,参考《LangChain文档》中的流式输出示例,通常是通过将模型的stream参数设为True,但Agent涉及到工具调用,所以需要更细致的处理。例如,在每次模型生成token时捕获,或者在每次工具调用前后发送信息。 现在需要将这些思路整合成一个教程。首先,导入必要的模块,如Agent、工具、回调处理器。然后,设置模型,这里可能使用OpenAI的模型,并启用流式。接着,定义工具,比如搜索工具或计算工具。之后,创建代理,并自定义执行流程,使用生成器函数逐步产生输出。在每一步处理中,比如选择工具、执行工具、获取结果时,将相关信息通过yield返回,实现流式传输。 可能遇到的问题包括:如何正确处理异步操作,如何确保回调函数在正确的时间被触发,以及如何处理可能出现的错误或中断。需要测试代码,确保每个步骤的输出都能实时显示,并且代理能正确完成整个流程。 最后,总结实现的关键点:使用回调或生成器函数截获中间步骤,自定义执行循环,以及正确设置模型的流式参数。同时,提醒用户注意代理的复杂性可能的优化方向,比如错误处理性能调整。</think>### LangChain代理流式输出实现教程 在LangChain中实现代理的流式输出,需要通过回调机制截获中间执行过程。以下是基于ReAct框架的实现方法: ```python from langchain.agents import AgentExecutor, initialize_agent from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler from langchain.llms import OpenAI from langchain.tools import Tool class StreamAgentExecutor(AgentExecutor): def stream_execute(self, input_str): intermediate_steps = [] result = "" for step in self.iter(input_str): if isinstance(step, dict): # 工具调用步骤 yield f"调用工具: {step[&#39;tool&#39;]}\n输入: {step[&#39;input&#39;]}" intermediate_steps.append((step[&#39;action&#39;], step[&#39;observation&#39;])) else: # 最终结果 result = step yield f"最终答案: {result}" # 初始化组件 llm = OpenAI(streaming=True, callbacks=[StreamingStdOutCallbackHandler()], temperature=0) tools = [ Tool( name="Search", func=lambda q: "搜索结果: " + q, # 替换为实际搜索工具 description="用于问题搜索" ) ] # 创建代理 agent = initialize_agent( tools, llm, agent="react-docstore", verbose=True ) # 转换为流式执行器 stream_agent = StreamAgentExecutor.from_agent_and_tools( agent=agent.agent, tools=tools, llm=llm ) # 使用示例 for chunk in stream_agent.stream_execute("北京的人口数量?"): print(chunk) print("---") # 模拟流式输出分隔 ``` 关键实现点: 1. 继承`AgentExecutor`并重写执行流程,通过生成器逐步输出 2. 在工具调用阶段捕获动作输入参数[^1] 3. 使用流式LLM配置(`streaming=True`)保证模型输出实时性[^2] 4. 通过`yield`机制实现分块输出
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值