昨天把第二週的六支腳本收成了一支 gemini.js,結尾留了一個問題:
Google 有沒有專門的框架,把「流程」本身也包起來,甚至附一個看得到每次 AI 呼叫的介面?
答案就是第三週的第一位主角:Genkit。
今天不寫功能,只做三件事:
1. 認識 Genkit 是什麼
2. 搞清楚它跟昨天的 gemini.js 差在哪
3. 把本機開發環境跑起來
今天要跑的環境,會先放在一個獨立的 genkit-day15/ 沙盒資料夾,還不會動到 devpulse/ 專案本體,原因在第三節說明。
Genkit 是一個開源的 AI 應用框架,由 Google 的 Firebase 團隊打造並用於正式產品,支援 JavaScript/TypeScript、Go、Python 等語言。
跟我們最相關的有兩點:
昨天手寫的每個函式,在 Genkit 裡幾乎都有對應的概念:
| 需求 | Day 14 手寫版 | Genkit 的做法 |
|---|---|---|
| 呼叫模型 | ai.interactions.create(...) |
ai.generate(...) |
| 結構化輸出 | askGeminiJSON:自己 parse、自己 safeParse |
ai.generate 搭配 output: { schema },Schema 一樣用 Zod |
| 工具呼叫 | askWithTools:自己接力 |
ai.defineTool 定義工具,交給 ai.generate 使用 |
| 包成可重用流程 | 自己寫函式 | ai.defineFlow(Day 17) |
| 看每次呼叫發生了什麼 | console.log |
Developer UI(Day 16) |
一句話總結:
gemini.js 是我自己蓋的工具箱,Genkit 是別人蓋好、還附一塊儀表板的工具箱。
這不代表前兩週白學了。正因為手寫過,才看得懂 Genkit 替我們省掉了哪些步驟。
LangChain 是個功能完整的大型生態系,但相對地,需要先熟悉的概念也比較多。DevPulse 的需求很單純:只用 Gemini、只寫 JavaScript、想看清楚每一次 AI 呼叫。
對現在的我來說,Genkit 由 Google 自己維護、和 Gemini 整合直接,又內建本機除錯介面,「夠用就好」。這只是我的選擇理由,不是誰比較好。
這裡刻意不直接動 devpulse/ 專案。第三週是探索期,Day 15–21 每天認識一個新工具,都先在各自的小資料夾裡試,確定摸熟了、有把握了,才會在 Day 22 開始的「實戰組裝」週把它們併進 devpulse/。這樣就算某天的工具最後試不順手,也不會弄髒正在成長中的專案。
需求:Node.js 20 以上。
建立今天的沙盒資料夾:
mkdir genkit-day15 && cd genkit-day15
npm init -y
npm pkg set type=module
# 核心套件 + Gemini 模型 plugin
npm install genkit @genkit-ai/google-genai dotenv
# 全域:Genkit CLI(Developer UI 由它啟動)
npm install -g genkit-cli
四個名稱各司其職:
| 套件 | 用途 |
|---|---|
genkit |
核心功能 |
@genkit-ai/google-genai |
接入 Gemini 模型 |
dotenv |
讀取 .env 裡的金鑰 |
genkit-cli |
本機工具,負責啟動 Developer UI |
在資料夾裡新增 .env,把 Day 2 申請好的金鑰貼進去:
GEMINI_API_KEY=你的金鑰
別忘了同時建立 .gitignore,至少要包含:
node_modules/
.env
在 genkit-day15/ 裡建立 genkit-hello.js:
import "dotenv/config";
import { genkit, z } from "genkit";
import { googleAI } from "@genkit-ai/google-genai";
// 沙盒資料夾先不接 devpulse 專案的共用設定
// 模型名稱直接寫死在這裡就好,Day 22 併入時才改成讀共用設定檔
const MODEL = "gemini-flash-latest";
const ai = genkit({
plugins: [googleAI()],
model: googleAI.model(MODEL),
});
// 先放一個最小的 flow,讓 Developer UI 有東西可以按
// (Flow 的細節,Day 17 再正式拆解)
export const helloFlow = ai.defineFlow(
{ name: "helloFlow", inputSchema: z.string(), outputSchema: z.string() },
async (name) => {
const { text } = await ai.generate(
`用一句話向 ${name} 打招呼,說你是 DevPulse 的 Coding 助理。`
);
return text;
}
);
只需要看懂兩個地方:
1. plugins: [googleAI()]:告訴 Genkit「我要用 Gemini」。
2. model: googleAI.model(MODEL):設定預設模型。這裡先把字串寫死,等 Day 22 併入 devpulse/ 時才會改成從共用設定檔讀取,避免現在為了一個沙盒範例就先牽動主專案的結構。
啟動:
genkit start -- node --watch genkit-hello.js
--watch 的作用是:存檔後 Developer UI 會自動反映修改,不用重啟。
終端機會印出類似:
Telemetry API running on http://localhost:4033
Genkit Developer UI: http://localhost:4000
用瀏覽器打開 http://localhost:4000。
進入畫面後,確認:
✅ Flows 裡有 helloFlow
✅ Models 裡有 Gemini 模型
✅ 在 helloFlow 輸入 "Genkit",按 Run 能收到 Gemini 的回應


小提醒:第一次執行如果看到
503 Service Unavailable(模型回覆目前流量過大),先別緊張。展開右側的 Trace details,只要能看到helloFlow → generate → googleai/...這條呼叫鏈確實跑到底,就代表環境設定沒問題,純粹是 Google 那端暫時滿載,隔幾秒重新按 Run 通常就會恢復。
今天先確定「環境活著」就夠了。至於執行後的 Traces 到底記錄了什麼,明天再看。
照著步驟建好環境,helloFlow 也順利出現在 Developer UI 裡,按下 Run 卻先收到一則紅字錯誤:
UNAVAILABLE: ... [503 Service Unavailable] This model is currently
experiencing high demand. Spikes in demand are usually temporary.
一開始有點心慌,直到點開右邊的 Trace details,才看到 helloFlow → generate → googleai/gemini-flash-latest 整條呼叫鏈其實都正確跑到底,卡住的只是 Google 端模型伺服器暫時滿載,不是我的程式碼或設定有問題。隔幾秒重新按一次 Run,很快就拿到正常回應了。
環境跑起來了,但 Developer UI 還沒真正用上。
明天來看它最有價值的功能:每一次 AI 呼叫的完整追蹤(Traces):模型收到了什麼、回了什麼、花了多久。
Day 16:善用 Genkit Developer UI,觀察每一次 AI 呼叫。
參考資料