知識庫查詢
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 平台設定:
- 建立 Knowledge Base — 上傳 PDF、文字檔、網頁等文件
- 設定 Embedding Model — 選擇向量化模型(如 OpenAI text-embedding-3-small)
- 在 Workflow 加入 Retrieve Knowledge Processor — 設定檢索策略與知識庫來源
- 發佈 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 說明。
下一步
- 串流回應處理 — 實作打字機效果
- Webhook 整合 — 自動化觸發 Workflow
- Knowledge Base 設定 — 上傳與管理知識庫文件