2026年4月9日 星期四

OpenAI API 學習筆記 : 應用程式專案 (一) 新聞稿生成器

我的 OpenAI API 帳戶自去年再次儲值 5 美元後, 只做了少許生圖測試便晾在一邊, 轉眼已過了大半年, 為了避免一年使用期限到期沒用完被沒收, 打算拿 Oreilly "AI 應用程式開發" 這本書第三章的六個 App 專案來消耗掉. 

測試環境使用最近為了 LangChain 測試而建立的乾淨虛擬環境, 參考 :


此書的範例程式可在 GitHub 下載 :


本篇旨在測試第三章中的專案 1 : 打造一個新聞稿生成器, 書中範例原始碼參考 : 


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


此專案的目的是建立一個 AI 應用程式, 可以指定文章長度, 語氣與風格來生成新聞稿. 書中範例程式使用了 typing.List 來進行類型提示 (Type Hinting), 例如 facts: List[str] 是告訴閱讀程式碼的人或 IDE : facts 這個參數應該是一個串列, 且這個串列裡面的每個元素都應該是字串. 不過, 這種用法在 Python 3.9 之後已經內建到 list 中了, 新寫法是 facts: list[str], 所以我將原始範例程式碼改寫為如下 :

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

config=dotenv_values('.env') 
openai_api_key=config.get('OPENAI_API_KEY')
client=OpenAI(api_key=openai_api_key)

def ask_gpt(
    messages: list[dict[str, str]],
    model: str = 'gpt-3.5-turbo'
    ) -> str:
    try:
        reply=client.chat.completions.create(
            model=model, 
            messages=messages
            )
        return reply.choices[0].message.content or ''
    except APIError as e:
        return e.message

prompt_role='''You are an assistant for journalists. 
Your task is to write articles, based on the FACTS that are given to you. 
You should respect the instructions: the TONE, the LENGTH, and the STYLE'''
# 你是記者的助理. 
# 你的任務是根據所提供的事實 (FACTS) 來撰寫一篇新聞稿.
# 文章需符合指定的語氣 (TONE), 長度 (LENGTH), 與風格 (STYLE). 

def assist_journalist(
    facts: list[str], 
    tone: str, 
    length_words: int, 
    style: str
    ) -> str:
    """根據傳入的事實、語氣, 長度與風格生成新聞稿"""
    facts_str=", ".join(facts)
    prompt=f'{prompt_role}\nFACTS: {facts_str}\nTONE: {tone}\nLENGTH: {length_words} words\nSTYLE: {style}'
    return ask_gpt([{"role": "user", "content": prompt}])

# 執行範例
if __name__ == "__main__":
    result=assist_journalist(
        facts=[
            '2026年東京櫻花預計在3月底滿開', 
            '上野公園是著名的賞櫻勝地,有超過1000棵櫻花樹', 
            '傍晚會有點燈活動,可以欣賞浪漫的夜櫻',
            '請使用繁體中文撰寫'  
            ],
        tone='浪漫且活潑', 
        length_words=300, 
        style='旅遊部落格文章'
        )
    print(result)

此處兩個函式 assist_journalist() 與 ask_gpt() 的傳入參數都使用了類型提示語法以增加程式碼可讀性. 例如 ask_gpt() 中的 messages: list[dict[str, str]] 意思是 :
  • messages 是一個串列, 裡面的每個元素都是字典.
  • 字典的鍵與值都是字串, 例如 {"role": "user", "content": "hello"}
而 model: str = 'gpt-3.5-turbo' 表示 model 是一個字串且有預設值. -> str 表示傳回值類型為字串. 

執行結果如下 :

(myvenv) D:\python\test>python news_generator_1.py   
東京櫻花季即將來臨!2026年的櫻花季預計在3月底盛大開放,其中上野公園絕對是不能錯過的賞櫻勝地之一。這個充滿浪漫氛圍的公園擁有超過1000棵櫻花樹,每年都吸引著無數遊客前來欣賞這片粉紅色的花海。

除了白天的賞櫻之外,上野公園還有一項令人神往的活動,那就是傍晚的點燈活動。當夜幕降臨時,整個公園被點亮,營造出一種浪漫的氛圍,讓遊客們可以在夜幕下欣賞到迷人的夜櫻。這種別具一格的賞櫻體驗絕對讓人流連忘返。

