2026年1月27日 星期二

三星 Galaxy Tab 螢幕截圖方法

水某研究計畫結束後留下一台三星 Tab A7 Lite 平板, 之前常用來看電子書, 前陣子因為買 BOOX 閱讀器得知 HyRead 可借閱圖書館的電子書與雜誌, 於是也在平板上安裝, 看雜誌時為了做筆記需截圖, 但每次要同按電源+音量小鍵很麻煩, 上谷歌找到下面這篇 :


其中的 "三星手機截圖方法三、輔助快選截圖" : 

前往「設定」→「協助工具」→「互動與敏銳度」→開啟「輔助快選」功能

完成後桌面會出現一個圓形四小孔的常駐浮動按鈕, 按一下就會出現好幾個選項, 按其中的 "螢幕截圖" 就可以把圖抓下來, 再丟到 Dropbox 即可. 

PS :

這支平板記憶體為 3GB/32GB, 寬度比 iPd mini  小一些, 剛好一手可掌握, 握持手感最佳, 左上角有 SIM 卡槽, 插卡即可上網撥電話, 規格參考 :


蝦皮購買手機平板架x5 + 迷你掛錶x5

最近把水某給我的 iPad Mini 5 與三星 Tab A7 Lite 都找出來用, 主要是安裝 HyRead 後可從市圖借閱電子書與雜誌, 抵厚重的實體書好幾倍. 今天在看雜誌時發現應該買個桌上的平板支架, 這樣就可避免手痠了, 蝦皮一個才 24 元, 為了免運加買了掛錶 : 




裕誠智取店取付 230 元免運. 

Windows 安裝米家 App

鄉下老家目前裡裡外外裝了七支攝影機, 平常都用手機的米家 App 關注爸的安全動態, 今天上網搜尋是否有米家 App 的電腦版, 在 Mobile1 找到這篇 :


原來在小米官網就有提供下載網址 : 





但按右上角的 Download 會得到 404, 需往下拉到步驟說明 3 底下的下載按鈕才行 : 




解壓縮下載的 zip 檔會得到一個 XiaomiCameraViewerInstaller.exe 安裝檔, 點擊執行時把預設的簡體中文改為英文 : 




然後一直按 Next 預設安裝下去即可 : 






安裝完畢執行軟體會先要求登入小米帳號, 我是用手機號碼搭配 ak 密碼登入, 會發一個 email 到谷歌信箱, 輸入驗證碼後就會看到攝影機影像了, 可以選擇 4/6/9 分割顯示畫面 :




與手機米家 App 比起來亮度較暗, 且大門口兩支 CW300 攝影機未入列, Mobile1 底下有人提到似乎 1080p 以上的都讀不到, CW300 是 2.5K 超高解析度 (2560x1440), 小米攝影機 2k 標準版都可以讀到. 

按每支攝影機右下角的照相按鈕可以手動拍照, 預設會將 jpg 檔存在桌面, 可以按右上角的帳號頭像點選 Mahage File 更改儲存位置 (例如建一個 D:\XiaomiCamera 來存圖片) : 





婷婷表妹上周為了處理小舅媽攬的外務 (幫市場阿桑解決手機監控攤位問題) 要買一支小米攝影機, 我順便叫她幫我買兩支 C201, 下標後阿桑說不用了, 我叫婷婷三支都給我 (1597 元), 本周來安裝在車庫, 祖堂, 與庫房. 

2026年1月26日 星期一

2026 年第 4 周記事

轉眼 2026 已走過近一個月, 再過三周就是春節啦! 周日下午有一位在附近田裡工作的伯母來問今年要不要年糕, 每年爸似乎都有跟她訂, 我說那就繼續好了. 

周六姊姊回高雄要跟同學商談下周去沖繩旅行的行程, 二哥則是 1/26 與 1/27 要去成大上 IC 設計課程, 因姐姐有王品禮券, 訂了周六晚上七點中正路王品聚餐, 但她出發時忘記把禮券帶回來, 上了高鐵才發現, 菁菁只好改定至聖路上的知名披薩店波士多 (很多外國人) : 





這個周末因為在推進 Gemini CLI 的學習, 所以老家的整理工作停滯, 但至少把浴室外牆掉落的小太陽能板重新固定 (難怪最近浴室感應燈不亮) 並且將螺絲等上油防鏽. 另外也清理了豬舍前的監控木箱與廁所上方被胡瓜頁遮住的 10W 太陽能板, 等我 Gemini CLI 上手, 用 Vibe coding 流程來完成 IoT 專案. 

周日又去了一趟種子行, 想買九層塔與朝天椒苗, 老闆說九層塔缺貨, 只買了四株朝天椒, 一株種鄉下, 三株帶來高雄種陽台. 原本在菜園到處長的草莓最近快絕跡了, 我打算在曬衣場的牆邊搭角鐵架用盆栽來種 (自動灑水), 這樣就不怕蝸牛來吃. 

下周待辦事項 :
  • 豬舍廁所馬桶蓋換新
  • 修理餐廳後面廁所漏水問題
  • 車庫採光板安裝
  • 小蟻攝影機重設
總之, 要趁年前三周大清理才行. 

2026年1月25日 星期日

蝦皮購買插卡手錶 DW100 Pro+ (黑色 3GB + 32GB)

這兩天做了一些插卡手錶市調, 最終選擇蝦皮賣家數碼盟主 (cutefoodiexinwei) 販售的這支 DW100pro+ 3GB/32GB 黑色款, 主要是透過與賣家溝通, 確定此錶為外貿版 (即國際版), 有內建 GPS 晶片與完整 Google 軟體, 電池為市場主流的 800 mAh, 雖不是大電池款, 但因為是要給爸方便聯絡與 Google 地圖定位追蹤之用, 主要是接電話, 應該不需要每天充電. 賣家做活動有送五項品至今天下午五點 : 






扣掉蝦皮折價券 20 元實付 2668 元, 裕誠至取店取付. 下周去遠傳門市買一張月付 149 元的兒童用 SIM 卡給爸使用. 


2026年1月24日 星期六

Gemini CLI 學習筆記 : 郵遞區號查詢小幫手專案 (二)

在前一篇測試中, 我們利用提示詞讓 Gemini CLI 生成程式碼, 正確地透過 API 取得給定地址的郵遞區號, 但是生成的程式是手動另開 DOS 或 PS 視窗執行的, 其實也可以叫 Gemini CLI 幫我們測試, 它會幫我們尋找本機的 Python 環境來執行, 本篇旨在接續先前靠一張嘴寫程式的方法, 叫 AI 測試它自己寫的程式. 

本系列之前的測試文章參考 : 


PS D:\gemini> cd postal-helper-proj1   
PS D:\gemini\postal-helper-proj1> gemini   

