LINE Bot Multimodal RAG (kkdai) 研究筆記¶
資料來源¶
| 項目 | 連結 |
|---|---|
| GitHub repo | https://github.com/kkdai/linebot-multimodal-rag |
| 作者 | https://github.com/kkdai(Evan Lin / 台灣 LINE 社群活躍開發者) |
| Gemini File Search 公告 | https://blog.google/innovation-and-ai/technology/developers-tools/expanded-gemini-api-file-search-multimodal-rag/ |
| Gemini Embedding 2 | https://deepmind.google/models/gemini/embedding/ |
| File Search API docs | https://ai.google.dev/gemini-api/docs/file-search?hl=zh-tw |
| 規模 | 26 stars / 4 forks(May 14 2026 抓取)、無 license、Python 3.12 |
專案概述¶
linebot-multimodal-rag 是 kkdai 在 2026-05-11 開的小型 PoC repo,把 Google 剛擴展的 Gemini File Search API(managed multimodal RAG)接到 LINE Bot 上,做出「LINE 上傳檔案就能建知識庫、用文字或圖片查詢」的最小可用範例。3 天內累積 26 stars,雖小但對 Gemini File Search 在亞洲市場(特別是 LINE 生態系)的落地很有示範意義。
幾個讓這個 repo 值得單獨研究的點:
- 完整擁抱 managed RAG:不接 ChromaDB / FAISS / pgvector,全部交給 Gemini File Search Store(Google 處理 chunking + embedding + indexing)。
- 單一 store + metadata_filter 做多租戶:所有 LINE 使用者共用一個 File Search Store,靠
custom_metadata: user_id=<LINE UID>上傳、metadata_filter='user_id="<UID>"'查詢,server-side enforce。 - CLAUDE.md 寫得很完整:作者把設計決策、API 呼叫 shape、未完成事項都列進 CLAUDE.md,是 Claude Code 友善 repo 的範本。
功能流程¶
LINE App
│ Webhook (HTTPS)
▼
FastAPI on Cloud Run
├─ 文字訊息 ──────────────────► Gemini File Search → 回覆 + page citation
├─ 圖片 / 檔案 ─► GCS 備份 ──► Quick Reply 按鈕 (5min session TTL)
└─ Postback 按鈕
├─ 📥 存入資料庫 ─► BackgroundTask ─► upload+poll ─► push_message
└─ 🔍 作為搜尋 ──► GCS 讀檔 ──► Gemini File Search → 回覆
| 互動 | 行為 |
|---|---|
| 傳 PDF / 文字檔 | Bot 詢問:存入 or 搜尋 |
| 傳圖片 | Bot 詢問:存入 or 搜尋 |
| 點「📥 存入資料庫」 | 非同步索引(含 user_id metadata)→ push 通知完成 |
| 點「🔍 作為搜尋」 | 用該檔/圖當 query,只在自己資料中找 |
| 輸入文字 | 直接對自己資料庫做 RAG |
| 工作階段 TTL | 5 分鐘 |
技術堆疊¶
| 元件 | 選型 |
|---|---|
| 框架 | FastAPI + uvicorn |
| LINE SDK | line-bot-sdk v3 (AsyncMessagingApi, AsyncMessagingApiBlob) |
| Gemini SDK | google-genai(新 SDK,不是 google-generativeai) |
| Embedding | models/gemini-embedding-2(多模態,文字 + 圖片同向量空間) |
| Generation | gemini-3-flash-preview(env GEMINI_MODEL 可調) |
| 儲存 | GCS(uploads/{user_id}/{message_id}.{ext} + config/file_search_store_name.txt) |
| Session | in-memory + 5min TTL(需要 min-instances=1) |
| 部署 | Cloud Run via Cloud Build |
| 限制 | 單檔 100 MB、不支援 audio / video |
關鍵 API 呼叫範式(從 CLAUDE.md 摘)¶
建立 File Search Store¶
store = client.file_search_stores.create(config={
"display_name": "linebot-multimodal-rag",
"embedding_model": "models/gemini-embedding-2",
})
上傳並帶 user metadata¶
operation = client.file_search_stores.upload_to_file_search_store(
file_search_store_name=store.name,
file=tmp_path,
config={
"display_name": filename,
"custom_metadata": [{"key": "user_id", "string_value": user_id}],
},
)
# operation 是 long-running,需 poll: client.operations.get(operation)
查詢時用 user filter¶
response = await client.aio.models.generate_content(
model=GEN_MODEL,
contents=text, # 或 Content(parts=[image_part, text_part])
config=types.GenerateContentConfig(
tools=[types.Tool(file_search=types.FileSearch(
file_search_store_names=[store_name],
metadata_filter=f'user_id="{user_id}"', # google.aip.dev/160
))],
),
)
metadata_filter 用的是 google.aip.dev/160 過濾語法(同 GCP 通用 API filter spec)。
部署摘要¶
# 本機
cp .env.example .env # 填 LINE 兩把 key + GEMINI_API_KEY + GCS_BUCKET
gcloud auth application-default login
uvicorn app.main:app --reload --port 8080
ngrok http 8080
# Cloud Run
gcloud builds submit \
--config=cloudbuild.yaml \
--substitutions=_GCS_BUCKET=你的-bucket
API 端點:/health、/store/info(看已索引文件數與 state)、/webhook。
目前限制與注意事項(作者自陳)¶
/store/info未做認證:production 前要加保護。- Session in-memory:Cloud Run 多實例會丟資料;要
min-instances=0必須換 Firestore。 - 沒有刪除流程:使用者無法透過 LINE 刪自己的文件。
- 沒有 quota / rate limit per user:被 spam 上傳會吃掉所有人額度。
- 不支援 audio / video:Gemini File Search 限制。
- LINE access token 30 天會過期:要 rotation 或申請長期 token。
- 無 license:repo 沒
LICENSE檔,引用前要主動問作者授權方式。
研究價值與啟示¶
關鍵洞察¶
- Managed RAG 已可取代多數自架 vector DB 場景:作者 CLAUDE.md 第一條設計決策直接寫「Do NOT add ChromaDB / FAISS / pgvector — that defeats the point」。這個立場呼應 Google 把 chunking + embedding + indexing 包成 service 的策略——對 PoC 與中小流量場景,自架 vector DB 的工程價值正在快速縮水。對照 [[rag-anything]] 那種「全套 self-host」與本研究「全套 managed」是同一光譜的兩端。
- 單一 store + metadata_filter 做多租戶是個聰明的取捨:N 個使用者開 N 個 store 操作成本高(quota、生命週期、刪除),共用 store + server-side filter 的設計把運維成本壓到極低。代價是 quota 共享、需要對抗 prompt injection(讓使用者繞過 filter)。對 LINE / Discord / Slack 這類「每個 user ID 都是已驗證身分」的場景特別合適。
google-genaivsgoogle-generativeai是兩個不同的 SDK:作者特別在 CLAUDE.md 提醒——許多人會誤裝舊版。新 SDK (google-genai) 是 google-deepmind 端整併後的官方版,File Search API 只在新 SDK 出現。這個提醒值得寫進任何接 Gemini 的 repo。- 非同步索引 + push notification 是 LINE Bot RAG 的必要模式:LINE reply token 30 秒會 expire,但建索引動輒 30 秒到 5 分鐘。作者用 FastAPI BackgroundTasks + LINE
push_message解這個問題,是值得抄的 pattern。對 Discord / Slack bot 同樣適用(webhook 都有類似的 timeout 限制)。 - CLAUDE.md as 設計決策契約:這個 repo 的 CLAUDE.md 是「給 AI 看的 ARCHITECTURE.md」典範——明確標註「Do NOT undo without asking」的設計決策、API call shape 範本、未完成事項清單。對 vibe-coding 場景,這種寫法可以大幅減少 AI 改動時的破壞性。值得提取成 CLAUDE.md 寫作 template。
gemini-embedding-2是多模態同向量空間:文字 + 圖片 + PDF 一起 embed 到同一空間(README 標 "5 種模態"),這意味著「傳圖找 PDF」、「傳 PDF 找圖」這類 cross-modal query 是免費送的,不需要再做 captioning 中介層——對比 [[rag-anything]] 為了做 cross-modal 還要拉 VLM 生 caption + 建多模態 KG,managed embedding 的工程成本省非常多(但代價是 black-box、模型 lock-in、無法離線)。
與其他研究的關聯¶
- 與 [[rag-anything]]:同一問題的兩種光譜端解法。RAG-Anything 走自架 + multimodal KG + Vector-Graph fusion 的學術深度路線;本研究走 fully managed + 只用 metadata_filter 的工程便利路線。同時讀完,能準確判斷專案要走哪條。
- 與 [[ai-agents-for-beginners]]:本研究實作的「multimodal query + cross-modal embedding」正好是 Microsoft 課程第 5 / 12 / 13 課的 Google 對應方案。對學習者來說是 Microsoft Agent Framework 之外的對照組。
- 與 [[ramp-ai-agents]]、[[appflowy]] 等 AI 應用研究:屬於同樣的「把新 AI 能力包成可用產品」族群,本案最小規模、最直接,適合作為「想做 LINE/Discord/Slack RAG bot」的起手 template。
- 與 [[why-your-ai-is-dumbing-down]] 的 context engineering:本研究示範了「retrieval 端的 context 是 Google 端建構好的」這個全託管路線。對使用者來說好處是不用煩惱 chunking 策略,壞處是無法檢視/控制 Google 怎麼切、怎麼排——對需要可審計性的場景必須慎用。
- 對「教 AI 寫 code」的人:CLAUDE.md 寫法值得直接 fork 來改。建議放在 [[learn-claude-code]]、[[claude-md-improver]](如果存在)這條學習鏈上一起讀。