流式传输(stream_runnabels)

流式传输(stream runnabels)

  • 流式传输是什么?
       - 流式传输是一种将文本或数据分段传输的技术,通常用于处理大量数据或需要实时显示结果的场景。
  • 流式传输有什么用?
       - 流式传输可以提高用户体验,因为它允许用户在结果生成的同时看到部分结果,而不是等到整个结果生成完毕。
  • 流式传输的实现方式
        - 方式一:使用 syncstream 方法:流式处理默认实现,传输最终输出
        - 方式二:使用 asyncastream 方式:从链流式传输中间步骤和最终结果
# 加载环境变量
from dotenv import load_dotenv
load_dotenv()

True

# 导入mistral模型
from langchain_mistralai import ChatMistralAI

chat_model=ChatMistralAI(model="mistral-large-latest")
chat_model.invoke("你好")

AIMessage(content=‘你好!有什么我可以帮忙的吗?’, additional_kwargs={}, response_metadata={‘token_usage’: {‘prompt_tokens’: 6, ‘total_tokens’: 23, ‘completion_tokens’: 17}, ‘model’: ‘mistral-large-latest’, ‘finish_reason’: ‘stop’}, id=‘run-cf712419-fc7e-453b-9b32-e602f8a81658-0’, usage_metadata={‘input_tokens’: 6, ‘output_tokens’: 17, ‘total_tokens’: 23})

chunks=[]
for chunk in chat_model.stream("简要回答,流式传输是什么"): #.stream()使用流式输出
    chunks.append(chunk)
    print(chunk.content,end="|",flush=True) #flash=True,刷新缓存,立即显示
print()
print(chunks[0])

||流|式|传|输|是|一|种|数据|传|输|方|式|,|数据|在|传|输|过|程|中|逐|段|发|送|,|而|不|是|一|次|性|传|输|整|个|文|件|。|这|种|方|式|常|用|于|音|频|、|视|频|等|媒|体|内|容|,|因|为|它|允|许|用|户|在|下|载|过|程|中|实|时|播|放|内|容|,|而|不|需|要|等|待|整|个|文|件|下|载|完|成|。|流|式|传|输|可|以|提|高|用|户|体|验|,|减|少|等|待|时|间|,|并|且|有|效|利|用|网|络|带|宽|。||

content=‘’ additional_kwargs={} response_metadata={} id=‘run-32fe98e7-4a0e-42cf-867c-724886cc85e0’

# 在异步环境中使用流式输出
chunks_async=[]
async for chunk in chat_model.astream("简要回答,流式传输是什么"):  #async for:异步迭代语法;astream是stream的异步版本
    chunks_async.append(chunk)
    print(chunk.content,end="|",flush=True)
print()
print(chunks_async[0])

||流式传输|是|一|种数据|传输方|式|,数据|在|传|输过|程中|被|分|割|成小|块|,|逐|块|发|送和|接|收,|而|不需|要等|待|整个|数据|文|件完|全|下|载或|上|传。|常|见|的|应|用包|括在|线|视|频播|放、|音|频|流|和|实|时数据|传|输。|流|式传|输允|许数据在|传|输过|程中即|时被|处|理和|展|示,|提|高|了用|户体|验。||

content=‘’ additional_kwargs={} response_metadata={} id=‘run-db2cb2af-75ba-40a6-ab1c-6335c4db9f51’

# 消息块之间可以相加
chunks[0]+chunks[1]+chunks[2]+chunks[3]+chunks[4]

AIMessageChunk(content=‘流式传’, additional_kwargs={}, response_metadata={}, id=‘run-32fe98e7-4a0e-42cf-867c-724886cc85e0’)

结合提示词模板和链的使用
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate  

prompt=ChatPromptTemplate.from_template("给我讲一个关于{topic}的笑话")
parser=StrOutputParser()    #StrOutputParser:将模型输出转换为字符串的解析器

chain=prompt|chat_model|parser  #|:将多个组件连接起来,形成一个链

async for chunk in chain.astream({"topic":"猴子"}):
    print(chunk,end="|",flush=True) #由于StrOutputParser(),所以不使用chunk.content 
    

||当|然|可|以!|这|里|有|一个|关|于|猴|子的|笑话:|

有|一天|,一|只|猴子|去|银|行|兑换|香|蕉。|银|行职|员看|到|猴|子拿|着|一|大|袋|香|蕉,|觉|得很|奇|怪,|就|问|猴|子:“|你|为|什么|要|兑换|这么|多香|蕉?|”

|猴子回|答道:“因|为我|听|说香|蕉|在|这|里|很|值|钱,|我|想|用|它|们|换|取一|些现|金。|”

|银行职|员笑|了|笑|,|说|:“|香|蕉在|这|里可|不|值|钱|,|但|是你|的|幽|默感|真|是|无|价|之|宝!|”

|