然後輸入 /res 或 /resume 恢復之前的對話, Gemini CLI 會找出之前的 session 列表, 可以上下移動選擇要恢復的對話後按 Enter (此處只有編號 1 的對話) :




輸入 : 

> 請幫我測試程式是否正確

Gemini CLI 這次找了一個台中的地址, 執行結果為找不到, 所以它寫了一個 test_api.py 的測試程式, 要求儲存程式檔 :




接著要求執行測試程式 test_api.py : 




測試程式執行時出現錯誤, 它會自行檢查原因與修正, 它發現需修改 postal-helper.py 原始碼, 要求授權 : 




接著修正測試程式 test_api.py : 




執行結果程式已正常, 但查詢台灣大道 99 號結果仍然找不到, 可能是地址有改, 它打算換別的地址測試來測試 : 




改用中港路二段99號就順利傳回郵遞區號了 :




以上的 Gemini CLI 測試中都是使用系統 Python 來執行程式, 如果 Gemini CLI 找不到 Python 執行環境就會出現錯誤. 目前最新的 Python 版本管理工具是 uv 工具, 它整合了 Python 版本, 套件安裝, 以及虛擬環境管理於一體, 使用上比傳統 pip + venv 方便許多, 參考 :


接下來輸入 "我使用 uv 工具" 提示詞看看 Gemini CLI 如何利用 uv 來執行測試, 首先它會初始化 uv 專案, 建立專案描述檔 pyproject.toml :




接著它會編輯 pyproject.toml, 加入腳本定義, 以便能用 uv run 來執行腳本 :




接下來它要求授權修改 postal-helper.py 腳本 : 




程式已改好, 要求授權用 uv run 執行腳本, 傳入地址參數為台北市信義區市府路 1 號 : 





uv run 指令執行成功, 取得正確 6 碼郵遞區號 110204 : 




最後, 我把 Gemini CLI 修改過的 postal-helper.py 抄錄如下 :

import sys
import json
import urllib.parse
import urllib.request
import io

# 確保在 Windows 上輸出為 UTF-8
if sys.platform == "win32" and isinstance(sys.stdout, io.TextIOWrapper) and sys.stdout.encoding != 'utf-8':
    try:
        sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
        sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
    except (AttributeError, io.UnsupportedOperation):
        pass

def get_postal_code(address):
    base_url = "https://zip5.5432.tw/zip5json.py"
    params = {'adrs': address}
    # Ensure the URL is correctly encoded
    url = f"{base_url}?{urllib.parse.urlencode(params)}"
    
    try:
        # User requested 6-digit postal code
        print(f"正在查詢地址: {address} ...")
        
        req = urllib.request.Request(url)
        # Some APIs require a User-Agent
        req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) PostalHelper/1.0')
        
        with urllib.request.urlopen(req) as response:
            if response.status != 200:
                print(f"錯誤: API 返回狀態碼 {response.status}")
                return

            data = response.read()
            try:
                result = json.loads(data)
            except json.JSONDecodeError:
                print("錯誤: 無法解析 JSON 回應。")
                print(f"回應內容: {data.decode('utf-8', errors='ignore')}")
                return
            
            # The API returns 'zipcode6' for the 6-digit code.
            # Sometimes it might return an empty string or null if not found.
            zip6 = result.get('zipcode6')
            
            if zip6:
                print("-" * 30)
                print(f"地址: {result.get('address', address)}")
                print(f"6碼郵遞區號: {zip6}")
                print("-" * 30)
            else:
                print("找不到該地址的 6 碼郵遞區號。")
                # Show full result just in case useful info is elsewhere
                if 'error' in result:
                    print(f"API 錯誤: {result['error']}")

    except urllib.error.URLError as e:
        print(f"網絡錯誤: {e}")
    except Exception as e:
        print(f"發生未預期的錯誤: {e}")

def main():
    if len(sys.argv) > 1:
        # Join arguments to handle addresses with spaces if not quoted
        address_input = " ".join(sys.argv[1:])
        get_postal_code(address_input)
    else:
        # Interactive mode
        print("台灣 6 碼郵遞區號小幫手 (uv 版)")
        print("用法: uv run postal-helper <地址>")
        print("或在下方輸入地址 (按 Ctrl+C 離開):")
        while True:
            try:
                address_input = input("\n請輸入地址: ").strip()
                if not address_input:
                    continue
                get_postal_code(address_input)
            except KeyboardInterrupt:
                print("\n程式結束。")
                break
            except EOFError:
                break

if __name__ == "__main__":
    main()

Python 學習筆記 : 整合型 Python 版本管理工具 uv

上周胡嘉璽老師的 vibe coding 課堂介紹了uv, 這是比 venv + pip 更好用的新一代整合型 Python 套件與專案管理工具, 使用 Rust 開發故執行速度快. 因為後續 Gemini CLI 與 Claude Code 的學習測試會用到, 所以今天得空來安裝看看. 

uv 的主要功能如下:
  • 可輕鬆且快速地安裝不同的 Python 版本, 並能在這些版本之間進行切換. 
  • 可建立和管理虛擬環境, 以利在不同的專案中使用不同的 Python 版本和套件依賴. 
  • 簡單直觀的命令行介面方便執行版本管理和虛擬環境操作.
  • 可在 Windows, macOS 和 Linux 等系統上跨平台運行.
  • 可在 CI/CD 環境中與其他工具搭配支援自動化工作流程. 
參考官網與 GitHub 說明 : 


網路教學文章參考 : 



1. 安裝 uv :

在 Windows 安裝 uv 的第一個方法是開啟 Power Shell 視窗, 輸入下列指令安裝 :

powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

如果已經安裝過軟體管理工具 scoop, 可以用 scoop install uv 來安裝 :

PS C:\Users\tony1> scoop install uv   
Updating Scoop...
Updating Buckets...
... (略) ...
Scoop was updated successfully!
Installing 'uv' (0.9.26) [64bit] from 'main' bucket
uv-x86_64-pc-windows-msvc.zip (21.0 MB) [=====================================================================] 100%
Checking hash of uv-x86_64-pc-windows-msvc.zip ... ok.
Extracting uv-x86_64-pc-windows-msvc.zip ... done.
Linking ~\scoop\apps\uv\current => ~\scoop\apps\uv\0.9.26
Creating shim for 'uv'.
Creating shim for 'uvx'.
Creating shim for 'uvw'.
Making C:\Users\tony1\scoop\shims\uvw.exe a GUI binary.
'uv' (0.9.26) was installed successfully!

安裝完可以用 uv --version 檢查版本 : 

PS C:\Users\tony1> uv --version   
uv 0.9.26 (ee4f00362 2026-01-15)

關於 scoop 安裝參考 :



2. 常用的 uv 指令 :