在櫻花季期間,上野公園也會舉辦不同的活動和表演,讓遊客可以感受到濃濃的日本文化氛圍。無論是品嚐傳統的日本料理、參加傳統音樂表演還是購買精美的手工藝品,都能讓遊客們深入體驗到日本的文化魅力。

此外,上野公園周邊還擁有眾多商店和小吃攤位,供遊客選擇,讓您可以在欣賞櫻花的同時品嚐道地的日本美食和購買紀念品。不僅如此,公園周邊還有許多著名的博物館和寺廟,讓遊客可以一次過體驗到日本的豐富文化遺產。

總括而言,2024年的東京櫻花季將會是一場難忘的賞櫻之旅。無論是白天還是夜晚,在上野公園中都能感受到浪漫氛圍,讓您與摯愛共度美好時光。趕快計劃您的行程,一起來感受日本春天的魅力吧!

下面是 Gemini 版本的程式碼 :

# news_generator_2.py
from google import genai
from google.genai.errors import APIError
from dotenv import dotenv_values

config=dotenv_values('.env') 
gemini_api_key=config.get('GEMINI_API_KEY')
client=genai.Client(api_key=gemini_api_key)

def ask_gemini(messages: str, model: str='gemini-2.5-flash') -> str:
    try:
        reply=client.models.generate_content(
            model=model, 
            contents=messages
            )
        return reply.text or ''
    except APIError as e:
        return e.message

prompt_role='''You are an assistant for journalists. 
Your task is to write articles, based on the FACTS that are given to you. 
You should respect the instructions: the TONE, the LENGTH, and the STYLE'''
# 你是記者的助理. 
# 你的任務是根據所提供的事實 (FACTS) 來撰寫一篇新聞稿.
# 文章需符合指定的語氣 (TONE), 長度 (LENGTH), 與風格 (STYLE). 

def assist_journalist(
    facts: list[str], 
    tone: str, 
    length_words: int, 
    style: str
    ) -> str:
    """根據傳入的事實、語氣, 長度與風格生成新聞稿"""
    facts_str=", ".join(facts)
    prompt=f'{prompt_role}\nFACTS: {facts_str}\nTONE: {tone}\nLENGTH: {length_words} words\nSTYLE: {style}'
    # Gemini 可直接接受字串作為 contents, 傳入串列可能會解析失敗
    return ask_gemini(prompt)

# 執行範例
if __name__ == "__main__":
    result=assist_journalist(
        facts=[
            '2026年東京櫻花預計在3月底滿開', 
            '上野公園是著名的賞櫻勝地,有超過1000棵櫻花樹', 
            '傍晚會有點燈活動,可以欣賞浪漫的夜櫻',
            '請使用繁體中文撰寫'  # 提示模型使用特定語言
            ],
        tone='浪漫且活潑', 
        length_words=300, 
        style='旅遊部落格文章'
        )
    print(result)

此 Gemini 版與上面 OpenAI 版主要不同處有二 :
  • 錯誤處理須匯入 google.genai.errors.APIError 類別.
  • Gemini SDK 可以接受字串作為 contents, 所以在 ask_gemini() 中傳入參數 messages 是字串, 而不是 OpenAI 中的串列 [{"role": "user", "content": prompt}], 否則 Gemini 的 SDK 可能會解析失敗 (視於版本相容性而定), 同時 assist_journalist() 內呼叫 ask_gemini() 也是直接傳 prompt 字串. 
注意, 此處使用新版 Gemini SDK : google-genai 而非舊版的 google-generativeai, 參考下面這篇底下的補充 :


執行結果如下 :

(myvenv) D:\python\test>python news_generator_2.py
## 2026東京櫻花前線速報!上野公園千株櫻花與夢幻夜櫻等你來!

嘿,各位櫻花迷們!是不是已經開始期待下一個粉紅色的春天了呢?告訴你一個振奮人心的好消息!2026年東京的櫻花季,預計將在**3月底**達到最美、最浪漫的滿開!準備好迎接這場不容錯過的春日盛典了嗎?

