實戰教學 · AI Integration

將 Azure AI Search 接成 Dify 外部知識庫:
使用 n8n 建立 Retrieval Adapter

PDF → Azure AI Search → n8n Retrieval Adapter → Dify External Knowledge → Dify App / Workflow
適用情境:企業已有 Azure AI Search,希望 Dify 直接使用既有搜尋結果

本文整理一條完整實作路徑:Data Source → Azure AI Search → n8n Retrieval Adapter → Dify External Knowledge → Dify App / Workflow。
適用情境:企業已經使用 Azure AI Search 管理文件與搜尋,希望 Dify 直接使用既有搜尋結果,而不是再把同一份文件重新匯入 Dify Knowledge,或是希望有更好的查找正確率與效果。

架構圖

1. 為什麼要這樣做?

Dify 本身已經有很方便的「知識庫(Knowledge)」功能。最簡單的 RAG 流程是:

PDF / Word / TXT
↓
Dify Knowledge
↓
Chunking
↓
Embedding / Index
↓
Retrieval
↓
LLM
↓
Answer

對一般應用或課程 Demo 來說,這非常方便。但企業裡常常已經有自己的搜尋或知識平台,例如:

  • Azure AI Search
  • Elasticsearch
  • OpenSearch
  • AWS Bedrock Knowledge Bases
  • 自建 Vector Database / RAG
  • 既有的企業搜尋系統

如果資料已經在 Azure AI Search 裡建立索引,再把同一份文件重新上傳到 Dify,會產生兩套知識庫:

同一份 PDF
↓
Azure AI Search
Dify Knowledge

這會帶來:

  • 資料重複
  • 索引重複
  • 更新要同步兩邊
  • 權限與治理較難維護

因此 Dify 提供 External Knowledge(外部知識庫) 機制。它的概念是:

Dify
↓
呼叫外部 Retrieval API
↓
企業既有搜尋 / RAG 系統
↓
取得相關 chunks
↓
Dify 把 chunks 交給 LLM
Dify 不一定要管理知識本身,它也可以只負責 AI Application / Workflow,而 Retrieval 交給企業既有系統。

2. Dify 內建知識庫 vs 外部知識庫

2.1 Dify 內建知識庫

Dify 的內建 Knowledge 適合:

  • 快速上傳 PDF / Word / TXT
  • 自動切 Chunk
  • 建立 Embedding
  • 建立索引
  • 設定 Top K / Score Threshold
  • 直接給 Chatflow / Workflow / Agent 使用

優點是非常快:

Upload→ Chunk→ Index→ Retrieval→ LLM

不用自己管理搜尋基礎設施。

2.2 Dify 外部知識庫

External Knowledge 則完全不同。Dify 不負責:

  • 儲存文件
  • Chunking
  • Embedding
  • Index
  • 更新外部資料

它只會在需要 Retrieval 時呼叫你的 API。架構變成:

User Question
↓
Dify
↓
External Knowledge API
↓
Azure AI Search
↓
Top K chunks
↓
Dify
↓
LLM
↓
Answer

Dify 官方文件也明確說明:

外部知識庫由外部系統自行管理,Dify 只有 Retrieval 存取能力,無法修改或管理外部內容。

3. 為什麼考慮 Azure AI Search?

如果只是要快速做 RAG,Dify Knowledge 已經很好用。Azure AI Search 的價值比較偏向「企業級 Retrieval」。它可以提供:

  • Full-text Keyword Search
  • Vector Search
  • Hybrid Search
  • Semantic Ranking
  • Metadata Filtering
  • Index / Indexer 管理
  • Azure Blob / SQL / SharePoint 等資料來源整合
  • Azure RBAC / Managed Identity
  • 企業治理與 Azure 生態系整合
  • Agentic Retrieval / Knowledge Source / Knowledge Base 等進階能力

所以兩者可以這樣定位:

  • Dify Knowledge:快速建立 RAG
  • Azure AI Search:企業級 Search / Retrieval
  • Dify External Knowledge:使用企業既有 Retrieval
  • n8n:API Integration / Adapter

這篇文章採用的架構是:

Azure AI Search = Retrieval Layer n8n = Retrieval Adapter Dify = AI Application / Workflow Layer

4. Azure AI Search 的「知識來源」與「知識庫」不要搞混

Azure AI Search 新版 Agentic Retrieval 中有兩個很容易混淆的名詞:

  • Knowledge Source(知識來源)
  • Knowledge Base(知識庫)

可以先用一句話記:

Knowledge Source = 資料從哪裡來。
Knowledge Base = 如何組織、查詢一個或多個 Knowledge Source。

大致關係:

PDF / Blob / SQL / SharePoint / Web
↓
Knowledge Source
↓
Knowledge Base
↓
Agentic Retrieval

Knowledge Base 可以進一步負責:

  • 多來源 Retrieval
  • Query Planning
  • 子查詢拆解
  • Ranking / Reranking
  • Answer Synthesis

但本篇的目標是:

讓 Azure AI Search 成為 Dify External Knowledge 的 Retrieval Backend。

所以暫時不需要 Azure AI Search Knowledge Base。我們只需要:

PDF
↓
File Knowledge Source
↓
Azure 自動建立的 Search Index
↓
Search REST API
↓
n8n
↓
Dify

5. 建立 Azure AI Search 的 File Knowledge Source

File Knowledge Source 目前仍帶有 Preview 性質
Azure Portal / Microsoft Foundry Portal 的功能呈現可能依區域與版本而不同。如果你的 Azure AI Search 介面已經可以直接建立 File 類型 Knowledge Source,可以依下列方式操作;若 Portal 沒看到 File 類型,可改從 Microsoft Foundry Portal、REST API 或 SDK 建立。

進入你的 Azure AI Search Service。選擇:

Agentic retrieval
→ Knowledge sources
→ Add knowledge source

選擇:

File

或畫面中標示為:

File (Indexed)

這裡建立的是:

Knowledge Source,不是 Knowledge Base。

5.1 建立 File Knowledge Source

設定名稱,例如:

course-files

依畫面要求設定:

  • Knowledge Source Name
  • Vectorizer / Embedding Model(如果啟用向量搜尋)
  • Authentication
  • 其他 Indexing 設定

建立完成後,上傳 PDF。例如:

course.pdf

Azure AI Search 會處理:

PDF
↓
文字抽取
↓
Chunk
↓
Embedding(如果有設定)
↓
Search Index

File Knowledge Source 的特點是:

不需要另外先建 Azure Blob Storage、Data Source、Indexer Pipeline,就可以直接把檔案放進 Azure AI Search。

Microsoft 文件目前列出的 File Knowledge Source 限制包含:

  • 單一檔案最大 50 MB
  • 一個 File Knowledge Source 最多 100 個檔案

6. 找出 Azure 自動建立的 Search Index

PDF 上傳並處理完成後,到:

Azure AI Search
→ Search management
→ Indexes

你會看到 Azure 建立的 Index。例如本次實驗建立出:

knowledgesource-1787392879659-index

接下來 Dify 並不是直接查 Knowledge Source。我們會直接查這個 Search Index:

Dify→ n8n→ Azure AI Search Index

7. 先用 Postman 測試 Azure AI Search REST API

在接 Dify 之前,務必先確認 Azure AI Search 本身能正常查詢。API:

POST https://<search-service>.search.windows.net/indexes('<index-name>')/docs/search.post.search?api-version=2026-04-01

例如:

POST https://azais2028.search.windows.net/indexes('knowledgesource-1787392879659-index')/docs/search.post.search?api-version=2026-04-01

7.1 Headers

api-key: <YOUR_AZURE_AI_SEARCH_KEY>
Content-Type: application/json

建議正式環境使用權限足夠的 Query Key / Entra ID,而不是把 Admin Key 寫死在 Workflow。

7.2 Request Body

先使用最簡單的 Keyword Search:

{
  "search": "AI相關的課程",
  "top": 5
}

如果成功,你會看到:

{
  "value": [
    {
      "@search.score": 2.9192886,
      "uid": "file-xxxxxxxx_0",
      "snippet": "Microsoft - AI102 ...",
      "snippet_vector": [
        ...
      ]
    }
  ]
}

這表示:

PDF→ Azure AI Search Index→ REST API

已經成功。

8. 不要把 Vector 全部傳回來

