智能体

用 WebSocket 订阅事件

在事件流的同一地址上建立只读 WebSocket:握手认证、帧格式、关闭码、限额与断线回填。

会话事件除了用 订阅事件(SSE)拉取,也可以在同一个地址上建立 WebSocket 接收:每个事件一帧,内容与 SSE 的事件数据完全相同。这是本平台在官方 SSE 之外额外提供的接入方式,适合在服务端长期挂着连接、把事件转发给自己系统的场景。

wss://api.deepraxis.ai/agent/v1/sessions/{session_id}/events/stream

这条连接是只读的:它只推送事件,不接收任何消息。发消息、打断仍然用 发送事件。

握手与认证

握手请求带与 HTTP 接口相同的认证头:Authorization: Bearer <API Key> 或 x-api-key: <API Key>。

浏览器原生的 WebSocket 不能设置请求头,所以这是服务端用法。浏览器里请用 SSE,或者由你的服务端建立连接后再转给前端。

握手失败时连接不会建立,服务端直接返回 HTTP 错误(错误体格式见错误):

情况返回
没带凭证,或 Key 无效、已禁用401
会话不存在,或不属于这个 Key 所在的工作区404
同时进行的请求超过 Key 的并发上限429,见限流

一条打开的 WebSocket 和一个进行中的 SSE 一样,会一直占用 Key 的一个并发名额,直到连接关闭。

帧

每一帧都是一个 JSON 文本。连接建立后,第一帧是就绪通知:

{"type":"session.events.ready"}

收到它之后,会话里产生的每个事件以一帧送达,event 字段就是 SSE 里的事件数据:

{"type":"session.event","event":{"id":"d4dc3d96-…","type":"agent.message","processed_at":"2026-09-26T13:35:04.906Z","content":[{"type":"text","text":"好"}]}}
字段说明
typesession.events.ready(就绪,只出现一次)或 session.event(一个事件)
event仅 session.event 帧有;结构与事件列表返回的单个事件相同

同一个事件可能送达不止一次。例如一条 user.message 会先以 processed_at: null(已接纳、待处理)出现,被处理后再以带时间的形式出现一次。请按 event.id 去重,以最后一次为准。

关闭码

关闭码含义你该做什么
1000服务端正常结束订阅需要继续接收就重新连接
1008客户端向连接发送了消息这条连接只读;不要发送任何帧
1011服务端内部中断重新连接,并用事件列表回填
1013暂时超出限额(见下)重新连接,并用事件列表回填

限额

  • 一条连接累计最多推送约 512 KB 的事件,超出后以 1013 关闭。长会话请准备好重连。
  • 服务端与会话之间的内部连接断开时会自动重试;多次重试仍失败,也以 1013 关闭。

断线与回填

断开期间产生的事件不会补发。重新连接后,用事件列表按时间补齐:

GET /agent/v1/sessions/{session_id}/events?order=asc&created_at[gt]=<你收到的最后一个事件的 processed_at>

回填的事件和新连接推送的事件可能重叠,按 event.id 去重即可。

示例

Bun(内置 WebSocket 支持 headers):

const ws = new WebSocket(
  `wss://api.deepraxis.ai/agent/v1/sessions/${sessionId}/events/stream`,
  { headers: { Authorization: `Bearer ${process.env.PRAXIS_API_KEY}` } },
);
ws.addEventListener("message", (message) => {
  const frame = JSON.parse(String(message.data));
  if (frame.type === "session.events.ready") console.log("ready");
  if (frame.type === "session.event") console.log(frame.event.type, frame.event);
});
ws.addEventListener("close", (close) => console.log("closed", close.code));

Node(ws 包):

import WebSocket from "ws";

const ws = new WebSocket(
  `wss://api.deepraxis.ai/agent/v1/sessions/${sessionId}/events/stream`,
  { headers: { Authorization: `Bearer ${process.env.PRAXIS_API_KEY}` } },
);
ws.on("message", (data) => {
  const frame = JSON.parse(String(data));
  if (frame.type === "session.event") console.log(frame.event.type, frame.event);
});
ws.on("close", (code) => console.log("closed", code));

Python(websockets 包):

import asyncio, json, os
import websockets

async def main(session_id: str):
    url = f"wss://api.deepraxis.ai/agent/v1/sessions/{session_id}/events/stream"
    headers = {"Authorization": f"Bearer {os.environ['PRAXIS_API_KEY']}"}
    async with websockets.connect(url, additional_headers=headers) as ws:
        async for message in ws:
            frame = json.loads(message)
            if frame["type"] == "session.event":
                print(frame["event"]["type"], frame["event"])

asyncio.run(main("sesn_123"))
导出

本页内容