> ## Documentation Index
> Fetch the complete documentation index at: https://simplellmfunc.cn/llms.txt
> Use this file to discover all available pages before exploring further.

# 事件流

> ReactOutput、事件类型，以及消费智能体事件流的模式

# 事件流

`@llm_chat` 调用返回 `AsyncGenerator[ReactOutput, None]`；`@llm_function` 的事件流通过 `fn.stream(...)` 返回。每个产出的项要么是**响应**（最终输出），要么是**事件**（生命周期信号）。

## ReactOutput

```python theme={null}
ReactOutput = ResponseYield | EventYield
```

使用类型守卫来区分：

```python theme={null}
from SimpleLLMFunc.hooks import is_response_yield, is_event_yield

async for output in agent("hello", history):
    if is_response_yield(output):
        # 最终响应——文本或类型化结果
        print(output.response)
        history = output.messages
    elif is_event_yield(output):
        # 生命周期事件
        handle_event(output.event)
```

## ResponseYield

包含智能体的最终输出：

```python theme={null}
@dataclass
class ResponseYield:
    response: Any              # The result (str, Pydantic model, raw dict)
    messages: NormalizedMessageList  # Updated conversation history
```

## EventYield

包含一个生命周期事件：

```python theme={null}
@dataclass
class EventYield:
    event: ReActEvent          # One of 14 event types
    origin: EventOrigin        # Source identification (main agent or fork)
```

## 14 种事件类型

### 循环生命周期

| 事件                         | 触发时机       | 关键字段                         |
| -------------------------- | ---------- | ---------------------------- |
| `ReactStartEvent`          | ReAct 循环开始 | —                            |
| `ReactIterationStartEvent` | 新迭代开始      | `iteration`                  |
| `ReactIterationEndEvent`   | 迭代完成       | `iteration`                  |
| `ReactEndEvent`            | 循环终止       | `final_messages`, `response` |

### LLM 调用

| 事件                    | 触发时机      | 关键字段                                       |
| --------------------- | --------- | ------------------------------------------ |
| `LLMCallStartEvent`   | 调用提供商之前   | `messages`（LLM 看到的内容）                      |
| `LLMChunkArriveEvent` | 每个流式数据块到达 | `chunk`（文本增量）                              |
| `LLMCallEndEvent`     | LLM 响应完成  | `usage`, `content`, `response`, `messages` |
| `LLMCallErrorEvent`   | LLM 调用失败  | `error`                                    |

### 工具执行

| 事件                            | 触发时机      | 关键字段                                               |
| ----------------------------- | --------- | -------------------------------------------------- |
| `ToolCallsBatchStartEvent`    | 工具批次开始    | `tool_calls`                                       |
| `ToolCallStartEvent`          | 单个工具开始执行  | `tool_name`, `tool_call_id`, `arguments`           |
| `ToolCallArgumentsDeltaEvent` | 流式工具参数    | `delta`                                            |
| `ToolCallEndEvent`            | 工具执行完成    | `tool_name`, `result`, `execution_time`, `success` |
| `ToolCallErrorEvent`          | 工具执行失败    | `tool_name`, `error`                               |
| `ToolCallsBatchEndEvent`      | 批次中所有工具完成 | —                                                  |

### 自定义事件

| 事件            | 触发时机      | 关键字段                                 |
| ------------- | --------- | ------------------------------------ |
| `CustomEvent` | 工具发出自定义数据 | `event_name`, `data`, `tool_call_id` |

自定义事件由工具通过 `ToolEventEmitter` 发出——用于流式输出工具结果（例如 PyRepl 的标准输出、shell 输出等）。

## 便捷过滤器

```python theme={null}
from SimpleLLMFunc.hooks import responses_only, events_only, filter_events

# 仅获取最终响应
async for resp in responses_only(agent("hello", history)):
    print(resp.response)

# 仅获取事件
async for evt in events_only(agent("hello", history)):
    handle(evt.event)

# 仅获取特定事件类型
from SimpleLLMFunc.hooks import LLMChunkArriveEvent

async for evt in filter_events(agent("hello", history), LLMChunkArriveEvent):
    print(evt.event.accumulated_content, end="")
```

## EventOrigin（分叉路由）

使用 SelfRef 分叉时，事件来自多个智能体。`EventOrigin` 标识事件来源：

```python theme={null}
@dataclass
class EventOrigin:
    session_id: str
    agent_call_id: str
    event_seq: int
    parent_agent_call_id: str | None = None
    fork_id: str | None = None
    fork_depth: int = 0
    fork_seq: int | None = None
    selfref_instance_id: str | None = None
    source_memory_key: str | None = None
    memory_key: str | None = None
    tool_name: str | None = None
    tool_call_id: str | None = None
```

可以利用它将事件路由到不同的 UI 面板（例如主智能体与子智能体）。

## 常见模式

### 流式文本输出到终端

```python theme={null}
async for output in agent("hello", history):
    if is_event_yield(output):
        if isinstance(output.event, LLMChunkArriveEvent):
            print(output.event.accumulated_content, end="", flush=True)
    elif is_response_yield(output):
        print()  # newline
        history = output.messages
```

### 进度追踪

```python theme={null}
async for output in agent("do complex task", history):
    if is_event_yield(output):
        event = output.event
        if isinstance(event, ToolCallStartEvent):
            print(f"  → calling {event.tool_name}...")
        elif isinstance(event, ToolCallEndEvent):
            print(f"  ✓ {event.tool_name} ({event.execution_time}ms)")
        elif isinstance(event, ReactIterationStartEvent):
            print(f"[iteration {event.iteration}]")
```

### 事件观察者装饰器

用于跨切面事件处理，无需修改消费逻辑：

```python theme={null}
from SimpleLLMFunc.hooks import with_event_observer

def log_events(event: ReActEvent, origin: EventOrigin):
    if isinstance(event, LLMCallEndEvent):
        print(f"Tokens: {event.usage}")

@with_event_observer(log_events)
@llm_chat(llm_interface=llm, toolkit=[...])
async def agent(message: str, history: list | None = None):
    """My agent."""
    pass
```

→ [API 参考：事件](/zh/api/events)
