跳转到内容

Node.js 后端接入

Terminal window
npm install @blade-hq/agent-kit@2608.0.4

Node.js 项目必须使用 ESM:package.json 设置 "type": "module"。只用 /client 入口,不需要 React。

{
"type": "module",
"dependencies": {
"@blade-hq/agent-kit": "2608.0.4"
}
}

:::danger 常见错误

// 错误:不要从包根导入
import { BladeClient } from "@blade-hq/agent-kit"
// 错误:不要用 require
const { BladeClient } = require("@blade-hq/agent-kit")
// 错误:不存在 createClient
import { createClient } from "@blade-hq/agent-kit/client"

:::

import { BladeClient } from "@blade-hq/agent-kit/client"
const client = new BladeClient({
baseUrl: process.env.BLADE_AGENT_URL, // 后端 origin,不带 pathname
token: process.env.BLADE_AGENT_TOKEN, // sk-blade-v3-...
})
const { session_id } = await client.sessions.createSession("用户任务")
const socket = client.socket()
socket.on("turn:start", (p) => console.log("开始:", p.role))
socket.on("turn:patch", (p) => { /* 增量更新 */ })
socket.on("turn:end", (p) => console.log("结束:", p.role))
socket.on("chat:end", (p) => {
console.log("完成:", p.status) // completed / failed
socket.disconnect()
})
socket.on("system:error", (p) => console.error(p.message))
socket.connect()
socket.emit("session:subscribe", { session_id })
socket.emit("chat:send", { session_id, message: "你好", mode: "executing" })

离开时清理:

socket.emit("session:unsubscribe", { session_id })
socket.disconnect()

最省事的后端入口,自动建会话、跑完、返回结果:

// 纯文本
const reply = await client.headless.run("用一句话介绍你自己")
console.log(reply) // string
// 结构化结果
const data = await client.headless.run("提取公司名和金额:...", {
schema: {
type: "object",
properties: {
company: { type: "string" },
amount: { type: "number" },
},
required: ["company", "amount"],
},
})
console.log(data.company, data.amount)
// 必须断开 socket,否则 Node 进程不会退出
client.socket().disconnect()

headless.run(prompt, options) 的 options:

参数类型说明
schemaJSON Schema 对象返回结构化数据
modelstring模型 ID
timeoutMsnumber超时,默认 300000
const { session_id } = await client.sessions.createSession("用户任务")
const detail = await client.sessions.getSession(session_id)
const sessions = await client.sessions.listSessions()
const turns = await client.sessions.getSessionTurns(session_id) // 渲染用的投影
const history = await client.sessions.getSessionHistory(session_id) // 原始历史树
await client.sessions.deleteSession(session_id)

将 Socket.IO 事件转为 HTTP SSE 流:

import express from "express"
import { BladeClient } from "@blade-hq/agent-kit/client"
const app = express()
app.use(express.json())
app.post("/api/sessions/:session_id/chat", async (req, res) => {
const { session_id } = req.params
const { message } = req.body
const client = new BladeClient({
baseUrl: process.env.BLADE_AGENT_URL!,
token: process.env.BLADE_AGENT_TOKEN!,
})
const socket = client.socket()
res.writeHead(200, {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache, no-transform",
Connection: "keep-alive",
})
res.write(`event: connected\ndata: {"ok":true}\n\n`)
const send = (event: string, data: unknown) => {
res.write(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`)
}
const heartbeat = setInterval(() => send("heartbeat", { ts: Date.now() }), 15000)
const cleanup = () => {
clearInterval(heartbeat)
socket.emit("session:unsubscribe", { session_id })
socket.disconnect()
}
const finish = () => { cleanup(); if (!res.writableEnded) res.end() }
res.on("close", cleanup)
socket.on("connect", () => {
socket.emit("session:subscribe", { session_id })
socket.emit("chat:send", { session_id, message, mode: "executing" })
})
socket.on("connect_error", (err) => { send("error", { message: err.message }); finish() })
socket.on("turn:start", (p) => send("turn:start", p))
socket.on("turn:patch", (p) => send("turn:patch", p))
socket.on("turn:end", (p) => send("turn:end", p))
socket.on("chat:end", (p) => { send("chat:end", p); finish() })
socket.on("system:error", (p) => { send("error", p); finish() })
socket.connect()
})