uv 是一個整合 Python 版本 + 套件 + 虛擬環境管理的工具, 常用指令如下表 : 


 常用 uv 指令  說明
 uv python list   列出本機已安裝及可供 uv 下載安裝的 Python 版本。
 uv python install <version>  下載並安裝指定的 Python 版本 (例如:uv python install 3.12)。
 uv python uninstall <version>  解除安裝指定的 Python 版本 (例如:uv python uninstall 3.12)。
 uv python find <version>  顯示指定的 Python 版本執行檔 python.exe 之安裝路徑。
 uv python dir  顯示 uv 用來存放所有下載安裝之 Python 版本的根目錄。
 uv python pin <version>  鎖定當前專案所使用的 Python 版本。
 uv init  初始化一個新的 Python 專案 (建立 pyproject.toml)。
 uv add <package>  新增套件依賴,並自動更新 lock 檔與環境。
 uv remove <package>  移除套件依賴。
 uv sync  根據 uv.lock 同步專案環境 (安裝/移除套件)。
 uv run <command>  在專案的虛擬環境中執行指令或腳本。
 uv venv  建立一個新的虛擬環境 (預設為 .venv)。
 uv pip install <package>  類似標準 pip install,用於低階套件安裝 (不建議使用)。
 uv tool install <tool>  安裝全域使用的 Python 工具 (如 ruff, black)。
 uv tree  顯示專案依賴關係的樹狀結構圖。
 uv self update  將 uv 更新至最新版本。


注意, 在 uv 專案中不建議使用 uv pip install 來安裝套件, 雖然不會汙染系統 Python (只要不加 --system 參數就很安全), 但不會更新 pyproject.toml, 會使專案依賴清單與實際環境不符. 


3. Python 版本管理 : 

uv python list 會列出目前本機已安裝以及網路上可下載安裝的 Python 版本 :

PS C:\Users\tony1> uv python list  
cpython-3.15.0a5-windows-x86_64-none                 <download available>
cpython-3.15.0a5+freethreaded-windows-x86_64-none    <download available>
cpython-3.14.2-windows-x86_64-none                   <download available>
cpython-3.14.2+freethreaded-windows-x86_64-none      <download available>
cpython-3.13.11-windows-x86_64-none                  <download available>
cpython-3.13.11+freethreaded-windows-x86_64-none     <download available>
cpython-3.12.12-windows-x86_64-none                  <download available>
cpython-3.12.1-windows-x86_64-none                   AppData\Local\Programs\Python\Python312\python.exe
cpython-3.11.14-windows-x86_64-none                  <download available>
cpython-3.10.19-windows-x86_64-none                  <download available>
cpython-3.9.25-windows-x86_64-none                   <download available>
cpython-3.8.20-windows-x86_64-none                   <download available>
pypy-3.11.13-windows-x86_64-none                     <download available>
pypy-3.10.16-windows-x86_64-none                     <download available>
pypy-3.9.19-windows-x86_64-none                      <download available>
pypy-3.8.16-windows-x86_64-none                      <download available>
graalpy-3.12.0-windows-x86_64-none                   <download available>
graalpy-3.11.0-windows-x86_64-none                   <download available>
graalpy-3.10.0-windows-x86_64-none                   <download available>

其中黃底部分即我的 LG Gram 筆電的系統 Python 3.12.1 環境, 其餘為可用 uv python install 下載安裝的版本. 可以在後面用 --only-installed 參數限制僅顯示已安裝的 Python 版本 : 

PS C:\Users\tony1> uv python list --only-installed   
cpython-3.12.1-windows-x86_64-none    AppData\Local\Programs\Python\Python312\python.exe

注意, 使用 uv python install 安裝指定版本的 Python 環境時, uv 會將此 Python 安裝到一個獨立的隔離目錄 (通常在 %LOCALAPPDATA%\uv\python\...), 而不是安裝到 Windows 的系統路徑中, uv 也不會把這個路徑加到系統 PATH 裡. 其次, 可以同時安裝多個 Python 版本, 例如 :

uv python install 3.13 3.10

解除安裝也是可以同時解除安裝多個 Python 版本. 


4. 用 uv run 執行 Python 腳本 : 

先在 PS 中用 notepad 指令啟動記事本, 編輯一個 show_version.py 腳本程式 :

PS C:\Users\tony1> notepad show_version.py   

輸入如下程式碼後存檔 : 

import sys
print(sys.version)

用 uv 安裝的 Python 版本其執行檔位置可用 uv python find 指令找到 :

PS C:\Users\tony1> uv python find 3.12  
C:\Users\tony1\AppData\Local\Programs\Python\Python312\python.exe

然後用此 python.exe 執行腳本 :

PS C:\Users\tony1> C:\Users\tony1\AppData\Local\Programs\Python\Python312\python.exe show_version.py   
3.12.1 (tags/v3.12.1:2305ca5, Dec  7 2023, 22:03:25) [MSC v.1937 64 bit (AMD64)]

但不需要這麼麻煩, 用 uv run 指令即可執行 Python 程式 :

PS C:\Users\tony1> uv run show_version.py   
3.12.1 (tags/v3.12.1:2305ca5, Dec  7 2023, 22:03:25) [MSC v.1937 64 bit (AMD64)]

因為我的筆電目前只有安裝 Python 3.12.1 而已, 所以 uv 會用系統 Python 來執行腳本. 如果用 uv 安裝多個 Python 版本, 則可在 uv run 後面以 --python 參數指定版本, 例如 : 

uv run --python 3.12 show_version.py

PS C:\Users\tony1> uv run --python 3.12 show_version.py   
3.12.1 (tags/v3.12.1:2305ca5, Dec  7 2023, 22:03:25) [MSC v.1937 64 bit (AMD64)]


5. 用 uv init 建立 Python 專案 : 

uv 為了符合 Vibe Coding 的效率提供了兩種建立專案的方式, 第一種是用 mkdir 手動建立專案目錄後進入該目錄, 再用 uv init 指令建立專案檔案 :

mkdir <project_dir>
cd <project_dir>
uv init

例如 :

PS C:\Users\tony1> mkdir my_project

    目錄: C:\Users\tony1

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----       2026/1/24  上午 09:51                my_project

PS C:\Users\tony1> cd my_project   
PS C:\Users\tony1\my_project> uv init   
Initialized project `my-project`
PS C:\Users\tony1\my_project> dir  

    目錄: C:\Users\tony1\my_project

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----       2026/1/24  上午 09:51            109 .gitignore
-a----       2026/1/24  上午 09:51              5 .python-version
-a----       2026/1/24  上午 09:51             88 main.py
-a----       2026/1/24  上午 09:51            156 pyproject.toml
-a----       2026/1/24  上午 09:51              0 README.md

