你在網頁打一句話,背後有 13 個容器在協作。這頁把 Dify 自架的完整組件架構、一次對話的生命週期、以及 RAG 文件怎麼變成可查的知識,一次畫給你看——全部照真實跑起來的環境整理,不是示意。
flowchart TB U(["🖥️ 瀏覽器 · 使用者"]):::result NG["nginx
反向代理 · 對外入口"]:::proc subgraph APP["應用層"] direction TB WEB["web
Next.js 前端 UI"]:::proc API["api ⭐
對話邏輯 · Agent Loop(ReAct)"]:::proc WSK["api_websocket
即時串流推送"]:::proc WK["worker
Celery 非同步任務"]:::proc WB["worker_beat
排程"]:::proc end subgraph EXEC["外掛 / 執行層"] direction TB PD["plugin_daemon
模型 & 工具外掛執行"]:::proc SB{"sandbox
程式碼節點安全執行"}:::decision SP{"ssrf_proxy
工具連外安全代理"}:::decision end subgraph STORE["資料層"] direction TB PG[("postgres
app · 對話 · 訊息 · 步驟")]:::infra RD[("redis
快取 · Celery broker")]:::infra VDB[("weaviate
向量庫 · RAG")]:::infra end subgraph EXT["外部能力"] direction TB LLM["推理服務
Ollama / 雲端 API"]:::data TOOLS["工具
搜尋 · 網頁讀取 · 自訂 API"]:::data end NET(["🌐 網際網路"]):::result U -->|HTTPS| NG NG --> WEB NG --> API NG --> WSK API --- PG API --- RD API -->|要用模型 / 工具| PD API -->|程式碼節點| SB WK --- RD WK -->|RAG 建索引| VDB WK --> PD API -->|檢索| VDB PD -->|推論| LLM PD -->|呼叫工具| TOOLS TOOLS --> SP SP -.安全連外.-> NET LLM -.結果.-> PD PD -.結果回饋.-> API classDef proc fill:#dbeafe,stroke:#2563eb,stroke-width:2px,color:#17335e classDef data fill:#fef3c7,stroke:#d97706,stroke-width:2px,color:#78350f classDef decision fill:#ede9fe,stroke:#7c3aed,stroke-width:2px,color:#4c1d95 classDef result fill:#dcfce7,stroke:#16a34a,stroke-width:2px,color:#14532d classDef infra fill:#e5e9f0,stroke:#475569,stroke-width:2px,color:#1e293b style APP fill:#f5f8ff,stroke:#cbd5e1,color:#475569 style EXEC fill:#faf7ff,stroke:#cbd5e1,color:#475569 style STORE fill:#f8fafc,stroke:#cbd5e1,color:#475569 style EXT fill:#fffdf5,stroke:#cbd5e1,color:#475569
重點:api 是大腦,Agent Loop 住在這;plugin_daemon 是它伸出去接「模型」和「工具」的手;真正回答的是外部的推理服務(Ollama/雲端),不是某顆 GPU 自己。
flowchart LR A(["① 使用者送出
「台北今天天氣」"]):::result B["② api 收到
啟動 Agent Loop"]:::proc C{"③ 想:該做什麼?"}:::decision D["④ 呼叫工具
經 plugin_daemon"]:::proc E["⑤ 觀察結果
塞回上下文"]:::data F["⑥ 呼叫模型
經推理服務生成"]:::proc G(["⑦ 回答 + 來源"]):::result A --> B --> C C -->|需要即時資料| D --> E --> C C -->|夠了,生成答案| F --> G classDef proc fill:#dbeafe,stroke:#2563eb,stroke-width:2px,color:#17335e classDef data fill:#fef3c7,stroke:#d97706,stroke-width:2px,color:#78350f classDef decision fill:#ede9fe,stroke:#7c3aed,stroke-width:2px,color:#4c1d95 classDef result fill:#dcfce7,stroke:#16a34a,stroke-width:2px,color:#14532d
這個「想 → 做 → 看 → 再想」的迴圈就是 Agent 的靈魂,一圈圈跑在 api 裡,直到有答案或撞迭代上限。帶工具比純聊天慢,就是因為它來回好幾圈。
flowchart LR DOC(["📄 上傳文件
PDF · Word · 網頁"]):::result CHUNK["切塊
worker 處理"]:::proc EMB["算向量
embedding 模型"]:::data V[("存進 weaviate
向量庫")]:::infra Q(["🙋 使用者提問"]):::result QEMB["問題也算成向量"]:::data RET["檢索:找語意最近的幾塊"]:::proc ANS(["塞進 prompt → 模型照小抄回答"]):::result DOC --> CHUNK --> EMB --> V Q --> QEMB --> RET V --> RET --> ANS classDef proc fill:#dbeafe,stroke:#2563eb,stroke-width:2px,color:#17335e classDef data fill:#fef3c7,stroke:#d97706,stroke-width:2px,color:#78350f classDef result fill:#dcfce7,stroke:#16a34a,stroke-width:2px,color:#14532d classDef infra fill:#e5e9f0,stroke:#475569,stroke-width:2px,color:#1e293b
建索引(上傳當下做一次)由 worker 非同步處理;查詢(每次提問)由 api 去 weaviate 撈最相關的幾塊當「小抄」。注意 embedding 也要一個模型——雲端不一定有,本機常用 bge-m3。
| 容器 | 層 | 職責 |
|---|---|---|
nginx | 入口 | 反向代理,把請求分派給 web / api |
web | 應用 | Next.js 前端,使用者看到的介面 |
api ⭐ | 應用 | 對話邏輯、Agent Loop(ReAct 迭代)、檢索——整個平台的大腦 |
api_websocket | 應用 | 即時串流推送(邊生成邊顯示) |
worker | 應用 | Celery 非同步任務(RAG 建索引、批次) |
worker_beat | 應用 | 排程任務 |
plugin_daemon | 執行 | 模型供應商外掛、工具外掛的執行環境 |
sandbox | 安全 | 程式碼節點的隔離執行(不讓任意 code 碰主機) |
ssrf_proxy | 安全 | 工具連外時的安全代理,擋 SSRF 攻擊 |
db (postgres) | 資料 | app 設定、對話、訊息、agent 步驟紀錄 |
redis | 資料 | 快取 + Celery 的訊息 broker |
weaviate | 資料 | 向量資料庫,RAG 的知識存這裡 |
ollama-bridge | 外部 | 把容器接到只聽 127.0.0.1 的本機 Ollama(socat 轉發) |
📚 回課綱總表 →