目錄

絕境長城之外:以 Firestore vector search 打造低成本、高效的雲端 RAG 應用

RAG(Retrieval Augmented Generation) 是一套 AI framework,能夠在不需要重新訓練 LLM 的前提下,讓開發者得以新增其他的外部資訊,以這些新增的資訊來改善 LLM 回答的精準度。在 2026 的今天已經是一項廣為人知的技術了。

整套概念大概是這樣的:先將要新增的外部資訊(希望 LLM 能夠回答的資料)用 embedding model 向量化後儲存,在使用者輸入 prompt 之後,透過 embedding model 將使用者輸入的 prompt 向量化,拿來跟之前已經存好的向量化資訊做比對,取出最相近的數個資料,再透過 LLM 整合拿回來的資訊與回答,再回覆給使用者。透過這個方式可以讓 LLM 回答出各種開發者整合進去的知識而不需要重新訓練。

我最近利用 RAG 開發了一個能用《權力遊戲:冰與火之歌》的台詞來回答我今天要不要翹掉重訓的 AI 機器人,這個專案叫 “Iron Counsel” ,專案目標是:

  1. 前端介面使用 Telegram Bot 方便我隨時玩這個小專案
  2. RAG 系統架設到雲端,我不打算用自己的電腦開機開整天,還要處理麻煩的網路連線以及安全問題
  3. 既 2.,我打算設個白名單,自用或者讓少數的親朋好友玩,避免流量被太大我的帳單會爆炸
  4. 雙語言,中英支援
  5. 低成本

這個專案的程式碼可以在我的 GitHub 找到,這篇主要是做一些概念的解釋,以及從架構的角度來解釋整個專案的技術選型,運作方式以及實作機制。


概念解釋

和傳統的關鍵字搜尋不同的是,向量化搜尋並非尋找和搜尋條件完全一致的資料。而是透過將每一筆資料都分別轉換成多維度的向量,在搜尋時透過運算來比對向量和搜尋條件之間的相似度,找到最接近的數個回答。

Embedding Model

將資料向量化轉換成多維度向量的模型,每種 embedding model 對各種不同的資料類型會有不同的支援度,有些支援多語言有些只支援單語言,有些支援圖片有些只支援文字…。不同的 embedding model 生成的向量維度也可能不同。 在選擇 embedding model 時必須根據需求選擇,而且在做前期資料處理以及後續要向量化使用者 prompt 的時候必須要用同一個 embedding model 來做轉換,否則向量化搜尋在做比對的時候會產生偏差。

低成本雲端 RAG 架構 & 技術選型

第一階段:資料煉金術 (The Ingestion Pipeline)

Ingestion Pipeline 的主要目的是將資料相量化之後儲存,以便之後可以拿來比對使用者輸入的 prompt 取得最相近的內容資訊。

在資料進入雲端之前,我選擇在自己的電腦完成最重的體力活。MacBook M1 以上的 CPU 透過較為輕量的 embedding model 來將資料向量化那叫一個輕輕鬆鬆XD

  • 本地向量化 (Local Embedding): 我開發了一個 ingest.py 腳本。不透過調用昂貴的雲端 API,而是直接利用 MacBook 的 CPU,透過 FastEmbed (ONNX) 將 2,000 多條 Game of Thrones 劇本台詞轉換為向量。
  • 脫鉤上傳: 生成 vectors.json 後,再批次上傳到 Firestore vector database。
  • Q&A: 為什麼不在雲端做?因為本地運算不花錢!這叫「離線預處理」,能確保雲端只負責最核心的儲存與查詢。

Embedding Model 選擇

為什麼選用 paraphrase-multilingual-MiniLM-L12-v2?

  • 多語言支援 (Multilingual): 我想要一個中英文都通的機器人,而這個模型能處理中英雙語,語義對齊上表現得很棒。
  • 專案使用者數量不多,我不需要去選用第三方以 token 計費的 embedding model API 來平衡負載量,那需要花更多預算。
  • 輕量化 (Tiny but Mighty): 它的維度只有 384 維。
    • 維度越小,Firestore 的儲存成本越低,查詢速度越快。
    • 相比於 OpenAI 的 1536 維模型,它在 CPU 上的運算速度極快,非常適合在沒有 GPU 的 Cloud Run 容器裡執行。
  • ONNX 兼容性: 透過 FastEmbed,這個 model 能以 ONNX 格式執行。就不需要安裝笨重的 PyTorch ,從而做到讓容器體積更小,啟動速度(Cold Start)更快。

Firestore 向量與歷史資料庫

  • 向量檢索的實踐 (Vector Store):Firestore 支援 KNN 向量搜尋功能。實作上我在 local 透過 embedding model 將台詞轉換為 384 維度的向量,再將這些向量和台詞上傳到 Firestore。在接收到使用者發出的 prompt 時,透過在 Firestore 執行 KNN 向量比對,就能抓出與使用者的 prompt 最相關的數個台詞。例如說,即使你沒提到「龍」,只要你的語義跟「強大的武力」相關,Firestore 也許就能幫你抓出丹妮莉絲的台詞。
  • 對話記憶的持久化 (Chat History): 除了向量台詞,專案還實作了利用 Firestore 儲存每一位白名單使用者的對話紀錄。透過子集合(Sub-collections)的設計,能以極低的延遲提取最近 10 次的對話內容,並將其注入到 LLM 的 Prompt。這個專案能夠以這個方式具備長期記憶,它會記得你兩分鐘前才剛抱怨過老闆。
  • 為什麼不選專門的向量資料庫(如 Pinecone)?因為在這種規模下,Firestore 的「一站式服務」能讓我們在同一個 ACID 交易空間內完成向量檢索與紀錄寫入。減少了一次網路跳轉(Network Hop)。這個選擇的考量主要出於延遲的高低與較維護的代價。

