2025年9月28日 星期日

LangChain 學習筆記 : 串接 LLM 模型 (一)

最近打算進行在本機安裝 llama 模型的學習測試, 但必須先學會 LangChain 才好上手. 之前已在筆電中安裝好 LangChain, 接下來要來測試它調用 LLM 模型的方法. 

本系列之前的文章參考 :



1. 安裝 LLM 原生 API 套件與其 LangChain 橋接套件 :    

本篇測試聚焦在 OpenAI 與 Gemini 這兩種 LLM 模型, 所以在使用 LangChain 呼叫 LLM 模型之前必須先安裝 LLM 的原生 API 套件與其 LangChain 橋接套件. 這是因為 LangChain 遵循不重複造輪子原則, 仍然依賴原生 API 來與模型做底層溝通, 不過 LangChain 另外寫一個橋接套件來封裝以統一各模型之調用介面. 

LangChain 在 2024 年升版至 v1.0 進行了模組化重構以便使核心輕量化, 將許多大型 LLM 提供商例如 OpenAI, Anthropic, Google 等公司的模型橋接介面移出主套件, 將它們拆成獨立的套件以利維護, 所以安裝因此使用 LangChain 與各 LLM 介接前須各自安裝該 LLM 的介面套件, 例如 :

pip install langchain-openai  (介接 OpenAI 的 GPT 模型)
pip install langchain-google-genai  (介接 Google 的 Gemini 模型) 

先來測試 OpenAI 的介面套件. 


2. 安裝 langchain-openai 套件 :      

由於 langchain-openai 套件只是封裝了透過 openai 套件串接 GPT 模型的介面而已, 它無法單獨串接 OpenAI 模型, 必須先用下列指令安裝原生的 openai 套件才行 : 

pip install openai   

參考 :


然後用 pip 安裝 langchain-openai 套件 : 

pip install langchain-openai    

D:\python\test>pip install langchain-openai   
Collecting langchain-openai
  Downloading langchain_openai-0.3.16-py3-none-any.whl.metadata (2.3 kB)
Requirement already satisfied: langchain-core<1.0.0,>=0.3.58 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from langchain-openai) (0.3.58)
Collecting openai<2.0.0,>=1.68.2 (from langchain-openai)
  Downloading openai-1.77.0-py3-none-any.whl.metadata (25 kB)
