Skip to content

[chat] perf: 聊天流式返回提速与 SSE 全链路修复 - #85

Merged
atoncooper merged 5 commits into
mainfrom
perf/chat-response-speed-improvement
Aug 21, 2026
Merged

[chat] perf: 聊天流式返回提速与 SSE 全链路修复#85
atoncooper merged 5 commits into
mainfrom
perf/chat-response-speed-improvement

Conversation

@atoncooper

@atoncooper atoncooper commented Aug 21, 2026

Copy link
Copy Markdown
Owner

背景

用户感知聊天"不是流式返回"(token 一次性整块到达)。排查发现首 token 延迟与 SSE 传输链路两层问题,且 APISIX 配置写法静默无效。

排查结论(逐层实证)

问题 证据
chat agent inject_context 强制 query rewrite 增加首 token 前一次 LLM 往返 ReAct LLM 已被 vector_search 工具描述指示自行优化 query
backend SSE session_summary / task-quiz 端点无防缓冲头 仅 chat 两端点有
APISIX nginx_config.http.proxy_buffering 不是支持的键,静默无效 ngx_tpl.lua 无该键;3.11.0 容器实测渲染后 nginx.conf 无此指令
frontendv2 Next.js rewrites 代理缓冲 SSE(代码注释已记录的已知问题) nginx 日志显示请求经 frontend 容器中转

改动

  1. [chat] perf 移除强制 query rewrite;rewritten_queries 保留空列表,下游 multi-path 契约不变
  2. [chat] fix 新增 app/routers/streaming.py(SSE_HEADERS + 工厂函数),4 个 SSE 端点统一防缓冲头;去掉 hop-by-hop 的 Connection: keep-alive
  3. [apisix] fix proxy_buffering 改用 http_server_location_configuration_snippet(已用一次性容器实测渲染进 nginx.conf)
  4. [frontend] fix client.ts 拆分浏览器/SSR base URL:浏览器直连网关(nginx:80),绕过 Next 代理;CORS 配套放行 X-Requested-With 头 + http://127.0.0.1:3000 origin
  5. [frontend] fix 聊天输入框单行文字垂直居中(textarea 与发送按钮等高)

链路保持 浏览器 → nginx → apisix → backend,仅绕开 frontend 容器内 Next.js 服务端转发一跳。

验证

  • 后端日志 event_counts={'on_chat_model_stream': 275} 确认逐 token 产出
  • APISIX 一次性容器 apisix test + grep 确认指令渲染
  • CORS 预检 OPTIONS 返回 200(补 X-Requested-With 后)
  • py_compile / router import / YAML 解析全过
  • 合并后端到端回归:重建 backend/frontend、重启 apisix,浏览器确认逐字流式 + 输入框居中

影响范围

chat agent 图、4 个 SSE 路由、APISIX http 级配置(全局 proxy_buffering off,对普通 JSON 响应无实质影响)、frontendv2 API base URL 解析、CORS 白名单。不涉及 DB schema / Milvus。

ReAct LLM 已被 vector_search 工具描述指示自行优化检索 query(指代消解/
上下文补全/多角度搜索),外层强制改写只增加首 token 前的一次 LLM 往返,
对召回无增益。rewritten_queries 保留为空列表,下游 multi-path 契约不变。
新增 app/routers/streaming.py(SSE_HEADERS + sse_streaming_response 工厂),
四个 SSE 端点统一走它:nginx/APISIX 认 X-Accel-Buffering: no,逐 token 下发
不再被代理攒成一次 bulk 投递。session_summary 与 task-quiz/chat 此前无任何
防缓冲头。去掉冗余的 hop-by-hop 头 Connection: keep-alive(nginx 会剥掉、
HTTP/2 语义非法)。
nginx_config.http.proxy_buffering 不是 APISIX 支持的键:ngx_tpl.lua 不渲染
该键,apisix test 通过但生成的 nginx.conf 里没有指令(3.11.0 实测)。
改用 http_server_location_configuration_snippet 落 proxy_buffering off 进
每个 location 块,已实测渲染成功。与后端 X-Accel-Buffering: no 形成双保险。
Next.js rewrites 代理会缓冲 SSE(frontendv2 代码注释已记录的已知问题),
浏览器经 :3000 访问时逐 token 流式被攒成一次投递。改动:
- client.ts: API_BASE_URL 拆分浏览器/SSR——浏览器用 NEXT_PUBLIC_API_URL
  (绝对地址直连 nginx:80),SSR 固定走内部 http://nginx:80(原逻辑设值后
  SSR 会误指容器自身)
- main.py: CORS 头白名单补 X-Requested-With(frontendv2 每个 API fetch 都
  携带,跨域预检声明它,缺了预检 400)
- default.yaml: CORS origin 白名单补 http://127.0.0.1:3000

链路仍为 浏览器 -> nginx -> apisix -> backend,仅绕开 frontend 容器内
Next.js 服务端转发这一跳。
容器 flex items-end 下,24px 单行 textarea 与 32px 发送按钮底对齐,
文字下方 8px、上方 16px,视觉偏下约 4px。改为 leading-6 + py-1,
MIN_HEIGHT 32px 与按钮等高:单行文字绝对居中,多行时按钮仍钉在右下。
@atoncooper
atoncooper merged commit c9b69d8 into main Aug 21, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant