最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

python后端流式處理LLM響應(yīng)數(shù)據(jù)使用解讀

 更新時(shí)間:2025年12月30日 09:02:24   作者:nvd11  
本文詳細(xì)介紹了通過(guò)流式處理優(yōu)化大語(yǔ)言模型響應(yīng)的方法,展示了其在提升用戶體驗(yàn)方面的優(yōu)勢(shì),并通過(guò)代碼實(shí)現(xiàn)和性能對(duì)比進(jìn)行了說(shuō)明,流式處理允許服務(wù)器逐塊發(fā)送數(shù)據(jù),而非一次性生成并返回完整響應(yīng),從而實(shí)現(xiàn)更流暢的用戶體驗(yàn)

本文檔詳細(xì)描述了我們?nèi)绾瓮ㄟ^(guò)流式處理(Streaming)來(lái)優(yōu)化大語(yǔ)言模型(LLM)的響應(yīng),以提升用戶體驗(yàn)。我們將通過(guò)代碼實(shí)現(xiàn)和性能對(duì)比,來(lái)展示流式處理的優(yōu)勢(shì)。

實(shí)際效果

1、問(wèn)題背景

在傳統(tǒng)的請(qǐng)求-響應(yīng)模式中,客戶端向服務(wù)器發(fā)送一個(gè)請(qǐng)求,然后必須等待服務(wù)器完全處理完該請(qǐng)求并生成完整的響應(yīng)后,才能接收到數(shù)據(jù)。

對(duì)于 LLM 應(yīng)用來(lái)說(shuō),這意味著用戶在輸入問(wèn)題后,需要等待模型生成完整的答案(可能需要幾十秒),這期間界面沒有任何反饋,用戶體驗(yàn)較差。

2、解決方案:流式處理

為了解決這個(gè)問(wèn)題,我們采用了流式處理技術(shù)。

其核心思想是,服務(wù)器不再一次性地返回完整的響應(yīng),而是將響應(yīng)分割成多個(gè)小的數(shù)據(jù)塊(chunks),并逐個(gè)地、實(shí)時(shí)地發(fā)送給客戶端。

在我們的實(shí)現(xiàn)中,我們使用了 FastAPI 的 StreamingResponse,它允許我們創(chuàng)建一個(gè)異步生成器,該生成器可以持續(xù)地 yield 數(shù)據(jù)塊,直到響應(yīng)完全結(jié)束。

2.1. 后端實(shí)現(xiàn)

我們的后端實(shí)現(xiàn)主要涉及以下幾個(gè)部分:

  • deepseek_chat_model.py:負(fù)責(zé)初始化 ChatDeepSeek 模型。
  • llm_service.py:封裝了與 LLM 模型的交互。
  • chat_router.py:定義了 FastAPI 路由和流式生成器。

src/llm/deepseek_chat_model.py

這個(gè)文件負(fù)責(zé)從配置文件中讀取 API 密鑰和基礎(chǔ) URL,并初始化 ChatDeepSeek 模型。

from langchain_deepseek import ChatDeepSeek
from src.configs.config import yaml_configs

def get_deepseek_llm():
    """
    Initializes and returns a ChatDeepSeek instance.
    """
    api_key = yaml_configs["deepseek"]["api-key"]
    base_url = yaml_configs["deepseek"]["base-url"]
    
    llm = ChatDeepSeek(
        model="deepseek-chat",
        temperature=0.2,
        max_tokens=None,
        api_key=api_key,
        base_url=base_url,
    )
    return llm
    ```
2.1.2. src/services/llm_service.py
這個(gè)服務(wù)類封裝了與 LLM 模型的交互,提供了 ainvoke(非流式)和 astream(流式)兩種方法。
```python
from langchain_core.language_models import BaseChatModel
from loguru import logger

class LLMService:
    def __init__(self, llm: BaseChatModel):
        logger.info("Initializing LLMService...")
        self.llm = llm
        logger.info("LLMService initialized.")

    async def ainvoke(self, prompt: str):
        logger.info(f"LLMService ainvoking with prompt: {prompt}")
        response = await self.llm.ainvoke(prompt)
        logger.info("LLMService ainvocation complete.")
        return response

    def astream(self, prompt: str):
        """Streams the response from the LLM."""
        logger.info(f"LLMService astreaming with prompt: {prompt}")
        return self.llm.astream(prompt)