|猴子|听|了|,|挠|了|挠头|,说|:|“原|来如|此,|看|来我|还|是|去|动|物|园找|工|作好|了,|那|里的|香|蕉可|能更|受|欢迎|。”

|

希|望这|个笑|话能|给你带|来一|些|欢|乐|!||

流式处理

# 使用解析器将输出转换为Json格式
from langchain_core.output_parsers import JsonOutputParser

chain=(chat_model|JsonOutputParser())   #JsonOutputParser:将模型输出转换为JSON格式

async for text in chain.astream(
    "以 JSON 格式输出国家/地区 France、Spain 和 Japan 及其人口的列表。"
    "使用外部键为 “countries” 的字典,其中包含国家/地区列表。"
    "每个国家/地区都应具有键 'name' 和 'population'"
):
    print(text,flush=True)

{}

{‘countries’: []}

{‘countries’: [{}]}

{‘countries’: [{‘name’: ‘’}]}

{‘countries’: [{‘name’: ‘Fr’}]}

{‘countries’: [{‘name’: ‘France’}]}

{‘countries’: [{‘name’: ‘France’, ‘population’: 6}]}

{‘countries’: [{‘name’: ‘France’, ‘population’: 67081000}, {‘name’: ‘Spain’, ‘population’: 47351567}, {‘name’: ‘Japan’, ‘population’: 1258100}]}

{‘countries’: [{‘name’: ‘France’, ‘population’: 67081000}, {‘name’: ‘Spain’, ‘population’: 47351567}, {‘name’: ‘Japan’, ‘population’: 12581000}]}

{‘countries’: [{‘name’: ‘France’, ‘population’: 67081000}, {‘name’: ‘Spain’, ‘population’: 47351567}, {‘name’: ‘Japan’, ‘population’: 125810000}]}

# 在对解析器处理后的json格式数据利用一个提取函数,获取国家名称
from langchain_core.output_parsers import (
    JsonOutputParser,
)
 

# 提取国家名称的函数
def _extract_country_name(inputs):
    if not isinstance(inputs,dict):
        return ""
    if "countries" not in inputs:
        return ""

    countries=inputs["countries"]   #只要countries键对应的值

    if not isinstance(countries,list):
        return ""
    country_names=[
        country.get("name") for country in countries if isinstance(country,dict)    #遍历countries列表,如果country是字典,则获取name键对应的值
    ]
    return country_names

  
chain=chat_model|JsonOutputParser()|_extract_country_name

async for text in chain.astream(
    "以 JSON 格式输出国家/地区 France、Spain 和 Japan 及其人口的列表。"
    "使用外部键为 “countries” 的字典,其中包含国家/地区列表。"
    "每个国家/地区都应具有键 'name' 和 'population'"
):
    print(text,flush=True)

[‘France’, ‘Spain’, ‘Japan’]

# 使用异步流式处理(收到一个处理一个,实时性更高)
async def _extract_country_names_streaming(input_stream):
    country_names_so_far=set()
    
    async for input in input_stream:    #不是一次处理所有数据,然是收到一个处理一个
        if not isinstance(input,dict):
            continue
        if "countries" not in input:
            continue

        countries=input["countries"]

        if not isinstance(countries,list):
            continue

        for country in countries:
            name=country.get("name")
            if not name:
                continue
            if name not in country_names_so_far:
                country_names_so_far.add(name)
                yield name

chain=chat_model|JsonOutputParser()|_extract_country_names_streaming

async for text in chain.astream(
    "以 JSON 格式输出国家/地区 France、Spain 和 Japan 及其人口的列表。"
    "使用外部键为 “countries” 的字典,其中包含国家/地区列表。"
    "每个国家/地区都应具有键 'name' 和 'population'"
):
    print(text,end="|",flush=True)

Fr|France|Spain|Japan|

处理非流式组件

  • error:没有openai的key使用不了OpenAIEmbeddings
        - 没有检索文档
  • 不懂的概念太多以后再学
from langchain_community.vectorstores import FAISS
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import OpenAIEmbeddings

template="""请根据以下内容回答问题:
{context}
提问:{question}
"""
prompt=ChatPromptTemplate.from_template(template)

# 创建一个向量存储
vectorstore=FAISS.from_texts(
    ["光头强在狗熊岭工作","光头强喜欢砍树"],
    embedding=OpenAIEmbeddings()
)

# 创建一个检索器
retriever=vectorstore.as_retriever()

# 使用流式处进行检索
chunks=[chunk for chunk in retriever.stream("光头强喜欢砍树吗?")]
chunks
#创建检索链
retrieval_chain = (
    {
        "context": retriever.with_config(run_name="Docs"),  #设置上下文,使用检索器获取相关文档
        "question": RunnablePassthrough(),  #直接传递问题
    }
    | prompt  #使用提示词模板
    | chat_model  #使用模型
    | StrOutputParser()  #使用字符串解析器
)

for chunk in retrieval_chain.stream({"question":"光头强喜欢砍树吗?"}):
    print(chunk,end="|",flush=True)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值