本地 LLM+RAG 架構:從 NASA CMO-DA 學部署

本地 LLM+RAG 架構:從 NASA CMO-DA 學部署

📌 本文重點

  • 斷網環境可用本地 LLM+RAG 解決醫療輔助
  • llama.cpp 搭配容器化可在受限硬體穩定推理
  • 使用 OSS 向量庫打造可控、可回滾的 RAG pipeline
  • 模型與知識庫需分版本管理確保合規與安全

在太空任務這種完全斷網、硬體受限且高合規的環境,NASA 的 CMO-DA 醫療助手用一套可攜、可封裝的本地 LLM+RAG 架構,解決了三個常見痛點:

  1. 不依賴雲端:模型推理與檔案檢索都在本地完成,沒有外部服務依賴。
  2. 可控資源與效能:透過 llama.cpp + 容器化(RamaLama 類工具),在 CPU/GPU 都受限的情況下仍能穩定跑推理。
  3. 安全與更新邊界清楚:醫療場景下做到知識庫可更新但可 rollback,模型版本可控且遵守合規要求。

💡 關鍵: 在完全斷網且高合規場景中,能本地推理並可回滾的 LLM+RAG 架構是可行且可維護的方案

下面用 NASA CMO-DA 的思路,拆成一個可直接套用的本地 LLM+RAG 模板。


重點說明

1. 為何選擇 llama.cpp + 容器化工具做本地推理

在 CMO-DA 這類場景,llama.cpp 有幾個關鍵優勢:

  • 硬體覆蓋廣:支援 x86、ARM、多種 GPU(CUDA、Metal、OpenCL 等),適合未知/多樣化載具(太空艙、工廠、船艦)。
  • GGUF 模型格式:支援量化(q4_0, q5_K 等),可以在有限記憶體上跑中大型模型。
  • 單一 binary,易封裝:搭配像 RamaLama 這種工具,把模型 + 推理程式封裝成容器映像,做到「模型即容器」。

實際好處:

  • 對你來說,部署路徑變成:git pullcmake → 放入 GGUF 模型 → 打包成 container,不需要大堆框架整合。
  • DeepSeek V4 已合併進 llama.cpp 主幹,你可以直接在本地跑 DeepSeek V4 GGUF,在推理品質與效能上有更好的選擇。

容器化工具(以 RamaLama 類工具為例)則負責:

  • 自動 GPU 偵測與穿透(在 Kubernetes / OpenShift 中把 GPU 資源暴露給容器)。
  • 統一啟動參數與模型路徑,讓模型像應用程式一樣可複製、可移動。

💡 關鍵: 透過 GGUF 量化與「模型即容器」封裝,能在受限硬體上穩定部署中大型本地模型

2. 斷網環境下的 RAG pipeline 設計

本地 RAG 的核心是:不要依賴雲端向量服務,一切用自架的 OSS 向量庫

常見 OSS 選擇:

  • Qdrant:Rust 實作,支援 HNSW、瀏覽器/邊緣友好,有好用 REST / gRPC API。
  • Milvus / Weaviate:功能更完整,適合資料量非常大但資源較充裕的內網環境。

醫療場景(也是典型高合規場景)的設計要點:

  1. Chunking 策略
  2. 醫療指引、SOP 文件為單位,再切成 512–1024 tokens chunk,重點是維持語境完整。
  3. 加上 overlap(例如 128 tokens),避免答案跨 chunk 斷裂。
  4. 針對表格或 checklist,考慮以「row / section」為粒度,而不是固定 tokens。

  5. Embedding 模型本地化

  6. 選一個能放進 GGUF 或支援 CPU/GPU 的 embedding 模型,例如 bge-large 的量化版本或 MiniLM 類模型。
  7. 避免用雲端 embedding API,保證完全離線。

  8. 延遲與資源限制

  9. 查詢流程:Embedding → Vector search → Top-k 文件 → LLM 回答,每一步都要評估延遲。
  10. 太空艙/工廠場景中通常只有 1–2 張 GPU,LLM 推理延遲是主瓶頸,可以:
    • 調低 max_tokens 回答長度。
    • 預先計算並緩存常見問答(FAQ)以降低實時查詢負擔。

💡 關鍵: 在離線場景中,512–1024 tokens chunk 加 128 overlap 能平衡上下文完整性與檢索效率

3. GPU 自動偵測與穿透:Kubernetes / OpenShift 配置

在 CMO-DA 中,他們透過類似 RamaLama 的工具,在 OpenShift 上做到:

  • 自動偵測節點是否有 GPU(透過標籤或 device plugin)。
  • 在 pod 內把 GPU 暴露給 llama.cpp

對你來說,可以簡化成 Kubernetes YAML 設計:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: local-llm
spec:
  replicas: 1
  selector:
    matchLabels:
      app: local-llm
  template:
    metadata:
      labels:
        app: local-llm
    spec:
      containers:
        - name: llama-cpp
          image: your-registry/llama-cpp-gguf:latest
          args:
            - "--model=/models/med-llm.gguf"
            - "--ctx-size=4096"
            - "--n-gpu-layers=35"  # **關鍵參數**:LLM 分配到 GPU 的層數
          resources:
            limits:
              nvidia.com/gpu: 1      # Kubernetes GPU 資源宣告
          volumeMounts:
            - name: models
              mountPath: /models
      volumes:
        - name: models
          persistentVolumeClaim:
            claimName: llm-model-pvc
      nodeSelector:
        nvidia.com/gpu.present: "true"  # **GPU 自動偵測:只排程到有 GPU 的節點

OpenShift 上同樣依賴 GPU Operator / device plugin,容器內不需要特殊程式碼,llama.cpp 會透過 CUDA / ROCm 自動偵測 GPU。


