跳至主要内容
使用 Asgard RAG 知識庫進行智慧問答的完整範例

知識庫查詢

Asgard 透過 Knowledge Base 搭配 Retrieve Knowledge Processor 實現 RAG(Retrieval-Augmented Generation)功能,讓 AI 能夠根據您上傳的文件與資料回答問題。

運作原理

RAG 查詢完全在 Workflow 伺服端執行,對外的 API 介面與一般發送訊息完全相同:

使用者提問

Asgard API(相同端點)

Retrieve Knowledge Processor(從知識庫檢索相關內容)

LLM(結合檢索結果生成回答)

SSE 串流回應

您無需修改 API 呼叫方式,只需在 Workflow 中加入 Retrieve Knowledge Processor 並設定對應的 Knowledge Base,RAG 功能即可自動運作。

前置設定

在呼叫 API 之前,請先完成以下 Asgard 平台設定:

  1. 建立 Knowledge Base — 上傳 PDF、文字檔、網頁等文件
  2. 設定 Embedding Model — 選擇向量化模型(如 OpenAI text-embedding-3-small)
  3. 在 Workflow 加入 Retrieve Knowledge Processor — 設定檢索策略與知識庫來源
  4. 發佈 App — 取得 namespace 與 bot-provider-name

詳細設定步驟請參考 Knowledge Base 設定


問題結構建議

良好的問題結構能顯著提升知識庫的檢索準確率:

建議範例
使用具體關鍵字退款流程需要幾個工作天?
避免過於模糊的提問請告訴我所有資訊
單次聚焦單一主題產品 A 的保固期是多久?
提供適當背景脈絡我是企業用戶,請問合約續約的流程是?

cURL 範例

curl -X POST "https://api.asgard-ai.com/generic/ns/your-namespace/bot-provider/your-bot-provider/message/sse" \
-H "Content-Type: application/json" \
-H "X-API-KEY: your-api-key" \
-d '{
"customChannelId": "kb-query-channel-001",
"customMessageId": "kb-msg-001",
"text": "請問退款申請需要哪些文件?流程是什麼?",
"action": "NONE"
}'

JavaScript 範例

const BASE_URL = 'https://api.asgard-ai.com';
const NAMESPACE = 'your-namespace';
const BOT_PROVIDER = 'your-bot-provider';
const API_KEY = process.env.ASGARD_API_KEY;

/**
* 向知識庫提問並取得 RAG 回答
* @param {string} question - 使用者提問
* @param {string} channelId - 對話頻道 ID(同頻道可維持對話記憶)
*/
async function queryKnowledgeBase(question, channelId = 'kb-channel-001') {
const url = `${BASE_URL}/generic/ns/${NAMESPACE}/bot-provider/${BOT_PROVIDER}/message/sse`;

const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-KEY': API_KEY,
},
body: JSON.stringify({
customChannelId: channelId,
text: question,
action: 'NONE',
}),
});

if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}

const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
let fullAnswer = '';

while (true) {
const { done, value } = await reader.read();
if (done) break;

buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop() || '';

for (const line of lines) {
if (!line.startsWith('data:')) continue;
const jsonStr = line.slice(5).trim();
if (!jsonStr) continue;

try {
const event = JSON.parse(jsonStr);

if (event.eventType === 'asgard.message.delta') {
const delta = event.fact.messageDelta.message.text;
fullAnswer += delta;
// 即時顯示(打字機效果)
process.stdout.write(delta);
}

if (event.eventType === 'asgard.run.done') {
console.log('\n\n查詢完成');
return fullAnswer;
}
} catch (_) {}
}
}

return fullAnswer;
}

// 使用範例:連續提問(同一 channelId 維持對話記憶)
async function main() {
const channelId = `kb-session-${Date.now()}`;

console.log('問題 1:');
await queryKnowledgeBase('退款申請需要哪些文件?', channelId);

console.log('\n\n問題 2(追問):');
await queryKnowledgeBase('大概需要多少個工作天完成?', channelId);
}

main().catch(console.error);

Python 範例

import requests
import json
import os
import time

BASE_URL = "https://api.asgard-ai.com"
NAMESPACE = "your-namespace"
BOT_PROVIDER = "your-bot-provider"
API_KEY = os.environ.get("ASGARD_API_KEY")


def query_knowledge_base(question: str, channel_id: str) -> str:
"""
向 Asgard 知識庫提問並取得 RAG 回答。

Args:
question: 使用者提問
channel_id: 對話頻道 ID(同頻道可維持對話記憶)

Returns:
完整回答文字
"""
url = f"{BASE_URL}/generic/ns/{NAMESPACE}/bot-provider/{BOT_PROVIDER}/message/sse"

headers = {
"Content-Type": "application/json",
"X-API-KEY": API_KEY,
}

payload = {
"customChannelId": channel_id,
"text": question,
"action": "NONE",
}

full_answer = ""

with requests.post(url, headers=headers, json=payload, stream=True) as response:
response.raise_for_status()

for line in response.iter_lines():
if not line:
continue

decoded = line.decode("utf-8")
if not decoded.startswith("data:"):
continue

json_str = decoded[5:].strip()
if not json_str:
continue

try:
event = json.loads(json_str)
event_type = event.get("eventType")

if event_type == "asgard.message.delta":
delta = event["fact"]["messageDelta"]["message"]["text"]
full_answer += delta
print(delta, end="", flush=True)

elif event_type == "asgard.run.done":
print("\n")
break

except json.JSONDecodeError:
pass

return full_answer


if __name__ == "__main__":
channel_id = f"kb-session-{int(time.time())}"

questions = [
"退款申請需要哪些文件?",
"大概需要多少個工作天完成退款?",
"如果超過退款期限還能申請嗎?",
]

for i, question in enumerate(questions, 1):
print(f"\n問題 {i}{question}")
print("回答:", end="")
answer = query_knowledge_base(question, channel_id)
print(f"(共 {len(answer)} 字)")

解析包含知識庫來源的回應

當 Workflow 設定回傳知識庫來源資訊時,資料會包含在 asgard.message.complete 事件的 template 欄位中:

if (event.eventType === 'asgard.message.complete') {
const message = event.fact.messageComplete.message;

// 完整回答文字
const answerText = message.text;

// 知識庫來源(若 Workflow 有設定回傳)
const template = message.template;
if (template && template.sources) {
console.log('參考來源:');
template.sources.forEach((source, i) => {
console.log(` ${i + 1}. ${source.title}${source.url || source.fileName}`);
});
}
}
提示

template 欄位的內容結構取決於您在 Workflow 中的設定。詳細說明請參考 Message Template 說明


下一步