Requirement already satisfied: tiktoken<1,>=0.7 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from langchain-openai) (0.8.0)
Requirement already satisfied: langsmith<0.4,>=0.1.125 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from langchain-core<1.0.0,>=0.3.58->langchain-openai) (0.3.42)
Requirement already satisfied: tenacity!=8.4.0,<10.0.0,>=8.1.0 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from langchain-core<1.0.0,>=0.3.58->langchain-openai) (8.2.3)
Requirement already satisfied: jsonpatch<2.0,>=1.33 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from langchain-core<1.0.0,>=0.3.58->langchain-openai) (1.33)
Requirement already satisfied: PyYAML>=5.3 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from langchain-core<1.0.0,>=0.3.58->langchain-openai) (6.0.1)
Requirement already satisfied: packaging<25,>=23.2 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from langchain-core<1.0.0,>=0.3.58->langchain-openai) (24.2)
Requirement already satisfied: typing-extensions>=4.7 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from langchain-core<1.0.0,>=0.3.58->langchain-openai) (4.12.2)
Requirement already satisfied: pydantic<3.0.0,>=2.5.2 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from langchain-core<1.0.0,>=0.3.58->langchain-openai) (2.11.4)
Requirement already satisfied: jsonpointer>=1.9 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from jsonpatch<2.0,>=1.33->langchain-core<1.0.0,>=0.3.58->langchain-openai) (2.4)
Requirement already satisfied: httpx<1,>=0.23.0 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from langsmith<0.4,>=0.1.125->langchain-core<1.0.0,>=0.3.58->langchain-openai) (0.28.1)
Requirement already satisfied: orjson<4.0.0,>=3.9.14 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from langsmith<0.4,>=0.1.125->langchain-core<1.0.0,>=0.3.58->langchain-openai) (3.10.18)
Requirement already satisfied: requests<3,>=2 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from langsmith<0.4,>=0.1.125->langchain-core<1.0.0,>=0.3.58->langchain-openai) (2.31.0)
Requirement already satisfied: requests-toolbelt<2.0.0,>=1.0.0 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from langsmith<0.4,>=0.1.125->langchain-core<1.0.0,>=0.3.58->langchain-openai) (1.0.0)
Requirement already satisfied: zstandard<0.24.0,>=0.23.0 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from langsmith<0.4,>=0.1.125->langchain-core<1.0.0,>=0.3.58->langchain-openai) (0.23.0)
Requirement already satisfied: anyio in c:\users\tony1\appdata\roaming\python\python310\site-packages (from httpx<1,>=0.23.0->langsmith<0.4,>=0.1.125->langchain-core<1.0.0,>=0.3.58->langchain-openai) (3.7.1)
Requirement already satisfied: certifi in c:\users\tony1\appdata\roaming\python\python310\site-packages (from httpx<1,>=0.23.0->langsmith<0.4,>=0.1.125->langchain-core<1.0.0,>=0.3.58->langchain-openai) (2023.7.22)
Requirement already satisfied: httpcore==1.* in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from httpx<1,>=0.23.0->langsmith<0.4,>=0.1.125->langchain-core<1.0.0,>=0.3.58->langchain-openai) (1.0.7)
Requirement already satisfied: idna in c:\users\tony1\appdata\roaming\python\python310\site-packages (from httpx<1,>=0.23.0->langsmith<0.4,>=0.1.125->langchain-core<1.0.0,>=0.3.58->langchain-openai) (3.4)
Requirement already satisfied: h11<0.15,>=0.13 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from httpcore==1.*->httpx<1,>=0.23.0->langsmith<0.4,>=0.1.125->langchain-core<1.0.0,>=0.3.58->langchain-openai) (0.14.0)
Requirement already satisfied: distro<2,>=1.7.0 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from openai<2.0.0,>=1.68.2->langchain-openai) (1.9.0)
Requirement already satisfied: jiter<1,>=0.4.0 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from openai<2.0.0,>=1.68.2->langchain-openai) (0.8.0)
Requirement already satisfied: sniffio in c:\users\tony1\appdata\roaming\python\python310\site-packages (from openai<2.0.0,>=1.68.2->langchain-openai) (1.3.0)
Requirement already satisfied: tqdm>4 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from openai<2.0.0,>=1.68.2->langchain-openai) (4.66.1)
Requirement already satisfied: exceptiongroup in c:\users\tony1\appdata\roaming\python\python310\site-packages (from anyio->httpx<1,>=0.23.0->langsmith<0.4,>=0.1.125->langchain-core<1.0.0,>=0.3.58->langchain-openai) (1.1.3)
Requirement already satisfied: annotated-types>=0.6.0 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from pydantic<3.0.0,>=2.5.2->langchain-core<1.0.0,>=0.3.58->langchain-openai) (0.7.0)
Requirement already satisfied: pydantic-core==2.33.2 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from pydantic<3.0.0,>=2.5.2->langchain-core<1.0.0,>=0.3.58->langchain-openai) (2.33.2)
Requirement already satisfied: typing-inspection>=0.4.0 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from pydantic<3.0.0,>=2.5.2->langchain-core<1.0.0,>=0.3.58->langchain-openai) (0.4.0)
Requirement already satisfied: charset-normalizer<4,>=2 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from requests<3,>=2->langsmith<0.4,>=0.1.125->langchain-core<1.0.0,>=0.3.58->langchain-openai) (3.2.0)
Requirement already satisfied: urllib3<3,>=1.21.1 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from requests<3,>=2->langsmith<0.4,>=0.1.125->langchain-core<1.0.0,>=0.3.58->langchain-openai) (1.26.19)
Requirement already satisfied: regex>=2022.1.18 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from tiktoken<1,>=0.7->langchain-openai) (2023.12.25)
Requirement already satisfied: colorama in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from tqdm>4->openai<2.0.0,>=1.68.2->langchain-openai) (0.4.6)
Downloading langchain_openai-0.3.16-py3-none-any.whl (62 kB)
Downloading openai-1.77.0-py3-none-any.whl (662 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 662.0/662.0 kB 4.3 MB/s eta 0:00:00
Installing collected packages: openai, langchain-openai
  Attempting uninstall: openai
    Found existing installation: openai 1.57.2
    Uninstalling openai-1.57.2:
      Successfully uninstalled openai-1.57.2
Successfully installed langchain-openai-0.3.16 openai-1.77.0


3. 檢視 langchain-openai 套件內容 :      

匯入 langchain_openai 後用 dir() 檢視內容 :

>>> import langchain_openai   
>>> dir(langchain_openai)    
['AzureChatOpenAI', 'AzureOpenAI', 'AzureOpenAIEmbeddings', 'ChatOpenAI', 'OpenAI', 'OpenAIEmbeddings', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'chat_models', 'embeddings', 'llms']

可見此套件包含了 OpenAI 的介面類別與其 Azure 版本, 以下測試僅使用 OpenAI 版本的 ChatOpenAI 類別來與 OpenAI API 進行對話 : 
  • ChatOpenAI : 
    此類別封裝 OpenAI 的 Chat Completions API (GPT-3.5 / GPT-4 系列), 可用於聊天式應用, 例如對話代理, 工具鏈等, 對應 LangChain 的 BaseChatModel.
  • OpenAI : 
    此類別封裝 OpenAI 的 Completion API (較舊的文字生成 API), 適合非對話式生成, 例如單純文字續寫, 對應 LangChain 的 LLM.
  • OpenAIEmbeddings : 
    此類別封裝 OpenAI 的 Embeddings API (text-embedding-ada-002 等), 用於將文字轉換為向量, 可搭配向量資料庫進行相似度搜尋.
ChatOpenAI 類別封裝的是 OpenAI 的 Chat Completions API, 所以建構式 ChatOpenAI() 有部分的參數與 OpenAI API 的參數是共通的 (但名稱可能稍微不同), 如下表所示 : 


 共通參數名稱  說明
 api_key  OpenAI API 金鑰
 model  指定模型名稱,例如 "gpt-4o-mini"
 temperature  控制生成隨機性,數值越高輸出越多樣化
 max_completion_tokens  限制最大回覆 token 數量(OpenAI API 參數名 : max_tokens
 stop  設定停止字串,模型生成到此字串會自動停止
 n  一次生成多少個候選回覆
 streaming  是否使用串流模式返回回應(OpenAI API 參數名 : stream
 logprobs / top_logprobs  是否回傳 token 機率與最可能的候選 token
 response_format  指定回覆格式,例如 JSON 模式
 reasoning_effort  指定 reasoning 模型的運算強度
 request_timeout  設定請求逾時(OpenAI API 參數名 : timeout
 openai_api_base  自訂的 API 端點(OpenAI API 參數名 : base_url


下表則是 LangChain 的 ChatOpenAI() 特有的額外參數 (OpenAI API 沒有的) : 


 參數名稱  說明
 openai_organization  指定組織 ID(OpenAI API 須透過支援環境變數)
 openai_proxy  設定 HTTP 代理伺服器
 max_retries  舍訂請求失敗時的重試次數(OpenAI API 需自己實作)
 tags  用於追蹤或 logging 的標籤
 tiktoken_model_name  指定用於 token 計算的模型名稱
 model_kwargs  以字典形式傳遞額外 OpenAI API 參數 (top_pstop 等)
 stream_usage  若啟用 streaming,是否回傳使用量資訊
 reasoning  傳入 dict 形式的 reasoning 設定,用於特定 reasoning 模型
 use_responses_api  是否使用新版 Responses API 取代傳統 Chat API
 output_version  控制 AIMessage 輸出格式版本,例如 'v0' 或 'responses/v1'
 use_previous_response_id  在 Responses API 模式下是否攜帶前次回應 ID 以延續上下文


其中 model_kwargs 參數用來傳遞 OpenAI API 支持但 ChatOpenAI() 沒有直接支持的參數, 這些 OpenAI API 參數要以字典形式 (鍵為參數名稱例如 'top_p') 透過 model_kwargs 參數傳給 ChatOpenAI(). 這些參數鍵如下表 : 


 model_kwargs 參數的鍵  說明
 top_p  控制生成隨機性(0~1),與 temperature 配合使用
 presence_penalty  對新主題或新 token 的偏好程度,增加可產生更多新內容
 frequency_penalty  避免重複 token 的懲罰值,數值越高,重複越少
 logit_bias  調整特定 token 出現機率的字典
 user  指定用戶 ID,用於 OpenAI 端追蹤或使用統計
 stop  停止字串或字串列表,模型生成遇到即可停止
 functions  定義可供模型呼叫的函式列表,用於 function-calling 功能
 function_call  控制函式呼叫行為,例如 "auto", "none" 或指定函式名稱
 max_tokens  限制生成 token 數量
 logprobs  回傳每個 token 的 log 機率資訊,可用於分析或生成控制


4. 用 langchain-openai 套件串接 OpenAI 模型 :      

串接 OpenAI 的 GPT 模型需要 API Key, 我已將其儲存在環境變數檔案 .env 裡面, 先用 dotenv 套件讀取出來放在 openai_api_key 變數裡 :

>>> from dotenv import dotenv_values    
config=dotenv_values('.env')     
openai_api_key=config.get('OPENAI_API')    

匯入 langchain-openai.ChatOpenAI 類別 : 

>>> from langchain_openai import ChatOpenAI   

然後呼叫 ChatOpenAI() 建構式並傳入 api_key 與 model 參數來建立 ChatOpenAI 物件 : 

>>> chat_model=ChatOpenAI(api_key=openai_api_key, model='gpt-3.5-turbo')    
>>> type(chat_model)     
<class 'langchain_openai.chat_models.base.ChatOpenAI'>    

這樣就可以呼叫此 ChatOpenAI 物件的 invoke() 方法並傳入提示詞來起始一個對話 : 

>>> response=chat_model.invoke('你是誰?')  
>>> type(response)  
<class 'langchain_core.messages.ai.AIMessage'>  

可見 invoke() 方法會傳回一個 AIMessage 物件, 檢視此物件內容 : 

>>> response     
AIMessage(content='我是AI助手。有什麼問題我可以幫助您解答?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 27, 'prompt_tokens': 12, 'total_tokens': 39, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'id': 'chatcmpl-CKgsNf6T6qnUtam5GJtJevTm9Jk1J', 'service_tier': 'default', 'finish_reason': 'stop', 'logprobs': None}, id='run--3abc232a-90da-44d1-870b-41a0c6ca4b03-0', usage_metadata={'input_tokens': 12, 'output_tokens': 27, 'total_tokens': 39, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})

模型的回應放在其 content 屬性內 : 

>>> response.content   
'我是AI助手。有什麼問題我可以幫助您解答?'

沒有留言 :