Skip to main content

AI 聊天 WebSocket

建立连接与鉴权

wss://ydzx.panretro.com/external/api/v1/sseStream/ws/{accessToken}

accessToken 必须是带 chat scope 的 OAuth2 access token。认证失败后服务端发送 error 帧并关闭连接。

认证成功:

{ "type": "ready", "focusConversationId": null }

连接建立时没有默认聊天。客户端必须先发送 focus 帧,再发送消息、读取历史或修改设置。

状态机

ready ── focus ──> focused ── send ──> streaming
│ │
├── setting ─────────┤
├── fetch ───────────┤
└── focus ───────────┘

focus 是每个 WebSocket 连接私有的状态。切换 focus 会取消该连接对旧会话的流订阅;服务端仍会继续生成旧会话的回复,但不会继续推送给这个连接。

所有帧都是 JSON 文本帧。服务端会校验 focus 会话归属,不能借由猜测会话 ID 访问其他用户的聊天。

客户端帧

focus:选择或新建聊天

选择已有聊天:

{ "type": "focus", "conversationId": 1950000000000000000 }

创建并自动 focus:

{ "type": "focus" }

conversationId: null 或空字符串的行为与省略相同,都会创建新聊天。可选 model 字段会成为新会话的默认模型。

成功响应:

{
"type": "focus",
"conversationId": 1950000000000000000,
"conversation": {
"id": 1950000000000000000,
"title": "新对话",
"defaultModel": "deepseek-chat",
"defaultModel": "deepseek-chat"
}
}

setting:设置当前聊天

{
"type": "setting",
"SYSTEM_PROMPT": "You are a concise assistant.",
"maxResponseLength": 1024
}

SYSTEM_PROMPT 也可写为 systemPrompt,最大长度为 8000 字符。null 或空字符串表示恢复使用全局系统提示词。

maxResponseLength(也兼容 maxTokens)范围为 1–32768;它会传给上游模型的 max_tokens 参数,单位是 token 而不是字符。传 null 表示不传该上游参数,使用无限制的上游默认行为。未出现的字段保持原值。

这些设置仅保存在当前 WebSocket 连接的内存中,并按会话 ID 隔离:设置会影响该连接当前 focus 会话后续发送的消息,不写入数据库,也不会影响其他连接。新连接或新会话默认使用全局系统提示词和无限输出长度。

send:发送消息

{
"type": "send",
"message": "解释一下 B+ 树",
"model": "deepseek-chat"
}

message 不能为空,最大 500 字符;model 可选。服务端先返回确认帧,再持续发送增量内容:

{ "type": "message", "messageId": 1950000000000000002, "conversationId": 1950000000000000000 }

fetch:分页读取当前聊天记录

{ "type": "fetch", "page": 1, "pageSize": 50 }

默认 page=1pageSize=50pageSize 最大 100。服务端返回:

{
"type": "history",
"conversationId": 1950000000000000000,
"page": 1,
"pageSize": 50,
"total": 2,
"list": []
}

subscribe / good:订阅正在生成的回复

{ "type": "subscribe" }

{ "type": "good" } 是兼容别名。当前 focus 没有进行中的生成时,服务端返回 idle

服务端推送帧

类型说明
ready认证成功,尚未 focus 会话
focusfocus 成功,包含会话信息
setting设置已保存
message消息已受理,包含助手消息 ID
historyfetch 的分页结果
delta回复增量;包含 conversationIdmessageIdcontent
done本次流式回复完成
idle当前会话没有进行中的回复
error请求未执行,见下方错误说明

delta 示例:

{
"type": "delta",
"conversationId": 1950000000000000000,
"messageId": 1950000000000000002,
"content": "B+ 树是一种"
}

完成示例:

{
"type": "done",
"conversationId": 1950000000000000000,
"messageId": 1950000000000000002
}

错误帧与心跳

错误统一使用以下结构:

{ "type": "error", "code": "BAD_REQUEST", "message": "尚未 focus 对话,请先发送 focus 帧" }

常见 code

code含义
UNAUTHORIZEDaccess token 无效、过期,或缺少 chat scope
BAD_FRAME帧不是合法 JSON 对象
BAD_REQUEST参数无效、没有 focus,或会话不存在
UNKNOWN_FRAME不支持的 type

服务端每 25 秒发送 WebSocket Ping。客户端应使用 WebSocket 库自动回复 Pong;如库未自动处理,应回复 Pong 并在重连后重新发送 focus 帧。

与旧端点的关系

旧客户端继续使用:

/external/api/v1/sseStream/ws/{conversationId}/{accessToken}

该路径保留用于兼容既有网页客户端,但新接入方应使用本文的 focus 协议。旧路径同样执行会话归属校验。