开始前,会这些就够了
- 知道网页可以逐步显示新内容
遇到不熟悉的词,先看这 2 个解释
- 工具调用
- 模型按工具说明提出要调用的功能和参数,由应用程序检查并执行,再把结果交回模型的交互方式。它把生成文字与查询、计算等实际操作连接起来。
- 流式输出
- 结果分成小片段逐步送来,页面可以边收到边显示。接收方需要区分正在接收、异常中断和协议说明的完成状态,不能把屏幕暂时不再变化当成成功。
假设预约助手先显示“可预约三个座位”,你刚想把消息转给朋友,后面又出现“但余位需要重新确认”。前半句确实已经到达屏幕,却还不能代表完整答复。内容逐步出现,和结论已经可以据此行动,是两件事。
流式输出把生成中的增量陆续送过来,让人不必等整段完成才开始看。它改变的是交付方式,没有自动增加事实核验,也没有替后端办理预约。设计界面时,最好把这些状态分别表达出来。
收到的是片段,不一定是一句完整的话
增量可以理解为这次新到的一小段内容。网络读取的一块字节、协议里的一条事件、模型的一个 token,并不必然一一对应。开发者需要按协议拼好事件,再把相应文本接到正确位置,不能拿一次网络读取就当作完整答案。
有些接口还会流式传来工具参数,可能暂时只是半截 JSON。它适合显示进度,不适合直接据此执行。等参数所属内容块完成后,还得检查是否被截断、格式是否合规、用户是否有权限以及业务条件是否允许。
停笔,也可能只是用完了长度预算
生成结束有不同原因:正常结束、达到长度上限、准备交给工具处理,都可能让当前文本停止增加;连接突然断开又是另一种情况。看到页面不再动,或者收到了流的结束信号,都不能省掉对结束原因的检查。
即使完整消息正常结束,也只说明这次生成流程结束。应用还可以核对引用、检查工具结果,再把内容标成定稿。对于预约这样的操作,办理成功要看服务端的业务结果;一段写得完整的“已预约”文字,本身不是成功凭证。
在本地重放四种收尾方式
下面自定义四种应用事件:追加草稿、生成结束、定稿和错误。它们是为了说明状态而设计的教学协议,不是某家模型接口的原始事件名。final 中的新文本代表应用核对后的替换版本;程序没有真的检查座位,也没有连模型。
观察同一段草稿遇到不同收尾:缺少结束事件时是未完成,达到上限也是未完成,正常结束仍待应用确认,收到定稿事件才替换展示。若核对推翻了草稿,界面应清楚标记已更新,不能让旧内容看起来仍然有效。
def replay(events):
text = ''
state = 'draft'
for kind, value in events:
if kind == 'delta' and state == 'draft':
text += value
elif kind == 'generation_end' and state == 'draft':
state = 'awaiting_review' if value == 'complete' else 'incomplete'
elif kind == 'final' and state == 'awaiting_review':
text = value
state = 'finalized'
elif kind == 'error':
state = 'incomplete'
if state == 'draft':
state = 'incomplete'
return state, text
draft = [('delta', '可预约'), ('delta', ' 3 个座位。')]
cases = {
'断开': draft,
'到达上限': draft + [('generation_end', 'limit')],
'等待核对': draft + [('generation_end', 'complete')],
'更新定稿': draft + [('generation_end', 'complete'),
('final', '余位待重新确认,暂未预约。')]
}
for name, events in cases.items():
state, text = replay(events)
print(f'{name}: {state} | {text}')怎样运行:保存为 stream_states.py,用 Python 3.10 或更新版本运行:python stream_states.py。仅用标准库,不联网。
运行后对照结果
断开: incomplete | 可预约 3 个座位。
到达上限: incomplete | 可预约 3 个座位。
等待核对: awaiting_review | 可预约 3 个座位。
更新定稿: finalized | 余位待重新确认,暂未预约。撤回的是展示,已办的事不会自动倒回去
用户可能已经复制了草稿,或者另一个程序已经读走片段,所以把页面上的字删掉,并不等于消除了影响。需要最终确认的业务操作,应由明确的状态和授权门槛触发;不能监听到“确认”两个字就开始扣库存,也不能指望后来改字能撤销已经完成的操作。
继续读 MDN 的事件格式与错误处理,再对照 Claude 文档中的文本增量、工具参数增量和结束原因。重连只能帮助恢复传输,不保证业务恰好执行一次。本文的重放程序没有实现重连、去重和事务,只把最容易混淆的四种展示状态拆开。
记住这三点
- 流式片段适合提前展示进度,不能自动当作完整或已核验结论。
- 生成停止、应用定稿和业务办理成功,应分别检查各自的信号。
- 替换或撤回草稿不能撤销已经发生的业务操作,执行需要独立的确认规则。
别把例子用过头
- 示例的
final是应用定义的定稿事件,不表示所有模型接口都能修改已经发出的文本。 - 流式工具参数可能不完整;即便拼接成功,也仍需格式、权限与业务检查。
- 本地重放不测量网络时延、模型速度或真实预约服务的可靠性。
自己试一小步
如果用户在生成一半时断网,界面怎样保留已有内容又避免误导?
- 设计生成中、未完成、等待核对和定稿四种文字状态。
- 在事件列表中插入 error,检查是否还会错误显示定稿。
- 列出展示恢复与业务恢复各自需要的记录。
做到这些,就算完成
- 是否把已到达的文本标成可能不完整?
- 是否把生成结束和业务成功分开?
- 是否说明替换草稿无法撤销已产生的外部动作?
查原始资料
想确认一个细节,先看这份资料对应的部分,不必从头读完所有文档。
- Claude:流式消息与增量事件 (新标签页)↗
文本增量、工具参数的部分 JSON、内容块结束及流中错误事件。
- Claude:处理停止原因 (新标签页)↗
正常结束、长度截断和工具调用等待是不同状态。
- MDN:使用服务器发送事件 (新标签页)↗
事件类型、UTF-8 事件流格式、错误处理及
EventSource重连行为。
找一份资料继续练
先选一项,按下面的范围继续学;不必从头读完整门课程。
Anthropic:读懂流式消息何时真的结束 (新标签页)↗
只追踪内容块、增量片段和结束原因,分别标出文本到齐、工具参数到齐与业务操作成功需要什么证据。
查看学习准备与访问说明 →Full Stack LLM Bootcamp:迭代测试与语言界面选学 (新标签页)↗
只选语言界面设计部分,给已有小助手画出生成中、已完成和需要确认三种状态,检查用户会不会把半句话当作定稿。
查看学习准备与访问说明 →