可見 uv init 會在專案資料夾下自動建立下面五個專案檔案 : 
  • pyproject.toml : 專案的核心設定檔 (紀錄依賴套件與專案資訊)
  • .python-version : 紀錄這個專案使用的 Python 版本
  • main.py : 專案主程式範例
  • .gitignore : Git 的忽略清單 (預設會把虛擬環境與快取忽略掉)
  • README.md : 專案的讀我說明文件
主程式 main.py 預設是一個顯示歡迎文字的簡單範例 :

PS C:\Users\tony1\my_project> cat main.py   
def main():
    print("Hello from my-project!")


if __name__ == "__main__":
    main()

可以用 uv run 執行看看 : 

PS C:\Users\tony1\my_project> uv run main.py   
Using CPython 3.12.1 interpreter at: C:\Users\tony1\AppData\Local\Programs\Python\Python312\python.exe
Creating virtual environment at: .venv
Hello from my-project!

也可以用 uv init 讓 uv 自動幫我們建立目錄與專案檔案 :

uv init <project_dir> 

或指定要用的 Python 版本 : 

uv init <project_dir> --python <version>

先用 rm 指令刪除上面手動建立的專案目錄 :

PS C:\Users\tony1> rm my_project -Recurse -Force  

用 uv init 建立專案目錄與檔案 : 

PS C:\Users\tony1> uv init my_project   
Initialized project `my-project` at `C:\Users\tony1\my_project`   
PS C:\Users\tony1> cd my_project  
PS C:\Users\tony1\my_project> dir   

    目錄: C:\Users\tony1\my_project

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----       2026/1/24  上午 10:06            109 .gitignore
-a----       2026/1/24  上午 10:06              5 .python-version
-a----       2026/1/24  上午 10:06             88 main.py
-a----       2026/1/24  上午 10:06            156 pyproject.toml
-a----       2026/1/24  上午 10:06              0 README.md

可見結果一樣. 

如果用 uv init 指令指定 Python 版本建立一個專案, 例如 :

uv init --python 3.13 

那麼在此專案目錄下可以用 uv run xxx.py 執行腳本, 這時就會用此專案的 Python 版本來執行腳本程式. 如果用 uv 安裝了多個版本, 則使用 uv run 指令時 uv 會按照下列順序由上而下依序尋找 python.exe 執行檔 :
  • 專案目錄下 .python-version 檔內設定的 Python 版本
  • 目前啟用的虛擬環境的 Python 版本
  • 專案目錄下 .venv 資料夾內設定的虛擬環境 Python 版本
  • uv 自己安裝的 Python 版本
  • 系統環境變數設定的 Python 版本
可見 .python-version 檔紀錄的 Python 版本是最優先的. 

PS C:\Users\tony1\my_project> cat .python-version      
3.12


6. 用 uv add 安裝套件 :   

先用 uv tree 來檢視專案目錄下的套件依賴關係 :

PS C:\Users\tony1\my_project> uv tree   
Using CPython 3.12.1 interpreter at: C:\Users\tony1\AppData\Local\Programs\Python\Python312\python.exe
Resolved 1 package in 5ms
my-project v0.1.0

由於目前還沒有在專案中安裝套件, 專案內還沒有虛擬環境 (.venv 子目錄不存在), 所以直接讀取了全域安裝 (System Global) 的系統 Python 3.12. 

在 uv 建立的 Python 專案下, 要使用 uv add 來安裝套件, uv 會自動建立一個虛擬環境子目錄 .venv 來放套件與其依賴套件, 例如 :

PS C:\Users\tony1\my_project> uv add requests   
Using CPython 3.12.1 interpreter at: C:\Users\tony1\AppData\Local\Programs\Python\Python312\python.exe
Creating virtual environment at: .venv
Resolved 6 packages in 668ms
Prepared 5 packages in 414ms
Installed 5 packages in 128ms
 + certifi==2026.1.4
 + charset-normalizer==3.4.4
 + idna==3.11
 + requests==2.32.5
 + urllib3==2.6.3

這時再用 uv tree 指令就會顯示此專案下有安裝了那些第三方套件與其依賴套件 : 

PS C:\Users\tony1\my_project> uv tree  
Resolved 6 packages in 2ms
my-project v0.1.0
└── requests v2.32.5
    ├── certifi v2026.1.4
    ├── charset-normalizer v3.4.4
    ├── idna v3.11
    └── urllib3 v2.6.3

可見 requests 的四個依賴套件都掛在它下面, 這比傳統 pip list 一古腦兒列出全部套件還棒. 接下來再安裝 yfinance 與 kbar 套件, 測試一下繪製 K 線圖功能 :

PS C:\Users\tony1\my_project> uv add yfinance   
Resolved 25 packages in 1.48s
      Built multitasking==0.0.12
Prepared 19 packages in 11.09s
Installed 19 packages in 775ms
 + beautifulsoup4==4.14.3
 + cffi==2.0.0
 + curl-cffi==0.13.0
 + frozendict==2.4.7
 + multitasking==0.0.12
 + numpy==2.4.1
 + pandas==3.0.0
 + peewee==3.19.0
 + platformdirs==4.5.1
 + protobuf==6.33.4
 + pycparser==3.0
 + python-dateutil==2.9.0.post0
 + pytz==2025.2
 + six==1.17.0
 + soupsieve==2.8.3
 + typing-extensions==4.15.0
 + tzdata==2025.3
 + websockets==16.0
 + yfinance==1.0

PS C:\Users\tony1\my_project> uv add kbar   
Resolved 35 packages in 2.10s
Prepared 11 packages in 6.29s
Uninstalled 1 package in 134ms
Installed 11 packages in 581ms
 + contourpy==1.3.3
 + cycler==0.12.1
 + fonttools==4.61.1
 + kbar==0.1.5
 + kiwisolver==1.4.9
 + matplotlib==3.10.8
 + mplfinance==0.12.10b0
 + packaging==26.0
 - pandas==3.0.0
 + pandas==2.3.3
 + pillow==12.1.0
 + pyparsing==3.3.2

再次用 uv tree 顯示已安裝套件 : 

