後端 SDK 使用指南
後端 SDK 是讓你的伺服器以可信端的角色與 Asgard Bot Provider 溝通的工具, 是 Backend Relay 模式的核心。本指南介紹後端語言 SDK 用法、以及後端中繼層的整體實作範式。
本頁專為採用 Backend Relay 模式的讀者撰寫 — 也就是「你的後端作為前端與 Asgard Edge Server 之間中繼層」的情境。其他 Pattern(Direct Connect / Workflow Auth / Hosted Embed)不需要後端 SDK。
如果你對 Pattern 還不熟悉, 請先閱讀 總覽與選型, 確認確實需要 Backend Relay 再回到本頁。
後端 SDK 是什麼
當你採用 Backend Relay 模式時,你的後端會成為前端與 Asgard Edge Server 之間的中繼層, 流程簡化如下:
後端 SDK 就是上方藍色節點 ③④ 用來與 Edge Server 溝通的工具(其餘步驟由你的後端自行實作)。完整流程的時序圖見 Pattern: Backend Relay — 架構圖。
語言支援現況
| 語言 | 套件 | 狀態 |
|---|---|---|
| Go | go.asgard-ai.com/asgard-sdk-go | ✅ 可用 |
| Node.js | @asgard-js/nodejs | ✅ 可用 |
| Java | 後端 Java SDK | 🔜 規劃中 |
| .NET | 後端 .NET SDK | 🔜 規劃中 |
| Python | 後端 Python SDK | 🔜 規劃中 |
若你使用的語言尚未有原生 SDK, 可以直接呼叫 Bot Provider 的 HTTP API(本質是 SSE / REST / Multipart 等標準協定)。請參考 Send Message API 介紹 取得完整的 endpoint、事件型別與 payload schema。
Asgard 的「後端 Node.js SDK」(@asgard-js/nodejs)是跑在你的伺服器(例如 Express / Fastify / Next.js Route Handler 的伺服器側), 用途是中繼前端到 Asgard。
這跟「前端 Javascript SDK」(@asgard-js/core / @asgard-js/react)完全不同。前端 SDK 跑在使用者瀏覽器中, 用途是渲染聊天 UI 與直連 Asgard 或你的後端。
兩者套件名稱、執行位置、用途都不同, 使用時請確認上下文。詳見 前端 SDK 使用指南。
SDK 完整指南
安裝
- Go
- Node.js
go get go.asgard-ai.com/asgard-sdk-go
npm install @asgard-js/nodejs
需要 Node.js 18+。後續所有 Node.js 範例皆以 TypeScript 撰寫; 接收 HTTP 請求的範例以 Express 樣式 (req, res) 示意 — Fastify / Next.js Route Handler / Hono 等 framework 寫法類似。
建立 Bot Provider Client
Bot Provider client 是與單一 Bot Provider 互動的入口, 提供 streaming、訊息發送、檔案上傳、自訂工具觸發等能力。
整個後端服務共用同一份 client 即可(client 設計為執行緒/併發安全), 無需每次請求都重建。Bot Provider API Key 從環境變數 / secrets manager 讀取, 絕對不要 hardcode 進程式碼。
- Go
- Node.js
import (
"os"
"go.asgard-ai.com/asgard-sdk-go/pkg/client"
)
// 從環境變數讀取設定,請勿 hardcode 機敏資訊到程式碼
var (
edgeServerHost = getEnvOrDefault("EDGE_SERVER_HOST", "https://api.asgard-ai.com")
namespace = os.Getenv("NAMESPACE")
botProviderName = os.Getenv("BOT_PROVIDER_NAME")
botProviderApiKey = os.Getenv("BOT_PROVIDER_API_KEY") // 從 secrets manager 注入
)
func getEnvOrDefault(key, defaultVal string) string {
if v := os.Getenv(key); v != "" {
return v
}
return defaultVal
}
// 建立 Bot Provider Client(整個後端共用一份即可)
bpClient := client.NewBotProviderClientWithConfig(&client.BotProviderConfig{
EdgeServerHost: edgeServerHost,
Namespace: namespace,
BotProviderName: botProviderName,
BotProviderApiKey: botProviderApiKey,
})
import { BotProviderClient } from '@asgard-js/nodejs';
// 從環境變數讀取設定,請勿 hardcode 機敏資訊到程式碼
const edgeServerHost = process.env.EDGE_SERVER_HOST ?? 'https://api.asgard-ai.com';
const namespace = process.env.NAMESPACE ?? '';
const botProviderName = process.env.BOT_PROVIDER_NAME ?? '';
const botProviderApiKey = process.env.BOT_PROVIDER_API_KEY ?? ''; // 從 secrets manager 注入
// 建立 Bot Provider Client(整個後端共用一份即可)
const bpClient = new BotProviderClient({
edgeServerHost,
namespace,
botProviderName,
botProviderApiKey,
});
SSE 串流
NewStreamer 對單則訊息建立 SSE 串流, 逐一接收事件, 使用結束務必 Close。事件型別與 payload schema 見 Send Message API 介紹。
- Go
- Node.js
import "go.asgard-ai.com/asgard-sdk-go/pkg/models"
// 組裝送往 Edge Server 的訊息
msg := &models.GenericBotMessage{
CustomChannelId: "channel-abc-123", // 對話識別,後續同 channel 訊息會串成一個 Conversation
CustomMessageId: "msg-001", // 訊息識別,用於去重 / idempotency
Text: "Hello",
Action: models.PostBackActionNone,
Payload: map[string]interface{}{ // 任意 JSON-serializable 資料,Workflow 內可透過 prevPayload.* 讀取
"user_id": "user-456",
},
}
// 建立串流(第三個參數可傳 options,通常 nil 即可)
stream, err := bpClient.NewStreamer(ctx, msg, nil)
if err != nil { /* ... */ }
defer stream.Close() // 必須關閉,避免連線洩漏
// 逐一處理事件。Next() 在串流結束或 ctx 取消時回傳 false
// 注意:asgard.run.error 不會走進 switch,而是讓 Next() 直接回 false;
// 發生錯誤時跳出迴圈後,從 stream.Err() 取得錯誤詳情
for stream.Next() {
event := stream.Current()
switch event.EventType {
case models.SseEventTypeRunInit: // Workflow 開始
case models.SseEventTypeMessageDelta: // AI 逐字回應
case models.SseEventTypeMessageComplete: // AI 一則訊息完成
case models.SseEventTypeToolCallComplete: // 工具呼叫完成
case models.SseEventTypeCompletionModelUsage: // LLM 用量
case models.SseEventTypeRunDone: // Workflow 結束
}
}
// 迴圈結束務必檢查 error,避免上游錯誤被吞掉
if err := stream.Err(); err != nil { /* ... */ }
import {
AsgardError,
PostBackActionNone,
SseEventTypeRunInit,
SseEventTypeMessageDelta,
SseEventTypeMessageComplete,
SseEventTypeToolCallComplete,
SseEventTypeCompletionModelUsage,
SseEventTypeRunDone,
type GenericBotMessage,
} from '@asgard-js/nodejs';
// 組裝送往 Edge Server 的訊息
const msg: GenericBotMessage = {
customChannelId: 'channel-abc-123', // 對話識別,後續同 channel 訊息會串成一個 Conversation
customMessageId: 'msg-001', // 訊息識別,用於去重 / idempotency
text: 'Hello',
action: PostBackActionNone,
payload: { // 任意 JSON-serializable 資料,Workflow 內可透過 prevPayload.* 讀取
user_id: 'user-456',
},
};
// 建立串流
const streamer = await bpClient.newStreamer(msg);
// 逐一處理事件。
// 注意:asgard.run.error 不會走進 switch,而是讓 for await 直接 throw;
// 發生錯誤時在 catch 區塊取得錯誤詳情(也可呼叫 streamer.err() 拿到同樣的物件)
try {
for await (const event of streamer) {
switch (event.eventType) {
case SseEventTypeRunInit: // Workflow 開始
case SseEventTypeMessageDelta: // AI 逐字回應
case SseEventTypeMessageComplete: // AI 一則訊息完成
case SseEventTypeToolCallComplete: // 工具呼叫完成
case SseEventTypeCompletionModelUsage: // LLM 用量
case SseEventTypeRunDone: // Workflow 結束
}
}
} catch (e) {
if (e instanceof AsgardError) { /* ... */ }
} finally {
streamer.close(); // 必須關閉,避免連線洩漏
}
把 SSE 串流接到 HTTP handler、轉發給前端、攔截事件做 side effects(寫 history、扣點、Human Handoff…)等完整 use case 整合範例, 見 Pattern: Backend Relay — 快速起步。
檔案上傳
UploadBlob 把檔案串流上傳到 Edge Server, 回傳含 blobId 的物件; 後續可將 blobId 放入 GenericBotMessage 的 blob 欄位讓 Bot 看到該檔案。
- Go
- Node.js
// 參數:ctx、channelId、檔案 reader、filename、MIME type 指標(nil 代表讓 Edge Server 自行偵測)
blob, err := bpClient.UploadBlob(ctx, channelId, fileReader, "filename.png", &mime)
if err != nil { /* ... */ }
// 取得 blob.BlobId 後,可放入後續訊息的 blob 欄位引用
import { createReadStream } from 'node:fs';
// 參數:channelId、檔案 { stream, filename, mime }(mime 省略則讓 Edge Server 自行偵測)
const blob = await bpClient.uploadBlob(channelId, {
stream: createReadStream('filename.png'),
filename: 'filename.png',
mime: 'image/png',
});
// 取得 blob.blobId 後,可放入後續訊息的 blobIds 欄位引用
把 HTTP
multipart/form-data解析後接到此 API 的完整 endpoint 範例, 見 Pattern: Backend Relay — 快速起步。
單發訊息(非串流)
SendMessage 同步等待 Workflow 跑完最終結果再回傳, 適合非面對使用者的場景(批次任務、server-side 排程):
- Go
- Node.js
// 注意:LLM 回應可能耗時數十秒,呼叫端要設好足夠的 timeout
resp, err := bpClient.SendMessage(ctx, msg, nil)
// resp 等同於 SSE 串流跑完後的彙整結果
// 注意:LLM 回應可能耗時數十秒,建構 client 時用 timeoutMs 設好足夠的 timeout(預設 300_000)
const reply = await bpClient.sendMessage(msg);
// reply 等同於 SSE 串流跑完後的彙整結果
自訂 HTTP Client
Bot Provider client 可自訂底層 HTTP 連線(用於分散式追蹤、metrics、retry policy 等), 把客製化的 HTTP client 實例傳進建構設定即可:
- Go
- Node.js
import (
"net/http"
"time"
"go.asgard-ai.com/asgard-sdk-go/pkg/client"
)
httpClient := &http.Client{
Transport: yourCustomTransport, // 例如 otelhttp.NewTransport(...) 加上 OpenTelemetry tracing
Timeout: 30 * time.Second, // 注意:SSE 是長連線,Timeout 不可設太短
}
bpClient := client.NewBotProviderClientWithConfig(&client.BotProviderConfig{
HTTPClient: httpClient,
EdgeServerHost: edgeServerHost,
Namespace: namespace,
BotProviderName: botProviderName,
BotProviderApiKey: botProviderApiKey,
})
Node.js SDK 底層使用全域 fetch,未提供 Go SDK 那樣的 HTTPClient 注入點。現階段可調整的選項只有:
headers: 靜態自訂 headertimeoutMs: 一般 REST 請求 timeout(SSE 串流不適用此 timeout, SSE 為長連線設計)
如需 OpenTelemetry tracing、metrics、retry policy 等 HTTP-level instrumentation, 請在呼叫端(例如 undici 全域 dispatcher)wrap, 或在外層 patch globalThis.fetch。
const bpClient = new BotProviderClient({
edgeServerHost,
namespace,
botProviderName,
botProviderApiKey,
headers: { 'x-trace-id': 'abc-123' }, // 靜態自訂 header
timeoutMs: 30_000, // 一般 REST 請求的 timeout
});
安全與部署注意事項
1. API Key 安全保管
- Bot Provider API Key 放在 secrets manager(AWS Secrets Manager / Vault / GCP Secret Manager)
- 絕對不要 寫死在程式碼或 commit 到版本控制
- 環境變數注入時也要避免在 Docker image / log 暴露
2. SSE 雙向長連線基礎設施
- 避免緩衝: 某些 API Gateway / CDN 預設會緩衝回應, 要明確關閉(
X-Accel-Buffering: nofor nginx) - 連線數: 預估同時上線使用者數量, 設定足夠的 file descriptor 上限與 Worker 數
- Idle Timeout: Load Balancer 的 timeout 要長於對話可能的閒置時間, 或實作 keepalive ping
3. 客戶端斷線清理
當使用者關閉頁面、切換頁籤、網路中斷, 你的後端應監聽請求層級的取消訊號(例如 request context / cancellation token / abort signal), 把它傳給 NewStreamer 並在偵測到取消時呼叫 stream.Close(), 避免上游 LLM 還在燒 token 但已無人接收。實作範例見 Pattern: Backend Relay — 快速起步。
4. 重試與冪等性
- 重試建立 SSE 串流時要考慮
customMessageId是否重複, 避免重複處理同一事件 - side effects(扣點、寫 history)需設計冪等, 使用
customMessageId或 SSE event ID 作為去重 key
延伸閱讀
- Pattern 完整流程: Pattern 4: Backend Relay
- 前端 SDK(配合使用): 前端 SDK 使用指南
- Auth 設計: Authentication & Access Control
- History 持久化: Conversation History
- Memory & Payload 注入: Memory & Payload 注入
- Audit Log 標準實作: Audit Logging
- Go SDK GitHub: asgard-sdk-go
- Node.js SDK npm:
@asgard-js/nodejs