嗨大家,我是 Debuguy。
還記得 Day 16 我們為了安全性和成本控制,把 GenKit 從直接連 Google AI 改成透過 LiteLLM 代理嗎?當時測試都正常,Code Review 也過了,就開心地 merge 了。
結果過了幾天,在測試其他功能時突然發現:
「欸...思考過程的串流怎麼不見了?Day 9 不是做好了嗎?」
一開始以為是網路問題,重開了幾次還是不行。突然靈光一閃:
「該不會...是 Day 16 的重構造成的?」
那時候我們直接用 Google AI Plugin:
// GenKit/src/index.ts (Day 9)
import { googleAI } from '@genkit-ai/google-genai';
const ai = genkit({
plugins: [
googleAI(),
],
});
Prompt 設定長這樣:
# prompts/chatbot.prompt (Day 9)
---
model: googleai/gemini-2.5-flash-lite
config:
temperature: 0.2
topP: 0.95
topK: 30
thinkingConfig:
thinkingBudget: -1 # 啟用動態思考
includeThoughts: true # 包含思考過程
---
串流處理的邏輯:
const { stream, response } = ai.prompt('chatbot').stream({
// ...
});
for await (const chunk of stream) {
for (const content of chunk.content) {
if (content.reasoning) {
sendChunk(chunk.reasoning); // ✅ 可以收到思考過程!
}
}
}
當時測試完全正常,Bot 會即時顯示 AI 的思考過程,體驗很棒。
為了安全性和成本控制,我們引入了 LiteLLM:
// GenKit/src/index.ts (Day 16)
import { liteLlm } from './plugin/litellm.js';
const ai = genkit({
plugins: [
liteLlm(), // 改用自己寫的 plugin
],
});
LiteLLM Plugin 的核心實作:
// GenKit/src/plugin/litellm.ts
import openAICompatible from '@genkit-ai/compat-oai';
export const liteLlm = (): GenkitPluginV2 => {
return openAICompatible({ // 基於 compat-oai
name: 'litellm',
apiKey: process.env['LITELLM_API_KEY'],
baseURL: process.env['LITELLM_API_URL'],
// ...
});
};
「架構看起來更優雅了,測試也都過了...但為什麼思考過程不見了?」
我先檢查了最可疑的地方 — Prompt 設定:
# prompts/chatbot.prompt (Day 16 還是用舊的)
---
model: litellm/gemini-2.5-flash-lite
config:
temperature: 0.2
topP: 0.95
topK: 30
thinkingConfig:
thinkingBudget: -1
includeThoughts: true
---
「等等...model 換了,參數不是也要跟著改嗎?」
因為我們用的是 gemini-2.5-flash-lite
,根據 Google 文件,是用 thinkingBudget: -1
來啟動 dynamic thinking(因為 flash-lite 預設是 disable thinking)。
但現在我們改用 LiteLLM 轉接,config 要改用 OpenAI 的格式。趕緊翻了 LiteLLM 的文件,發現一個關鍵事實:
LiteLLM 支援 reasoning models,但參數格式遵循 OpenAI 的規範!
OpenAI 的 reasoning model (o1 系列) 的參數是這樣的:
config:
reasoning_effort: "low" | "medium" | "high"
而且:
topP
(OpenAI 的 o1 不支援這參數)thinkingConfig
(這是 Google 專屬的)「好吧,參數名稱錯了...改一下應該就好了...」
改完參數重跑後:
「還是沒有!這...不科學啊?」
還好在 Day 17 我們架設了 Langfuse,可以攔截到從 LiteLLM 輸出的內容。打開 trace 一看:
「咦?LiteLLM 明明有回傳 reasoning 啊!而且欄位名稱是
reasoning_content
...」
突然想到一件事:
「該不會是 plugin 本身的問題?」
仔細看了 Day 16 寫的 LiteLLM plugin,它是基於 @genkit-ai/compat-oai
這個套件:
import openAICompatible from '@genkit-ai/compat-oai';
export const liteLlm = (): GenkitPluginV2 => {
return openAICompatible({ // 這裡!
// ...
});
};
「
openAICompatible
...這不就是 OpenAI API 的抽象層嗎?」
趕緊去翻 OpenAI 的 Chat Completion API 文件:
OpenAI 的標準 API 根本不包含 reasoning_content!
真相大白了!
reasoning_content
@genkit-ai/compat-oai
只處理標準 OpenAI 格式reasoning_content
被直接忽略了!「原來如此...我被『OpenAI-compatible』這四個字騙了」
雖然大家都說自己是「OpenAI-compatible」,但現實很複雜。
各家的擴充:
提供商 | 擴充欄位 | 說明 |
---|---|---|
xAI (Grok) | reasoning_content |
文件 |
DeepSeek | reasoning_content |
文件 |
LiteLLM | reasoning_content |
文件 |
問題的核心是:
@genkit-ai/compat-oai
是基於「標準 OpenAI API」設計的,不認識這些擴充欄位。
// @genkit-ai/google-genai 的實作
// 它直接對接 Gemini API
// 完全了解 Gemini 的 thinking 機制
// 知道怎麼處理 reasoning 內容
當我們從 Google AI Plugin 切換到 OpenAI-compatible Plugin 時:
獲得:
失去:
這就是架構決策的取捨。
發現問題後,我開始思考怎麼解決。擺在眼前的有三條路:
優點:
缺點:
「這個...好像不太行。Day 14-16 可是為了生產環境的安全性才做的重構啊」
優點:
缺點:
短期:
reasoning_effort: "medium"
)長期:
「這個...好像比較務實?」
經過一番掙扎,我選擇了選項 C。
1. 使用者體驗不能打折
雖然暫時看不到即時的思考過程,但 Langfuse trace link 還在,點開就能看完整的。比起退回去用沒有安全保護的架構,這個折衷可以接受。
2. 技術債要還,但不急於一時
這個 PR 應該要做,但可以慢慢研究、好好寫。不要為了趕進度寫出爛 code。
3. 保持架構的正確性
LiteLLM 架構是對的,這只是實作細節的問題。
短期修復(Day 22):
# prompts/chatbot.prompt
---
model: litellm/gemini-2.5-flash-lite
config:
temperature: 0.2
topK: 30
reasoning_effort: "medium" # ✅ 改用 OpenAI 格式
---
修改 @genkit-ai/compat-oai
(進行中):
「雖然 PR 還沒 merge,但至少踏出第一步了」
今天這個 bug 給我很多反思:
重構不是免費的午餐,總會有些東西在轉換過程中掉在地上。
從 Google AI Plugin → LiteLLM + OpenAI Compatible Plugin:
這就是架構決策的本質:取捨。
沒有完美的架構,只有在特定情境下最適合的架構。
當你看到「OpenAI-compatible」時,要知道:
Devil is in the details.
就像「方言」一樣,雖然都是中文,但各地區還是有差異彼此還是有差異的。OpenAI Compatible API 也是如此。
這次的經歷讓我決定給 GenKit 提 PR。
當你遇到 Open Source 工具的限制時,你有兩個選擇:
- 抱怨它不夠完美
- 動手讓它變得更好
我選擇後者。這也是為什麼我們一開始選擇 Open Source 工具的原因 — 當它不符合需求時,我們有能力去改進它。
有時候,完美主義是工程師的敵人。
「沒有即時串流就先沒有吧,至少 trace 還能看到完整的思考過程」
要在「理想」和「現實」之間找到平衡點。
AI 的發展變化很快,目前這個想法以及專案也還在實驗中。但也許透過這個過程大家可以有一些經驗和想法互相交流,歡迎大家追蹤這個系列。
也歡迎追蹤我的 Threads @debuguy.dev