Skip to content

TUI 流式文本在 Kimi 模型下显示卡顿 / 一跳一跳的 #990

Description

@chengkeen

TUI 流式文本在 Kimi 模型下显示卡顿 / 一跳一跳的

问题描述

kimi-code 的 TUI 中使用 Kimi 模型 时,助手回复的流式显示不够平滑,文字会明显“一跳一跳”地更新。同样的代码在 DeepSeek 模型 下就流畅很多。

同一个 Kimi 模型,在 oh-my-pi 的 TUI 中流式输出是流畅的。这说明卡顿不是 Kimi API 本身的问题,而是 kimi-code 当前的渲染/flush 策略和 Kimi provider 的 delta 节奏不匹配。

oh-my-pi 设置中的 Smooth Streaming 选项(已开启),其说明为 "Reveal assistant text and streamed tool input smoothly while chunks arrive"

oh-my-pi Smooth Streaming setting

复现步骤

  1. 启动 kimi-code 并使用 Kimi 模型(例如 kimi k2.7 code)。
  2. 请求一个较长的 prose 回复,例如“给我讲讲这个代码库”。
  3. 观察输出:字符以短而不规则的 bursts 出现,视觉上卡顿。
  4. 切换到 DeepSeek 模型,使用同样的 prompt,输出明显更平滑。

原因分析

  1. 固定 50ms flush 窗口

    apps/kimi-code/src/tui/constant/streaming.ts

    export const STREAMING_UI_FLUSH_MS = 50;

    第一个 delta 立即 flush,但后续 delta 必须等至少 50ms。Kimi provider 的 delta 间隔较长、每次内容较少,导致 UI 按 provider 的节奏“蹦字”显示。

  2. 每次 flush 都重建 Markdown 组件

    apps/kimi-code/src/tui/components/messages/assistant-message.ts

    updateContent(text: string): void {
      this.contentContainer.clear();
      if (displayText.trim().length > 0) {
        this.contentContainer.addChild(new Markdown(displayText.trim(), 0, 0, createMarkdownTheme()));
      }
    }

    每次更新都 clear()new Markdown(...),导致 pi-tui 的缓存完全失效,每次都要对全文重新解析、重新折行。消息越长越卡。

  3. 缺少平滑 reveal 层

    当前 UI 直接显示当前累积的全部文本,没有动画层把不均匀的 delta 流转换成稳定帧率的逐字显示。Kimi 的 delta 节奏一不均匀,观感就是卡顿。

修复建议

参考 oh-my-pi 的做法:

  1. 复用 Markdown 实例

    AssistantMessageComponent 中不要每次 updateContent 都重建 Markdown,而是持有一个实例,只调用 setText(fullText)thinking.ts 里已经这么做了,可以照搬。

  2. 降低或自适应 flush 间隔

    STREAMING_UI_FLUSH_MS 从 50ms 降到 20–30ms,或者改成自适应策略:delta 来得密集时合并,间隔较长时立即 flush。

  3. 增加平滑 reveal 动画层

    StreamingUIControllerAssistantMessageComponent 之间加一个 StreamingRevealController

    • 维护一个已显示的 grapheme 计数。
    • 以固定 30fps 逐帧推进。
    • 每帧至少推进几个字符,最多推进剩余未显示字符的 1/8。
    • 消息结束时(message_end)再一次性显示完整文本并做语法高亮。

    这样不管 API 多久来一个 delta,TUI 都按自己的节奏平滑显示。

  4. 流式渲染跳过同步语法高亮

    给流式中的渲染加一个 transient 标记,最终消息到达前不做同步 highlightCode,结束时再补一次完整渲染。

参考实现

  • oh-my-pi-main/packages/coding-agent/src/modes/controllers/streaming-reveal.ts
  • oh-my-pi-main/packages/coding-agent/src/modes/components/assistant-message.ts
  • oh-my-pi-main/packages/tui/src/components/markdown.ts

相关代码

  • apps/kimi-code/src/tui/components/messages/assistant-message.ts
  • apps/kimi-code/src/tui/components/messages/thinking.ts
  • apps/kimi-code/src/tui/controllers/streaming-ui.ts
  • apps/kimi-code/src/tui/constant/streaming.ts

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions