RAG 最適合配一張圖。這頁把 Dify 知識庫的真實架構畫清楚:它其實存「兩個庫」(Postgres 文字 + Weaviate 向量),建庫與查詢怎麼跨兩庫,以及 RAG 對話流程裡最容易漏、卻是命脈的那一條「上下文」線。全部照真實自架環境整理。
flowchart TB
subgraph BUILD["建庫(上傳當下,做一次)"]
DOC["📄 文件
PDF / Word / Excel"] --> CH["切塊 chunk"] --> EM["bge-m3
算成向量"]
end
EM --> PG[("🗄️ Postgres
document_segments
文字 content + index_node_id")]:::pg
EM --> WV[("🧭 Weaviate
1024 維向量 + doc_id")]:::wv
subgraph QUERY["查詢(每次提問)"]
Q["🙋 問題"] --> QE["bge-m3 算向量"] --> SR["找最近 top-k → doc_id"]
end
WV -.同一把 id.-> SR
SR -->|"用 id 回撈文字"| PG
PG -->|"content 當小抄"| LLM["🤖 LLM
照文件回答 + 附出處"]:::r
classDef pg fill:#e5e9f0,stroke:#475569,color:#1e293b
classDef wv fill:#fef3c7,stroke:#d97706,color:#78350f
classDef r fill:#dcfce7,stroke:#16a34a,color:#14532d
Postgres 存真正的文字(內容真相來源)、Weaviate 存向量(語意搜尋),靠 index_node_id ↔ doc_id 對應。查到向量卡片,再回文字庫拿內容 —— 像「按語意排的索引卡」找到「圖書館的書」。
| pgvector(一個庫) | 專用向量庫(Weaviate / Qdrant / Milvus) | |
|---|---|---|
| 架構 | 向量 + 文字同在 Postgres | 向量獨立一個服務 |
| 運維 | ✅ 簡單,一個 DB 顧到底 | 多一個服務要顧 |
| 規模 / 效能 | 中小量夠用 | 大量、高並發、ANN 進階功能強 |
| 切換方式 | VECTOR_STORE=pgvector / weaviate / qdrant…(一個環境變數) | |
| 適合 | 單位內用、量可控 | 多租戶、要極致檢索效能 |
同一套 RAG 邏輯,底層向量庫是可抽換的零件。這台 demo 用 Weaviate;要跟既有系統統一也可改成 pgvector(需重建索引)。
flowchart TB Q(["🙋 非營利幼兒園費用?"]):::q R["🔎 知識檢索
(TEST 知識庫)"]:::proc C{"LLM 的『上下文』
接了知識檢索嗎?"}:::dec A1["❌ 沒接 + 無約束
用舊知識亂編
『以中國大陸為例…』"]:::bad A2["⚠️ 加『禁止編造』但上下文空
『文件裡查不到』"]:::warn A3["✅ 上下文接 result
『每月 3,000 元』+ 出處"]:::good Q --> R --> C C -->|沒接| A1 C -->|接了但沒給內容| A2 C -->|接上 result| A3 classDef q fill:#dcfce7,stroke:#16a34a,color:#14532d classDef proc fill:#dbeafe,stroke:#2563eb,color:#17335e classDef dec fill:#ede9fe,stroke:#7c3aed,color:#4c1d95 classDef bad fill:#fdecea,stroke:#c0392b,color:#7f1d1d classDef warn fill:#fff3e0,stroke:#a85a00,color:#7c2d12 classDef good fill:#dcfce7,stroke:#16a34a,color:#14532d
開始 → 知識檢索 → LLM → 回覆。最容易漏的坑是——知識檢索撈到了,但 LLM 節點的「上下文」欄位是空的,撈回的塊沒進 LLM 的 prompt。把 LLM 的「上下文」設成「知識檢索 / result」,那條線才通。沒接就「查不到」甚至亂編;接上才「照文件答 + 附出處」。
| 存哪 | 存什麼 |
|---|---|
Postgres · datasets | 知識庫(名稱、索引方式 high_quality、embedding = bge-m3) |
Postgres · documents | 每份文件(狀態、字數、切了幾塊) |
Postgres · document_segments | 每一塊:content 文字 + position + tokens + index_node_id + hit_count |
Weaviate · Vector_index_<dataset> | 每一塊的 1024 維向量 + doc_id(= index_node_id)+ text 副本 |
hit_count 就是「檢索次數」的來源——每塊被撈到幾次,DB 有記,是驗證「真的走了檢索」的鐵證。
📚 回課綱總表 →