想抓住這份稍縱即逝的絕美風景,怎能錯過東京最經典、最有活力的賞櫻勝地——**上野公園**呢?這裡可是名符其實的「櫻花海」!園內種植了**超過1000棵**櫻花樹,想像一下,漫步在粉白色的花海隧道下,微風輕拂,花瓣如雪般飄落,光是想像就讓人心醉神迷。白天,公園裡總是充滿著歡聲笑語,野餐、散步、拍照,每一處都是生機勃勃的春日氣息。

但別以為太陽下山就結束了!上野公園的魅力在傍晚時分才真正達到高潮!入夜後,園內精心設計的**點燈活動**會將這些嬌嫩的櫻花裝扮得如夢似幻。一盞盞溫暖的光芒,輕柔地映照著粉白花朵,將白天的活潑氣氛轉化為一片極致浪漫的**夜櫻仙境**。和心愛的人手牽手,在微光中欣賞這份獨特的景色,絕對會是2026年春日最難忘的記憶,為你的東京之旅增添無限美好的浪漫色彩!

所以,親愛的朋友們,2026年3月底,趕快把你的行事曆空下來吧!東京上野公園的千株櫻花與夢幻夜櫻正等著你,一起來感受這場浪漫又活潑的春日盛典!別再猶豫了,現在就開始規劃你的東京櫻花之旅吧!

2026年4月7日 星期二

好書 : 歸剛 Vibe Coding

今天在博客來找到這本 Vibe coding 的電子書 :


我用 HyRead 查詢市圖未進此書, 但台灣雲端書庫有, 借期 14 天, 由於篇幅不大, 我今天就看完了, 摘要心得如下 :
  • 創作時只要專注在 "我要完成甚麼", 而不是去糾結 "我要學習甚麼", 碰到問題才查才問, 這樣完成率就會很高. 這種狀態下, 沒有刻意要學, 卻學得超快. 
  • 對企業來說, 員工永遠都是可有可無的開銷. 
  • 創業的原理很簡單 : 發現需求 -> 發揮想像力與觀察力 -> 勇敢去實踐
  • 創業=解決問題+創造價值+實際賺錢.
  • 上班族賣的是時間, 創業者賣的是點子變出來的資產.
  • AI 時代的成功不再是靠背景, 學歷, 資源, 而是靠有想法+會動手. 
  • Vibe coding 的核心觀念 : 先創造感覺, 再修細節>
  • Vibe coding 步驟 :
    • 快速生成原型 : 利用 AI 工具+現成框架 (Next.js, Tailwind, Supabase, ...)
    • 即時發布 (Vercel 等)
    • 社群平台 (Discord, Threads, ...) 回饋驅動迭代
  • Vibe coding 是從寫得正確轉向為先做出感覺. 市場變化很快, 與其寫規格書, 不如先丟作品上去看市場反應. 
  • 不論是做網站還是 App, 開發任何產品前首先要問 : 誰是使用者? 不要去想 "他們需要甚麼功能" (feature-to-be-shipped), 而是要想 "他們想完成甚麼事" (job-to-be-done). 總之, 不要急著做, 先把使用人的問題搞懂. 
  • Rig : 一套能把靈感迅速變成現實的工具組合 (AI 工具 + 開發框架 + 雲端佈署). 
  • 開發框架技術堆疊 :
    • Next.js : 最快速的 React 框架
    • Tailwind : 直接用 class 寫樣式
    • Supabase / PlanetScal : 資料庫即服務
    • Bun / Vite : 快速的 Javascript 框架
  • 網頁工具技術堆疊 :
    • Figma : 網頁 UI 外觀
    • Wenflow / Proto.io : 互動網頁工具
    • Vercel : 一鍵完成佈署
  • Vibe coding 的關鍵不是要懂很多技術, 而是要選對工具與問對問題. 
  • 向 AI 提問時最大的忌諱是一次丟出一個又大又模糊的問題, 否則它會亂猜你的需求, 應該要這樣問 : "我想做一個 xxx, 裡面有 xxx, 先問我問題跟我討論". 在動手開發之前, 應該先進行討論, 而不是直接行動. 問 AI 有甚麼問題要問你其實就是讓 AI 幫你找出完成此專案需要考慮的事項, 讓你得到一連串切中核心的問題. 
  • 與 AI 溝通的要訣 :
    • 可在專案目標後面加上這段 : "請針對我提出的目標和方向提出最詳細的問題, 不要當好好先生, 別甚麼都同意, 要質疑我選的方向與決定, 永遠不要自行假設", 可避免 AI 亂編內容, 並能主動問你問題以釐清細節.
    • 請 AI 一次做一個步驟, 否則它會一股腦兒把全部解決方案爆出來, 如果方向錯誤要浪費較多時間導正. 可加上這段提示 : "請一步一步來, 不要一次全部給我". 
  • 隨著來回討論越長, AI 的反應會越慢效率變差, 可用下列提示詞來做一個總結與繼承動作 : "請整理目前我們所建立的重要上下文, 包含所有決策, 定義, 專案目標, 技術設置, 程式結構, 使用工具, 命名規則, 文字語氣, 以及任何對此專案重要的資訊, 請整理得清楚明瞭, 方便我複製貼上". 然後複製下來, 開啟一個新對話貼上, 同時貼上專案資料夾的專案結構樹 (用 tree 指令). 然後加上這句 "請在開始對話前, 告訴我你想要我貼上哪些檔案的內容?", 將第一個檔案內容貼給它時, 加上這句 "這是第一個檔案, 只要告訴我你收到了即可, 不用進行分析,  然後告訴我你要看的下一個檔案, 等全部貼完再分析." 

