昨天,我讓 Gemini 依照 JSON Schema 整理網站安全分析,也寫了程式檢查欄位與引用來源。
但在核對結果時,我發現模型提到搜尋參數 q,附上的引用卻只有 <form>,沒有包含定義 q 的 <input>。程式找得到引用,仍然不能證明整句主張都有證據支持。
這時,我希望能接著問:「你剛才提到 q,引用真的有包含它嗎?」
所以今天,我把操作方式做成終端機對話工具。輸入問題、取得分析,再繼續追問;底層仍然使用 Structured outputs,每輪都保留 JSON 與驗證結果。
加入 HTTP 或 HTML 證據
↓
輸入問題,連同對話歷史送出
↓
取得 JSON 回答並檢查
↓
顯示分析、保存結果
↓
繼續追問,或開始新對話
我把專案放在本地並建立 Python 虛擬環境:
cd $PATH_TO_FILE
python3 -m venv .venv
source .venv/bin/activate
python -m pip install google-genai python-dotenv jsonschema
本次套件版本分別是 google-genai 2.24.0、python-dotenv 1.2.3 與 jsonschema 4.26.0。版本另外保存在需求檔中,方便重建環境。
.venv 管理 Python 套件,API Key 則寫在根目錄的 .env:
GEMINI_API_KEY=你的API金鑰
對話介面負責讓我輸入訊息、繼續追問;Structured outputs 負責約束模型回答的結構。
概念上的核心程式如下。這段用來說明對話與輸出設定的關係,完整版本另外處理金鑰載入、證據登錄、保存、驗證與錯誤:
import json
from google import genai
from google.genai import types
# api_key、schema、system_instruction 由本機設定載入。
# evidence_sources 是已透過介面登錄的證據。
with genai.Client(api_key=api_key, vertexai=False) as client:
chat = client.chats.create(
model="gemini-3.8-flash",
config=types.GenerateContentConfig(
system_instruction=system_instruction,
response_mime_type="application/json",
response_json_schema=schema,
),
)
while True:
message = input("你 > ").strip()
if message == "/quit":
break
if not message:
continue
response = chat.send_message(json.dumps({
"user_message": message,
"evidence_sources": evidence_sources,
}, ensure_ascii=False))
print(response.text)
實際版本把 Schema 與系統規則當成固定設定,問題則由我直接在終端機輸入,不需要先寫進 prompt.txt。
昨天的 schema.json 與來源驗證程式仍然沿用。系統規則則補上多輪對話的要求:可以參考上一輪來理解追問,但模型先前的回答不是新的網站證據。
本次預設使用 Gemini 3.8 Flash,Thinking level 為 Medium,輸出上限為 8192 tokens,沒有啟用搜尋或工具呼叫。昨天記錄的輸出上限是 65536,這項差異也保留在實驗紀錄中。
第二輪除了新問題,也會帶入前面已完成的對話,讓模型理解「剛才那項分析」指的是什麼。
實際程式會以已完成歷史建立本輪對話,再送出新訊息。收到正常結束、可解析的回答後,才更新本機保存的歷史;完整 SDK Content 物件也會保留,包括可能附帶的 thought signature。
如果回答能解析,但引用檢查失敗,我仍會保留這一輪,讓下一輪可以要求它修正。保留在歷史裡不代表認可結論;畫面會顯示檢查未通過。
如果回答被截斷或無法解析,原文仍會保存,但不加入下一輪歷史。API 失敗時也維持原本歷史,避免重送時重複插入同一個問題。
這個版本的對話狀態保留在當次執行的記憶體中。重新啟動會是新對話;已保存的紀錄可供查閱,但目前沒有自動還原舊對話的功能。
另外,多輪請求會帶入先前歷史,對話越長,輸入用量可能越大。切換到另一個案例時,我會用 /reset 清空歷史與證據,再重新開始。
模型回傳 JSON 之後,程式會把它整理成觀察、潛在風險、引用、成立條件與下一步,直接顯示在終端機。需要查看完整結構時,再輸入 /json。
每輪結果分開保存:
results/chats/對話識別碼/
├── turn-001/
└── turn-002/
每個目錄包含本輪問題、先前歷史、證據、生成設定、SDK 回應紀錄、回答文字、解析後的 JSON 與驗證結果。SDK 回應紀錄是物件序列化,不是 HTTP 原始封包。
其他常用指令如下:
| 指令 | 用途 |
|---|---|
/paste |
輸入多行問題,以 /end 結束並送出 |
/sources |
查看目前的證據 |
/reset |
開始新對話,保留既有結果檔 |
/quit |
結束程式 |
正式開始之後,多次收到了503的錯誤,實際到 AI Studio 查看,也沒有發現API用量耗盡的情形
所以明天要做的,就是解決這個問題,並且完成前面設計的實驗
今天把對話相關功能處理完了,明天搞好 503 Error 處理掉今天沒做的事情
那就…
明天見!