src/routers/chat_router.py

這是我們的 FastAPI 路由,它定義了 /api/v1/chat 這個(gè)端點(diǎn)。它使用 Depends 來(lái)注入 LLMService,并通過(guò)一個(gè)異步生成器 stream_generator 來(lái)調(diào)用 LLMService 的 astream 方法,然后將返回的數(shù)據(jù)塊逐個(gè)地 yield 給客戶端。

from fastapi import APIRouter, Depends
from starlette.responses import StreamingResponse
from src.llm.deepseek_chat_model import get_deepseek_llm
from src.services.llm_service import LLMService

# ...

def get_llm_service():
    """Dependency to get a singleton instance of LLMService."""
    try:
        deepseek_model = get_deepseek_llm()
        return LLMService(llm=deepseek_model)
    except Exception as e:
        logger.error(f"Failed to initialize LLM service for dependency: {e}")
        return None

# ...

async def stream_generator(prompt: str, llm_service: LLMService):
    """Async generator that yields response chunks from the LLM stream."""
    # ...
    try:
        # Call the astream method on the service
        llm_stream = llm_service.astream(prompt)
        
        # Iterate over the stream and yield each chunk to the client
        async for chunk in llm_stream:
            if hasattr(chunk, 'content') and chunk.content:
                yield f"data: {chunk.content}\n\n"
    # ...

@router.post("/chat")
async def chat(request: ChatRequest, llm_service: LLMService = Depends(get_llm_service)):
    # ...
    return StreamingResponse(stream_wrapper(), media_type="text/event-stream")

2.2. yield 的作用:流式處理的核心

在我們的實(shí)現(xiàn)中,yield 關(guān)鍵字是實(shí)現(xiàn)流式處理的核心。它在兩個(gè)關(guān)鍵位置發(fā)揮作用:

在 stream_generator 中:

yield f"data: {chunk.content}\n\n"

在 StreamingResponse 中: FastAPI 在內(nèi)部處理 stream_wrapper 生成器時(shí),也是通過(guò) yield 來(lái)逐塊發(fā)送數(shù)據(jù)。

專業(yè)解釋

當(dāng)一個(gè)函數(shù)包含 yield 關(guān)鍵字時(shí),它就不再是一個(gè)普通的函數(shù),而是一個(gè)生成器(Generator)。

yield 在 stream_generator 中:

  • 當(dāng)我們調(diào)用 stream_generator 時(shí),它不會(huì)立即執(zhí)行函數(shù)體,而是返回一個(gè)生成器對(duì)象。
  • async for chunk in llm_stream: 循環(huán)每次從 LLM 模型獲取一個(gè)數(shù)據(jù)塊(chunk)。
yield f"data: {chunk.content}\n\n" 

這行代碼的作用是:暫停函數(shù)的執(zhí)行,并將 f"data: {chunk.content}\n\n" 這個(gè)值作為當(dāng)前迭代的結(jié)果發(fā)送出去。

當(dāng)外部代碼(在這里是 stream_wrapper)請(qǐng)求下一個(gè)值時(shí),stream_generator 會(huì)從上次暫停的地方恢復(fù)執(zhí)行,直到遇到下一個(gè) yield 或函數(shù)結(jié)束。

StreamingResponse 如何使用 yield:

  • FastAPI 的 StreamingResponse 接收一個(gè)生成器(在我們的例子中是 stream_wrapper)。
  • 它在內(nèi)部迭代這個(gè)生成器。每當(dāng) stream_generator yield 一個(gè)數(shù)據(jù)塊時(shí),StreamingResponse 就會(huì)立即將這個(gè)數(shù)據(jù)塊通過(guò) HTTP 連接發(fā)送給客戶端,而不會(huì)等待整個(gè)響應(yīng)生成完畢。
  • 這個(gè)過(guò)程會(huì)一直持續(xù),直到生成器執(zhí)行完畢,此時(shí) StreamingResponse 會(huì)關(guān)閉 HTTP 連接。
  • 這個(gè)機(jī)制實(shí)現(xiàn)了服務(wù)器和客戶端之間的持續(xù)通信通道,數(shù)據(jù)可以源源不斷地從服務(wù)器流向客戶端。

通俗解釋

我們可以把這個(gè)過(guò)程比作看一場(chǎng)正在直播的足球比賽。

非流式處理(傳統(tǒng)方式):

