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

5.8 KiB
Raw Blame History

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. 请求体

{
  "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:

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=falseWebUI 只向前端返回 finalerror
  • 当设置 WEBUI_EXPOSE_REASONING=trueWebUI 会额外透传 thoughttool_calltool_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)

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可用于自动改造其他前端项目:

你要改造一个前端项目的聊天页面,把非流式接口 `/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: 开头并以空行结尾
  • 确认 finalerror 都能正确结束当前轮次
  • 验证弱网下不会丢失已收到的事件
  • 验证用户快速连续提问时,旧流可被取消