2026年4月6日 星期一

Hahow 購買黑木太太日語課

最近在 fb 看到黑木太太日語課在募資, 今天是 88 折優惠最後一天, 想說退休前的這幾年會很常去日本玩, 最好把日語練好一點, 就購買了此課程 :





最近開車都在聽 Yumi 老師的日文課, 聽久了不知不覺就背起來了. 

2026 年第 13 周記事

本周清明連假只上四天班, 下周一補假, 周五天氣酷熱, 按計畫完成芭樂樹下雜草清除, 並到墓園巡視給花瓶添水. 周六下雨待在家, 雖然完成兩篇 LangChain 測試, 但原本要在車庫安裝監視器的計畫, 卻因為沉迷 fb 上的雍正王朝解說短片而沒做. 週日與周一終於抽空動手組裝置物櫃與衣櫥, 準備整理庫房的衣服與三樓的書籍. 

第二季的學習重點是 Vibe coding, 首先要把購買的線上課程抽空看完, 目前還是使用 Gemini CLI, 下一季再考慮切入 Claude Code. 其次要複習一月以來的幾個很棒的內訓課程, 但上課時我幾乎都沒時間實作, 光聽不練其實沒有用, 所以我上課必定錄影 (但錄到現在卻幾乎沒時間複習). 

我最近實在花太多時間在滑臉書了, 演算法總是丟一些吸引我眼球的天文學與歷史劇害我難以脫身. 進入四月後較無俗事 (下次事六月的端午節拜拜), 應該要靜下心來好好追進度了. 另外, 路旁水圳蓮霧樹上的照明燈打算改裝, 想製作一個鳥屋來安裝監視器 + 照明燈. 




菜園旁的舊豬舍牆上則想要裝上草莓的垂直栽培架 :




兩周前安安表弟幫我用舊電腦弄了一台 NAS, 目前只有一顆 500GB 硬碟, 但一直沒時間去設定路由器, 今天檢查發現居然當機了, 等有時間再來玩看看. 

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

2026年3月30日 星期一

如何利用 Gemini 搜尋 Youtube 教學影片

我最近專心在看洪老師寫的 "史上最強 Gemini/NotebookLM 領軍" 這本書, 發現利用 AI 可以大大地加速學習進程. 眾所周知, Youtube 就是最好的技能補習班, 想學甚麼上 Youtube 找就對了, 不論甚麼題材與領域的知識, 都有能人製作成影片供大家免費學習. 

但是直接上 YT 搜尋容易迷失在茫茫片海中, 請  Gemini 推薦快又省事, 方法是在提示詞前先下 "@YouTube" 然後輸入自己想學習甚麼領域知識, 請它提供教學影片, 例如 : 

@YouTube
我正在學習 Vibe coding, 請幫我找最多人看的五部 Google Antigravity 的教學影片

結果如下 : 