PS C:\Users\tony1\my_project> uv tree
Resolved 35 packages in 2ms
my-project v0.1.0
├── kbar v0.1.5
│   ├── matplotlib v3.10.8
│   │   ├── contourpy v1.3.3
│   │   │   └── numpy v2.4.1
│   │   ├── cycler v0.12.1
│   │   ├── fonttools v4.61.1
│   │   ├── kiwisolver v1.4.9
│   │   ├── numpy v2.4.1
│   │   ├── packaging v26.0
│   │   ├── pillow v12.1.0
│   │   ├── pyparsing v3.3.2
│   │   └── python-dateutil v2.9.0.post0
│   │       └── six v1.17.0
│   ├── mplfinance v0.12.10b0
│   │   ├── matplotlib v3.10.8 (*)
│   │   └── pandas v2.3.3
│   │       ├── numpy v2.4.1
│   │       ├── python-dateutil v2.9.0.post0 (*)
│   │       ├── pytz v2025.2
│   │       └── tzdata v2025.3
│   ├── numpy v2.4.1
│   └── pandas v2.3.3 (*)
├── requests v2.32.5
│   ├── certifi v2026.1.4
│   ├── charset-normalizer v3.4.4
│   ├── idna v3.11
│   └── urllib3 v2.6.3
└── yfinance v1.0
    ├── beautifulsoup4 v4.14.3
    │   ├── soupsieve v2.8.3
    │   └── typing-extensions v4.15.0
    ├── curl-cffi v0.13.0
    │   ├── certifi v2026.1.4
    │   └── cffi v2.0.0
    │       └── pycparser v3.0
    ├── frozendict v2.4.7
    ├── multitasking v0.0.12
    ├── numpy v2.4.1
    ├── pandas v2.3.3 (*)
    ├── peewee v3.19.0
    ├── platformdirs v4.5.1
    ├── protobuf v6.33.4
    ├── pytz v2025.2
    ├── requests v2.32.5 (*)
    └── websockets v16.0
(*) Package tree already displayed

執行記事本程式編輯 main.py : 

PS C:\Users\tony1\my_project> notepad main.py   

將 main.py 改成如下 : 

from kbar import KBar   
import yfinance as yf   

def main():
    df=yf.download('0050.TW', start='2024-07-01', end='2024-08-21', auto_adjust=False)    
    df.columns=df.columns.map(lambda x: x[0])    # 改成舊版單層索引
    kb=KBar(df)    # 未傳 font 參數預設使用正黑體
    kb.plot(title='台灣五十(0050.TW)', volume=True)

if __name__ == "__main__":
    main()

用 uv run 執行 main.py :

PS C:\Users\tony1\my_project> uv run main.py  
[*********************100%***********************]  1 of 1 completed
設定字型為: Microsoft JhengHei
使用指定字型: Microsoft JhengHei
字型候選清單: ['Microsoft JhengHei', 'DejaVu Sans', 'Arial']




可見順利繪製了 K 線圖. 


7. 建立 uv 專案的標準流程 :   

最後將 uv 建立 Python 專案的流程摘要整理如下 :


(1). 建立並初始化專案 : 

直接指定專案名稱與 Python 版本一步到位 : 

# 建立一個名為 my_project 的專案, 並指定使用 Python 3.12 

uv init my_project --python 3.12

# 進入專案目錄 

cd my_project


(2). 安裝套件 (關鍵步驟) : 

如果還沒有虛擬環境會自動建立 .venv 子目錄, 然後下載並安裝套件到虛擬環境中 (可以一次安裝多個套件), 最後將套件依賴寫入 pyproject.toml 方便以後管理 :

uv add requests yfinace kbar


(3). 執行程式 : 

不需要先啟動虛擬環境直接用 uv run, 它會自己去用專案裡的環境跑 (假設主程式為 main.py) :

uv run main.py


(4). 同步環境 (可選) : 

如果是從 Github 下載別人的 uv 專案或者換了電腦, 需要執行 uv sync 指令, 它會根據鎖定檔 (uv.lock) 把整個虛擬環境還原回來 : 

uv sync

最後來看一下 .venv 子目錄內容 :

PS C:\Users\tony1\my_project> dir .venv

    目錄: C:\Users\tony1\my_project\.venv

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----       2026/1/24  上午 11:22                Lib 
d-----       2026/1/24  下午 12:36                Scripts  
d-----       2026/1/24  下午 12:36                share
-a----       2026/1/24  上午 11:22              1 .gitignore
-a----       2026/1/24  上午 11:22              0 .lock
-a----       2026/1/24  上午 11:22             43 CACHEDIR.TAG
-a----       2026/1/24  上午 11:22            178 pyvenv.cfg

我們用 uv add 安裝的套件都會放在 Lib\site-packages 裡面. 

2026年1月21日 星期三

蝦皮購買 iPad Mini 5 透明殼

上周跟水某到夢時代熊老闆的店買了一台 7 吋電子紙閱讀器, 以便將手中的 4000 點夢時代點數用掉, 雖然安裝 HyRead 可以借市圖電子書與電子雜誌很方便, 但我覺得閱讀器反應較慢, 還是 iPad 較好用, 於是將擱置已久的 iPad mini 5 拿出來, 安裝 HyRead 後同樣可登入市圖借電子書, 覺得要好好來用它, 便上蝦皮買了兩個透明殼 :





滿 149 免運, 所以就買了兩個, 裕誠智取店取付. 

2026年1月18日 星期日

2026 年第 3 周記事

時序已來到一月中旬, 眼看一個月後就是春節了, 小時候期待過年, 現在年歲越長越是感到恐懼啊! 但一想到年底有年終獎金, 就不覺得有甚麼好怕啦! 呵呵. 不過一轉眼六年後退休, 到時沒薪水沒年終, 過年該是多恐怖的一件事啊! 看來現在就要開始替退休設想了, 退休後起碼要能維持每月 6 萬現金流 (勞保 21K + 勞退 20K + 投資 20K + ...), 以投資年收大約 50 萬回推, 平均 0056 報酬率 5% 簡單計算, 須持有 1000 萬 0056 才行, 加油! 

離過年不到一個月了, 這個周末開始著手整理老家庫房, 周六清了一批回收, 今日去上元買了廚廁清潔劑, 把廚房旁的浴室刷洗乾淨了, 下周要洗另外兩間浴廁, 但主要還是清庫房, 畢竟這一年來累積太多東西, 該丟就丟吧! 今天也在五金行買了一支矽膠槍, 下周要把餐廳後面浴廁的馬桶漏水問題徹底搞定. 

早上去市集時順路到種子行買六棵蔥來補盆栽中之前沒種活的空位, 我發現用盆栽種蔥非常方便, 幾乎沒雜草. 另外還買了 30 株香菜, 也是種在盆栽裡, 應該可以趕上過年之用. 下周再跑一趟種子行買九層塔苗來種, 最近菜園都沒看到半棵, 想做打拋豬沒九層塔不行. 

這一周我把閒暇時光花在 Vibe coding, 我發現 Gemini CLI 其實不輸 Claude Code, 還在持續探索中. 我有非常多小專案要做, 但常常卡在學過的東西生疏淡忘了, 要用時又花很多時間去複習與測試, 現在有 AI 幫我搞定軟體, 完成專案應該可以 50 倍速度前進. 

2026年1月17日 星期六

2026年1月16日 星期五

Gemini CLI 學習筆記 : 郵遞區號查詢小幫手專案 (一)