實作範例:Minimal 本地 LLM+RAG PoC

下面是一個可離線部署的小型 RAG 助理範例,組合:llama.cpp + DeepSeek V4 GGUF + Qdrant

1. 準備模型與 llama.cpp

# 取得最新 llama.cpp(含 DeepSeek V4 支援)
git clone https://github.com/ggml-org/llama.cpp.git
cd llama.cpp
git pull
cmake -B build
cmake --build build -j

# 假設你已下載 DeepSeek V4 GGUF 模型到 ./models/deepseek-v4-med.q4_0.gguf

2. 啟動本地 Qdrant 向量庫

docker run -d --name qdrant \
  -p 6333:6333 \
  -v qdrant_data:/qdrant/storage \
  qdrant/qdrant

3. 建立 RAG Pipeline(Python 範例)

import requests
from sentence_transformers import SentenceTransformer

# **Embedding 模型**:可替換為你量化後的本地模型
embed_model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")

QDRANT_URL = "http://localhost:6333"
COLLECTION = "med_docs"

def create_collection():
    body = {
        "vectors": {
            "size": 384,
            "distance": "Cosine"
        }
    }
    requests.put(f"{QDRANT_URL}/collections/{COLLECTION}", json=body).raise_for_status()

def index_documents(docs):
    vectors = embed_model.encode([d["text"] for d in docs])
    points = [{
        "id": i,
        "vector": vectors[i].tolist(),
        "payload": docs[i]
    } for i in range(len(docs))]
    requests.put(f"{QDRANT_URL}/collections/{COLLECTION}/points", json={"points": points}).raise_for_status()

def rag_search(query, top_k=3):
    vec = embed_model.encode([query])[0].tolist()
    body = {
        "vector": vec,
        "limit": top_k
    }
    res = requests.post(f"{QDRANT_URL}/collections/{COLLECTION}/points/search", json=body).json()
    return [r["payload"]["text"] for r in res]

# 初始化
create_collection()
index_documents([
  {"text": "若出現輕微頭痛且無其他症狀,建議先休息並補充水分。"},
  {"text": "若有持續胸痛或呼吸困難,應立即啟動緊急醫療流程。"}
])

print(rag_search("胸口痛怎麼辦?"))

4. 將檢索結果交給 llama.cpp

在本地,你可以用簡單的 HTTP wrapper 把 context 拼接給 llama.cpp--prompt

./build/bin/llama-cli \
  --model ./models/deepseek-v4-med.q4_0.gguf \
  --ctx-size 4096 \
  --n-gpu-layers 35 \
  --prompt "根據以下醫療指引回答問題:
[指引1]
若有持續胸痛或呼吸困難,應立即啟動緊急醫療流程。

問題:胸口痛怎麼辦?"

在正式專案中,你會把 Qdrant 的 top-k 結果串接到 prompt,組成完整 RAG 回答流程。


建議與注意事項

1. 醫療場景的安全邊界與 offline 更新策略

醫療、工業安全等場景,關鍵是 模型與知識庫的版本分離

  • 模型(LLM)版本:透過容器映像管理,例如在 tag 中寫明版本:med-llm:v1.2.0
  • 知識庫(向量庫 + 原始文件)版本:在 Qdrant collection 命名中加入版本:med_docs_v2024_06

更新策略建議:

  1. 離線同步
  2. 透過 USB / 專用線路將新模型(GGUF)與新向量庫 dump 帶到現場。
  3. 先在 staging 節點載入,跑自動化驗收測試(醫療 QA 集)。

  4. Rollback 機制

  5. 保留上一版模型映像與向量庫快照,決策錯誤時可以在幾分鐘內回退。
  6. 配置開關:只允許在非緊急任務時切換版本,避免任務中途變更行為。

2. 常見坑與最佳實踐

  1. 坑:只量化模型但忘記量化記憶體 footprint
  2. 即使用 q4_0,context 太大(例如 32k)時仍可能爆 RAM。
  3. 建議:先用 --ctx-size=4096 做壓力測試,再逐步拉高。

  4. 坑:Chunk 太小導致回答失去上下文

  5. 斷網場景下沒有「多輪 call retriever 補充」的餘裕,chunk 要適度放大。
  6. 建議:醫療/工廠 SOP 至少維持 512–1024 tokens + 128 overlap

  7. 坑:GPU 穿透配置錯誤導致 fallback 到 CPU

  8. 沒有設 resources.limits.nvidia.com/gpu 或節點沒正確標記,pod 會跑在無 GPU 節點上。
  9. 建議:在 CI/CD 中加入簡單檢查:呼叫 nvidia-smillama.cpp GPU info API,確認有 GPU 再部署。

  10. 最佳實踐:在高合規場景用「白名單指令 + RAG」模式

  11. 不允許模型「自由想像」,回答必須引用 RAG 檢索到的片段。
  12. prompt 設計中加入:「只能根據提供的文件回答,若無相關資訊請回答『資料不足』」,降低幻覺風險。

總結來說,NASA CMO-DA 的做法給了我們一個清晰模板:llama.cpp + 容器化 + OSS 向量庫 + 可控版本策略。只要把這套思路搬到你的工廠、船艦、礦場或企業內網,就能在斷網或高合規環境下建立一個可維護、可升級又安全的本地 LLM+RAG 助理。

🚀 你現在可以做的事

  • 在 GitHub 搜尋並 git clone 官方 llama.cpp 專案,編譯並測試本地推理
  • 使用 Docker 拉起 Qdrant,依照文中 Python 範例建立一個最小 RAG PoC
  • 寫一份 Kubernetes Deployment YAML,把你的 GGUF 模型封裝成「模型即容器」,並在測試環境驗證 GPU 穿透与延遲表现

留言

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *