Run Event
Run Event 是 Agent Run 执行过程中产生的各类事件,包括文本增量、工具调用、进度更新、错误和完成事件。它是前端渲染和后端记录的数据来源。
#type / concept
#status / evergreen
#tech / ai
#tech / architecture
[!info] related notes
- 所属 MOC: Agent Runtime MOC
- 相关: 事件契约, Heartbeat Event
Run Event
一句话定义
Run Event 是 Agent Run 执行过程中产生的各类事件。它是 Agent Runtime 的输出格式,前端用它来渲染 UI,后端用它来记录 Trace。
核心原理
事件类型
| 事件 | 触发时机 | 数据 |
|---|---|---|
text_delta | LLM 产生 token | {delta: "..."} |
tool_call_start | 开始调用工具 | {tool_name, arguments} |
tool_call_result | 工具执行完成 | {result, duration_ms} |
progress | 进度更新 | {message, step, total} |
interrupt | 需要人类审批 | {tool_call, message} |
error | 发生错误 | {code, message, recoverable} |
done | Run 完成 | {total_tokens, duration_ms} |
heartbeat | 心跳保活 | {} |
Python 实现
from dataclasses import dataclass
from typing import Any
@dataclass
class RunEvent:
event: str
data: Any
meta: dict = None
def to_sse(self) -> str:
return f"event: {self.event}\ndata: {json.dumps(self.data)}\n\n"
class EventEmitter:
def __init__(self, run_id: str):
self.run_id = run_id
self.sequence = 0
def emit(self, event_type: str, data: Any) -> RunEvent:
self.sequence += 1
return RunEvent(
event=event_type,
data=data,
meta={
"run_id": self.run_id,
"sequence": self.sequence,
"timestamp": time.time(),
},
)
事件流
async def agent_run(context) -> AsyncIterator[RunEvent]:
emitter = EventEmitter(context.run_id)
# 开始
yield emitter.emit("progress", {"message": "开始执行", "step": 0})
for step in range(MAX_STEPS):
response = await llm.chat(messages)
if response.tool_calls:
for tc in response.tool_calls:
yield emitter.emit("tool_call_start", {
"tool_call_id": tc.id,
"tool_name": tc.name,
"arguments": tc.arguments,
})
result = await execute_tool(tc)
yield emitter.emit("tool_call_result", {
"tool_call_id": tc.id,
"result": result,
})
else:
yield emitter.emit("text_delta", {"delta": response.content})
break
# 完成
yield emitter.emit("done", {
"total_tokens": total_tokens,
"duration_ms": duration_ms,
})
常见坑
- 事件类型不够用: 新增功能时没有对应的事件类型
- 不带序列号: 前端无法检测丢包和乱序
- 数据太大: 工具返回了 1MB 的结果,事件太大