本篇旨在以使用 https://zip5.5432.tw 的 API 查詢郵遞區號為例來說明一個文組出身的程式小白如何透過 Gemini CLI 介面利用 Vibe coding 方式用嘴寫程式. 此網站可線上輸入地址來查詢郵遞區號, 也有提供 API 讓應用程式查詢, 此範例出自旗標 "Claude Code Vibe Coding 開發手冊" 這本書的第二章, 此處只是將 AI 工具改換成 Gemini CLI 而已 : 




此書範例程式碼與提示詞可在 GitHub 取得 :


本系列之前的文章參考 :


先摘要整理一下安裝 Gemin CLI 的步驟, Gemin CLI 必須在 Node.js 18 版以上才能跑, 首先開啟一個 Power Shell 視窗, 先安裝套件管理工具 Scoop :

PS C:\Users\tony1> Invoke-RestMethod -Uri https://get.scoop.sh | Invoke-Expression   

在 Windows 中使用 Scoop 來安裝 nvm 不僅可簡化安裝過程, 省去手動下載和配置的麻煩, 還可集中管理軟體與提高相容性. 

接著用 Scoop 安裝 Node.js 版本管理工具 nvm : 

PS C:\Users\tony1> scoop install nvm     

然後用 nvm 安裝 Node.js :

PS C:\Users\tony1> nvm install node   

安裝 Node.js 時會同時安裝 Node.js 的套件管理工具 npm, 最後用 npm 來安裝 Gemini CLI (是一個 Node.js 套件包) :

PS C:\Users\tony1> npm install -g @google/gemini-cli    

安裝好 Gemini CLI 後就可以馬上 "動口" 做 Vive coding, 用嘴來寫程式了. 

程式小白只要懂基本電腦操作 (其實就是常用的 DOS 檔案管理指令例如 mkdir/cd/del 等等),  即使是文組出身的人也可以快速開發出自己想要的軟體作品. 


1. 建立專案目錄 : 

首先在 Power shell 視窗中建立一個 gemini 資料夾來放置所有 Gemini CLI 專案 : 

PS C:\Users\tony1> d:   
PS D:\> mkdir gemini   

    目錄: D:\

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----       2026/1/13  上午 09:36                gemini

切換到 gemini 資料夾下建立一個 "postal-helper-proj1" 專案資料夾 : 

PS D:\> cd gemini   
PS D:\gemini> mkdir postal-helper-proj1   

    目錄: D:\gemini

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----       2026/1/13  上午 09:39                postal-helper-proj1

切換到專案目錄下 :

PS D:\gemini> cd postal-helper-proj1   
PS D:\gemini\postal-helper-proj1>  


2. 用 Google 帳號登入 Gemini CLI : 

在專案目錄下輸入 gemini 啟動 Gemini CLI : 

PS D:\gemini\postal-helper-proj1>gemini   




接下來就可輸入提示詞請 Gemini CLI 幫我們寫軟體了, 在旗標 "Claude Code Vibe Coding 開發手冊" 這本書 GitHub 資源的第二章可以找到提示詞 :


複製提示詞貼到 Gemini CLI 提示號後面按 Enter :

> 請用Python寫一個可以在命令列執行的郵遞區號小幫手,輸入是地址,輸出是 6 碼郵遞區號,台灣地址郵遞區號查詢程式使用 zip5.5432.tw API 查詢地址對應的郵遞區號

這時 Gemini CLI 會去讀取專案目錄, 發現裡面空空如也, 先顯示 Directory is empty 訊息後, 輸出如下訊息表示會寫一個 Python 程式利用 zip5.5432.tw 的 API (http://zip5.5432.tw/zip5json.py?adrs=地址) 來查詢給定地址之 6 碼郵遞區號, 寫好程式碼之後會先顯示, 並徵求允許將程式碼寫入專案目錄下的 postal_helper.py 檔案裡 (這檔名是它自訂的, 我們也可以在提示詞中指定) :

✦ I will create a Python script postal_helper.py that uses the zip5.5432.tw API to query the 6-digit postal code for a given address.




在程式碼後面會問 Apply this change? 我們可以直接按 Enter 選擇預設的 1. Allow once (每次寫入會詢問), 或按向下鍵移到 2. Allow for this session (本對話之後都不會再詢問, 直接寫入), 為了慎重起見, 用預設 1 即可. 

程式檔寫入完成後, Gemini CLI 輸出如下資訊, 表示它會用一個地址來測試這的程式看看是否能輸出正確的郵遞區號 : 

✦ I will now test the script with the address "台北市信義區市府路1號" (Taipei City Hall) to ensure it works correctly.

一樣直接按 Enter 選預設的 1. Allow once : 




查詢結果郵遞區號 11024 是正確的 : 




但它發現程式碼在處理中文輸出時出現怪碼 (可能是 UTF-8 編碼問題), 它立即自動更新程式碼, 並要求寫入檔案, 直接按 Enter 選預設的 1. Allow once : 




寫入後要求允許執行程式來測試是否繁體中文輸出 : 




雖然看起來似乎還是輸出怪碼, 但它卻回覆已解決此問題 :




另開一個命令提示字元或 PS 視窗, 切換到專案目錄下, 執行此 Python 程式 :

D:\gemini\postal-helper-proj1>dir   
 Volume in drive D is 新增磁碟區
 Volume Serial Number is 1258-16B8

 Directory of D:\gemini\postal-helper-proj1   

2026/01/16  下午 01:06    <DIR>          .
2026/01/13  上午 09:39    <DIR>          ..
2026/01/16  下午 02:16             2,924 postal_helper.py
               1 File(s)          2,924 bytes
               2 Dir(s)  934,934,114,304 bytes free

D:\gemini\postal-helper-proj1>python postal_helper.py 台北市信義區市府路1號   
正在查詢地址: 台北市信義區市府路1號 ...
------------------------------
地址: 台北市信義區市府路1號
6碼郵遞區號: 110204
------------------------------

果然能正確顯示繁體中文與輸出正確郵遞區號. 

以上我們只出一張嘴, 靠提示詞就讓 Gemini CLI 幫我們寫好可正確運行的程式, 從撰寫到測試 Gemini CLI 一手包辦, 我們連原始碼都還未一賭全貌, 好奇到底長怎樣的話, 可以用記事本開啟專案目錄下的 postal_helper.py 來看看 :

import sys
import json
import urllib.parse
import urllib.request
import io

# 確保在 Windows 上輸出為 UTF-8,避免亂碼
if sys.platform == "win32":
    sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
    sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')

def get_postal_code(address):
    base_url = "https://zip5.5432.tw/zip5json.py"
    params = {'adrs': address}
    # Ensure the URL is correctly encoded
    url = f"{base_url}?{urllib.parse.urlencode(params)}"
    
    try:
        # User requested 6-digit postal code
        print(f"正在查詢地址: {address} ...")
        
        req = urllib.request.Request(url)
        # Some APIs require a User-Agent
        req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) PostalHelper/1.0')
        
        with urllib.request.urlopen(req) as response:
            if response.status != 200:
                print(f"錯誤: API 返回狀態碼 {response.status}")
                return

            data = response.read()
            try:
                result = json.loads(data)
            except json.JSONDecodeError:
                print("錯誤: 無法解析 JSON 回應。")
                print(f"回應內容: {data.decode('utf-8', errors='ignore')}")
                return
            
            # The API returns 'zipcode6' for the 6-digit code.
            # Sometimes it might return an empty string or null if not found.
            zip6 = result.get('zipcode6')
            
            if zip6:
                print("-" * 30)
                print(f"地址: {result.get('address', address)}")
                print(f"6碼郵遞區號: {zip6}")
                print("-" * 30)
            else:
                print("找不到該地址的 6 碼郵遞區號。")
                # Show full result just in case useful info is elsewhere
                if 'error' in result:
                    print(f"API 錯誤: {result['error']}")

    except urllib.error.URLError as e:
        print(f"網絡錯誤: {e}")
    except Exception as e:
        print(f"發生未預期的錯誤: {e}")