這就像是等待比賽結(jié)束后,一次性地觀看完整的比賽錄像。你必須等到終場(chǎng)哨聲吹響,電視臺(tái)把90分鐘的比賽全部錄制打包好,然后才能開始觀看。在等待的90分鐘里,你什么也看不到,只能干等。

流式處理(我們的實(shí)現(xiàn)):

這就像是直接觀看電視直播。

  • yield 在 stream_generator 中:可以看作是解說(shuō)員。他不會(huì)等到比賽結(jié)束才說(shuō)話,而是每當(dāng)有精彩瞬間(比如進(jìn)球、犯規(guī)、換人),他就會(huì)立即 yield 一句解說(shuō)詞(一個(gè)數(shù)據(jù)塊)。
  • StreamingResponse:可以看作是電視臺(tái)。它不會(huì)把所有解說(shuō)詞都攢起來(lái),而是一旦收到解說(shuō)員 yield 的一句話,就立刻通過(guò)電視信號(hào)(HTTP 連接)把它廣播給千家萬(wàn)戶(客戶端)。
  • 你(客戶端):坐在電視機(jī)前,幾乎是實(shí)時(shí)地聽到解說(shuō)員的每一句話,看到球場(chǎng)上的每一個(gè)動(dòng)作。雖然整場(chǎng)比賽(完整的 LLM 響應(yīng))還沒結(jié)束,但你已經(jīng)可以持續(xù)地獲取信息,體驗(yàn)非常好。

通過(guò)這種方式,yield 就像一個(gè)聰明的“暫停-繼續(xù)”按鈕,它讓服務(wù)器能夠“邊說(shuō)邊送”,而不是“說(shuō)完再說(shuō)”,從而實(shí)現(xiàn)了流暢的流式體驗(yàn)。

2.3. 前端實(shí)現(xiàn)

在前端,我們可以使用 fetch API 或 EventSource API 來(lái)接收服務(wù)器發(fā)送的流式數(shù)據(jù)。

每當(dāng)接收到一個(gè)新的數(shù)據(jù)塊時(shí),我們就可以立即將其追加到界面上,從而實(shí)現(xiàn)打字機(jī)一樣的效果。

3、性能對(duì)比:流式 vs. 非流式

為了量化流式處理的優(yōu)勢(shì),我們編寫了一個(gè) pytest 測(cè)試用例,分別測(cè)試了 invoke(非流式)和 stream(流式)兩種模式下的響應(yīng)時(shí)間。

test/services/test_deepseek_chat_model.py:

def test_deepseek_chat_model_invoke():
    # ...
    start_time = time.time()
    result = model.invoke(prompt)
    end_time = time.time()
    response_time = end_time - start_time
    logger.info(f"Invoke mode - Total response time: {response_time:.4f} seconds")
    # ...

def test_deepseek_chat_model_stream():
    # ...
    start_time = time.time()
    stream = model.stream(prompt)
    # ...
    for chunk in stream:
        if not first_chunk_received:
            time_to_first_chunk = time.time() - start_time
            logger.info(f"Stream mode - Time to first chunk: {time_to_first_chunk:.4f} seconds")
            first_chunk_received = True
        # ...
    total_stream_time = time.time() - start_time
    logger.info(f"Stream mode - Total response time: {total_stream_time:.4f} seconds")
    # ...

3.1. 測(cè)試結(jié)果

我們的測(cè)試結(jié)果非常清晰地展示了流式處理的優(yōu)勢(shì):

非流式(Invoke)模式:

  • 總響應(yīng)時(shí)間:7.31 秒

流式(Stream)模式:

  • 首個(gè)數(shù)據(jù)塊響應(yīng)時(shí)間:1.03 秒
  • 總響應(yīng)時(shí)間:30.93 秒

3.2. 結(jié)果分析

從測(cè)試結(jié)果中我們可以看到:

  • 用戶感知延遲:在流式模式下,用戶在 1.03 秒 內(nèi)就看到了第一個(gè)數(shù)據(jù)塊,這給了用戶一個(gè)“系統(tǒng)正在工作”的即時(shí)反饋。而在非流式模式下,用戶需要等待 7.31 秒 才能看到任何內(nèi)容。
  • 總響應(yīng)時(shí)間:流式處理的總時(shí)間(30.93 秒)比非流式處理(7.31 秒)要長(zhǎng)。這是因?yàn)榱魇教幚硇枰饓K地生成和傳輸數(shù)據(jù),而 invoke 模式則是一次性地在服務(wù)器端生成所有內(nèi)容。

