AI CLI 流式渲染:边输出边保存,别只顾炫酷

AI CLI 流式渲染:边输出边保存,别只顾炫酷

一、流式输出提升体感

AI CLI 支持流式输出后,用户不必等完整回答返回,体验会明显变好。但流式输出不只是把 token 打到终端。中断、保存、日志、错误恢复、终端宽度、Markdown 渲染都要考虑。

边输出边保存,比单纯炫酷更重要。

二、流式链路要分层

flowchart TD A[模型流] --> B[解析器] B --> C[终端渲染] B --> D[缓存保存] B --> E[日志记录]

模型流进入后,最好先经过统一解析器,再分发给终端、缓存和日志。不要把渲染逻辑和网络读取混在一起。

for await (const chunk of stream) { renderer.write(chunk.text); buffer.append(chunk.text); }

这样中断时也能保存已生成内容。

三、中断要优雅

用户按 Ctrl+C 时,工具应该停止请求、保存已生成内容,并提示如何继续,而不是直接丢掉所有输出。

stream_interrupt: abort_request: true save_partial_output: true print_resume_hint: true

如果支持会话历史,部分输出要标记为 incomplete,避免后续被当成完整答案。

四、终端渲染要克制

Markdown、代码块、表格在流式场景里可能还没闭合。渲染器要能处理不完整结构,或者先用纯文本输出,结束后再做格式化。

render_policy: during_stream: plain_text after_complete: markdown_format

还要考虑日志。debug 日志不要和用户输出混在 stdout,应该走 stderr 或文件。

最后,流式输出要有测试。模拟慢 token、断流、错误 chunk、用户中断,才能知道 CLI 是否稳定。

还要处理终端能力差异。有些终端支持 ANSI 控制,有些 CI 日志不支持动态刷新。CLI 应该检测是否是 TTY,在非交互环境下输出稳定纯文本。

const interactive = process.stdout.isTTY;

如果用户把输出重定向到文件,工具不应该写入光标控制字符。开源 CLI 经常被放进脚本里,这类细节决定它能不能被自动化使用。

流式保存也要考虑文件一致性。可以先写临时文件,完成后再 rename;中断时保留.partial文件,并在下次运行时提示是否恢复。

最后,流式输出要有节流。每个 token 都刷新复杂 UI,可能让终端渲染成为瓶颈。按时间片刷新更稳。

还要处理多路输出。模型内容、工具执行进度、警告、错误如果都直接写在同一区域,会让终端很乱。可以把最终回答、状态行和 debug 日志分开。

stream_channels: answer: stdout progress: stderr debug: log_file

如果 CLI 支持管道模式,就更要保持 stdout 干净。用户可能把回答传给jqgrep或写入文件,混入进度条会破坏下游命令。

最后,流式失败也要返回合适退出码。部分输出保存了,不代表命令成功;脚本用户需要通过退出码判断是否继续下一步。

五、总结

AI CLI 流式渲染要分离模型流、终端渲染、缓存保存和日志记录,并支持优雅中断。

边输出边保存,别只顾炫酷。好 CLI 要在异常时也可靠。