Langchain學習筆記(1)——如何調用Huggingface的模型并實現實時返回生成結果

Langchain支持很方便的OpenAI模型的調用,可以做到快速開發大模型應用。但是要使用Huggingface上的開源模型就沒有那么方便了,本文就詳細闡述如何用Langchain開發基于Huggingface上的模型,并實時返回生成結果。

實時返回生成結果是LLM很關鍵的一環,大模型的響應速度很大程度上會影響用戶的使用體驗,較長的等待時間會導致用戶流失。同時,Langchain可以很方便的調用openAI的接口,但是對于我們這種窮屌絲來說用不起GPT的接口,只能用huggingface上的開源模型。所以本文將詳細介紹如何使用Langchain調用Huggingface的模型并做到實時返回生成結果。

本文選用Qwen2.5-0.5B-Instruct作為部署的模型,同時我是下載到了本地,所以代碼中的路徑是本地路徑,如果不想下載到本地的話直接用Huggingface上的路徑即可。

1. Quick start

如果使用OpenAI的模型,要實現實施返回結果(即流式調用),只需要以下幾行代碼就可以快速實現:

from langchain_openai import ChatOpenAImodel = ChatOpenAI(model='gpt-4')
chunks = []
for chunk in model.stream('天空是什么顏色?'):chunks.append(chunk)print(chunk.content, end='|', flush=True)

但是鑒于我們是窮批,用不起GPT的API,所以我們只能借助transformers庫自己實現上述的功能。

首先加載模型及其 tokenizer:

from transformers import Qwen2Tokenizer, Qwen2ForCausalLMtokenizer = Qwen2Tokenizer.from_pretrained(r'D:\huggingface\Qwen2.5-0.5B-Instruct')
model = Qwen2ForCausalLM.from_pretrained(r'D:\huggingface\Qwen2.5-0.5B-Instruct')

接著我們采用以下代碼即可實現流式迭代返回生成結果:

import threading
from transformers import TextIteratorStreamer
from langchain_core.messages import AIMessageChunkdef hf_stream(prompt: str):inputs = tokenizer(prompt, return_tensors='pt')# 創建一個 “流式文本迭代器”, 每當模型生成一個新 token,就會立刻把它變成字符串,通過 streamer 吐出來(yield)streamer = TextIteratorStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True)generation_kwargs = dict(**inputs,streamer=streamer,max_new_tokens=100,do_sample=True,temperature=0.95,)# 啟動模型的文本生成過程,但用新線程異步執行,讓主線程能實時處理輸出# 因為 model.generate() 是 阻塞函數(會等生成完才返回),我們要“邊生成邊取結果”,所以不能直接運行它,而是讓它在后臺線程里跑thread = threading.Thread(target=model.generate, kwargs=generation_kwargs)thread.start()# 流式迭代返回的 token 段for new_text in streamer:yield AIMessageChunk(content=new_text)

上述代碼中需要注意的有幾個地方:streamer 是一個關鍵點,這里是將 tokenizer 放入到流式處理中,這是因為 model.generate 是個同步操作,無法執行異步調用,所以采用多線程的方式將 model.generate 放入到多線程中,這樣就可以多線程執行模型的生成。同時,由于 generate 的結果是 token id 而非文字,這里 tokenzier 會將 token id decode 成為文字,并用 yield 流式輸出,所以 streamer 是將 tokenizer 放入到的流中。

接著就可以直接查看模型的輸出結果:

for chunk in hf_stream('請為我介紹夢幻西游的天宮門派'):print(chunk.content, end='|')

由于用了end='|',所以在每個輸出字符后都會看到"|",以下是運行結果:
生成1

2. 采用鏈式調用的方式執行代碼

Langchain 一個核心功能就是鏈式調用,即我們可以用諸如:

chain = prompt | llm | parser

的方式,同時執行提示模板、大模型生成、結構化輸出的功能。當然,由于窮批用不起API,所以我們這里依舊自己打造 Langchain 調用 huggingface 的鏈式調用。

首先我們定義如下的類:

from langchain_core.runnables import Runnable
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParserclass HuggingFaceStreamWrapper(Runnable):def __init__(self, model, tokenizer, max_new_tokens=128):self.model = modelself.tokenizer = tokenizerself.max_new_tokens = max_new_tokensdef invoke(self, input_text, config=None) -> AIMessage:# Runnable 類要求強制實現抽象方法, 否則會報錯 TypeError: Can't instantiate abstract class with abstract method invokehuman_texts = [msg.content for msg in input_text.messages if isinstance(msg, HumanMessage)]prompt = "\n".join(human_texts)inputs = self.tokenizer(prompt, return_tensors='pt').to(self.model.device)outputs = self.model.generate(**inputs,max_new_tokens=self.max_new_tokens,do_sample=True,top_p=0.95,temperature=0.8,)decoded = self.tokenizer.decode(outputs[0], skip_special_tokens=True)return AIMessage(content=decoded)async def astream(self, input_text, config=None):human_texts = [msg.content for msg in input_text.messages if isinstance(msg, HumanMessage)]prompt = "\n".join(human_texts)# tokenizer encodeinputs = self.tokenizer(prompt, return_tensors='pt').to(self.model.device)# streamerstreamer = TextIteratorStreamer(self.tokenizer, skip_prompt=True, skip_special_tokens=True)# 生成參數generation_kwargs = dict(**inputs,streamer=streamer,max_new_tokens=self.max_new_tokens,do_sample=True,top_p=0.95,temperature=0.8,)# 用線程調用生成(阻塞生成轉異步)thread = threading.Thread(target=self.model.generate, kwargs=generation_kwargs)thread.start()for token in streamer:# 手動觸發事件循環調度,允許其他任務執行。# 它的作用不是延時,而是調度讓步await asyncio.sleep(0)  # 允許事件循環切換# yield 是 Python 中的一個“進階但極其實用”的關鍵字,它的作用是讓函數變成一個生成器(generator),# 實現“邊計算邊返回”的效果,非常適合處理大數據、流式生成、異步 LLM 響應等場景。# yield 會暫停函數執行,返回一個值,但不會結束函數;yield AIMessageChunk(content=token)

這個是繼承了 langchain Runable 類,用于我們自定義開發 langchain 的鏈式調用。在這里有幾個要注意的點:Runable 中有個方法,名為 invoke,這個函數是必須要實現的函數,就算是

def invoke(self):pass

都沒問題,但是如果沒有該函數,那么會報錯:

TypeError: Can't instantiate abstract class with abstract method invoke

說明 invoke 這個函數是必須實現的。

而調用 invoke 函數也能夠返回結果,不過 invoke 是同步執行的,模型會一次性返回所有的結果,而非一個字一個字的蹦出來,比如執行下面代碼:

hf_model = HuggingFaceStreamWrapper(model, tokenizer)# 構建鏈
prompt = ChatPromptTemplate.from_template('請給我介紹夢幻西游中{topic}門派')
parser = StrOutputParser()
chain = prompt | hf_model | parser# 如果調用 invoke 方法, 必須實現 invoke 函數, 否則可以 pass
outputs = chain.invoke({'topic': '九黎城'})print(outputs)

會獲得:
invoke
就是這樣一次性輸出出來(前面我刪了三百多幀),這種用戶體驗感就會很差。

在上述代碼中,我們可以看到,采用 ChatPromptTemplate.from_template('請給我介紹夢幻西游中{topic}門派') 可以生成一個提示語,之后我們在調用的時候,傳入 topic 參數,就能夠直接將 九黎城 傳入進去,這樣在做實際開發的時候,就能夠給定一個提示模板,由用戶自行填充內容。

那么說完了 invoke 調用,鏈式調用流式輸出其實就很簡單了,只需要用如下代碼即可實現:

hf_model = HuggingFaceStreamWrapper(model, tokenizer)# 構建鏈
prompt = ChatPromptTemplate.from_template('請給我介紹夢幻西游中{topic}門派')
parser = StrOutputParser()
chain = prompt | hf_model | parserasync def async_stream():# 這里同樣, 如果要調用 astream 方法, 必須實現 astream 函數, 否則可以 passasync for chunk in chain.astream({'topic': '九黎城'}):print(chunk, end='|', flush=True)asyncio.run(async_stream())

