Files
LaodingBot/doc/WebUI_Stream_API_前端对接说明.md

198 lines
5.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# WebUI `/api/chat/stream` 前端对接说明
本文档用于指导前端项目接入 LaodingBot 的流式聊天接口,并可直接作为提示词输入给 LLM批量改造其他前端代码。
## 1. 接口总览
- 方法: `POST`
- 路径: `/api/chat/stream`
- 请求头: `Content-Type: application/json`
- 响应类型: `text/event-stream`
- 协议: SSE (Server-Sent Events)
说明: 该接口为单次请求、多次推送。后端会持续推送 `data: <json>\n\n` 格式的事件。
## 2. 请求体
```json
{
"text": "请帮我分析当前目录",
"session_id": "sess_abc",
"user_id": "user_001"
}
```
字段说明:
- `text` (string, required): 用户输入文本,去除空白后不能为空。
- `session_id` (string, optional): 会话 ID不传时后端自动生成。
- `user_id` (string, optional): 用户 ID不传时后端自动生成。
兼容字段:
- `sessionId` 等价于 `session_id`
- `userId` 等价于 `user_id`
## 3. SSE 事件格式
每条 SSE 消息只包含 `data` 字段,内容是 JSON:
```text
data: {"type":"thought","content":"我先判断是否需要调用工具","step":1}
data: {"type":"tool_call","content":"{\"input\":\"pwd\"}","step":1,"tool_name":"shell"}
data: {"type":"tool_result","content":"C:/Project/MyProject","step":1,"tool_name":"shell"}
data: {"type":"final","content":"当前目录是 C:/Project/MyProject","step":2}
```
事件字段:
- `type` (string): 事件类型
- `content` (string): 事件文本内容
- `step` (number, optional): ReAct 步骤编号
- `tool_name` (string, optional): 工具名
事件类型:
- `thought`: LLM 思考片段(可选透传)
- `tool_call`: 工具调用请求(可选透传)
- `tool_result`: 工具执行结果(可选透传)
- `final`: 最终回答
- `error`: 错误信息
说明:
- 默认情况下(`WEBUI_EXPOSE_REASONING=false`WebUI 只向前端返回 `final``error`
- 当设置 `WEBUI_EXPOSE_REASONING=true`WebUI 会额外透传 `thought``tool_call``tool_result` 事件。
- 无论是否透传推理事件,`final` 都会分段累计推送,以便前端实现打字机效果。
## 4. 连接生命周期
- 正常结束: 收到 `type=final` 后结束渲染,连接可由浏览器自然关闭。
- 异常结束: 收到 `type=error`,前端应显示错误并结束当前轮次。
- 网络中断: 前端应允许用户重试,并保留已收到的事件记录。
## 5. 前端渲染建议
推荐前端仅处理两类结果:
- 答案区: 显示最后一个 `final`
- 错误区: 显示 `error`
如果开启了 `WEBUI_EXPOSE_REASONING=true`,建议额外提供“思考面板”:
- 思考区: 渲染 `thought`
- 工具区: 渲染 `tool_call` / `tool_result`
建议状态机:
- `idle`: 初始状态
- `streaming`: 请求中且持续接收事件
- `done`: 收到 `final`
- `failed`: 收到 `error` 或请求异常
## 6. TypeScript 对接示例 (fetch + ReadableStream)
```ts
type StreamEventType = 'thought' | 'tool_call' | 'tool_result' | 'final' | 'error';
interface StreamEvent {
type: StreamEventType;
content: string;
step?: number;
tool_name?: string;
}
export async function streamChat(
payload: { text: string; session_id?: string; user_id?: string },
onEvent: (event: StreamEvent) => void,
signal?: AbortSignal,
): Promise<void> {
const resp = await fetch('/api/chat/stream', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
signal,
});
if (!resp.ok) {
throw new Error(`HTTP ${resp.status}`);
}
if (!resp.body) {
throw new Error('ReadableStream is not available');
}
const reader = resp.body.getReader();
const decoder = new TextDecoder('utf-8');
let buffer = '';
while (true) {
const { value, done } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
// SSE message delimiter: blank line
let idx = buffer.indexOf('\n\n');
while (idx >= 0) {
const chunk = buffer.slice(0, idx).trim();
buffer = buffer.slice(idx + 2);
for (const line of chunk.split('\n')) {
const text = line.trim();
if (!text.startsWith('data:')) continue;
const raw = text.slice(5).trim();
if (!raw) continue;
const event = JSON.parse(raw) as StreamEvent;
onEvent(event);
}
idx = buffer.indexOf('\n\n');
}
}
}
```
## 7. 给 LLM 的改造任务提示词模板
将下面模板发给 LLM可用于自动改造其他前端项目:
```text
你要改造一个前端项目的聊天页面,把非流式接口 `/api/chat` 改为流式接口 `/api/chat/stream`。
后端协议约束:
1) 请求方法 POSTContent-Type=application/json
2) 请求体: { text, session_id?, user_id? }
3) 响应是 SSE 文本流,事件格式为 `data: <json>\n\n`
4) JSON 结构:
- type: thought | tool_call | tool_result | final | error
- content: string
- step?: number
- tool_name?: string
5) 收到 final 视为本轮完成;收到 error 视为失败
6) 默认不要假设前端一定会收到 thought/tool_call/tool_result仅当 `WEBUI_EXPOSE_REASONING=true` 才会透传
你的改造要求:
1) 保留现有 UI 风格和组件结构,不做无关重构
2) 新增流式读取逻辑,支持中途取消 (AbortController)
3) 将事件按 step 渲染到消息区
4) 兼容旧会话字段命名 (session_id / sessionId, user_id / userId)
5) 增加错误态与重试按钮
6) 不破坏原有上传、历史消息和输入框行为
7) 输出改动文件列表 + 每个文件的关键变更说明
请直接给出可运行代码补丁。
```
## 8. 调试清单
- 检查响应头是否为 `text/event-stream`
- 检查每条事件是否以 `data:` 开头并以空行结尾
- 确认 `final``error` 都能正确结束当前轮次
- 验证弱网下不会丢失已收到的事件
- 验证用户快速连续提问时,旧流可被取消