if __name__ == "__main__":
    if len(sys.argv) > 1:
        # Join arguments to handle addresses with spaces if not quoted
        address_input = " ".join(sys.argv[1:])
        get_postal_code(address_input)
    else:
        # Interactive mode
        print("台灣 6 碼郵遞區號小幫手")
        print("用法: python postal_helper.py <地址>")
        print("或在下方輸入地址 (按 Ctrl+C 離開):")
        while True:
            try:
                address_input = input("\n請輸入地址: ").strip()
                if not address_input:
                    continue
                get_postal_code(address_input)
            except KeyboardInterrupt:
                print("\n程式結束。")
                break
            except EOFError:
                break

程式小白欣賞就好, 但對常寫 Python 程式的我來說, 這可能要花我半天才能搞定, 而且 AI 採用的實作方法會與我自行撰寫的大異其趣. 

完成後輸入 exit 或按 Ctrl + C 跳出 Gemin CLI 結束對話. 

2026年1月13日 星期二

Gemini CLI 學習筆記 : 與 Claude Code 的比較

以前 Claude Code 是 Vibe coding 的首選, 它在程式碼生成品質與準確性上表現優異, 尤其是在複雜任務, 跨檔案重構, 與深度程式分析上都優於 Gemini CLI 與其它 AI 工具. 但 Google AI 在 2025 年底推出 Gemini 3 後, 在多個軟體工程與程式碼生成的基準上, Gemini 3 都已超越包括 Claude 系列在內的主要競爭者, 本篇旨在整理這兩大工具的性能比較. 

本系列之前的測試文章參考 :



1. 效能與功能比較 : 

為了公平起見, 我用第三方的 M365 Copilot Chat 針對 Vibe coding 開發軟體專案, 評比 Claude Code 與 Gemini CLI (Gemini 3) 的優缺點, 得到下面的比較表 : 


比較項目 Gemini 3 (Pro / Flash) Claude 3.5 Sonnet
代表性程式基準 在 SWE‑bench 場景報告中居領先;LiveCodeBench Pro 得分 2439,高於 GPT‑5.1 與 Claude Sonnet。 在 HumanEval 類型基準中表現穩定,但在 Live/Agentic 類基準不及 Gemini 3。
代理式終端工作 (CLI) Terminal‑Bench 2.0 取得 54.2%,領先 Claude 與 GPT‑5.1;適合 agentic coding。 表現穩定但在代理式任務比例上落後,偏向保守增量修改。
速度/延遲 (CLI 迭代) Gemini 3 Flash 主打低延遲與高吞吐,適合快速反覆嘗試。 速度中等,複雜推理時品質穩定,但迭代時間通常較長。
上下文視窗 可達超長上下文 (100 萬個 token),適合大型專案整體分析。 約 20 萬個 tokens,上下文足夠多數場景,但不及 Gemini 系列。
跨模態能力 在多模態基準領先,對 UI/畫面理解與多媒體輔助程式工作更有利。 跨模態能力有限,偏重文字場景。
工具/平台整合 支援 Gemini CLI、Google AI Studio、Vertex AI、Android Studio,Flash 為預設模型。 支援 Anthropic API、Amazon Bedrock、Vertex AI,但 CLI 官方工具較弱。
行為特徵 (提示遵循) 最新版本在思考與工具調用穩定性強化,格式與上下文管理已改進。 格式一致性與保守變更表現佳,較少過度重構。
適用場景總結 快速迭代、代理式工具使用、跨模態理解、超大上下文,適合 CLI 驅動的 vibe coding。 保守修補、嚴格遵循格式、低風險漸進修改,適合長期維護與精細重構。


摘要如下 :
  1. Gemini 3 Pro (Deep Think/Flash)  在包括程式生成 (LiveCodeBench), 代理編程 (Terminal‑Bench) 以及跨模態與邏輯推理的大型基準中表現領先.
  2. Claude 3.5 Sonnet 依舊可靠 (尤其在格式穩定與多步邏輯上), 但在程式產出量, 效能與大型 context 支援上, 目前已不如 Gemini 3. 
  3. 使用最新的 Gemini CLI + Gemini 3 Flash/Pro 在程式生成速度, 質量與 agentic 工作流方面已普遍被認為比 Claude 3.5 Sonnet 更強.
結論是 : 

目前改用 Gemini 3 CLI  (特別是 Flash 或 Pro 模式) 進行 vibe coding 或程式產出已明顯優於 Claude 3.5 Sonnet, 不僅速度快, 工程維度也更強大. 


2. 操作指令比較 : 

Gemini CLI 與 Claude Code 的操作指令之名稱與功能類似, 對照表如下 :


功能分類 功能描述 Gemini CLI Claude Code
安裝與啟動 全域安裝與基本啟動方式 npm install -g @google/gemini-cli
啟動後使用斜線指令 (/settings、/model)
npm install -g @anthropic-ai/claude-code
claude 啟動 REPL
互動模式 (REPL) 在終端中開啟持續對話 執行 gemini
內建斜線指令管理會話
claude(REPL)
可加初始提示 claude "query"
非互動/單次執行 單次執行並輸出結果
(適合 CI)
支援 Headless/print 模式
輸出 JSON 或文字
claude -p "query"
支援 --output-format json|text
會話續接 續接最近或指定會話 /chat save|resume|list|delete 管理對話 claude -c (續接最近) 
--resume 或 --fork-session
模型選擇 指定或切換模型 /model 選擇 Auto/Pro
支援 Gemini 3 Pro/Flash
--model
支援 --fallback-model
模型路由/容量處理 超載或配額時的回退策略 自動路由與回退
Pro 配額用盡時回退到 Flash
--fallback-model sonnet 等
MCP 整合 連接外部服務/工具 支援 MCP 伺服器與工具(grep, terminal) claude mcp
支援 --chrome 啟動瀏覽器
檔案/目錄存取 指定工作目錄, 附加路徑 /directory 管理範圍 --add-dir ../apps ../lib
權限/安全 控管可執行工具與跳過提示 --allowedTools / --disallowedTools
--dangerously-skip-permissions
系統提示 追加或覆寫系統提示 --append-system-prompt