以下是結果:
生成2

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/909714.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/909714.shtml
英文地址,請注明出處:http://en.pswp.cn/news/909714.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java安全-常規漏洞問題(SQL注入,XXE,SSRF,RCE)

靶場搭建 靶場下載 : https://github.com/whgojp/JavaSecLab這個靶場是使用Springboot搭建的所以不要下載 jar 文件運行,要使用IDEA運行他的文件夾 先打開pom 然后進行maven一下 改一下端口 配置完成之后修改一下 運行的模式 使用phpstudy搞一個sql數…

基于視頻的 AI 內存庫,極速語義檢索

簡介 在大模型應用里,將文本數據分塊嵌入存儲在向量數據庫已經是標準做法。然而,傳統向量數據庫雖然功能強大,但其高昂的RAM和存儲需求,以及復雜的部署運維,常常讓開發者望而卻步。今天,介紹一個名為 Memv…

接口適配器模式實現令牌桶算法和漏桶算法

以下是令牌桶算法、漏桶算法和雪花算法的清晰對比解析。它們屬于完全不同的技術領域,前兩者用于流量控制,后者用于分布式ID生成: 1. 令牌桶算法(Token Bucket) 領域:流量整形 / 速率限制核心目標&#xff…

618背后的電商邏輯重構:從價格血戰到價值共生

“今年終于沒做數學題。” 618進行到一半,行云已經買了很多,大件的有iPad、iWatch,小件的有運動鞋、面膜、紙巾。往年她要湊湊減減,經常要找個店鋪湊單,下完單再馬上退掉,今年她沒廢太多腦細胞&#xff0c…

解決 PyTorch 與 Python 3.12 的兼容性問題:`operator torchvision::nms does not exist` 深度解析

解決 PyTorch 與 Python 3.12 的兼容性問題 問題現象錯誤根源分析終極解決方案?? 推薦方案:創建 Python 3.11 虛擬環境? 備選方案:使用 PyTorch 夜間構建版(Python 3.12)驗證修復技術深度解析最佳實踐建議問題現象 當在 Python 3.12 環境中運行以下代碼時: from tran…

Git 實戰場景

四、標簽管理 4.1、標簽的理解 在使用 Git 進行版本管理時,**標簽(Tag)**扮演著非常重要的角色。它其實就是對某次提交(commit)的一個簡潔標識,相當于給這次提交起了一個可讀、易記的“別名”。比如&…

在同態加密系統中,參與角色以及各角色的功能作用流程圖,私鑰和公鑰分發流程,可能遇到的攻擊

一、角色劃分與職責 角色身份核心任務密鑰權限客戶端數據所有者 (如醫院、用戶)1. 加密原始數據 2. 上傳密文至服務器 3. 接收并解密結果(可選)持有公鑰服務器計算服務提供方 (如云平臺)1. 接收客戶端密文…

langchain從入門到精通(六)——LCEL 表達式與 Runnable 可運行協議

1. 多組件 invoke 嵌套的缺點 prompt ChatPromptTemplate.from_template("{query}") llm ChatOpenAI(model"gpt-3.5-turbo-16k") parser StrOutputParser() # 獲取輸出內容 content parser.invoke( llm.invoke( prompt.invoke( {"query": r…

ArcGIS中批量獲取輸入面圖層A中各要素的四至點的實現方法

一、背景及意義 在日常工作中,我們經常會需要獲取面圖層的四至點,我們能否在ArcGIS中直接獲取面圖層的四至點呢?答案是肯定的,請繼續往下看。 二、大體思路 使用字段計算器計算輸入面圖層A中各面要素的XY的最大值和最小值&…

大IPD之——華為的戰略本質與實踐(二)