總結(jié)

盡管流式處理的總時(shí)間更長(zhǎng),但它通過(guò)顯著降低首次響應(yīng)時(shí)間,極大地提升了用戶體驗(yàn)。對(duì)于任何需要與 LLM 進(jìn)行交互的應(yīng)用來(lái)說(shuō),流式處理都是一個(gè)必不可少的優(yōu)化手段。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Python元組常見操作示例

    Python元組常見操作示例

    這篇文章主要介紹了Python元組常見操作,結(jié)合實(shí)例形式分析了Python元組的概念、功能、常見定義、獲取、遍歷等相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下
    2019-02-02
  • 使用python語(yǔ)言,比較兩個(gè)字符串是否相同的實(shí)例

    使用python語(yǔ)言,比較兩個(gè)字符串是否相同的實(shí)例

    今天小編就為大家分享一篇使用python語(yǔ)言,比較兩個(gè)字符串是否相同的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-06-06
  • Python中import的用法陷阱解決盤點(diǎn)小結(jié)

    Python中import的用法陷阱解決盤點(diǎn)小結(jié)

    這篇文章主要為大家介紹了Python中import的用法陷阱解決盤點(diǎn)小結(jié),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • python3 deque 雙向隊(duì)列創(chuàng)建與使用方法分析

    python3 deque 雙向隊(duì)列創(chuàng)建與使用方法分析

    這篇文章主要介紹了python3 deque 雙向隊(duì)列創(chuàng)建與使用方法,結(jié)合實(shí)例形式分析了python3 deque 雙向隊(duì)列創(chuàng)建、添加、清空、拷貝等相關(guān)操作技巧與使用注意事項(xiàng),需要的朋友可以參考下
    2020-03-03
  • Python字典循環(huán)添加一鍵多值的用法實(shí)例

    Python字典循環(huán)添加一鍵多值的用法實(shí)例

    今天小編就為大家分享一篇Python字典循環(huán)添加一鍵多值的用法實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-01-01
  • python實(shí)現(xiàn)超級(jí)瑪麗游戲

    python實(shí)現(xiàn)超級(jí)瑪麗游戲

    這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)超級(jí)瑪麗游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • 使用python繪制人人網(wǎng)好友關(guān)系圖示例

    使用python繪制人人網(wǎng)好友關(guān)系圖示例

    這篇文章主要介紹了使用python繪制人人網(wǎng)好友關(guān)系圖示例,需要的朋友可以參考下
    2014-04-04
  • 基于Python實(shí)現(xiàn)自動(dòng)化文檔整理工具

    基于Python實(shí)現(xiàn)自動(dòng)化文檔整理工具

    一個(gè)人可能會(huì)在計(jì)算機(jī)上存儲(chǔ)大量的照片、視頻和文檔文件,這些文件可能散落在不同的文件夾中,難以管理和查找。所以本文就來(lái)用Python制作一個(gè)自動(dòng)化文檔整理工具吧
    2023-04-04
  • Python中scatter函數(shù)參數(shù)及用法詳解

    Python中scatter函數(shù)參數(shù)及用法詳解

    這篇文章主要介紹了Python中scatter函數(shù)參數(shù)及用法詳解,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-11-11
  • pandas重復(fù)行刪除操作df.drop_duplicates和df.duplicated的區(qū)別

    pandas重復(fù)行刪除操作df.drop_duplicates和df.duplicated的區(qū)別

    本文主要介紹了pandas重復(fù)行刪除操作df.drop_duplicates和df.duplicated的區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08

最新評(píng)論

婺源县| 周口市| 乌鲁木齐县| 大姚县| 福鼎市| 沅陵县| 长治市| 米脂县| 共和县| 龙胜| 滦南县| 德令哈市| 台前县| 平泉县| 上栗县| 西丰县| 松潘县| 河北区| 花垣县| 西林县| 如东县| 防城港市| 巴林右旗| 阳东县| 布尔津县| 周口市| 恩平市| 日土县| 托克托县| 侯马市| 伊金霍洛旗| 巴林右旗| 浙江省| 科技| 阿拉尔市| 扬中市| 青海省| 盈江县| 新巴尔虎右旗| 建瓯市| 大同县|