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 訓練。'  

沒有留言 :