華為戰略執行的能力如此強,有兩個核心原因:一是管理體系起了非常重大的作用;二是企業文化導致華為的執行力特別強。華為在戰略方面,為什么每次都能轉型成功?背后是有很多實質性的內容支撐的。而華為如何做戰略&#xf…

『大模型筆記』第3篇:多長的 Prompt 會阻塞其他請求?優化策略解析

『大模型筆記』多長的 Prompt 會阻塞其他請求?優化策略解析 文章目錄 一、更簡單的問題:長 Prompt 阻塞請求隊列1. 請求并行預填方案(Request-Parallel Prefills)二、根本的問題(Fundamental Flaw):Token 生成被并行預填拖慢1. 解耦預填(Disaggregated Prefill):以延遲優…

21 - GAM模塊

論文《Global Attention Mechanism: Retain Information to Enhance Channel-Spatial Interactions》 1、作用 這篇論文提出了全局注意力機制(Global Attention Mechanism, GAM),旨在通過保留通道和空間方面的信息來增強跨維度交互&#xf…

Java01--使用IDEA編寫運行第一個Java程序HelloWorld

一.先新建一個文件夾存放項目(后續可以推送到Gitee) 二.創建項目 1.打開IDEA,點擊首頁的新建項目 2.新建空項目并命名,存放路徑為步驟一創建的文件夾: 3.在新項目中新建一個src文件夾(用于集中管理文件) 4.在src文件夾…

目標檢測相關【清晰易懂】

目標檢測相關 (b)是語義分割,(c)是實例分割 目標檢測 每個目標一個框標簽 實例分割 語義分割 識別每一個目標個體 目標檢測基礎上進一步提升模型能力有兩個方向:實例分割、旋轉目標檢測。 實例分割 …

強化學習 A2C算法

3.actor-critic方法 3.1 Reinforce 算法,也稱為蒙特卡洛策略梯度。蒙特卡洛方差 第一節介紹了DQN 在上一節基于策略的方法中,我們的目標是直接優化策略,而無需使用價值函數。更準確地說,Reinforce 是 基于策略的方法 的一個子類…

關于MCU、MPU、SoC、DSP四大類型芯片

目錄 MCU、MPU、SoC、DSP四大類型芯片分析 一、MCU 1、概念 2、特點 3、常見芯片 4、應用場景 二、MPU 1、概念 2、特點 3、常見芯片 4、應用場景 三、SoC 1、概念 2、特點 3、常見芯片 4、應用場景 四、DSP 1、概念 2、特點 3、常見芯片 4、應用場景 MCU、…

【數據結構】圖論最短路圣器:Floyd算法如何用雙矩陣征服負權圖?

最短路徑 穿越負權迷霧:Floyd算法如何解鎖全圖最短路徑???一、Floyd算法1.1 算法思想1.2 算法邏輯1.3 算法評價1.4 算法限制 二、三種算法對比🌟結語 穿越負權迷霧:Floyd算法如何解鎖全圖最短路徑??? 大家好&…

寶塔面板集成阿里云 OSS 備份失敗的解決方案

寶塔面板集成阿里云OSS備份失敗的解決方案 一、問題背景 在使用寶塔面板配置阿里云OSS云存儲備份功能時,用戶遇到如下錯誤: Traceback (most recent call last):File "class/CloudStoraUpload.py", line 144, in __init__from alioss_main import OSSClient as ocFile "…

如何安全高效地維護CMS智能插件?

作為網站開發者或運維人員,你是否經歷過這樣的場景:滿懷期待地點擊了插件“更新”按鈕,刷新頁面后卻看到一片刺眼的500錯誤?或發現網站加載速度從2秒驟降到10秒?智能插件為CMS系統(如WordPress、Drupal、億…

FastAPI如何用角色權限讓Web應用安全又靈活?

title: FastAPI如何用角色權限讓Web應用安全又靈活? date: 2025/06/13 05:46:55 updated: 2025/06/13 05:46:55 author: cmdragon excerpt: 基于角色的路由訪問控制是Web應用中常見的安全控制模式,通過為用戶分配特定角色來管理權限。FastAPI利用依賴注入系統實現權限控制…