哈哈, 第一部就是林鼎淵老師 (上周才來我司內訓) 教學影片, 我之前已看到一半. 所推薦的每一部有亮點簡介與影片連結, 真不錯. 
  1. 【Vibe Coding 學習地圖】用實戰帶你搞懂 Gemini、Google AI Studio、Antigravity 的使用情境
    這部是中文圈最推薦的入門影片。它完整梳理了從入門到專業的工具使用情境(Gemini -> AI Studio -> Antigravity),並示範了如何透過 Antigravity 完善專案並發佈至 GitHub Pages。
  2. The Ultimate AntiGravity Masterclass (3+ HOUR FREE COURSE)
    這是一部超過 3 小時的「大師課」,適合想深度掌握 Antigravity 核心功能的學習者。內容涵蓋了將創意轉化為應用程式、連接 NotebookLM 與 MCP 協議等進階技巧。
  3. VIBE CODING FULL COURSE: Gemini 3.1 + Antigravity (6 Hrs)
    長達 6 小時的完整課程。教學內容非常紮實,帶領觀眾實作 5 個完整的應用程式,並深入探討軟體設計模式、版本控制以及如何使用代理(Agents)進行編程。
  4. [Uncle Kevin] 手把手教你 Antigravity 的設定與應用:Rules + Skills + Workflows
    中文詳解 Antigravity 的三大核心要素:規則 (Rules)、工作流 (Workflows) 與 技能 (Skills)。這部影片特別適合想了解如何透過 MCP 協議連接外部工具(如 Notion, Slack)的開發者。
  5. Google AntiGravity + Stitch 太猛了!用 Vibe Coding 打造超強前端設計
    重點在於前端設計的實戰範例,展示了如何結合 Antigravity 與 Stitch 等工具,在極短時間內完成高品質的 UI/UX 開發。
注意, 提示詞前加 "@YouTube" 並非必要, 但加上它有助於更精準地啟動 YouTube 擴充功能, 可以確保它直接調用 YouTube 的 API 只從 YouTube 搜尋, 而不是抓取一般的網頁文章或部落格. 

蝦皮購買 DW100Pro+ 充電線

由於 DW100Pro+ 手錶需每日充電, 所以上蝦皮再買兩個充電線 :

# 華強北手錶充電線DW100 華強北 電話手錶 充電線 無線磁吸充電線 智能手錶充電器 蜂窩插卡充電線 $159 x 2 = 317




貨到付款 317 元. 

2026年3月29日 星期日

2026 年第 12 周記事 (掃墓)

上周六從日本回來就感冒了一周, 應該是搭大阪地鐵沒帶口罩被傳染, 在機場就流鼻水, 第二天咳嗽, 去看黃昭文拿藥 + 龍角散, 經過一周終於好了. 人多的地方還是戴著口罩為妙啊!

本周主要任務是掃墓, SOP 參考 (需要修訂) :


這次掃墓有些不同, 首先是上個月堂哥傳 LINE 說因為堂嫂健康問題今年無法參加大眾墓園的掃墓, 昨天與嬸嬸確認早上掃墓時間才理解並非僅今年, 而是以後都不會參加, 箇中緣由恐有難言之隱, 我也不便多問, 也難為他了. 其次, 嬸嬸找我商量既然以後早上掃墓只剩我們兩家, 是否可在年十五元宵後就掃墓, 這樣堂弟可在元宵後返回雲南, 雖然這樣就無法與來台祖同一日掃墓, 但好處是不用同一天處理兩份牲禮. 另外, 由於退伍軍人去年八月停業, 今年掃墓的紅龜粄與發粄我改向郵局旁邊的早餐店訂購, 出奇的好吃.

鄉下家的貓小乖離家已逾兩周未歸, 應該是不會再回來了. 我去日本的前一天 (3/11 週三) 下班回鄉下即未看到小乖, 推測應該是那個周日~週三之間離家的. 這一胎四姊妹只剩吉哇哇, 哇哇吉, 與小黑了, 只有小乖與吉哇哇我摸得到不怕人. 懷念可愛的小乖. 

週日下午忙完廚事, 到菜園巡芭樂, 大概只套了五顆而已. 樹下雜草叢生, 打算下周要來進行刮地皮作業清除雜草. 此外, 菜園的三棵再生鳳梨又結果了 :