📌 本文重點
- 斷網環境可用本地 LLM+RAG 解決醫療輔助
- llama.cpp 搭配容器化可在受限硬體穩定推理
- 使用 OSS 向量庫打造可控、可回滾的 RAG pipeline
- 模型與知識庫需分版本管理確保合規與安全
在太空任務這種完全斷網、硬體受限且高合規的環境,NASA 的 CMO-DA 醫療助手用一套可攜、可封裝的本地 LLM+RAG 架構,解決了三個常見痛點:
- 不依賴雲端:模型推理與檔案檢索都在本地完成,沒有外部服務依賴。
- 可控資源與效能:透過 llama.cpp + 容器化(RamaLama 類工具),在 CPU/GPU 都受限的情況下仍能穩定跑推理。
- 安全與更新邊界清楚:醫療場景下做到知識庫可更新但可 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 pull→cmake→ 放入 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:功能更完整,適合資料量非常大但資源較充裕的內網環境。
醫療場景(也是典型高合規場景)的設計要點:
- Chunking 策略
- 以醫療指引、SOP 文件為單位,再切成 512–1024 tokens chunk,重點是維持語境完整。
- 加上 overlap(例如 128 tokens),避免答案跨 chunk 斷裂。
-
針對表格或 checklist,考慮以「row / section」為粒度,而不是固定 tokens。
-
Embedding 模型本地化
- 選一個能放進 GGUF 或支援 CPU/GPU 的 embedding 模型,例如
bge-large的量化版本或 MiniLM 類模型。 -
避免用雲端 embedding API,保證完全離線。
-
延遲與資源限制
- 查詢流程:Embedding → Vector search → Top-k 文件 → LLM 回答,每一步都要評估延遲。
- 太空艙/工廠場景中通常只有 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。
更新策略建議:
- 離線同步:
- 透過 USB / 專用線路將新模型(GGUF)與新向量庫 dump 帶到現場。
-
先在 staging 節點載入,跑自動化驗收測試(醫療 QA 集)。
-
Rollback 機制:
- 保留上一版模型映像與向量庫快照,決策錯誤時可以在幾分鐘內回退。
- 配置開關:只允許在非緊急任務時切換版本,避免任務中途變更行為。
2. 常見坑與最佳實踐
- 坑:只量化模型但忘記量化記憶體 footprint
- 即使用
q4_0,context 太大(例如 32k)時仍可能爆 RAM。 -
建議:先用
--ctx-size=4096做壓力測試,再逐步拉高。 -
坑:Chunk 太小導致回答失去上下文
- 斷網場景下沒有「多輪 call retriever 補充」的餘裕,chunk 要適度放大。
-
建議:醫療/工廠 SOP 至少維持 512–1024 tokens + 128 overlap。
-
坑:GPU 穿透配置錯誤導致 fallback 到 CPU
- 沒有設
resources.limits.nvidia.com/gpu或節點沒正確標記,pod 會跑在無 GPU 節點上。 -
建議:在 CI/CD 中加入簡單檢查:呼叫
nvidia-smi或llama.cppGPU info API,確認有 GPU 再部署。 -
最佳實踐:在高合規場景用「白名單指令 + RAG」模式
- 不允許模型「自由想像」,回答必須引用 RAG 檢索到的片段。
- prompt 設計中加入:「只能根據提供的文件回答,若無相關資訊請回答『資料不足』」,降低幻覺風險。
總結來說,NASA CMO-DA 的做法給了我們一個清晰模板:llama.cpp + 容器化 + OSS 向量庫 + 可控版本策略。只要把這套思路搬到你的工廠、船艦、礦場或企業內網,就能在斷網或高合規環境下建立一個可維護、可升級又安全的本地 LLM+RAG 助理。
🚀 你現在可以做的事
- 在 GitHub 搜尋並
git clone官方llama.cpp專案,編譯並測試本地推理- 使用 Docker 拉起 Qdrant,依照文中 Python 範例建立一個最小 RAG PoC
- 寫一份 Kubernetes
DeploymentYAML,把你的 GGUF 模型封裝成「模型即容器」,並在測試環境驗證 GPU 穿透与延遲表现


發佈留言