# 事件流说明(轮询返回 events) `GET /api/v1/tasks/` 返回的 `events` 字段,是一个按时间顺序(`idx` 递增)的**事件流**。 本项目的目标是:**与网页端 WebSocket 事件保持同一粒度**。因此你会看到: - token 级别的 `text_chunk`/`thinking_chunk` - 工具调用生命周期事件(准备/意图/开始/状态更新) - 工具执行结果的状态更新与系统消息 > 提示:客户端应只依赖 `type` 字符串与 `data` 字段,并对未知事件类型保持兼容(忽略或记录)。 ## 1. 事件统一包裹格式(envelope) 每个事件的结构: ```json { "idx": 12, "type": "text_chunk", "data": { "content": "你好", "index": 5, "elapsed": 0.003 }, "ts": 1769182968.154797 } ``` 字段含义: - `idx`:事件序号(从 0 开始递增),用于轮询 offset 与去重 - `type`:事件类型(字符串) - `data`:事件载荷(不同 type 不同结构) - `ts`:服务端记录的 UNIX 时间戳(秒,float) ## 2. offset 与去重 轮询接口支持 `from` 参数: - `GET /api/v1/tasks/?from=0`:从头拉取 - `GET /api/v1/tasks/?from=next_offset`:增量拉取 正确做法: 1. 客户端本地保存 `offset`(初始 0) 2. 轮询请求带上 `from=offset` 3. 处理返回 `events` 4. 将 `offset` 更新为返回的 `next_offset` ## 3. 常见事件类型与载荷 以下为**常见**事件类型(实际可能随版本增加更多 type)。 ### 3.1 AI 消息生命周期 #### `ai_message_start` AI 新一轮回复开始(一次用户消息可能触发多次迭代,但 UI 通常以此作为“助手消息开始”的信号)。 ```json { "type": "ai_message_start", "data": {} } ``` ### 3.2 思考(reasoning) #### `thinking_start` ```json { "type": "thinking_start", "data": {} } ``` #### `thinking_chunk` 逐段思考内容(细粒度流式)。 ```json { "type": "thinking_chunk", "data": { "content": "..." } } ``` #### `thinking_end` 思考结束(带完整思考文本)。 ```json { "type": "thinking_end", "data": { "full_content": "..." } } ``` 建议客户端处理方式: - 若你想还原“实时思考流”,就持续 append `thinking_chunk.data.content`; - 若你只想最终值,可忽略 chunk,只在 `thinking_end` 读取 `full_content`。 ### 3.3 正文输出(token 级) #### `text_start` ```json { "type": "text_start", "data": {} } ``` #### `text_chunk` 逐 token/子串输出。字段: - `content`:本次增量内容 - `index`:从 1 开始的 chunk 序号(仅用于调试/对齐) - `elapsed`:与上一 chunk 的时间间隔(秒) ```json { "type": "text_chunk", "data": { "content": "你好", "index": 5, "elapsed": 0.003 } } ``` #### `text_end` 正文结束,包含 `full_content`(完整文本)。 ```json { "type": "text_end", "data": { "full_content": "..." } } ``` 建议客户端处理方式: - 实时显示:append `text_chunk.data.content` - 最终落盘:以 `text_end.data.full_content` 为准(如果你做了实时 append,最终可用 full_content 校验/纠偏) > 注意:若模型在工具调用后没有再次输出总结文本,则可能出现“最后一轮事件是工具相关,没有 text_end”的情况;这属于模型行为/迭代次数限制导致,并不代表任务异常。 ### 3.4 工具调用(tool)相关 工具链路通常会出现如下事件: 1) `tool_hint`(可选,提前猜测意图) 2) `tool_preparing`(模型开始输出 tool_calls 时) 3) `tool_intent`(从增量 arguments 中抽取 intent 字段) 4) `tool_start`(真正执行工具时) 5) `update_action`(执行进度与结果状态更新) #### `tool_hint`(可选) ```json { "type": "tool_hint", "data": { "id": "early_web_search_...", "name": "web_search", "message": "检测到可能需要调用 web_search...", "confidence": "low", "conversation_id": "conv_..." } } ``` #### `tool_preparing` ```json { "type": "tool_preparing", "data": { "id": "web_search:0", "name": "web_search", "message": "准备调用 web_search...", "intent": "搜索明日方舟终末地游戏信息", "conversation_id": "conv_..." } } ``` #### `tool_intent` ```json { "type": "tool_intent", "data": { "id": "web_search:0", "name": "web_search", "intent": "搜索明日方舟终末地游戏信息", "conversation_id": "conv_..." } } ``` #### `tool_start` ```json { "type": "tool_start", "data": { "id": "tool_0_web_search_...", "name": "web_search", "arguments": { "...": "..." }, "preparing_id": "web_search:0", "monitor_snapshot": null, "conversation_id": "conv_..." } } ``` 说明: - `preparing_id` 用于把“模型输出的 tool_call”与“真实执行的工具卡片”关联起来 - `arguments` 为工具参数(通常是 JSON 对象) #### `update_action` 该事件用于更新工具卡片(或其他 action)的状态。字段随工具不同可能略有差异,但通常包含: - `id`:与 `tool_start.data.id` 对应 - `status`:`running/completed/failed/...` - `message`:可读描述 - 可能还带 `result/summary/monitor_snapshot/...` 客户端建议: - 把 `update_action` 当作通用的“状态更新”事件处理; - 对未知字段保持兼容(直接展示或忽略)。 ### 3.5 系统消息与错误 #### `system_message` ```json { "type": "system_message", "data": { "content": "..." } } ``` #### `error` 任务内错误(不同于 HTTP 层错误)。出现后通常任务会进入 `failed`。 ```json { "type": "error", "data": { "message": "..." } } ``` ### 3.6 任务结束 #### `task_complete` ```json { "type": "task_complete", "data": { "total_iterations": 2, "total_tool_calls": 1, "auto_fix_attempts": 0 } } ``` > 结束条件以轮询返回的 `status != running` 为准;`task_complete` 是一个“完成事件”,但客户端仍应读取 `status`。 ## 4. 事件缓冲与性能建议 - 服务端每个任务保存最近 **1000** 条事件(队列会丢弃更早的数据) - 建议轮询间隔 `0.5s ~ 2s` - 长任务建议客户端把 `text_chunk` 与关键工具事件持久化到本地,避免错过