KEEL · 龙骨 · A CURRICULUM FOR THE AI ERA
03. 屏幕上的字为什么不等于运行完成? — keel 龙骨
流式输出让用户更快看到模型生成的内容,但它改变的是传输方式,不是运行完成的含义。
流式输出让用户更快看到模型生成的内容,但它改变的是传输方式,不是运行完成的含义。
增量和完整结果是两种对象
一次流式响应可能分成:
chunk 1: "支付"
chunk 2: "服务"
chunk 3: "发生超时"
chunk 4: done
前几个 chunk 只能用于增量展示或累积,不能直接作为最终答案,更不能因为看到了半个工具名就执行工具。
事件和消息也不是同一个概念
| 对象 | 用途 | 示例 |
|---|---|---|
| Message | 给模型看的协议历史 | assistant、tool |
| Stream Chunk | 供应商发来的增量传输 | content_delta |
| Runtime Event | 运行时已经发生的事实 | tool.started |
| Final Result | 运行对外给出的结论 | completed |
事件是给 Harness、日志和回放系统看的;消息是给模型协议看的。一个事件可能导致一条消息,但两者不能互相替代。
运行流式示例
python courses/foundation/agent-harness/course/project/examples/02_stream.py
运行前预测:如果流在第三个 chunk 后断开,程序能否把已有文字当成最终答案?如果已经收到部分 tool call 参数,能否执行?
正确处理应类似:
flowchart TD
A[收到 chunk] --> B[记录 model.delta 事件]
B --> C[累积 content/tool fields]
C --> D{流是否完成?}
D -->|否| A
D -->|是| E[组装完整响应]
E --> F[协议校验]
F --> G[最终回答或工具决定]
D -->|失败/取消| H[记录 failed/cancelled,不提交半成品]
事件序列为什么需要 sequence
事件可能来自模型、工具、用户取消和后台 worker。每条事件至少应带:
run_id 属于哪次运行
event_id 这条事件的唯一 ID
sequence 在本次运行中的顺序
event_type 发生了什么
occurred_at 什么时候发生
时间戳可能因为并发而相同或乱序,sequence 让回放有明确顺序。项目示例中的事件是内存实现,后续会讨论持久化。
流式 thinking 不等于权限
thinking 是模型生成过程的增量字段。它可以帮助调试,但不能成为工具授权依据,也不应默认展示或进入长期记忆。真正能执行动作的,必须是完整、结构化、经过策略检查的决定。
本章自测
回答下面三个问题:
- 为什么不能在收到半个工具参数时执行?
- 为什么
model.delta事件不能直接当作run.completed? - 为什么取消后仍要处理迟到的 chunk?
下一章把“完整模型输出”进一步变成内部协议对象:Decision、Action 和 Result。