--system-prompt-file
IDE/代理整合 VS Code/IDE 整合能力 Gemini Code Assist 代理模式與 CLI 聯動 --ide 啟動 IDE
支援 agents
自動化/腳本 CI 友善輸出與腳本化 Headless/print 模式;Cloud Shell 支援 -p/--print 搭配輸出格式
更新 CLI 自我更新 npm 更新至最新版本 claude update


注意, Gemini CLI 並沒有 Claude Code 那樣的權限/安全與系統提示操作指令, 這反映了兩大工具設計哲學的差異, Claude Code 有點像一個 "外部承包商", 它非常在意是否被授予權限 (例如它會一直問你 Allow?), 並提供操作指令來管理; 而 Gemini CLI 則像是一個 "深度整合的終端機外掛", 它將安全性與權限交給了底層系統 (OS 權限) 與文件化管理, 而不是透過互動式指令來開關.


3. 斜線指令比較 : 

因斜線指令較常用, 所以從上面的操作指令中抽離出來, 對照表如下 :


功能分類 功能描述 Gemini CLI Claude Code
基礎操作 顯示說明 /help /help
清除畫面/清除上下文 /clear /clear
退出程式 /quit /exit 或 Ctrl+D
報告 Bug /bug /bug
上下文管理 初始化專案配置 (重要) /init (建立 GEMINI.md) /init (建立 CLAUDE.md)
壓縮/精簡對話歷史 /compress /compact
查看/管理記憶與規則 /memory /memory
查看 Token 使用量/統計 /stats /cost 或 /stats
對話與任務 儲存/暫存當前對話 /chat save <tag> /rename (命名 Session)
恢復之前的對話 /chat resume <tag> /resume
計畫/思考模式 無專用指令, 需用 Prompt /plan (進入計畫模式)
配置與擴充 開啟設定 /settings /config
管理 MCP /mcp /mcp
檢查安裝健康度 (無直接對應) /doctor
更改介面主題/樣式 /theme /output-style


斜線指令中最主要的差異是 Gemini CLI 沒有 /doctor 與 /plan 指令, 其中 /plan 是 Claude Code 最棒的功能之一, 在此模式下 Claude Code 會先進行深度思考和規劃再開始寫程式, 這在處理複雜重構時非常有用, 也可避免 AI 衝太快直接改動原始碼, 可惜 Gemini CLI 並沒有此指令, 但可以靠提示工程或自訂指令來達成同樣功能. 

在 Gemini CLI 中用提示詞模擬 /plan 指令的方法有如下三種 :

(1). 單次對話提示詞 (One-off Prompt) :

例如 : 我想重構目前的 XXX 架構, 請先不要寫任何程式碼。請先切換到「規劃模式」, 分析目前的專案結構, 並列出你打算執行的具體步驟 (Step-by-step plan), 等我確認這個計畫並回覆「同意」後你再開始寫程式.

(2). 永久生效設定 (寫入 GEMINI.md) :

執行 /init 指令, 編輯 GEMINI.md, 加入以下內容 :

# Coding Guidelines
1. **Thinking First**: 對於涉及多個檔案修改或邏輯複雜的任務, **嚴禁直接產生程式碼**
2. **Plan Mode**: 必須先輸出一個詳細的「執行計畫 (Action Plan)」, 列出預計修改的檔案路徑和邏輯
3. **Approval**: 只有在使用者明確回覆「Go」或「同意」後才可以使用工具寫入檔案

(3). 自製 /plan 指令 :

在家目錄下建立檔案 : ~/.gemini/commands/plan.toml, 在檔案中貼上以下內容 : 

# 這裡定義指令名稱為 /plan
description = "分析需求並產出執行計畫,但不寫入程式碼"
prompt = """
你現在是架構師模式。請針對使用者的需求: "{{args}}"
1. 讀取相關檔案以理解現狀。
2. **不要** 進行任何寫入或修改檔案的操作。
3. 輸出一個詳細的步驟計畫 (Step-by-step Implementation Plan)。
4. 最後詢問使用者是否依此計畫執行。
"""

然後在 Gemini CLI 中輸入 /plan 指令, 例如 : 

/plan 幫我把資料庫從 SQLite 遷移到 PostgreSQL

這樣 Gemini CLI 就會像一個謹慎的工程師一樣執行規劃而不會貿然地直接動手修改檔案. 


3. 在 Gemini CLI 中實現系統提示控制 : 

從上面的比較可知, Gemini CLI 沒有提供 Claude Code 的系統提示與權限/安全指令, Google 的想法是 : 讓 AI 讀文件 (GEMINI.md 檔) 比讓人類背指令更符合自然語言交互的直覺, 只要善用 GEMINI.md (這是 Gemini CLI 的操作手冊, 啟動時會優先閱讀這個檔案), 不需要指令也可以達到 Claude 那種 "嚴格控制安全與行為" 的效果. 總之, Gemini CLI 適合喜歡文件化管理的人, 它沒有繁瑣的權限指令, 因為它希望使用者透過專案目錄和 GEMINI.md 設好防護欄. 

在 GEMINI.md 中加入安全與權限指令的範例如下 (markdown) :

# 專案規範與安全指令

## 行為限制 (System Rules)
1. **禁止操作**: 未經許可,禁止修改 `config/` 資料夾下的任何 .env 檔案。
2. **安全檢查**: 在執行任何 `rm` 或 `delete` 相關指令前,必須先列出檔案清單供我確認。
3. **程式碼風格**: 嚴格遵守 Python PEP 8 規範。

## 自動化權限
- 允許自動執行 `git status` 與 `ls` 等唯讀指令。
- 寫入檔案前,必須先顯示 diff 差異。

這麼做的好處是, 當我們把安全與權限規則寫在 GEMINI.md, 這份規則會跟著 Git 走, 亦即同組的開發者啟動 Gemini CLI 時會獲得相同的安全規範, 不需要每次換一台電腦就要重新 /config 一次. 

雖然最近會聚焦於 Gemini CLI 的探索, 但由於在四月初之前有胡嘉璽老師的 Vibe Coding 課程 (使用 Claude Code), 所以最近應該就會課金購買 Claude Code 月付方案, 同時學習兩套工具也好互相比較.