顯示具有 LangChain 標籤的文章。 顯示所有文章
顯示具有 LangChain 標籤的文章。 顯示所有文章

2026年4月11日 星期六

LangChain 學習筆記 : 提示詞模板 (二)

上一篇測試是針對字串提示詞模板類別 PromptTemplate, 主要是用於單一句子的簡單提問, 功能類似於 f 字串, 可快速填充模板參數以得到完整的訊息字串. 本篇旨在測試需要更多上下文語境的對話提示模板類別 ChatPromptTemplate 之用法. 

本系列全部文章索引參考 :


本篇同樣會使用 OpenAI 與 Gemini API 來測試對話提示詞模板用法, 首先匯入所需之金鑰與外掛套件並預先建立模型物件 :  

(myvenv) D:\python\test>python   
Python 3.12.1 (tags/v3.12.1:2305ca5, Dec  7 2023, 22:03:25) [MSC v.1937 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from langchain_openai import ChatOpenAI   
>>> from langchain_google_genai import ChatGoogleGenerativeAI  
>>> from dotenv import dotenv_values   
>>> config=dotenv_values('.env')   
>>> openai_api_key=config.get('OPENAI_API_KEY')   
>>> gemini_api_key=config.get('GEMINI_API_KEY')   
>>> gpt_model=ChatOpenAI(api_key=openai_api_key, model='gpt-3.5-turbo')     
>>> gemini_model=ChatGoogleGenerativeAI(api_key=gemini_api_key, model='gemini-2.5-flash')   

然後從 langchain_core 匯入 prompts 子模組下的 ChatPromptTemplate 類別 (因為之前只安裝 langchain_core, 沒有安裝大禮包 langchain) :

>>> from langchain_core.prompts import ChatPromptTemplate   

ChatPromptTemplate 類別的核心在於角色扮演, 它不像 PromptTemplate 那樣把所有內容塞成一個大字串, 而是將對話拆解成不同的角色訊息, 在 LangChain 的訊息物件中有三種角色 : 
  • System (系統) : 設定 AI 的人格, 背景, 規則 (例如 "你是一位 Python 專家")
  • Human (使用者) : 你對 AI 的提問
  • AI (助手) : AI 之前回覆過的內容 (用於提供對話脈絡)
呼叫 ChatPromptTemplate 類別的建構式 ChatPromptTemplate() 時, 要把對話內容依照角色拆分, 將其 system, human, 與 ai 三種角色的訊息組成元組串列傳入建構式, 傳回值為一個 ChatPromptTemplate 物件, 例如下面的翻譯對話模板 : 

>>> chat_template=ChatPromptTemplate.from_messages([
    ("system", "你是一位專業的 {style} 翻譯員,擅長將繁體中文翻譯成優雅的 {language}。"), 
    ("human", "請翻譯這段話:{text}"), 
    ]) 

此模板中嵌入了三個模板參數 : style, language, 與 text, 填充此三個參數可以呼叫 ChatPromptTemplate 物件的兩個方法 : 
  • format_message() : 傳入值為個別模板參數, 傳回值為訊息物件串列
  • invoke() : 傳入值為模板參數字典, 傳回值為 ChatPromptValue 物件
不論是哪一種傳回值, 都可以做為參數直接傳給模型物件的 invoke() 方法向 LLM 提交提示詞. 首先來測試使用 format_message() 來填充模板參數, 先準備要翻譯的文本 text : 

>>> text='''趁著午後的陽光灑進窗台,我決定暫時放下手中的電路板與程式碼,給自己泡一杯清茶,享受這難得的靜謐時光。生活不應該只有邏輯與迴圈,還要有隨處可見的驚喜。''' 

然後傳入 style, language, 與 text 參數來填充模板 :

>>> messages=chat_template.format_messages(style="出版業", language="英文", text=text)    
>>> type(messages)   
<class 'list'>   
>>> messages    
[SystemMessage(content='你是一位專業的 出版業 翻譯員,擅長將繁體中文翻譯成優雅的 英文。', additional_kwargs={}, response_metadata={}), HumanMessage(content='請翻譯這段話:趁著午後的陽光灑進窗台,我決定暫時放下手中的電路板與程式碼,給自己泡一杯清茶,享受這難得的靜謐時光。生活不應該只有邏輯與迴圈,還要有隨處可見的驚喜。', additional_kwargs={}, response_metadata={})]

可見 format_messages() 傳回一個訊息物件串列, 裡面有 SystemMessage 與 HumanMessage 等角色的訊息物件 (此對話尚未有 AIMessage 物件), 這樣就可以把填充完的訊息物件串列傳給模型的 invoke() 方法來生成回應了, 例如 GPT : 

>>> response=gpt_model.invoke(messages)   
>>> print(response.content)     
With the afternoon sunlight streaming in through the window, I decided to temporarily set aside the circuit boards and code in my hands, brew myself a cup of clear tea, and savor this rare moment of tranquility. Life shouldn't just be about logic and loops; it should also be filled with unexpected delights at every turn.

下面是串接 Gemini 的回應 :

>>> response=gemini_model.invoke(messages)   
>>> print(response.content)  
以下是幾種翻譯選項,從較為直接到更為優雅的風格:

**選項一 (較為直接,但仍優雅):**

> As the afternoon sun streamed onto the windowsill, I decided to temporarily set aside my circuit board and code. I would brew myself a cup of soothing tea and savor this rare moment of tranquility. Life shouldn't be solely about logic and loops; it should also be filled with readily found surprises.

**選項二 (更為優雅,帶有文學氣息):**

> Bathed in the afternoon sun gracing the windowsill, I chose to momentarily put down my circuit board and code. A cup of fine tea beckoned, promising a rare interlude of serenity. Life, after all, should not be confined to logic and loops, but should also embrace the unexpected delights found at every turn.

**選項三 (簡潔而富有詩意):**

> With the afternoon sun warming the windowsill, I paused from my circuit board and code. A soothing cup of tea, a rare moment of quietude – these were my new companions. For life, I believe, demands more than just logic and loops; it calls for the unexpected joys that lie around every corner.

---

**選擇建議:**

*   如果希望保持原句的結構和語氣,**選項一** 是個不錯的選擇。
*   如果希望加入更多文學色彩和更豐富的詞彙,讓譯文讀起來更具美感,**選項二** 會是最佳選擇。
*   如果偏好更精煉、更具哲思的表達,**選項三** 則能達到這個效果。

我個人最推薦**選項二**,它最能體現「優雅的出版業翻譯」的要求。

接下來改用 ChatPromptTemplate 物件的 invoke() 方法來填充, 這時要把模板參數打包成字典傳給模型物件的 invoke() 方法 : 

>>> messages=chat_template.invoke({
    'style': '科技業', 
    'language': '日文', 
    'text': '這支程式的執行效率非常高。'
    })
>>> type(messages)   
<class 'langchain_core.prompt_values.ChatPromptValue'>   
>>> messages   
ChatPromptValue(messages=[SystemMessage(content='你是一位專業的 科技業 翻譯員,擅長將繁體中文翻譯成優雅的 日文。', additional_kwargs={}, response_metadata={}), HumanMessage(content='請翻譯這段話:這支程式的執行效率非常高。', additional_kwargs={}, response_metadata={})])

可見傳回值是一個 ChatPromptValue 物件, 裡面包裹著 SystemMessage 與 HumanMessage 等角色的訊息物件, 可以直接把這個 ChatPromptValue 物件傳給模型的 invoke() 方法來生成回應, 例如 GPT : 

>>> response=gpt_model.invoke(messages)   
>>> print(response.content)     
このプログラムの実行効率は非常に高いです。

也可串接 Gemini :

>>> response=gemini_model.invoke(messages)   
>>> print(response.content)   
這支程式的執行效率非常高。
**このプログラムは実行効率が非常に高いです。**

或者,稍微更強調性能的話:
**このプログラムの実行効率は非常に優れています。**
*(This program's execution efficiency is excellent.)*

2026年4月10日 星期五

LangChain 學習筆記 : 提示詞模板 (一)

LangChain 的提示詞模板 (Prompt Templates) 功能利用預留變數將靜態文字轉化為動態指令, 可根據不同的傳入參數重複生成結構化的提示詞. LangChain 的 langchain_core.prompts 子模組提供兩種提示詞模板 :
  • 字串提示模板 (PromptTemplate 類別):
    用於單一句子的簡單提問
  • 對話提示模板 (ChatPromptTemplate 類別) :
    用於需要更多上下文語境之完整對話
本篇旨在測試字串提示模板 PromptTemplate 類別的用法. 

本系列全部文章索引參考 :


以下將使用 OpenAI 與 Gemini API 來測試字串提示模板用法, 首先匯入所需之金鑰與外掛套件並預先建立模型物件 :  

(myvenv) D:\python\test>python   
Python 3.12.1 (tags/v3.12.1:2305ca5, Dec  7 2023, 22:03:25) [MSC v.1937 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from langchain_openai import ChatOpenAI   
>>> from langchain_google_genai import ChatGoogleGenerativeAI  
>>> from dotenv import dotenv_values   
>>> config=dotenv_values('.env')   
>>> openai_api_key=config.get('OPENAI_API_KEY')   
>>> gemini_api_key=config.get('GEMINI_API_KEY')   
>>> gpt_model=ChatOpenAI(api_key=openai_api_key, model='gpt-3.5-turbo')     
>>> gemini_model=ChatGoogleGenerativeAI(api_key=gemini_api_key, model='gemini-2.5-flash')   

由於之前在虛擬目錄下只安裝 langchain_core, 沒有安裝大禮包 langchain; 所以要從 langchain_core 匯入 prompts 子模組下的 PromptTemplate 類別 :

from langchain_core.prompts import PromptTemplate

>>> from langchain_core.prompts import PromptTemplate    

然後呼叫其建構式 PromptTemplate() 並傳入 template (字串) 與 input_variables (串列) 參數建立 PromptTemplate 物件, 其中 input_variables 中列舉了要傳入之模板參數, 例如 : 

prompt_template=PromptTemplate(
    template='用 300 個以內的字說明關於{topic}的知識',
    input_variables=['topic']  
    )

此 PromptTemplate 物件含有一個模板參數 topic. 

>>> prompt_template=PromptTemplate(
...     template='用 300 個以內的字說明關於{topic}的知識',   
...     input_variables=['topic']  
...     )  
>>> type(prompt_template)   
<class 'langchain_core.prompts.prompt.PromptTemplate'>
>>> prompt_template   
PromptTemplate(input_variables=['topic'], input_types={}, partial_variables={}, template='用 300 個以內的字說明關於{topic}的知識')

上面所建立的 PromptTemplate 物件只是一個模板結構而已, 還不能直接做為訊息物件傳給語言模型, 必須呼叫 PromptTemplate 物件的 format() 或 invoke() 方法傳入模板參數進行填充後才行, 這兩個方法的差異如下 : 
  • format() :
    單純的字串填充, 傳入值為單一字串, 傳回值是填充後的字串, 效果類似 f 字串的功能. 
  • invoke() :
    這是 LCEL (LangChain Expression Language) 的標準接口, 是為了配合 LCEL 的鏈式調用而設, 也是推薦的用法. 它的傳入值為模板參數字典, 傳回值為 PromptValue 物件, 它會根據後續接的是純文字模型還是對話模型自動轉成 StringPromptValue 或 ChatPromptValue 物件後傳回. 
總之, 如果是要除錯, 列印提示詞內容, 或串接非 LangChain 的自定義函數等場景, 可以呼叫 format() 以快速得到填充後的字串; 如果是要參與 LangChain 的鏈 (Chain) 運算, 則應該呼叫 invoke(). 

首先用 format() 方法來填充 :

>>> prompt_string=prompt_template.format(topic='疊加態')   
>>> type(prompt_string)    
<class 'str'>  
>>> prompt_string   
'用 300 個以內的字說明關於疊加態的知識'

可見 format() 傳回填充後的訊息字串, 這樣就可以傳給模型物件的 invoke() 讓模型來生成回應了, 例如 OpenAI 的 GPT :

>>> response=gpt_model.invoke(prompt_string)   
>>> print(response.content)  
疊加態是一種量子物理學中的概念,指的是當一個系統同時處於多個可能的狀態時,這些狀態之間可以相互叠加,而不會直接混合在一起。
在疊加態中,系統可以同時存在於不同的狀態中,直到進行測量時才會產生確定的結果。這也解釋了量子超密碼等量子現象的奇異性。
疊加態是量子力學中的一個核心概念,也是量子計算和量子通信等領域的基礎。通過利用疊加態,科學家們可以設計出更快速和更強大的計算機系統,以及更加安全和高效的通訊技術。
總的來說,疊加態是一個深奧而又神秘的概念,它挑戰了我們對現實世界的直覺和理解,也為我們揭示了量子世界的獨特之處。

或者谷歌的 Gemini : 

>>> response=gemini_model.invoke(prompt_string)   
>>> print(response.content)   
疊加態是量子力學中的一個基本概念,指微觀粒子在被測量前,可以同時處於多個可能的狀態。例如,一個電子可以同時向上和向下自旋,或同時在多個位置。只有當我們進行觀測或測量時,疊加態才會「坍縮」,粒子隨機選擇其中一個狀態顯現出來。在未觀測前,它並非處於某個確定的狀態,而是所有可能性的疊加。

其次, 改為呼叫 invoke() 方法, 這時傳入參數是模板參數字典 : 

>>> prompt_value=prompt_template.invoke({'topic': '普郎克常數'})   
>>> type(prompt_value)   
<class 'langchain_core.prompt_values.StringPromptValue'>  
>>> prompt_value   
StringPromptValue(text='用 300 個以內的字說明關於普郎克常數的知識')    

由於模板是純文字模型, 所以傳回值為 StringPromptValue 物件, 可以直接將此 PromptValue 物件傳給模型來生成回應, 例如 GPT :

>>> response=gpt_model.invoke(prompt_value)   
>>> print(response.content)     
普朗克常數是物理學中的一個重要常數,通常用符號h表示。它的數值約為6.626×10^-34 J·s。普朗克常數被廣泛應用於量子力學和粒子物理學中,尤其是在描述微觀世界中微小粒子的運動和行為時。根據普朗克常數,能量和頻率之間存在著一個固定的關係,即E=hf,其中E是能量,h是普朗克常數,f是頻率。普朗克常數還與黑體輻射和光子的能量密度等現象密切相關。因此,普朗克常數在物理學中具有重要的地位,對於我們理解微觀世界的運作方式至關重要。

或者 Gemini 模型 : 

>>> response=gemini_model.invoke(prompt_value)   
>>> print(response.content)  
普朗克常數(h)是一個基本物理常數。它揭示了能量的量子化現象,即能量不是連續的,而是以離散的「量子」形式存在。它將光子的能量E與其頻率ν聯繫起來,公式為E=hν。普朗克常數是量子力學的基石,描述了微觀世界中能量的最小作用量單位。

這就是使用 LangChain 的好處, 不論是串接哪一個 LLM, 呼叫介面都相同. 

2026年4月5日 星期日

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

在前一篇測試中, 我使用 venv 建立一個虛擬環境, 並於其中安裝 langchain-google-genai 與 langchain-openai 這兩個外掛套件來分別串接 Gemini 與 OpenAI API, 目前 Gemini 免費帳戶可用 gemini-2.5-flash 與 gemini-2.5-flash-lite 等快捷與低成本模型; OpenAI 可使用經典的 gpt-3.5-turbo 或較新的 gpt-4o-mini 模型 (需付費購買 API key). 

本篇旨在測試如何查詢有哪些模型可用, 這會用到 OpenAI 與 Gemini 的原生 API : openai 與 google_genai, 這兩個套件在安裝 langchain_openai 與 langchain_google_genai 時都會作為底層依賴套件被自動安裝. 

本系列全部文章索引參考 :



1. 查詢 OpenAI 模型 : 

查詢 OpenAI 模型列表是透過 OpenAI 物件的 models 屬性的 list() 方法 : 

# list_openai_models.py
from openai import OpenAI
from dotenv import dotenv_values

# 讀取 .env 中的 OPENAI_API_KEY
config=dotenv_values('.env')
client=OpenAI(api_key=config.get('OPENAI_API'))

print("--- OpenAI 目前可用模型清單 ---")
try:
    models=client.models.list()
    for m in models:
        # 過濾掉一些老舊或非對話的模型,只看主流的
        if "gpt" in m.id or "o3" in m.id or "o5" in m.id:
            print(f"模型 ID: {m.id}")
except Exception as e:
    print(f"查詢失敗:{e}")

結果如下 :

(myvenv) D:\python\test>python list_openai_models.py
--- OpenAI 目前可用模型清單 ---
模型 ID: gpt-4-0613
模型 ID: gpt-4
模型 ID: gpt-3.5-turbo
模型 ID: gpt-5.4-mini
模型 ID: gpt-5.4
模型 ID: gpt-5.4-nano-2026-03-17
模型 ID: gpt-5.4-nano
模型 ID: gpt-5.4-mini-2026-03-17
模型 ID: gpt-3.5-turbo-instruct
模型 ID: gpt-3.5-turbo-instruct-0914
模型 ID: gpt-3.5-turbo-1106
模型 ID: gpt-3.5-turbo-0125
模型 ID: gpt-4-turbo
模型 ID: gpt-4-turbo-2024-04-09
模型 ID: gpt-4o
模型 ID: gpt-4o-2024-05-13
模型 ID: gpt-4o-mini-2024-07-18
模型 ID: gpt-4o-mini
模型 ID: gpt-4o-2024-08-06
模型 ID: gpt-4o-audio-preview
模型 ID: gpt-4o-realtime-preview
模型 ID: gpt-4o-realtime-preview-2024-12-17
模型 ID: gpt-4o-audio-preview-2024-12-17
模型 ID: gpt-4o-mini-realtime-preview-2024-12-17
模型 ID: gpt-4o-mini-audio-preview-2024-12-17
模型 ID: gpt-4o-mini-realtime-preview
模型 ID: gpt-4o-mini-audio-preview
模型 ID: o3-mini
模型 ID: o3-mini-2025-01-31
模型 ID: gpt-4o-2024-11-20
模型 ID: gpt-4o-mini-search-preview-2025-03-11
模型 ID: gpt-4o-mini-search-preview
模型 ID: gpt-4o-transcribe
模型 ID: gpt-4o-mini-transcribe
模型 ID: gpt-4o-mini-tts
模型 ID: o3-2025-04-16
模型 ID: o3
模型 ID: gpt-4.1-2025-04-14
模型 ID: gpt-4.1
模型 ID: gpt-4.1-mini-2025-04-14
模型 ID: gpt-4.1-mini
模型 ID: gpt-4.1-nano-2025-04-14
模型 ID: gpt-4.1-nano
模型 ID: gpt-image-1
模型 ID: gpt-4o-realtime-preview-2025-06-03
模型 ID: gpt-4o-audio-preview-2025-06-03
模型 ID: gpt-4o-transcribe-diarize
模型 ID: gpt-5-chat-latest
模型 ID: gpt-5-2025-08-07
模型 ID: gpt-5
模型 ID: gpt-5-mini-2025-08-07
模型 ID: gpt-5-mini
模型 ID: gpt-5-nano-2025-08-07
模型 ID: gpt-5-nano
模型 ID: gpt-audio-2025-08-28
模型 ID: gpt-realtime
模型 ID: gpt-realtime-2025-08-28
模型 ID: gpt-audio
模型 ID: gpt-5-codex
模型 ID: gpt-image-1-mini
模型 ID: gpt-5-pro-2025-10-06
模型 ID: gpt-5-pro
模型 ID: gpt-audio-mini
模型 ID: gpt-audio-mini-2025-10-06
模型 ID: gpt-5-search-api
模型 ID: gpt-realtime-mini
模型 ID: gpt-realtime-mini-2025-10-06
模型 ID: gpt-5-search-api-2025-10-14
模型 ID: gpt-5.1-chat-latest
模型 ID: gpt-5.1-2025-11-13
模型 ID: gpt-5.1
模型 ID: gpt-5.1-codex
模型 ID: gpt-5.1-codex-mini
模型 ID: gpt-5.1-codex-max
模型 ID: gpt-image-1.5
模型 ID: gpt-5.2-2025-12-11
模型 ID: gpt-5.2
模型 ID: gpt-5.2-pro-2025-12-11
模型 ID: gpt-5.2-pro
模型 ID: gpt-5.2-chat-latest
模型 ID: gpt-4o-mini-transcribe-2025-12-15
模型 ID: gpt-4o-mini-transcribe-2025-03-20
模型 ID: gpt-4o-mini-tts-2025-03-20
模型 ID: gpt-4o-mini-tts-2025-12-15
模型 ID: gpt-realtime-mini-2025-12-15
模型 ID: gpt-audio-mini-2025-12-15
模型 ID: chatgpt-image-latest
模型 ID: gpt-5.2-codex
模型 ID: gpt-5.3-codex
模型 ID: gpt-realtime-1.5
模型 ID: gpt-audio-1.5
模型 ID: gpt-4o-search-preview
模型 ID: gpt-4o-search-preview-2025-03-11
模型 ID: gpt-5.3-chat-latest
模型 ID: gpt-5.4-2026-03-05
模型 ID: gpt-5.4-pro
模型 ID: gpt-5.4-pro-2026-03-05
模型 ID: gpt-3.5-turbo-16k


2. 查詢 Gemini 模型 : 

查詢 Gemini 模型列表是透過 genai 物件的 models 屬性的 list() 方法, 注意, 新版 API 的判斷欄位改為 supported_actions (舊版為 supported_generation_methods) : 

# list_gemini_models.py
from google import genai
from dotenv import dotenv_values

# 1. 讀取 .env
config=dotenv_values('.env')
api_key=config.get('GEMINI_API_KEY')

# 2. 初始化 Client (新版 API 不再用 genai.configure)
client=genai.Client(api_key=api_key)
print("--- 可用的 Google AI 模型如下: ---")

try:
    # 3. 使用 client.models.list() 查詢
    for m in client.models.list():
        # 新版 API 的判斷欄位為 supported_actions
        if 'generateContent' in m.supported_actions:
            print(f'模型 ID: {m.name:}')
            
except Exception as e:
    print(f"查詢出錯:{e}")

執行結果 : 

(myvenv) D:\python\test>python list_gemini_models.py  
--- 可用的 Google AI 模型如下: ---
模型 ID: models/gemini-2.5-flash
模型 ID: models/gemini-2.5-pro
模型 ID: models/gemini-2.0-flash
模型 ID: models/gemini-2.0-flash-001
模型 ID: models/gemini-2.0-flash-lite-001
模型 ID: models/gemini-2.0-flash-lite
模型 ID: models/gemini-2.5-flash-preview-tts
模型 ID: models/gemini-2.5-pro-preview-tts
模型 ID: models/gemma-3-1b-it
模型 ID: models/gemma-3-4b-it
模型 ID: models/gemma-3-12b-it
模型 ID: models/gemma-3-27b-it
模型 ID: models/gemma-3n-e4b-it
模型 ID: models/gemma-3n-e2b-it
模型 ID: models/gemma-4-26b-a4b-it
模型 ID: models/gemma-4-31b-it
模型 ID: models/gemini-flash-latest
模型 ID: models/gemini-flash-lite-latest
模型 ID: models/gemini-pro-latest
模型 ID: models/gemini-2.5-flash-lite
模型 ID: models/gemini-2.5-flash-image
模型 ID: models/gemini-3-pro-preview
模型 ID: models/gemini-3-flash-preview
模型 ID: models/gemini-3.1-pro-preview
模型 ID: models/gemini-3.1-pro-preview-customtools
模型 ID: models/gemini-3.1-flash-lite-preview
模型 ID: models/gemini-3-pro-image-preview
模型 ID: models/nano-banana-pro-preview
模型 ID: models/gemini-3.1-flash-image-preview
模型 ID: models/lyria-3-clip-preview
模型 ID: models/lyria-3-pro-preview
模型 ID: models/gemini-robotics-er-1.5-preview
模型 ID: models/gemini-2.5-computer-use-preview-10-2025
模型 ID: models/deep-research-pro-preview-12-2025

也可以不直接使用原生 API (google_genai 套件), 而是透過 LangChain 調用底層 Client 物件 :

# list_gemini_models_2.py
from langchain_google_genai import ChatGoogleGenerativeAI
from dotenv import dotenv_values

config=dotenv_values('.env')
api_key=config.get('GEMINI_API_KEY')

# 初始化 LangChain 模型物件
chat_model=ChatGoogleGenerativeAI(model='gemini-2.5-flash', api_key=api_key)
print("--- 透過 LangChain 的底層 Client 查詢模型 ---")

try:
    # 直接存取 LangChain 內部的 client 物件 (這就是 google-genai 的實體)
    # 注意:這屬於「私有屬性」存取,通常用於調錯或特殊查詢
    client=chat_model.client
    for m in client.models.list():
        if 'generateContent' in m.supported_actions:
            print(f"可用模型: {m.name}")
            
except Exception as e:
    print(f"查詢失敗:{e}")

執行結果與上面直接使用原生 API 相同 : 

(myvenv) D:\python\test>python list_gemini_models_2.py    
--- 透過 LangChain 的底層 Client 查詢模型 ---
可用模型: models/gemini-2.5-flash
可用模型: models/gemini-2.5-pro
可用模型: models/gemini-2.0-flash
可用模型: models/gemini-2.0-flash-001
可用模型: models/gemini-2.0-flash-lite-001
可用模型: models/gemini-2.0-flash-lite
可用模型: models/gemini-2.5-flash-preview-tts
可用模型: models/gemini-2.5-pro-preview-tts
可用模型: models/gemma-3-1b-it
可用模型: models/gemma-3-4b-it
可用模型: models/gemma-3-12b-it
可用模型: models/gemma-3-27b-it
可用模型: models/gemma-3n-e4b-it
可用模型: models/gemma-3n-e2b-it
可用模型: models/gemma-4-26b-a4b-it
可用模型: models/gemma-4-31b-it
可用模型: models/gemini-flash-latest
可用模型: models/gemini-flash-lite-latest
可用模型: models/gemini-pro-latest
可用模型: models/gemini-2.5-flash-lite
可用模型: models/gemini-2.5-flash-image
可用模型: models/gemini-3-pro-preview
可用模型: models/gemini-3-flash-preview
可用模型: models/gemini-3.1-pro-preview
可用模型: models/gemini-3.1-pro-preview-customtools
可用模型: models/gemini-3.1-flash-lite-preview
可用模型: models/gemini-3-pro-image-preview
可用模型: models/nano-banana-pro-preview
可用模型: models/gemini-3.1-flash-image-preview
可用模型: models/lyria-3-clip-preview
可用模型: models/lyria-3-pro-preview
可用模型: models/gemini-robotics-er-1.5-preview
可用模型: models/gemini-2.5-computer-use-preview-10-2025
可用模型: models/deep-research-pro-preview-12-2025

注意, 由於 Google 與 OpenAI 兩家公司在 SDK 設計邏輯上的根本差異, 使得 LangChain 在整合這兩者時採取了不同策略, Gemini 可以直接透過 .client 取得模型清單, 而 OpenAI 則不行, 因此查詢 OpenAI 的模型清單必須用底層 SDK 套件 openai. 

2026年4月4日 星期六

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

3/21 從日本旅行回來後感覺有很多東西要學, 但卻不知從哪一個著手. 昨天整理書桌看到案上的 LangChain 書籍, 想說那就從 LangChain 開始吧! 記得 LangChain 就是去年九月第一次關西之旅回來後開始學習的.

由於我的 LG Gram 筆電的 Thonny Python 執行環境太亂了, 存在嚴重的版本衝突問題, 所以在重新出發之前, 先建立一個專門用來串接 GenAI 的乾淨虛擬環境較好. 我之前曾使用 poetry 來建立與管理虛擬環境, 但本篇則是要使用傳統且熟悉的 venv. 

本系列全部測試文章參考 :


開啟命令提示字元視窗建立一個名為 myvenv 虛擬環境 :

D:\python\test>python -m venv myvenv  
D:\python\test>myvenv\Scripts\activate   
(myvenv) D:\python\test>  

用 pip list 檢視可知只有一個 pip 套件而已 :

(myvenv) D:\python\test>pip list
Package Version
------- -------
pip     23.2.1

[notice] A new release of pip is available: 23.2.1 -> 26.0.1
[notice] To update, run: python.exe -m pip install --upgrade pip

更新 pip 版本 : 

(myvenv) D:\python\test>python.exe -m pip install --upgrade pip   
Requirement already satisfied: pip in d:\python\test\myvenv\lib\site-packages (23.2.1)
Collecting pip
  Obtaining dependency information for pip from https://files.pythonhosted.org/packages/de/f0/c81e05b613866b76d2d1066490adf1a3dbc4ee9d9c839961c3fc8a6997af/pip-26.0.1-py3-none-any.whl.metadata
  Downloading pip-26.0.1-py3-none-any.whl.metadata (4.7 kB)
Downloading pip-26.0.1-py3-none-any.whl (1.8 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.8/1.8 MB 2.1 MB/s eta 0:00:00
Installing collected packages: pip
  Attempting uninstall: pip
    Found existing installation: pip 23.2.1
    Uninstalling pip-23.2.1:
      Successfully uninstalled pip-23.2.1
Successfully installed pip-26.0.1

(myvenv) D:\python\test>

用下列指令來安裝透過 LangChain 串接 Gemini 與 OpenAI 所需的套件 : 

pip install langchain-google-genai langchain-openai python-dotenv  

其中 langchain-google-genai 與 langchain-openai 分別是串接 Gemini 與 OpenAI 的外掛, 安裝它們時會自動安裝 LangChain 的核心引擎 langchain-core, 這是 LangChain 的心臟, 包含所有的基礎邏輯 (Base Message, Chat Prompt 等), 安裝外掛時會自動附帶. 注意, 不需要安裝 langchain 套件, 這是一個塞滿了各種實驗性功能和舊代碼的大禮包, 非常龐雜. 

(myvenv) D:\python\test>pip install langchain-google-genai langchain-openai python-dotenv    
Collecting langchain-google-genai
  Downloading langchain_google_genai-4.2.1-py3-none-any.whl.metadata (2.7 kB)
Collecting langchain-openai
  Downloading langchain_openai-1.1.12-py3-none-any.whl.metadata (3.1 kB)
Collecting python-dotenv
  Downloading python_dotenv-1.2.2-py3-none-any.whl.metadata (27 kB)
Collecting filetype<2.0.0,>=1.2.0 (from langchain-google-genai)
  Using cached filetype-1.2.0-py2.py3-none-any.whl.metadata (6.5 kB)
Collecting google-genai<2.0.0,>=1.56.0 (from langchain-google-genai)
  Using cached google_genai-1.70.0-py3-none-any.whl.metadata (52 kB)
Collecting langchain-core<2.0.0,>=1.2.5 (from langchain-google-genai)
  Downloading langchain_core-1.2.26-py3-none-any.whl.metadata (4.4 kB)
Collecting pydantic<3.0.0,>=2.0.0 (from langchain-google-genai)
  Downloading pydantic-2.12.5-py3-none-any.whl.metadata (90 kB)
Collecting anyio<5.0.0,>=4.8.0 (from google-genai<2.0.0,>=1.56.0->langchain-google-genai)
  Using cached anyio-4.13.0-py3-none-any.whl.metadata (4.5 kB)
Collecting google-auth<3.0.0,>=2.48.1 (from google-auth[requests]<3.0.0,>=2.48.1->google-genai<2.0.0,>=1.56.0->langchain-google-genai)
  Using cached google_auth-2.49.1-py3-none-any.whl.metadata (6.2 kB)
Collecting httpx<1.0.0,>=0.28.1 (from google-genai<2.0.0,>=1.56.0->langchain-google-genai)
  Using cached httpx-0.28.1-py3-none-any.whl.metadata (7.1 kB)
Collecting requests<3.0.0,>=2.28.1 (from google-genai<2.0.0,>=1.56.0->langchain-google-genai)
  Downloading requests-2.33.1-py3-none-any.whl.metadata (4.8 kB)
Collecting tenacity<9.2.0,>=8.2.3 (from google-genai<2.0.0,>=1.56.0->langchain-google-genai)
  Downloading tenacity-9.1.4-py3-none-any.whl.metadata (1.2 kB)
Collecting websockets<17.0,>=13.0.0 (from google-genai<2.0.0,>=1.56.0->langchain-google-genai)
  Downloading websockets-16.0-cp312-cp312-win_amd64.whl.metadata (7.0 kB)
Collecting typing-extensions<5.0.0,>=4.14.0 (from google-genai<2.0.0,>=1.56.0->langchain-google-genai)
  Using cached typing_extensions-4.15.0-py3-none-any.whl.metadata (3.3 kB)
Collecting distro<2,>=1.7.0 (from google-genai<2.0.0,>=1.56.0->langchain-google-genai)
  Using cached distro-1.9.0-py3-none-any.whl.metadata (6.8 kB)
Collecting sniffio (from google-genai<2.0.0,>=1.56.0->langchain-google-genai)
  Downloading sniffio-1.3.1-py3-none-any.whl.metadata (3.9 kB)
Collecting idna>=2.8 (from anyio<5.0.0,>=4.8.0->google-genai<2.0.0,>=1.56.0->langchain-google-genai)
  Downloading idna-3.11-py3-none-any.whl.metadata (8.4 kB)
Collecting pyasn1-modules>=0.2.1 (from google-auth<3.0.0,>=2.48.1->google-auth[requests]<3.0.0,>=2.48.1->google-genai<2.0.0,>=1.56.0->langchain-google-genai)
  Downloading pyasn1_modules-0.4.2-py3-none-any.whl.metadata (3.5 kB)
Collecting cryptography>=38.0.3 (from google-auth<3.0.0,>=2.48.1->google-auth[requests]<3.0.0,>=2.48.1->google-genai<2.0.0,>=1.56.0->langchain-google-genai)
  Downloading cryptography-46.0.6-cp311-abi3-win_amd64.whl.metadata (5.7 kB)
Collecting certifi (from httpx<1.0.0,>=0.28.1->google-genai<2.0.0,>=1.56.0->langchain-google-genai)
  Downloading certifi-2026.2.25-py3-none-any.whl.metadata (2.5 kB)
Collecting httpcore==1.* (from httpx<1.0.0,>=0.28.1->google-genai<2.0.0,>=1.56.0->langchain-google-genai)
  Downloading httpcore-1.0.9-py3-none-any.whl.metadata (21 kB)
Collecting h11>=0.16 (from httpcore==1.*->httpx<1.0.0,>=0.28.1->google-genai<2.0.0,>=1.56.0->langchain-google-genai)
  Downloading h11-0.16.0-py3-none-any.whl.metadata (8.3 kB)
Collecting jsonpatch<2.0.0,>=1.33.0 (from langchain-core<2.0.0,>=1.2.5->langchain-google-genai)
  Using cached jsonpatch-1.33-py2.py3-none-any.whl.metadata (3.0 kB)
Collecting langsmith<1.0.0,>=0.3.45 (from langchain-core<2.0.0,>=1.2.5->langchain-google-genai)
  Downloading langsmith-0.7.25-py3-none-any.whl.metadata (15 kB)
Collecting packaging>=23.2.0 (from langchain-core<2.0.0,>=1.2.5->langchain-google-genai)
  Downloading packaging-26.0-py3-none-any.whl.metadata (3.3 kB)
Collecting pyyaml<7.0.0,>=5.3.0 (from langchain-core<2.0.0,>=1.2.5->langchain-google-genai)
  Downloading pyyaml-6.0.3-cp312-cp312-win_amd64.whl.metadata (2.4 kB)
Collecting uuid-utils<1.0,>=0.12.0 (from langchain-core<2.0.0,>=1.2.5->langchain-google-genai)
  Downloading uuid_utils-0.14.1-cp39-abi3-win_amd64.whl.metadata (4.9 kB)
Collecting jsonpointer>=1.9 (from jsonpatch<2.0.0,>=1.33.0->langchain-core<2.0.0,>=1.2.5->langchain-google-genai)
  Downloading jsonpointer-3.1.1-py3-none-any.whl.metadata (2.4 kB)
Collecting orjson>=3.9.14 (from langsmith<1.0.0,>=0.3.45->langchain-core<2.0.0,>=1.2.5->langchain-google-genai)
  Downloading orjson-3.11.8-cp312-cp312-win_amd64.whl.metadata (43 kB)
Collecting requests-toolbelt>=1.0.0 (from langsmith<1.0.0,>=0.3.45->langchain-core<2.0.0,>=1.2.5->langchain-google-genai)
  Using cached requests_toolbelt-1.0.0-py2.py3-none-any.whl.metadata (14 kB)
Collecting xxhash>=3.0.0 (from langsmith<1.0.0,>=0.3.45->langchain-core<2.0.0,>=1.2.5->langchain-google-genai)
  Downloading xxhash-3.6.0-cp312-cp312-win_amd64.whl.metadata (13 kB)
Collecting zstandard>=0.23.0 (from langsmith<1.0.0,>=0.3.45->langchain-core<2.0.0,>=1.2.5->langchain-google-genai)
  Downloading zstandard-0.25.0-cp312-cp312-win_amd64.whl.metadata (3.3 kB)
Collecting annotated-types>=0.6.0 (from pydantic<3.0.0,>=2.0.0->langchain-google-genai)
  Using cached annotated_types-0.7.0-py3-none-any.whl.metadata (15 kB)
Collecting pydantic-core==2.41.5 (from pydantic<3.0.0,>=2.0.0->langchain-google-genai)
  Downloading pydantic_core-2.41.5-cp312-cp312-win_amd64.whl.metadata (7.4 kB)
Collecting typing-inspection>=0.4.2 (from pydantic<3.0.0,>=2.0.0->langchain-google-genai)
  Downloading typing_inspection-0.4.2-py3-none-any.whl.metadata (2.6 kB)
Collecting charset_normalizer<4,>=2 (from requests<3.0.0,>=2.28.1->google-genai<2.0.0,>=1.56.0->langchain-google-genai)
  Downloading charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl.metadata (41 kB)
Collecting urllib3<3,>=1.26 (from requests<3.0.0,>=2.28.1->google-genai<2.0.0,>=1.56.0->langchain-google-genai)
  Downloading urllib3-2.6.3-py3-none-any.whl.metadata (6.9 kB)
Collecting openai<3.0.0,>=2.26.0 (from langchain-openai)
  Downloading openai-2.30.0-py3-none-any.whl.metadata (29 kB)
Collecting tiktoken<1.0.0,>=0.7.0 (from langchain-openai)
  Downloading tiktoken-0.12.0-cp312-cp312-win_amd64.whl.metadata (6.9 kB)
Collecting jiter<1,>=0.10.0 (from openai<3.0.0,>=2.26.0->langchain-openai)
  Downloading jiter-0.13.0-cp312-cp312-win_amd64.whl.metadata (5.3 kB)
Collecting tqdm>4 (from openai<3.0.0,>=2.26.0->langchain-openai)
  Downloading tqdm-4.67.3-py3-none-any.whl.metadata (57 kB)
Collecting regex>=2022.1.18 (from tiktoken<1.0.0,>=0.7.0->langchain-openai)
  Downloading regex-2026.4.4-cp312-cp312-win_amd64.whl.metadata (41 kB)
Collecting cffi>=2.0.0 (from cryptography>=38.0.3->google-auth<3.0.0,>=2.48.1->google-auth[requests]<3.0.0,>=2.48.1->google-genai<2.0.0,>=1.56.0->langchain-google-genai)
  Downloading cffi-2.0.0-cp312-cp312-win_amd64.whl.metadata (2.6 kB)
Collecting pycparser (from cffi>=2.0.0->cryptography>=38.0.3->google-auth<3.0.0,>=2.48.1->google-auth[requests]<3.0.0,>=2.48.1->google-genai<2.0.0,>=1.56.0->langchain-google-genai)
  Downloading pycparser-3.0-py3-none-any.whl.metadata (8.2 kB)
Collecting pyasn1<0.7.0,>=0.6.1 (from pyasn1-modules>=0.2.1->google-auth<3.0.0,>=2.48.1->google-auth[requests]<3.0.0,>=2.48.1->google-genai<2.0.0,>=1.56.0->langchain-google-genai)
  Downloading pyasn1-0.6.3-py3-none-any.whl.metadata (8.4 kB)
Collecting colorama (from tqdm>4->openai<3.0.0,>=2.26.0->langchain-openai)
  Using cached colorama-0.4.6-py2.py3-none-any.whl.metadata (17 kB)
Downloading langchain_google_genai-4.2.1-py3-none-any.whl (66 kB)
Using cached filetype-1.2.0-py2.py3-none-any.whl (19 kB)
Using cached google_genai-1.70.0-py3-none-any.whl (760 kB)
Using cached anyio-4.13.0-py3-none-any.whl (114 kB)
Using cached distro-1.9.0-py3-none-any.whl (20 kB)
Using cached google_auth-2.49.1-py3-none-any.whl (240 kB)
Using cached httpx-0.28.1-py3-none-any.whl (73 kB)
Downloading httpcore-1.0.9-py3-none-any.whl (78 kB)
Downloading langchain_core-1.2.26-py3-none-any.whl (508 kB)
Using cached jsonpatch-1.33-py2.py3-none-any.whl (12 kB)
Downloading langsmith-0.7.25-py3-none-any.whl (359 kB)
Downloading pydantic-2.12.5-py3-none-any.whl (463 kB)
Downloading pydantic_core-2.41.5-cp312-cp312-win_amd64.whl (2.0 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.0/2.0 MB 4.2 MB/s  0:00:00
Downloading pyyaml-6.0.3-cp312-cp312-win_amd64.whl (154 kB)
Downloading requests-2.33.1-py3-none-any.whl (64 kB)
Downloading charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl (159 kB)
Downloading idna-3.11-py3-none-any.whl (71 kB)
Downloading tenacity-9.1.4-py3-none-any.whl (28 kB)
Using cached typing_extensions-4.15.0-py3-none-any.whl (44 kB)
Downloading urllib3-2.6.3-py3-none-any.whl (131 kB)
Downloading uuid_utils-0.14.1-cp39-abi3-win_amd64.whl (187 kB)
Downloading websockets-16.0-cp312-cp312-win_amd64.whl (178 kB)
Downloading langchain_openai-1.1.12-py3-none-any.whl (88 kB)
Downloading openai-2.30.0-py3-none-any.whl (1.1 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.1/1.1 MB 3.1 MB/s  0:00:00
Downloading jiter-0.13.0-cp312-cp312-win_amd64.whl (205 kB)
Downloading tiktoken-0.12.0-cp312-cp312-win_amd64.whl (878 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 878.7/878.7 kB 4.4 MB/s  0:00:00
Downloading python_dotenv-1.2.2-py3-none-any.whl (22 kB)
Using cached annotated_types-0.7.0-py3-none-any.whl (13 kB)
Downloading certifi-2026.2.25-py3-none-any.whl (153 kB)
Downloading cryptography-46.0.6-cp311-abi3-win_amd64.whl (3.5 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.5/3.5 MB 5.0 MB/s  0:00:00
Downloading cffi-2.0.0-cp312-cp312-win_amd64.whl (183 kB)
Downloading h11-0.16.0-py3-none-any.whl (37 kB)
Downloading jsonpointer-3.1.1-py3-none-any.whl (7.7 kB)
Downloading orjson-3.11.8-cp312-cp312-win_amd64.whl (127 kB)
Downloading packaging-26.0-py3-none-any.whl (74 kB)
Downloading pyasn1_modules-0.4.2-py3-none-any.whl (181 kB)
Downloading pyasn1-0.6.3-py3-none-any.whl (83 kB)
Downloading regex-2026.4.4-cp312-cp312-win_amd64.whl (277 kB)
Using cached requests_toolbelt-1.0.0-py2.py3-none-any.whl (54 kB)
Downloading tqdm-4.67.3-py3-none-any.whl (78 kB)
Downloading typing_inspection-0.4.2-py3-none-any.whl (14 kB)
Downloading xxhash-3.6.0-cp312-cp312-win_amd64.whl (31 kB)
Downloading zstandard-0.25.0-cp312-cp312-win_amd64.whl (506 kB)
Using cached colorama-0.4.6-py2.py3-none-any.whl (25 kB)
Downloading pycparser-3.0-py3-none-any.whl (48 kB)
Downloading sniffio-1.3.1-py3-none-any.whl (10 kB)
Installing collected packages: filetype, zstandard, xxhash, websockets, uuid-utils, urllib3, typing-extensions, tenacity, sniffio, regex, pyyaml, python-dotenv, pycparser, pyasn1, packaging, orjson, jsonpointer, jiter, idna, h11, distro, colorama, charset_normalizer, certifi, annotated-types, typing-inspection, tqdm, requests, pydantic-core, pyasn1-modules, jsonpatch, httpcore, cffi, anyio, tiktoken, requests-toolbelt, pydantic, httpx, cryptography, openai, langsmith, google-auth, langchain-core, langchain-openai, google-genai, langchain-google-genai
Successfully installed annotated-types-0.7.0 anyio-4.13.0 certifi-2026.2.25 cffi-2.0.0 charset_normalizer-3.4.7 colorama-0.4.6 cryptography-46.0.6 distro-1.9.0 filetype-1.2.0 google-auth-2.49.1 google-genai-1.70.0 h11-0.16.0 httpcore-1.0.9 httpx-0.28.1 idna-3.11 jiter-0.13.0 jsonpatch-1.33 jsonpointer-3.1.1 langchain-core-1.2.26 langchain-google-genai-4.2.1 langchain-openai-1.1.12 langsmith-0.7.25 openai-2.30.0 orjson-3.11.8 packaging-26.0 pyasn1-0.6.3 pyasn1-modules-0.4.2 pycparser-3.0 pydantic-2.12.5 pydantic-core-2.41.5 python-dotenv-1.2.2 pyyaml-6.0.3 regex-2026.4.4 requests-2.33.1 requests-toolbelt-1.0.0 sniffio-1.3.1 tenacity-9.1.4 tiktoken-0.12.0 tqdm-4.67.3 typing-extensions-4.15.0 typing-inspection-0.4.2 urllib3-2.6.3 uuid-utils-0.14.1 websockets-16.0 xxhash-3.6.0 zstandard-0.25.0

檢視目前 pip 套件 :

(myvenv) D:\python\test>pip list
Package                Version
---------------------- ---------
annotated-types        0.7.0
anyio                  4.13.0
certifi                2026.2.25
cffi                   2.0.0
charset-normalizer     3.4.7
colorama               0.4.6
cryptography           46.0.6
distro                 1.9.0
filetype               1.2.0
google-auth            2.49.1
google-genai           1.70.0
h11                    0.16.0
httpcore               1.0.9
httpx                  0.28.1
idna                   3.11
jiter                  0.13.0
jsonpatch              1.33
jsonpointer            3.1.1
langchain-core         1.2.26
langchain-google-genai 4.2.1
langchain-openai       1.1.12
langsmith              0.7.25
openai                 2.30.0
orjson                 3.11.8
packaging              26.0
pip                    26.0.1
pyasn1                 0.6.3
pyasn1_modules         0.4.2
pycparser              3.0
pydantic               2.12.5
pydantic_core          2.41.5
python-dotenv          1.2.2
PyYAML                 6.0.3
regex                  2026.4.4
requests               2.33.1
requests-toolbelt      1.0.0
sniffio                1.3.1
tenacity               9.1.4
tiktoken               0.12.0
tqdm                   4.67.3
typing_extensions      4.15.0
typing-inspection      0.4.2
urllib3                2.6.3
uuid_utils             0.14.1
websockets             16.0
xxhash                 3.6.0
zstandard              0.25.0

可見除了核心套件 langchain-core 外, 還有串接 OpenAI 與 Gemini 的 langchain-openai 與 langchain-google-genai 套件; 此外還會安裝底層的 SDK 依賴套件 google-genai 與 openai. 如果想用原生 SDK 串接 API 就可以使用這兩個套件. 其中 google-genai 是谷歌 2024 年底發布的新版 SDK, 用來取代舊版的 google-generativeai (已於 2025 年進入維護模式), 用法參考下面這篇的補充說明 :


先來串接 OpenAI API :

(myvenv) D:\python\test>python   
Python 3.12.1 (tags/v3.12.1:2305ca5, Dec  7 2023, 22:03:25) [MSC v.1937 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from dotenv import dotenv_values    
>>> config=dotenv_values('.env')   
>>> openai_api_key=config.get('OPENAI_API')   
>>> from langchain_openai import ChatOpenAI   
>>> chat_model=ChatOpenAI(api_key=openai_api_key, model='gpt-3.5-turbo')   
>>> response=chat_model.invoke('你是誰?')    
>>> response.content     
'我是一個機器人助手,可以回答你的問題和提供幫助。有什麼我可以為你做的嗎?'

更換為 gpt-4o-mini 模型 :

>>> chat_model=ChatOpenAI(api_key=openai_api_key, model='gpt-4o-mini')   
>>> response=chat_model.invoke('你是誰?')   
>>> response.content     
'我是一个人工智能助手,旨在回答你的问题和提供帮助。如果你有任何疑问或需要的信息,请随时告诉我!'

下面是串接 Gemini :

>>> from dotenv import dotenv_values   
>>> config=dotenv_values('.env')   
>>> gemini_api_key=config.get('GEMINI_API_KEY')   
>>> from langchain_google_genai import ChatGoogleGenerativeAI   
>>> chat_model=ChatGoogleGenerativeAI(api_key=gemini_api_key, model='gemini-2.5-flash')    
>>> response=chat_model.invoke('你是誰?')     
>>> response.content   
'我是一个大型语言模型,由 Google 训练。'

更換模型 :

>>> chat_model=ChatGoogleGenerativeAI(api_key=gemini_api_key, model='gemini-2.5-flash-lite')   
>>> response=chat_model.invoke('你是誰?')   
>>> response.content   
'我是一個大型語言模型,由 Google 訓練。'  

2025年9月28日 星期日

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

晚上繼續測試 LangChain, 本篇旨在測試串接谷歌 Gemini 的方法.

本系列之前的文章參考 :


關於谷歌原生的 Gemini 串接套件 google-generativeai 用法參考 :



5. 安裝 langchain-google-genai 套件 :    

LangChain 用來串接 Gemini 的套件為 langchain-google-genai, 與前一篇串接 GPT 模型一樣, langchain-google-genai 套件只是封裝了透過谷歌原生套件 google-generativeai 串接 Gemini 模型的介面而已, 它無法單獨與 Gemini 聊天, 必須搭配 google-generativeai 當底層介面才行. 

不過, 由於 langchain-google-genai 與 google-generativeai 這兩個套件在安裝時會與相依套件 google-ai-generativelanguage 有版本衝突問題 (安裝時會出現 ERROR 訊息), 我向 ChatGPT 尋求解決方案, 經測試發現只要指定特定版本即可順利安裝, 若已安裝此兩套件出現錯誤, 請先用下列指令解除安裝 :

pip uninstall -y google-ai-generativelanguage google-generativeai langchain-google-genai  

D:\python\test>pip uninstall -y google-ai-generativelanguage google-generativeai langchain-google-genai
Found existing installation: google-ai-generativelanguage 0.7.0
Uninstalling google-ai-generativelanguage-0.7.0:
  Successfully uninstalled google-ai-generativelanguage-0.7.0
Found existing installation: google-generativeai 0.8.5
Uninstalling google-generativeai-0.8.5:
  Successfully uninstalled google-generativeai-0.8.5
Found existing installation: langchain-google-genai 2.1.12
Uninstalling langchain-google-genai-2.1.12:
  Successfully uninstalled langchain-google-genai-2.1.12

然後指定安裝 0.6.15 版的 google-ai-generativelanguage : 

pip install google-ai-generativelanguage==0.6.15    

D:\python\test>pip install google-ai-generativelanguage==0.6.15   
Collecting google-ai-generativelanguage==0.6.15
  Using cached google_ai_generativelanguage-0.6.15-py3-none-any.whl.metadata (5.7 kB)
Requirement already satisfied: google-api-core!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0dev,>=1.34.1 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0dev,>=1.34.1->google-ai-generativelanguage==0.6.15) (2.19.2)
Requirement already satisfied: google-auth!=2.24.0,!=2.25.0,<3.0.0dev,>=2.14.1 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from google-ai-generativelanguage==0.6.15) (2.22.0)
Requirement already satisfied: proto-plus<2.0.0dev,>=1.22.3 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from google-ai-generativelanguage==0.6.15) (1.24.0)
Requirement already satisfied: protobuf!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<6.0.0dev,>=3.20.2 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from google-ai-generativelanguage==0.6.15) (5.28.1)
Requirement already satisfied: googleapis-common-protos<2.0.dev0,>=1.56.2 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from google-api-core!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0dev,>=1.34.1->google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0dev,>=1.34.1->google-ai-generativelanguage==0.6.15) (1.65.0)
Requirement already satisfied: requests<3.0.0.dev0,>=2.18.0 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from google-api-core!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0dev,>=1.34.1->google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0dev,>=1.34.1->google-ai-generativelanguage==0.6.15) (2.31.0)
Requirement already satisfied: grpcio<2.0dev,>=1.33.2 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0dev,>=1.34.1->google-ai-generativelanguage==0.6.15) (1.66.1)
Requirement already satisfied: grpcio-status<2.0.dev0,>=1.33.2 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0dev,>=1.34.1->google-ai-generativelanguage==0.6.15) (1.66.1)
Requirement already satisfied: cachetools<6.0,>=2.0.0 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from google-auth!=2.24.0,!=2.25.0,<3.0.0dev,>=2.14.1->google-ai-generativelanguage==0.6.15) (5.3.1)
Requirement already satisfied: pyasn1-modules>=0.2.1 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from google-auth!=2.24.0,!=2.25.0,<3.0.0dev,>=2.14.1->google-ai-generativelanguage==0.6.15) (0.3.0)
Requirement already satisfied: rsa<5,>=3.1.4 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from google-auth!=2.24.0,!=2.25.0,<3.0.0dev,>=2.14.1->google-ai-generativelanguage==0.6.15) (4.9)
Requirement already satisfied: six>=1.9.0 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from google-auth!=2.24.0,!=2.25.0,<3.0.0dev,>=2.14.1->google-ai-generativelanguage==0.6.15) (1.17.0)
Requirement already satisfied: urllib3<2.0 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from google-auth!=2.24.0,!=2.25.0,<3.0.0dev,>=2.14.1->google-ai-generativelanguage==0.6.15) (1.26.19)
Requirement already satisfied: charset-normalizer<4,>=2 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from requests<3.0.0.dev0,>=2.18.0->google-api-core!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0dev,>=1.34.1->google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0dev,>=1.34.1->google-ai-generativelanguage==0.6.15) (3.2.0)
Requirement already satisfied: idna<4,>=2.5 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from requests<3.0.0.dev0,>=2.18.0->google-api-core!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0dev,>=1.34.1->google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0dev,>=1.34.1->google-ai-generativelanguage==0.6.15) (3.4)
Requirement already satisfied: certifi>=2017.4.17 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from requests<3.0.0.dev0,>=2.18.0->google-api-core!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0dev,>=1.34.1->google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0dev,>=1.34.1->google-ai-generativelanguage==0.6.15) (2025.6.15)
Requirement already satisfied: pyasn1>=0.1.3 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from rsa<5,>=3.1.4->google-auth!=2.24.0,!=2.25.0,<3.0.0dev,>=2.14.1->google-ai-generativelanguage==0.6.15) (0.5.0)
Using cached google_ai_generativelanguage-0.6.15-py3-none-any.whl (1.3 MB)
Installing collected packages: google-ai-generativelanguage
Successfully installed google-ai-generativelanguage-0.6.15