第二階段:執行時期 (The Runtime)

智商與速度 — LLM (Groq)

在選 LLM 的時候我考慮過也測試過好幾個不同的選項,最後選擇使用 Groq 搭配 Llama 3.3 70B。

  • 對 RAG 專案來說,LLM 不需要"夠大",因為真正核心的資料是開發者向量化後儲存以提供比對的資料,而不是 LLM。LLM 在這個情境中只要回答得夠快就可以了。Groq 的 LPU (Language Processing Unit) 架構提供了飛快的推論速度。當一般的 GPU 還在載入模型權重時,Groq 已經噴出了上百個 Token。
  • 模型選型:Llama 3.3 70B: 我需要一個能支援中英雙語語境,還能執行指定人設的模型。Llama 3.3 70B 的推理能力與 GPT-4 很接近,而且它的反應速度在 Groq 的加持下真的非常快。
  • 成本與效能的 Pareto 效率: Groq 目前對開發者非常!!非常!!非常的慷慨!!能讓我在不支付太多(甚至量少的話幾乎沒有) API 費用的情況下,享受到當今開源模型界高度推崇的強大的邏輯推理能力。

LangChain

LangChain 在整個專案中負責的是協調使用者、embedding model 和 LLM 之間的對話。 我用了 LangChain 的 Embeddings 介面封裝的 FastEmbed。當使用者問:「我該喝這杯酒嗎?」,整套流程會像這樣:

  1. LangChain 呼叫 FastEmbed 將這句話轉化為一個 [0.12, -0.05, …] 的 384 維陣列。
  2. LangChain 接著把這個陣列交給 Firestore 進行向量比對。
  3. LLM 透過 LangChain 拿到的回應就會是與使用者問題真正相關的台詞。

GCP Cloud Run

  • 自動縮減至零 (Scale-to-Zero): 我選擇 Google Cloud Run。因為這機器人一天可能只會被呼叫十幾次,Cloud Run 只有在請求進來時才會計費,平常沒人用時,帳單上的數字就是 $0。如果有大量的使用者那用 Cloud Run 就不適合了,cost 過高。
  • 使用者數量少,不需要使用 GKE 常駐,那會需要維護複雜的 cluster。
  • GCP 強大的生態系:GCP 包含了 Firestore, Cloud Run, 和 Artifact 這些一站式的服務,整套架在上面當我需要看 log、找資訊的時候不需要轉來轉去,而且自動化從 Artifact 取得最新的 image 來跑很方便。

CI/CD: Terraform & GitHub Actions

  • Infrastructure as Code (IaC): 用 Terraform 來定義所有的雲端資源。從 Firestore 的索引配置、Secret Manager 的金鑰儲存到 Cloud Run 的權限設定,全部寫成 HCL 檔案。這是為了「可重複性」以及降低維運的複雜度。如果有天我想把這個機器人搬到另一個專案,我只需要 terraform apply,五分鐘內一切就能原地重建。或者我想要一次修改 Cloud Run 的數量上限以及其他各種設定,我只要把檔案改完再 apply 一次就能將設定全部更新,也能避免手動去點介面的時候可能會出現的人為失誤。
  • CI/CD 與環境變數管理: 透過 GitHub Actions 來實現全自動化的部署流程。當 push 程式碼時,Action 會自動構建 Docker 映像檔並推送到 Artifact Registry。
  • 環境變數的安全性: 將 Telegram Token 和 Groq API Key 儲存在 GCP Secret Manager 中,並透過 Terraform 授權給 Cloud Run 的 Service Account。在 GitHub Actions 的部署腳本中,操控這些環境變數以確保敏感資訊永遠不會出現在 Log, source code 或任何可能被其他人看到的地方。這種「最小權限原則 (Principle of Least Privilege)」的實踐非常重要。

Telegram Bot Webhook

  • 低傳輸量:Telegram bot 和後端系統的溝通有兩種方式:一種是 Long-polling,行為上類似於每隔一秒就派個信使去門口問一次:「有信嗎?有信嗎?」,效率極低而且不斷佔用網路頻寬。第二種就是 Webhook ,類似於一種被動觸發的機制,當收到訊息才會來後端尋求回應。
  • Scale to Zero: 當有人在 Telegram 裡向 bot 傳訊,Telegram 會主動發送一個 HTTPS POST 請求到我們的 Cloud Run 的 FastAPI 後端系統。完全符合我們「自動縮減至零」的要求:只有當有人向 bot 傳訊時,Cloud Run 伺服器才會醒來工作,其餘時間完全不消耗任何資源。
  • Token 驗證:為了防止「異鬼」入侵(未經授權的腳本惡意呼叫端點),我實作了 Secret Token 驗證機制,透過校驗 X-Telegram-Bot-Api-Secret-Token 這個 header,來確保每一則訊息都來自 Telegram。
  • 存取控制 (The Gatekeeper): 我在程式碼裡實作了 Telegram 使用者 ID 白名單。只有我確認過的使用者才能使用,有效防止路人耗盡我的預算。

全系統架構圖 (Architecture Blueprint)


結語

在這個專案成功地打造了一個極低成本的 RAG 應用,同時包含了幾個特性:

  • 開發與生產解耦: 匯入管線在本地,執行管線在雲端。
  • 穩健性:GCP 整個當掉或者被攻擊到不能用的機率非常低。
  • 安全性: 透過白名單機制、Telegram header 以及 Secret Manager 確保。
  • 合理的效能與低成本: 利用 Groq 的高速度與慷慨的額度、 Cloud Run 的彈性,在指定的使用者規模下,實現了合理的反應速度以及低成本(近乎零成本)的實作。

這個專案的設計原則:我要用最少的資源,設計出最合理且安全、穩定的架構。