如果沒有指定 select,Azure 可能會把 snippet_vector 也一起傳回。

Embedding Vector 可能有數百到數千個數字,對 Dify 沒有用途,反而增加:

  • Response Size
  • Network Traffic
  • n8n 執行負擔

所以建議修改 Request:

{
  "search": "AI相關的課程",
  "top": 5,
  "select": "uid,snippet"
}

這樣回傳會乾淨很多:

{
  "value": [
    {
      "@search.score": 2.9192886,
      "uid": "file-xxxxxxxx_0",
      "snippet": "Microsoft - AI102 ..."
    }
  ]
}

9. 用 curl 測試

可以使用:

curl --location \
'https://<search-service>.search.windows.net/indexes('\''<index-name>'\'')/docs/search.post.search?api-version=2026-04-01' \
--header 'api-key: <YOUR_AZURE_AI_SEARCH_KEY>' \
--header 'Content-Type: application/json' \
--data '{
  "search": "AI相關的課程",
  "top": 5,
  "select": "uid,snippet"
}'
不要把真正的 Azure API Key 放到 GitHub、教材、部落格或公開對話中。
如果 Key 曾經公開貼出,應視為已外洩並立即 Rotate / Regenerate。

10. Dify External Knowledge API 規格

Azure AI Search 的 API 格式和 Dify 要求的格式不同。因此兩者不能直接相接。

Dify External Knowledge 要求你提供一個 Retrieval API:

POST {YOUR-ENDPOINT}/retrieval

例如你在 Dify 設定:

https://n8n.example.com/webhook

Dify 會自動呼叫:

https://n8n.example.com/webhook/retrieval
Dify 會自動在 API Endpoint 後面加 /retrieval。

11. Dify 呼叫 Retrieval API 的 Request

Dify 會送:

POST /retrieval
Content-Type: application/json
Authorization: ******

Body:

{
  "knowledge_id": "azure-ai-search",
  "query": "AI相關的課程",
  "retrieval_setting": {
    "top_k": 5,
    "score_threshold": 0.5
  }
}

欄位意義:

  • knowledge_id:外部知識來源識別碼
  • query:使用者查詢
  • top_k:最多回傳幾個 Chunk
  • score_threshold:最低相關度,0~1

knowledge_id 可以用來做 Routing。例如:

coursehrproducttechnical-doc

未來 n8n 可以根據 knowledge_id 決定要查哪一個 Azure AI Search Index。

12. Dify 要求的 Response

成功時必須:

HTTP 200

Response:

{
  "records": [
    {
      "content": "Microsoft - AI102 ...",
      "score": 0.95,
      "title": "課程資料",
      "metadata": {
        "uid": "file-xxxxxxxx_0"
      }
    }
  ]
}

主要欄位:

  • content:Retrieval 找到的文字 Chunk
  • score:0~1 的相關度
  • title:文件標題
  • metadata:任意 Metadata

注意:metadata 如果有傳,必須是 Object:

"metadata": {}

不要傳:

"metadata": null

否則可能造成 Dify Retrieval Pipeline 錯誤。查不到資料時:

{
  "records": []
}

13. 為什麼 Azure AI Search 不能直接接 Dify?

因為 Azure 回的是:

{
  "value": [
    {
      "@search.score": 2.9192886,
      "uid": "...",
      "snippet": "..."
    }
  ]
}

Dify 要的是:

{
  "records": [
    {
      "content": "...",
      "score": 0.95,
      "title": "...",
      "metadata": {}
    }
  ]
}

Request 格式也不同。因此中間需要一個 Adapter,負責:

Dify Request
↓
轉 Azure Search Request
↓
Azure AI Search
↓
轉 Dify Response

14. 為什麼使用 n8n 當 Retrieval Adapter?

當然可以自己寫:

ASP.NET CoreNode.jsPython FastAPIAzure Functions

但這個 Adapter 的工作其實非常簡單:

接 HTTP
↓
改 JSON
↓
呼叫 HTTP
↓
改 JSON
↓
回 HTTP

這正是 n8n 很適合的工作。而且 n8n 的 Webhook 不只能「非同步觸發」。Webhook Node 可以設定:

Respond:
Using "Respond to Webhook" Node

流程會:

收到 Request
↓
Workflow 執行
↓
呼叫 Azure AI Search
↓
轉換資料
↓
Respond to Webhook
↓
原本的 HTTP Client 收到 Response

所以對 Dify 來說:

n8n = 一個正常的同步 REST API

這讓我們可以完全不寫後端程式。

15. 最終 n8n Workflow

整體只需要幾個 Node:

Webhook
POST /retrieval
↓
檢查 Authorization
↓
HTTP Request
Azure AI Search
↓
Code
轉 Dify records[]
↓
Respond to Webhook

16. Step 1:建立 Webhook Node

新增:

Webhook

設定:

HTTP Method:
POST

Path:
retrieval

最重要的是:

Respond:
Using "Respond to Webhook" Node

不要選:

Immediately

因為 Dify 必須等待 Retrieval 完成後取得結果。

16.1 Test URL 與 Production URL

n8n 有兩個 URL:

Test URLProduction URL

開發測試時可以用 Test URL。正式給 Dify 使用時:

  • Activate Workflow
  • 使用 Production URL

例如:

https://n8n.example.com/webhook/retrieval

17. Step 2:Dify Authorization 驗證

Dify 會送:

Authorization: ******

你可以在 Webhook 後加一個 IF Node。檢查:

$json.headers.authorization

是否等於:

******

失敗時回:

HTTP 401

Body:

{
  "error_code": 1002,
  "error_msg": "Authorization failed."
}

Dify 文件建議的錯誤碼:

  • 1001:Authorization Header 格式錯誤
  • 1002:驗證失敗
  • 2001:Knowledge Base 不存在

這些是建議 Convention,不是 Dify 強制規定。

18. Step 3:HTTP Request 呼叫 Azure AI Search

新增:

HTTP Request

設定:

Method:
POST

URL:

https://<search-service>.search.windows.net/indexes('<index-name>')/docs/search.post.search?api-version=2026-04-01

例如:

https://azais2028.search.windows.net/indexes('knowledgesource-1787392879659-index')/docs/search.post.search?api-version=2026-04-01

18.1 HTTP Headers

加入:

api-key
<YOUR_AZURE_AI_SEARCH_KEY>

以及:

Content-Type
application/json

正式環境建議把 Azure Key 存在:

  • n8n Credential
  • Environment Variable
  • Secret 管理機制

不要直接寫死在 Node。

19. Step 4:把 Dify Query 送給 Azure

n8n Webhook 收到的資料通常會像:

{
  "headers": {
    "authorization": "******"
  },
  "body": {
    "knowledge_id": "azure-ai-search",
    "query": "AI相關的課程",
    "retrieval_setting": {
      "top_k": 5,
      "score_threshold": 0.5
    }
  }
}

所以 Azure HTTP Request 的 Body 可以設定:

{
  "search": "={{ $json.body.query }}",
  "top": "={{ $json.body.retrieval_setting.top_k }}",
  "select": "uid,snippet"
}

如果 n8n 版本的 JSON Expression 編輯器行為不同,也可以改成「Using Fields Below」:

search
{{ $json.body.query }}

top
{{ $json.body.retrieval_setting.top_k }}

select
uid,snippet

目的就是:

Dify query→Azure search
Dify top_k→Azure top

20. Step 5:Azure 回傳內容

Azure 會回:

{
  "value": [
    {
      "@search.score": 2.9192886,
      "uid": "file-xxxxxxxx_0",
      "snippet": "Microsoft - AI102 ..."
    }
  ]
}

接下來要轉成 Dify 的 records[]。

21. Step 6:加入 Code Node 轉格式

新增:

Code

JavaScript:

const items = $json.value ?? [];

const records = items.map((item, index) => ({
  content: item.snippet ?? "",
  score: Math.max(0.01, 1 - index * 0.05),
  title: "Azure AI Search",
  metadata: {
    uid: item.uid ?? ""
  }
}));

return [
  {
    json: {
      records
    }
  }
];

最後會得到:

{
  "records": [
    {
      "content": "Microsoft - AI102 ...",
      "score": 1.0,
      "title": "Azure AI Search",
      "metadata": {
        "uid": "file-xxxxxxxx_0"
      }
    },
    {
      "content": "...",
      "score": 0.95,
      "title": "Azure AI Search",
      "metadata": {
        "uid": "file-yyyyyyyy_0"
      }
    }
  ]
}

22. 為什麼不直接使用 @search.score?

這點非常重要。Azure AI Search 可能回:

@search.score = 2.9192886

但 Dify 定義的 score 要求是 0~1。所以不能直接:

score: item["@search.score"]

第一版 Lab 建議先使用:

1.00
0.95
0.90
0.85
...

這是一個「依排名產生的替代分數」,目的只是先把整條流程打通。因此在初始測試階段,建議 Dify 的 Score Threshold 先關閉或設很低。

正式 Production 如果要讓 Threshold 真正有意義,應再設計較合理的 Normalization / Reranking 策略。例如後續可研究:

  • Azure Semantic Ranker
  • Hybrid Search
  • 自訂 Score Normalization
  • 依 Search / Reranker Score 做校準
不要把 Azure 原始 @search.score 當成機率或 0~1 Confidence。

23. Step 7:Respond to Webhook

最後加入:

Respond to Webhook

設定:

Respond With:
JSON

Response Code:
200

Response Body:

{{ $json }}

因此整個 n8n Workflow 會同步回:

{
  "records": [
    {
      "content": "...",
      "score": 1,
      "title": "Azure AI Search",
      "metadata": {}
    }
  ]
}

24. 先不要接 Dify,先用 Postman 測 n8n

這一步非常重要。先直接測:

POST https://n8n.example.com/webhook/retrieval

Headers:

Authorization: ******
Content-Type: application/json

Body:

{
  "knowledge_id": "azure-ai-search",
  "query": "AI相關的課程",
  "retrieval_setting": {
    "top_k": 5,
    "score_threshold": 0.0
  }
}

如果 Postman 最後拿到:

{
  "records": [
    ...
  ]
}

代表:

Postman
↓
n8n Webhook
↓
Azure AI Search
↓
n8n Code
↓
Respond to Webhook
↓
Postman

整條 Adapter 已經成功。

25. Step 8:在 Dify 註冊 External Knowledge API

進 Dify:

Knowledge
→ External Knowledge API
→ Add an External Knowledge API

輸入:

Name:
Azure AI Search via n8n

API Endpoint:

https://n8n.example.com/webhook
不要填 /retrieval。

Dify 會自己加上 /retrieval,所以實際呼叫會變成:

https://n8n.example.com/webhook/retrieval

API Key:

<YOUR_DIFY_EXTERNAL_KB_KEY>

Dify 會把它送成:

Authorization: ******

儲存時 Dify 會測試連線,因此:

  • n8n Workflow 必須已 Activate
  • Production Webhook 必須能從 Dify Server 存取
  • HTTPS / DNS 必須正常
  • Self-hosted Dify 的 SSRF Proxy 設定不能擋住 n8n Domain

26. Step 9:建立 Dify External Knowledge Base

接著:

Knowledge
→ Connect to an External Knowledge Base

設定:

External Knowledge Name:
Azure Course Knowledge

選擇:

External Knowledge API:
Azure AI Search via n8n

External Knowledge ID:

azure-ai-search

這個值之後會送給 n8n:

{
  "knowledge_id": "azure-ai-search"
}

目前只有一個 Index 時,n8n 可以先忽略這個欄位。未來有多個 Knowledge Source / Index 時,可以拿它做 Routing:

knowledge_id = course
→ course-index

knowledge_id = hr
→ hr-index

knowledge_id = product
→ product-index

27. Step 10:測試 Dify Retrieval

建立完成後,可以直接在 Dify Knowledge 的 Retrieval Test 測:

AI相關的課程有哪些?

流程會變成:

Dify
↓
POST /retrieval
↓
n8n
↓
Azure AI Search
↓
找到 AI-102 等 Chunk
↓
n8n 轉成 records[]
↓
Dify

如果能看到 Azure AI Search 回來的 Chunk,就表示 External Knowledge 已經成功。

28. Step 11:放進 Dify Workflow / Chatflow

接下來就和一般 Dify Knowledge 一樣使用。例如:

User Question
↓
Knowledge Retrieval
↓
Azure AI Search External Knowledge
↓
Top K chunks
↓
LLM
↓
Answer

從 Dify Application 的角度看,這個 External Knowledge 和 Dify 自己的 Knowledge 使用方式幾乎沒有差別。但真正的資料和 Retrieval 都在 Azure。

29. 最後完整架構

完成後:

Azure
PDF
↓
File Knowledge Source
↓
Azure AI Search Index
↓
Search REST API
n8n
Webhook
↓
HTTP Request
↓
Adapter
↓
Response
Dify
External Knowledge
↓
Knowledge Retrieval
↓
Workflow / Chatflow / Agent
↓
LLM
Azure AI Search 負責「找資料」,n8n 負責「轉接 API」,Dify 負責「使用知識建立 AI 應用」。

30. 這個架構的優點

最大的優點是「責任分層」。

  • Azure:Knowledge / Search / Retrieval
  • n8n:Integration / Adapter / Routing
  • Dify:Prompt / LLM / Workflow / Agent / AI App

因此企業原本已經存在 Azure AI Search 時:

不需要把全部文件搬到 Dify,也不需要維護兩份索引。

31. 可以再往下升級的方向

目前 Lab 使用的是 Keyword Search,也就是:

{
  "search": "AI相關的課程"
}

這已經足以驗證整條 Integration。正式使用時可以進一步升級成:

Keyword + Vector
↓
Hybrid Search
↓
Semantic Ranker
↓
Top K

Azure AI Search 的價值也會在這裡更明顯。另外還可以擴充:

Dify knowledge_id
↓
n8n Switch
↓
HR
Course
Product
...
↓
不同 Azure AI Search Index

如此一個 n8n Retrieval Adapter 就可以服務很多個 Dify External Knowledge Base。

32. 常見問題

Q1:Azure AI Search Knowledge Base 要不要建立?

這個案例不需要。本篇:

File Knowledge Source
→ Generated Search Index
→ REST Search API
→ n8n
→ Dify

Azure AI Search Knowledge Base 是更上層的 Agentic Retrieval / Multi-source Orchestration 能力。

Q2:為什麼不直接 Azure AI Search → Dify?

因為 API Contract 不一樣。Azure:

{
  "value": [...]
}

Dify:

{
  "records": [...]
}

所以需要 Adapter。

Q3:一定要 n8n 嗎?

不用。可以換成:

ASP.NET Core Minimal API Azure Functions FastAPI Node.js API Management Policy

n8n 的優點是:

  • Low-code
  • Webhook 很方便
  • HTTP Request 很方便
  • JSON Transformation 容易
  • 可以同步 Respond
  • 很適合教學
  • 未來容易加 Routing / Logging / Auth / Retry

Q4:Dify 的 API Endpoint 為什麼不能填完整 /retrieval?

因為 Dify 會自動 append /retrieval。假設設定:

https://n8n.example.com/webhook

實際呼叫:

https://n8n.example.com/webhook/retrieval

如果設定成:

https://n8n.example.com/webhook/retrieval

就可能變成:

https://n8n.example.com/webhook/retrieval/retrieval

Q5:n8n Webhook 不是非同步 Trigger 嗎?

n8n Webhook 可以設定 Using "Respond to Webhook" Node。因此可以:

HTTP Request
↓
等 Workflow
↓
Respond to Webhook
↓
回給同一個 HTTP Client

這正適合做 Dify Retrieval API。

33. 官方文件

Dify:

  1. Connect to External Knowledge Base
  2. External Knowledge API

Microsoft:

  1. Azure AI Search:Knowledge Source Overview
  2. Azure AI Search:File Knowledge Source
  3. Azure AI Search REST API:Search Documents

34. 最後總結

如果只是快速做 RAG:

PDF→Dify Knowledge→LLM

最方便。

但如果企業已經有 Azure AI Search:

PDF→ Azure AI Search→ n8n Retrieval Adapter→ Dify External Knowledge→ LLM

更合理。因為這讓:

核心不是「哪個知識庫比較好」

而是把 Retrieval、Integration、AI Application
三個責任拆清楚。

Knowledge 留在企業既有的 Azure 架構裡,Dify 專心做 AI Application。