其次安裝 0.8.5 版的 google-generativeai : 

pip install google-generativeai==0.8.5 --no-deps

D:\python\test>pip install google-generativeai==0.8.5 --no-deps  
Collecting google-generativeai==0.8.5
  Using cached google_generativeai-0.8.5-py3-none-any.whl.metadata (3.9 kB)
Using cached google_generativeai-0.8.5-py3-none-any.whl (155 kB)
Installing collected packages: google-generativeai
Successfully installed google-generativeai-0.8.5

最後安裝 2.1.12 版的 langchain-google-genai : 

pip install langchain-google-genai==2.1.12 --no-deps

D:\python\test>pip install langchain-google-genai==2.1.12 --no-deps   
Collecting langchain-google-genai==2.1.12
  Using cached langchain_google_genai-2.1.12-py3-none-any.whl.metadata (7.1 kB)
Using cached langchain_google_genai-2.1.12-py3-none-any.whl (50 kB)
Installing collected packages: langchain-google-genai
Successfully installed langchain-google-genai-2.1.12


6. 檢視 langchain-google-genai 套件內容 :    

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

>>> import langchain_google_genai     
>>> dir(langchain_google_genai)   
['AqaInput', 'AqaOutput', 'ChatGoogleGenerativeAI', 'DoesNotExistsException', 'GenAIAqa', 'GoogleGenerativeAI', 'GoogleGenerativeAIEmbeddings', 'GoogleVectorStore', 'HarmBlockThreshold', 'HarmCategory', 'Modality', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', '_common', '_enums', '_function_utils', '_genai_extension', '_image_utils', 'chat_models', 'embeddings', 'genai_aqa', 'google_vector_store', 'llms']

其中的 ChatGoogleGenerativeAI 類別便是用來串接 Gemini 模型用的, 其建構式 ChatGoogleGenerativeAI() 的參數如下表所示 : 


 參數名稱  說明
model Gemini 模型名稱,例如 "gemini-1.5-pro",對應 API 的 model 參數
temperature 生成隨機性,範圍 0~1,對應 API 的 temperature
max_output_tokens 最大生成 token 數量,對應 API 的 max_output_tokens
top_p nucleus sampling 控制生成多樣性,對應 API 的 top_p
top_k top-k sampling 控制生成多樣性,對應 API 的 top_k
api_key Google API Key,可直接傳入或使用環境變數 GOOGLE_API_KEY
request_timeout 請求超時秒數,對應 SDK 的 timeout / request_timeout
model_kwargs 可傳遞額外參數給 Gemini SDK,例如 stop_sequences、candidate_count 等
verbose 布林值,是否印出 debug 訊息
client 可傳自訂 Gemini SDK client,一般不用


在互動環境測試如下 :

我已將 Gemini API Key 儲存在環境變數檔案 .env 裡面 (名稱為 'GEMINI_API_KEY'), 先用 dotenv 套件讀取出來放在 gemini_api_key 變數中 :

>>> from dotenv import dotenv_values    
config=dotenv_values('.env')     
gemini_api_key=config.get('GEMINI_API_KEY')    

從 langchain_google_genai 套件中匯入 ChatGoogleGenerativeAI 類別 :  

>>> from langchain_google_genai import ChatGoogleGenerativeAI   

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

>>> chat_model=ChatGoogleGenerativeAI(api_key=gemini_api_key, model='gemini-2.5-flash')    
>>> type(chat_model)         
<class 'langchain_google_genai.chat_models.ChatGoogleGenerativeAI'>   

注意, 目前可用的 Gemini 模型如下 (之前測試使用的 1.5 版已下架, 無法串接了, 如果 model 指定舊版 1.5 版會得到 404 錯誤) : 


模型名稱 描述 適合場景 穩定性
gemini-2.5-flash 快速、低延遲的輕量模型 聊天、即時回應 穩定
gemini-2.5-pro 先進推理模型,支援長上下文 複雜問題、程式碼生成 穩定
gemini-2.5-flash-lite 更輕量的 Flash 變體 行動裝置、成本敏感應用 穩定
gemini-2.0-flash 舊 2.0 版本,快速但較舊 基本任務 穩定


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

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

檢視 invoke() 傳回的 AIMessage 物件內容 : 

>>> response   
AIMessage(content='我是一个大型语言模型,由 Google 训练。', additional_kwargs={}, response_metadata={'prompt_feedback': {'block_reason': 0, 'safety_ratings': []}, 'finish_reason': 'STOP', 'model_name': 'gemini-2.5-flash', 'safety_ratings': []}, id='run--9c115a61-fc2d-4c74-a611-a7da5465b65b-0')

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

>>> response.content     

'我是一个大型语言模型,由 Google 训练。'

由這兩篇測試可知 LangChain 的好處是對於不同的模型都可以用相同的 API 與模型交談. 

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_p、stop 等)
 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助手。有什麼問題我可以幫助您解答?'

2025年8月26日 星期二

高科大還書一本 : LangChain開發手冊

這本書被預約了, 雖然離到期日還遠, 但因為預約了 "京阪神地圖 Go" 到館, 中午吃過午飯就拿這本去換 : 


此書我已看完前三章但還沒實測, 市圖也也有得借, 等從日本回來就開始來玩 LangChain 吧!

2025年6月2日 星期一

向天龍文創購買林則徐小楷金剛經 + LangChain 書籍 x 4

今天突然想起以前服役時帶在身邊的 "林則徐書經小楷" 一書, 從金門移防回花蓮時我記得有放在移防箱裡, 但退伍後卻遍尋不著, 應該是遺留在部隊了. 今天搜尋網路找到這家位於重慶南路的天龍圖書有賣這本書 (雖然不是同一本) : 


可以超商取貨 (但須先匯款) 或宅配, 運費 60 元. 此書店專賣大陸簡體書, 我另外附帶買了下面五本 LangChain 的簡體書 :


五書合計 1938.4 元 + 手續費 30 元共 1968.4 元, 宅配約一個月到貨 :




在天龍文創訂書滿 1300 元免運, 下訂後 12 小時內可取消 :




2025-06-20 補充 :

今日到貨, 約 18 天可收到.