# 大规模 Agent 网络流量状态机建模

## 1. 建模目标

目标是描述大规模 Agent 网络中的消息如何产生、传播、排队、处理和返回，并预测：

- 每个节点的入站和出站流量；
- 每条链路上的消息量和字节流量；
- 消息平均经过的跳数；
- 节点队列长度和处理延迟；
- 工具调用、Agent 协作和重试带来的流量放大；
- 网络拥塞、超时和失败情况下的整体行为。

整体模型可以理解为：

> 动态通信图 + 节点能力 + 通用节点状态机 + 消息队列 + 随机状态转移。

## 2. 三类基本对象

### 2.1 节点

节点是网络中的通信和计算实体。所有节点原则上都可能与其他 Agent、工具或服务相连，也都可能收发消息。因此不将“任务分发 Agent”“子任务 Agent”“工具”等作为固定且互斥的节点类别。

将一个节点记为 $v$。节点的行为由以下信息共同决定：

$$
v=(x_v,q_v,G_v,c_v)
$$

其中：

- $x_v$：节点能力和资源，例如是否能推理、拆分任务、调用工具或查询数据库；
- $q_v$：节点当前的资源状态，例如空闲、忙碌、满载或失败。它是节点级状态，不表示某一条消息处于哪个业务处理阶段；
- $G_v$：节点周围的局部拓扑，例如邻居、连接数量、距离和邻居负载；
- $c_v$：当前任务上下文，例如任务类型、消息类型和任务阶段。

节点可以使用能力向量描述，而不是使用固定类型：

```text
can_reason = true
can_split_task = true
can_call_tool = true
can_query_database = false
can_forward = true
max_concurrency = 4
```

角色或类型仍可以作为辅助标签，例如“当前承担协调角色”，但它不是决定节点行为的唯一依据，也可以随任务阶段动态变化。

### 2.2 消息

消息是网络中实际传输的对象，可以抽象为：

$$
m=(message\_id,task\_id,parent\_message\_id,correlation\_id,attempt\_id,source,destination,next\_hop,message\_type,message\_size,priority,path,h,\ldots)
$$

其中：

- `message_id`：当前消息的唯一标识，用于追踪消息从产生到完成、失败或重试的完整生命周期；
- `task_id`：消息所属任务的唯一标识，用于关联同一任务产生的多条消息；
- `parent_message_id`：产生当前消息的上游消息标识。对于任务拆分、工具调用和重试等场景，可据此恢复消息之间的触发关系；
- `correlation_id`：请求与响应之间的关联标识。工具响应、协作结果或错误消息使用它匹配对应的请求；
- `attempt_id`：一次具体发送尝试的标识。相同逻辑请求的重试可以拥有不同的 `attempt_id`；
- `source`：消息的逻辑发送端，即消息产生的节点；
- `destination`：消息的逻辑接收端，即本次消息最终要到达的节点。二者表示端到端关系，不表示多跳传播中的每一条链路；
- `next_hop`：本次传输实际要到达的下一跳节点。它可以等于 `destination`，也可以是通往 `destination` 的中间转发节点；
- `message_type`：消息的业务类型，决定节点收到消息后的处理方式以及可能产生的后续消息；
- `message_size`（或 $b$）：消息大小，统一以 Byte 计，用于计算链路和节点的字节流量；
- `priority`：消息优先级，用于消息队列中的调度。其取值范围和相同优先级下的排序规则由系统配置决定；
- `path`：消息已经确认或实际经过的节点序列，记为 $(v_0,v_1,\ldots,v_h)$；使用预先计算路由时也可以保存完整计划路径。通常有 $v_0=source$，到达最终目标时最后一个节点为 `destination`；
- $h$：消息已经完成的跳数，取非负整数，表示消息当前位于已确认路径的 $v_h$，因此初始位于 $source=v_0$ 时 $h=0$，每成功到达一个下一跳后增加 1；
- `retry_count`：当前消息已发生的重试次数，用于控制重试上限并统计额外流量；
- 时间字段（如 `timestamp`、创建时间、到达时间和超时时间）：用于计算排队时间、处理时延、链路时延和超时；
- `payload`：消息承载的业务内容。在网络性能模型中通常不展开其具体内容，只通过 `message_type` 和 `message_size` 描述其处理类别和传输开销。

其中，`source`、`destination`、`message_type`、`message_size` 和 `priority` 是消息的基本属性；`next_hop`、`path`、$h$、队列位置和时间字段是消息传播过程中的动态状态。`message_id` 标识逻辑消息，`attempt_id` 标识一次实际发送尝试。若只研究消息传播、任务分解、请求响应和重试关系，则应保留 `task_id`、`message_id`、`parent_message_id`、`correlation_id`、`attempt_id` 和 `retry_count`。

例如，路径为 $A\rightarrow B\rightarrow C\rightarrow D$ 时，消息位于 $C$，则 $h=2$。

消息类型可以包括：新任务、子任务请求、工具调用、工具返回结果、Agent 间协商、最终结果、错误通知和重试请求。

### 2.3 节点状态与消息处理状态

需要区分两类状态：

- 节点资源状态 $q_v$：描述节点整体是否有可用处理资源。它可以表示为 `{Idle, Busy, Saturated, Failed}`，其中 `Busy` 表示至少有一个活跃处理上下文，`Saturated` 表示活跃处理数达到 `max_concurrency`；
- 消息处理状态 $q_m$：描述某条消息或某个任务处理上下文当前正在做什么，例如接收、排队、思考、调用工具、等待结果、发送结果、失败或重试。

因此，下面的通用状态机是“每条消息/任务处理上下文”的状态机，而不是整个节点在任意时刻只能拥有一个状态。一个节点可以在同一时刻拥有多个 $q_m$，但其活跃处理上下文数量不能超过 `max_concurrency`。

$$
q_m=\{空闲, 接收消息, 排队, 思考, 调用工具, 等待结果, 发送结果, 失败, 重试\}
$$

典型状态变化如下：

```mermaid
stateDiagram-v2
    [*] --> Idle: Agent启动
    Idle --> Receive: 收到任务消息
    Receive --> Think: 消息解析完成
    Think --> CallTool: 需要外部信息
    CallTool --> Wait: 工具请求已发送
    Wait --> Think: 收到工具结果
    Think --> Send: 任务已经完成
    Send --> Idle: 结果发送完成
```

## 3. 混合自动机的两层结构

### 3.1 外层自动机：消息在网络中的传播位置

外层自动机只负责消息在网络中的传播：确定逻辑目的地、选择当前下一跳、安排链路传输和处理到达事件。它不负责决定目标节点收到消息后执行 `Think`、`CallTool` 或 `Split` 等业务状态。

可以将外层状态理解为：

$$
大状态=(当前节点, 当前交互上下文, 当前路径位置)
$$

外层每次只选择一个 `next_hop`。候选下一跳必须属于当前节点的可用出邻居集合；最终 `destination` 可以是多跳之外的节点。若采用预先计算的路由，`path` 保存完整计划路径；若采用逐跳路由，`path` 保存已经确认的实际路径，并在每次发送后追加新的下一跳。消息到达 `destination` 后，不再执行普通转发；响应消息应作为新的逻辑消息沿反向或重新计算的路径传播。

```mermaid
stateDiagram-v2
    [*] --> Node_A: 外部任务到达
    Node_A --> Node_B: 根据局部拓扑选择协作者
    Node_B --> Node_C: 具备工具调用能力且邻域中存在可用工具
    Node_C --> Node_B: 返回工具结果
    Node_B --> Node_D: 根据任务上下文请求其他节点
    Node_D --> Node_B: 返回协作结果
    Node_B --> Node_A: 返回阶段性结果
    Node_A --> [*]: 任务完成
    Node_C --> Node_B: 调用超时或失败
    Node_B --> Node_C: 根据重试策略重新发送
```

例如，一条消息可能经历：

```text
Node_A -> Node_B -> Node_C -> Node_B -> Node_A
```

这里的 $Node_A$、$Node_B$ 和 $Node_C$ 不是预先固定的节点类型。它们在当前任务中分别表现为协调、执行和工具服务等不同功能，具体行为由能力、邻域结构和任务上下文决定。

### 3.2 内层自动机：所有节点共享的通用行为

内层自动机绑定到一个具体的消息或任务处理上下文，不按节点类型拆成多套固定流程，而是使用一套通用状态机。节点是否能够执行某个分支，由节点能力、周围拓扑、任务上下文、当前负载和可用并发槽决定。

```mermaid
stateDiagram-v2
    [*] --> Idle
    Idle --> Receive: 收到消息
    Receive --> Queue: 没有可用处理资源
    Receive --> Think: 获得处理资源
    Queue --> Think: 获得处理资源

    Think --> Send: 可以直接处理
    Think --> Split: 具备任务拆分能力
    Think --> CallAgent: 存在合适的Agent邻居
    Think --> CallTool: 具备工具调用能力且邻域中有可用工具
    Think --> Query: 具备数据查询能力且邻域中有数据服务
    Think --> Forward: 具备转发能力且需要改变路由

    Split --> Wait: 发送多个子任务
    CallAgent --> Wait: 发送协作请求
    CallTool --> Wait: 发送工具请求
    Query --> Wait: 发送查询请求
    Forward --> Wait: 转发消息

    Wait --> Think: 收到返回结果
    Wait --> Retry: 请求超时或失败
    Retry --> Think: 继续执行
    Retry --> Failed: 超过重试次数

    Send --> Idle: 发送完成
    Failed --> Idle: 返回错误或放弃任务
```

例如：

- 没有 `can_call_tool` 能力时，`Think -> CallTool` 不可用；
- 附近没有可用工具时，即使节点具备该能力，也不能执行 `CallTool`；
- 出度较高且任务需要拆分时，`Think -> Split` 的概率可能更高；
- 邻居负载较高时，`CallAgent` 可能选择其他邻居或进入等待；
- 同一个节点在不同任务阶段，可以表现出协调、执行、查询或转发等不同功能。

### 3.3 消息处理上下文的完整状态

一条消息或任务处理上下文的最小状态可以表示为：

```text
(消息或任务上下文, 当前节点, 当前消息处理状态)
```

例如：

```text
(M_1, Node_A, Think)
(M_1, Node_A, CallTool)
(M_2, Node_B, Query)
(M_1, Node_A, Wait)
(M_1, Node_A, Send)
```

同一个节点可以同时存在多个处理上下文，例如：

```text
Node_A:
  (M_1, Think)
  (M_2, Wait)
  (M_3, Queue)
```

其中活跃上下文数量受 `max_concurrency` 限制，`M_3` 仍在等待资源。节点级状态由资源占用汇总得到：没有活跃上下文时为 `Idle`，有活跃上下文但未达到上限时为 `Busy`，达到 `max_concurrency` 时为 `Saturated`。具体的队列操作由第 7 章定义。

### 3.4 带流量信息的状态机

第 3.2 节给出了通用的内层自动机。本节在其状态转移上增加消息数量、消息大小、入站/出站字节数、超时概率和重试流量。下面的图是“工具调用或直接返回”场景的简化子集，不是独立于内层自动机的新模型：

```mermaid
stateDiagram-v2
    [*] --> Idle
    Idle --> Receive: 收到消息 / 消息数 +1 / 入站字节 +S
    Receive --> Queue: 加入队列
    Queue --> Think: 开始处理
    Think --> CallTool: 需要工具 / 概率 p_tool
    Think --> Send: 直接返回 / 概率 1-p_tool
    CallTool --> Wait: 发送工具请求 / 出站字节 +S_request
    Wait --> Think: 收到工具结果 / 入站字节 +S_response
    Wait --> Retry: 超时 / 概率 p_timeout
    Retry --> CallTool: 重试 / 额外出站字节 +S_request
    Send --> Idle: 发送结果 / 出站字节 +S_result
```

`Split`、`CallAgent`、`Query`、`Forward` 和 `Failed` 等状态并未消失。在具体场景中，应以同样的方式为这些状态转移增加消息数量、大小、目标节点、失败概率和流量变化。例如，`Think -> Split` 产生多个子任务消息，`Think -> Query` 产生查询请求，`Think -> Forward` 产生转发流量。`Done` 仅作为流程完成标记，不作为独立的节点内部状态，正式状态转移使用 `Send -> Idle`。

在一个节点上，`Idle`、`Receive`、`Think` 等图中的状态表示某个消息处理上下文的状态。节点整体状态由并发资源汇总得到，不应把多个上下文强行合并成一个唯一的业务状态。

其中：

- $p_{tool}$：思考后调用工具的概率；
- $p_{timeout}$：工具请求超时的概率；
- $S_{request}$：工具请求大小；
- $S_{response}$：工具响应大小；
- $S_{result}$：最终结果大小。

例如：

$$
P(Think\rightarrow CallTool)=0.7
$$

如果每秒有 100 个任务进入 Agent，则工具请求约为：

$$
100\times0.7=70\text{ 条/秒}
$$

若每条请求大小为 5 KB，则工具请求出站流量约为：

$$
70\times5\text{ KB}=350\text{ KB/秒}
$$

### 3.5 完整的两层模型

完整模型由外层自动机和内层自动机共同组成：

- 外层自动机描述消息在不同节点之间的传播、目标选择、返回和重试路径；
- 内层自动机描述消息到达节点后如何接收、排队、处理、调用服务和返回结果；
- 流量标注附着在内层状态转移和外层链路传播上。

```mermaid
flowchart TD
    subgraph Outer[外层自动机：消息在节点之间传播]
        A[Node_A] -->|外部任务到达| B[Node_B]
        B -->|选择协作或工具目标| C[Node_C]
        C -->|返回工具结果| B
        B -->|返回阶段性结果| A
        A -->|汇总并返回最终结果| End([任务完成])
        C -->|超时或失败| B
        B -->|按照重试策略重新发送| C
    end

    subgraph Inner[内层自动机：每个节点的内部处理]
        I[Idle] --> R[Receive]
        R --> Q[Queue]
        Q --> T[Think]
        T -->|需要工具| CT[CallTool]
        T -->|直接处理完成| S[Send]
        CT --> W[Wait]
        W -->|收到返回结果| T
        W -->|超时或失败| RT[Retry]
        RT --> T
        S --> I
    end

    B -.收到消息后触发.-> R
    C -.收到消息后触发.-> R
    W -.生成返回消息并回到外层传播.-> B
    S -.生成结果消息并回到外层传播.-> A
```

对于一条具体消息，完整状态可以表示为：

```text
(当前节点, 节点资源状态, 当前消息处理状态, 任务上下文, 消息路径, 消息属性, 队列负载)
```

仿真循环可以概括为：

```text
外层自动机选择下一跳
    -> 目标节点进入内层自动机
    -> 内层状态转移产生处理动作和新消息
    -> 更新队列、链路路径和流量
    -> 新消息再次由外层自动机传播
```

## 4. 关键参数

### 4.1 节点能力和资源 $x_v$

节点行为首先由能力和资源决定，而不是由一个固定类型决定。能力可以表示为布尔值、离散等级或数值：

$$
x_v=(能力向量, 并发上限, 计算资源, 可访问服务)
$$

例如：

```text
can_reason = true
can_split_task = true
can_call_tool = true
can_query_database = false
can_forward = true
max_concurrency = 4
```

节点角色或类型可以作为辅助标签，但它不是硬约束。同一个节点可以在不同任务阶段承担不同角色。

### 4.2 局部拓扑及其特征 $G_v$、$z_v$

节点 $v$ 周围的局部拓扑决定它当前能够联系谁，以及不同动作是否具有可行目标。用 $G_v$ 表示节点 $v$ 的局部拓扑子图，并从中提取供状态机使用的特征 $z_v$：

$$
z_v=(degree_{in},degree_{out},邻居数量,邻居能力,距离,邻居负载)
$$

其中 $G_v$ 表示节点周围的局部子图，$z_v$ 是从这个局部子图中提取出来、供状态机使用的特征。

其中：

- $degree_{in}$：可以向节点 $v$ 发送消息的邻居数量；
- $degree_{out}$：节点 $v$ 可以发送消息的邻居数量；
- `邻居能力`：邻居是否支持工具调用、推理、查询等能力；
- `距离`：节点到潜在目标的跳数或网络距离；
- `邻居负载`：邻居当前队列长度、并发数或带宽占用。

拓扑只能决定节点的可达范围，不能单独决定业务意图，因此还需要结合节点状态、消息和任务上下文。

### 4.3 拓扑结构 $G=(V,E)$

其中 $V$ 表示所有节点，$E$ 表示节点之间的通信关系。例如：

$$
A\rightarrow B,\quad B\rightarrow C
$$

消息的完整路径可以表示为：

$$
路径=(v_0,v_1,\dots,v_k)
$$

在消息模型中已经定义了 $h$：它表示消息当前位于路径中的第几个节点，也就是已经完成的转发次数。例如消息从 $A$ 出发，路径为 $A\rightarrow B\rightarrow C\rightarrow D$：

- 位于 $A$ 时，$h=0$；
- 位于 $B$ 时，$h=1$；
- 位于 $C$ 时，$h=2$；
- 位于 $D$ 时，$h=3$。

跳数只能描述传播步数，不能单独代表网络代价，因为不同链路的带宽、时延和拥塞程度可能不同。

### 4.4 消息到达率 $\lambda$

$\lambda$ 表示一般消息的单位时间到达率。对于外部任务，单独使用 $\lambda_{ext}$ 表示外部任务到达率；对于节点 $v$，分别使用 $\lambda_v^{in}$ 和 $\lambda_v^{out}$ 表示入站和出站消息率。例如：

$$
\lambda=100\text{ 条/秒}
$$

表示平均每秒产生 100 条消息。最好为每个节点分别记录 $\lambda_v$，因为不同 Agent 的忙闲程度通常不同。

### 4.5 消息大小 $b$

$b$ 表示每条消息包含多少字节。如果每秒有 $\lambda$ 条消息，每条消息平均大小是 $b$，字节流量约为：

$$
流量=\lambda\times b
$$

例如：

$$
\lambda=1000\text{ 条/秒},\quad b=10\text{ KB}
$$

则：

$$
流量=1000\times10\text{ KB}=10\text{ MB/秒}
$$

### 4.6 下游数量 $F$

$F$ 表示一条输入消息平均会触发多少个下游消息。

如果外部任务到达率为 $\lambda_{ext}$，则内部消息量可以粗略估计为：

$$
\lambda_{internal}=\lambda_{ext}\times F
$$

例如每秒 100 个外部任务，每个任务平均拆成 5 个子任务：

$$
\lambda_{internal}=100\times5=500\text{ 条/秒}
$$

### 4.7 处理速度 $\mu$

$\mu$ 表示节点总的单位时间处理能力。存在并发槽时，不能默认将单槽处理速度直接乘以 `max_concurrency`；如果日志记录的是单个并发槽速度，则还需要额外建模并发竞争、资源共享和不同消息类型的处理时间。

如果：

$$
\lambda<\mu
$$

节点通常能够及时处理消息；如果：

$$
\lambda>\mu
$$

消息会不断进入队列，最终导致延迟和拥塞。

## 5. 参数估计、数据采集与数据量要求

本章回答“模型参数从哪里来、需要记录什么以及需要多少数据”。第 6 章再定义这些条件变量和参数如何进入状态转移模型；因此，本章讨论的是参数的可观测性、估计方法和数据充分性，而不是新增状态机结构。

状态机中的概率和持续时间，主要通过小规模实验或真实运行日志估计。这里的“训练”首先是统计参数，不一定需要复杂的机器学习模型。

例如，可以记录 10 个节点上的消息交互日志，先按照节点能力、局部拓扑、消息类型和任务类型分组，再估计每组的状态转移规律。

### 5.1 需要记录的日志字段

每条消息最好带有唯一的任务 ID 和消息 ID，并记录：

| 字段                  | 用途                                     |
| --------------------- | ---------------------------------------- |
| `timestamp`         | 计算消息到达时间、状态持续时间和链路延迟 |
| `task_id`           | 还原一次完整任务的执行过程               |
| `message_id`        | 追踪一条具体消息                         |
| `parent_message_id` | 判断当前消息由哪条消息产生               |
| `correlation_id`     | 匹配请求、响应、错误和超时事件             |
| `attempt_id`         | 区分同一逻辑请求的不同发送尝试             |
| `message_type`      | 区分任务、工具调用、工具返回、错误和重试 |
| `source`            | 记录发送节点                             |
| `destination`       | 记录接收节点                             |
| `next_hop`          | 记录本次传输实际到达的下一跳节点         |
| `node_capabilities` | 记录节点当前具备的能力                   |
| `local_topology`    | 记录节点的邻居、连接数量、距离和邻居负载 |
| `state_before`      | 记录状态转移前的状态                     |
| `state_after`       | 记录状态转移后的状态                     |
| `message_size`      | 统计消息大小和字节流量                   |
| `success`           | 统计成功率和失败率                       |
| `retry_count`       | 估计重试行为                             |
| `queue_length`      | 分析排队和拥塞                           |

如果没有 `task_id`、`message_id` 和时间戳，就很难还原完整的状态转移链。

### 5.2 未分层的状态转移概率

假设日志中有 1000 次“思考”状态结束事件，其中：

- 650 次进入“调用工具”；
- 350 次进入“直接返回”。

则：

$$
P(Think\rightarrow CallTool)=\frac{650}{1000}=0.65
$$

$$
P(Think\rightarrow Send)=\frac{350}{1000}=0.35
$$

这里的 0.65 和 0.35 是未区分任务类型、任务阶段、节点能力、局部拓扑和系统负载时得到的总体基础概率，仅适合作为基线参数或分层模型的全局初始值。

在简单仿真中，如果所有样本处于相似上下文，可以直接使用这两个概率。在分层仿真中，则应将它们作为基础参数，再结合节点能力、任务上下文、局部拓扑和系统负载进行修正。不可行的状态转移概率应设为 0，并在剩余可行转移之间重新归一化。例如，节点没有工具调用能力，或邻域中没有可用工具时，`Think -> CallTool` 的概率应为 0，`Think -> Send` 或其他可行转移的概率需要重新归一化。

第 6 章的分层模型正是在此基础上计算条件概率：

$$
P(Think\rightarrow CallTool\mid 任务类型,任务阶段,x_v,z_v,系统负载)
$$

### 5.3 状态持续时间

日志需要记录状态开始和结束时间。例如：

```text
进入 Think：10.0 秒
离开 Think：12.4 秒
```

则本次状态持续时间为：

$$
\Delta t_{Think}=12.4-10.0=2.4\text{ 秒}
$$

仿真时不应只使用平均值，还应保存平均值、中位数、P95、P99 和经验分布。因为一次思考可能持续 0.5 秒，另一次可能持续 10 秒。

### 5.4 其他需要估计的参数

小规模日志还应估计：

#### 状态持续时间

$$
T_{think}\sim D_{think}
$$

$D_{think}$ 表示从日志中得到的思考时间分布。仿真时从该分布中抽取一个具体持续时间，而不是每次固定使用同一个数值。

端到端延迟拆分为排队时间、节点处理时间、链路传输时间和等待外部结果时间。`Think` 的持续时间只表示节点实际思考/处理时间；`Wait` 的持续时间表示从请求发送到匹配响应或超时的等待时间；队列等待时间和链路传输时间单独记录，不能重复计入状态持续时间。

#### 消息大小分布

工具请求、工具结果和最终结果应分别统计：

$$
S_{request},\quad S_{response},\quad S_{result}
$$

#### 一次状态转移产生的消息数量

$$
N_{out}=一次状态转移产生的消息数量
$$

输出消息集合可以表示为：

$$
M_{out}=\{m_1,m_2,\dots,m_{N_{out}}\}
$$

#### 下游节点选择

$$
P(destination\mid 当前节点,消息类型,网络状态)
$$

目标选择先构造满足能力、可达性和资源约束的候选集合，再在候选集合内抽样；不可达或能力不满足的节点概率为 0。若消息需要多跳传播，目标选择确定 `destination`，路由模型再为每一步确定 `next_hop`。没有可行目标时，消息按照配置进入等待、改路由、重试或 `Failed`。

#### 超时和重试概率

$$
P_{timeout}=0.05
$$

`p_timeout` 表示一次发送尝试在规定超时时间内未收到匹配响应的概率；超时时间由请求的 `timeout_at` 或条件超时分布确定，不与处理失败概率混为一谈。每次重试都创建新的 `attempt_id`，递增同一逻辑请求的 `retry_count`，保留原有 `correlation_id`，并重新执行目标选择和链路传输。达到 `max_retries` 后，当前请求进入 `Failed`，并按配置向父上下文发送错误消息或结束任务。

### 5.5 条件参数

不能简单地让所有节点共用一套概率。状态转移通常与节点能力、局部拓扑、任务类型、消息类型和系统负载有关：

$$
P(q_{next},\Delta t,M_{out}\mid q_{current},x_v,z_v,任务类型,消息类型,系统负载)
$$

例如：

```text
附近没有可用工具时调用工具概率：0
附近存在可用工具且任务复杂时调用工具概率：0.8
低负载时超时概率：0.02
高负载时超时概率：0.15
```

### 5.6 小规模日志可以估计的参数

十个节点的数据可以用于学习：

- 节点内部状态转换；
- 工具调用概率；
- 单个 Agent 的处理时间；
- 消息大小分布；
- 基本调用链结构；
- 不同局部拓扑下的目标选择和状态转移规律；
- 初步的失败和重试概率。

但它不能直接代表十万节点网络中的：

- 大规模队列增长；
- 热点节点竞争；
- 动态路由变化；
- 高负载下的处理速度下降；
- 拥塞引发的超时和重试放大。

因此，小规模日志适合先建立基础行为模型；容量、队列、延迟和重试模型所需的数据规模与适用边界见第 5.8～5.10 节。

### 5.7 数据量估算方法

按照本文模型的定义，所谓“训练”主要是从运行日志中估计状态转移概率、状态持续时间、消息大小、目标节点选择、失败概率和重试行为等参数，并不一定需要训练大规模深度学习模型。因此，数据量主要取决于需要区分的条件组合数量，而不是网络节点总数。

消息级日志、状态事件和任务级轨迹应分别统计：

- **消息级记录**：描述一条消息的产生、传输、排队、处理、完成、失败或重试；
- **状态事件记录**：描述节点一次状态转移及其持续时间，例如 `Think -> CallTool`；
- **任务级轨迹**：通过 `task_id` 和 `parent_message_id` 连接同一任务产生的多条消息，用于恢复任务拆分、协作和返回过程。

对于当前模型，状态事件数通常比完整任务数更适合作为参数估计的数据量指标。

设需要区分的条件组合数量为：

$$
K=K_{task}\times K_{phase}\times K_{message}\times K_{capability}\times K_{load}\times K_{topology}
$$

其中各项分别表示任务类型、任务阶段、消息类型、节点能力类别、负载区间和局部拓扑类别的数量。若每个条件组合至少需要 $n$ 次有效状态事件，则：

$$
N_{event}\approx K\times n
$$

实际采集量还应考虑数据清洗、无效记录和验证集划分，建议将结果扩大约 $1.5\sim2$ 倍。分层模型通过共享全局参数和上级层次参数，可以降低每个条件组合所需的独立样本量。

### 5.8 推荐数据量级

| 目标 | 完整任务数 | 消息或状态事件数 | 适用范围 |
| --- | ---: | ---: | --- |
| 原型验证 | $10^3\sim10^4$ | $10^4\sim10^5$ | 验证状态机、消息路径和仿真流程 |
| 基础可用 | $10^4\sim10^5$ | $10^5\sim10^6$ | 估计主要状态转移、处理时间和消息大小 |
| 较稳定预测 | $10^5\sim10^6$ | $10^6\sim10^7$ | 覆盖不同任务、负载、拓扑和失败场景 |
| 大规模容量评估 | $10^6$ 以上 | $10^7$ 以上 | 预测热点、拥塞、超时和重试放大 |

对于目前的十节点模型，建议至少收集 $10^5\sim10^6$ 条消息或状态事件，或者 $10^4\sim10^5$ 个完整任务轨迹。若重点研究拥塞、失败和重试，则建议达到 $10^6\sim10^7$ 条事件，并确保覆盖高负载和异常场景。

普通状态转移概率每个重要条件组合至少需要 100～300 次状态结束事件；状态持续时间和消息大小分布建议每个主要类别有 300～1000 个样本。失败、超时和重试等稀有事件应至少观察到 50～100 次；若超时率约为 5%，通常需要约 2000 次相关请求才能得到相对稳定的估计。

### 5.9 十节点场景示例与运行速率换算

假设需要区分 5 种任务类型、5 个任务阶段、5 类消息、2 类节点能力和 3 个负载区间，暂不单独划分拓扑类别，则：

$$
K=5\times5\times5\times2\times3=750
$$

若每个条件组合收集 200 次状态事件，基础需求为：

$$
750\times200=150000
$$

考虑数据清洗、验证集和异常场景后，建议收集约 $2\times10^5\sim5\times10^5$ 条有效事件。

若系统总消息到达率为 $\lambda$，连续观测时间为 $T$，则：

$$
N_{message}\approx\lambda T
$$

例如 $\lambda=100$ 条/秒时，1 小时约产生 36 万条消息，1 天约产生 864 万条消息。这里的 $\lambda$ 必须明确是整个网络的总到达率，还是每个节点的到达率。消息数量不等于完整任务数量，因为一个任务可能通过拆分、工具调用和重试产生多条消息。

### 5.10 参数回退、校准与数据适用边界

如果某个条件组合的样本过少，应使用分层模型向任务类型、任务阶段、节点能力或全局参数回退，并记录 `parameter_source` 和 `confidence`。新增任务或节点类型可以先继承相似类别的参数，再用运行数据进行增量校准。

十个节点的日志可以用于学习节点内部状态转换、工具调用概率、处理时间、消息大小分布和基本调用链结构，也可以初步估计失败与重试行为。但它不能单独保证模型能够准确预测大规模网络中的热点竞争、链路拥塞和容量变化，因此还需要压测或更大规模实验进行校准。

## 6. 条件状态转移与分层参数模型

本章只定义模型如何使用任务类型、任务阶段、节点能力、局部拓扑和系统负载等条件变量，不讨论日志应该采集多少或参数如何校准；这些内容统一放在第 5 章。需要区分两件事：

```text
类别定义：系统如何描述任务、阶段和节点能力
参数学习：这些类别对应的状态转移、时间和流量参数如何估计
```

类别可以在运行时新增，但新增类别是否能够立即得到准确行为，取决于它是否能够用已有特征表示，以及是否有足够的新数据进行校准。

### 6.1 分层参数结构

不为每一种任务类型、任务阶段和节点分别建立完全独立的状态机，而是让不同层次共享一部分基础参数：

```text
全局基础行为
    ↓
任务类型修正
    ↓
任务阶段修正
    ↓
节点能力修正
    ↓
局部拓扑和系统负载修正
```

例如，状态转移概率可以表示为：

$$
P(q'\mid q,c,x_v,z_v,m,\ell_v)
$$

其中：

- $q$：当前消息处理上下文的状态，即本文的 $q_m$；
- $c$：任务类型、任务阶段和其他业务上下文；
- $x_v$：节点能力和资源；
- $z_v$：局部拓扑特征；
- $m$：消息类型和属性；
- $\ell_v$：节点队列、并发数和系统负载。

对于“思考后调用工具”的转移，可以使用：

$$
\operatorname{logit}(p_{tool})=
\beta_0+\alpha_{task}+\gamma_{phase}+\eta_{capability}+\delta_{topology}+\rho_{load}
$$

其中 $\beta_0$ 是全局基础行为，其余项分别表示任务类型、任务阶段、节点能力、局部拓扑和负载的修正。多种候选状态转移时，可以对各候选转移计算分数，再使用 softmax 归一化。

分层模型也应作用于状态持续时间、输出消息数量和消息大小：

$$
\log T_q=\mu_q+\alpha_{task}+\gamma_{phase}+\eta_{node}+\epsilon
$$

$$
\log S_m\sim\mathcal N(\mu_{message\ type}+\gamma_{phase},\sigma^2)
$$

这样，同一个 `Think` 状态在不同任务阶段可以具有不同的处理时间、调用工具概率、输出大小和下游消息数量。

### 6.2 条件状态转移的计算过程

在仿真中，状态转移不是直接查找一个固定概率，而是对每一条候选转移分别计算分数，再转换为概率。一次计算可以分为以下步骤。

**第 1 步：读取当前事件和上下文。**

假设当前事件为：

```text
节点：Node_B
当前消息处理状态：Think
任务类型：recruitment
任务阶段：detailed_evaluation
消息类型：resume_request
```

同时读取：

```text
节点能力：can_call_tool = true
局部拓扑：Node_C 是可用工具节点
Node_B 队列长度：5
Node_B 当前并发数：3 / 4
链路利用率：0.60
```

这些信息构成条件变量：

$$
X=(q,c,x_v,z_v,m,\ell_v)
$$

**第 2 步：筛选可行转移。**

对于 `Think` 状态，先列出通用状态机中的候选分支：

```text
Think → Send
Think → Split
Think → CallAgent
Think → CallTool
Think → Query
Think → Forward
```

然后根据硬约束删除不可行分支。例如，没有工具能力或工具邻居时，`Think → CallTool` 的概率直接设为 0；没有数据查询能力时，删除 `Think → Query`。因此，能力和拓扑先决定“能否做”，概率模型再决定“在可行动作中选择什么”。

**第 3 步：计算候选转移分数。**

对于每个候选转移 $j$，计算：

$$
s_j=\beta_j+\alpha_{task,j}+\gamma_{phase,j}+\eta_{capability,j}+\delta_{topology,j}+\rho_{load,j}
$$

假设 `Think → CallTool` 的示例分数为：

```text
全局基础项 β0              = 0.00
招聘任务修正 αtask          = 0.10
详细分析阶段修正 γphase     = 1.20
具备工具能力修正 ηcapability = 0.80
存在可用工具邻居 δtopology   = 0.60
当前负载修正 ρload          = -0.20
```

则：

$$
s_{tool}=0.00+0.10+1.20+0.80+0.60-0.20=2.50
$$

假设 `Think → Send` 的分数为：

$$
s_{send}=0.20-0.80=-0.60
$$

这里的分数不是概率，可以是任意实数。

**第 4 步：使用 softmax 得到概率。**

只对当前可行的转移归一化：

$$
P(j\mid X)=\frac{e^{s_j}}{\sum_{k\in\mathcal A(X)}e^{s_k}}
$$

本例只剩 `CallTool` 和 `Send`，因此：

$$
P(CallTool)=\frac{e^{2.50}}{e^{2.50}+e^{-0.60}}\approx0.956
$$

$$
P(Send)=\frac{e^{-0.60}}{e^{2.50}+e^{-0.60}}\approx0.044
$$

如果使用日志估计的 `p_tool=0.7`，应将它作为阶段基础参数参与计算，而不是再额外叠加一个独立概率。第 10 节示例中的 `0.7` 表示不考虑额外上下文修正时的基础概率；本节根据任务类型、阶段、能力、拓扑和负载修正后得到的 `0.956` 是条件概率，两者不应在同一次转移中相乘或相加。

**第 5 步：抽样下一状态。**

仿真器生成随机数 $u\in[0,1]$：

```text
u < 0.956  → Think → CallTool
u ≥ 0.956  → Think → Send
```

假设本次抽样进入 `CallTool`，则继续计算处理时间和输出消息。

**第 6 步：抽样状态持续时间。**

状态持续时间也依赖任务类型、任务阶段、节点和负载：

$$
\log T_q\sim\mathcal N(\mu_q+\alpha_{task}+\gamma_{phase}+\eta_{node}+\rho_{load},\sigma_q^2)
$$

例如详细分析阶段的 `Think` 时间可以显著长于初筛阶段。仿真器从该条件分布抽样，例如得到：

```text
T_Think = 7.6 秒
```

这个值用于安排 `Think` 完成事件，而不是让所有 `Think` 状态都使用同一个平均值。

**第 7 步：抽样输出消息和目标节点。**

进入 `CallTool` 后，继续计算：

```text
输出消息数量：N_out = 1
消息类型：tool_request
消息大小：从 S_request(· | task_type, task_phase) 抽样
目标节点：从 P(destination | tool_request, z_v, load) 抽样
```

例如：

$$
\log S_{request}\sim\mathcal N(\mu_{request,phase},\sigma_{request}^2)
$$

本次抽样得到工具请求大小 2 KB，目标节点为 `Node_C`，于是更新：

```text
Node_B 出站消息数 +1
Node_B 出站字节数 +2 KB
链路 B-C 流量 +2 KB
Node_C 队列 +1
```

**第 8 步：安排后续事件。**

仿真器将消息到达、工具完成和请求超时等事件加入全局事件队列：

```text
Node_C 消息到达事件
Node_C 工具处理完成事件
Node_B 工具请求超时事件
```

如果工具正常返回，执行 `Wait → Think`；如果发生超时，则执行：

```text
Wait → Retry → CallTool → Wait
```

每次重试都要重新计算请求消息、目标节点和链路流量，因此会产生额外流量。

### 6.3 分层计算的伪代码

```text
处理事件(event):
    读取 node、q、task_type、task_phase、message_type、load
    candidates = 获取状态 q 的候选转移
    candidates = 根据能力、拓扑和资源过滤(candidates)

    for transition in candidates:
        score[transition] = 全局参数
            + 任务类型修正
            + 任务阶段修正
            + 节点能力修正
            + 拓扑修正
            + 负载修正

    probability = softmax(score)
    next_state = 按 probability 随机抽样
    duration = 从条件持续时间分布抽样
    messages = 根据 next_state 生成输出消息
    更新节点、队列、链路和流量统计
    安排完成、返回、超时或重试事件
```

### 6.4 新类别的模型表达

#### 新增任务类型

新任务类型不应只依赖一个从未见过的离散名称，而应尽量使用可解释特征描述：

```text
需要长文本理解 = true
需要外部工具 = true
需要多人协作 = false
实时性要求 = low
可靠性要求 = high
结果复杂度 = high
```

例如，训练数据中没有“法律合同审查”，但它可以被描述为长文本理解、法规查询、高可靠性和多轮验证任务。模型可以借用文档分析、外部查询和高可靠性任务的参数，这属于组合泛化。

如果新任务具有训练数据中没有的交互模式，例如需要持续的流式协作，则不能只依赖参数泛化，还需要扩展状态机结构并采集少量新场景数据。

#### 新增任务阶段

新阶段可以采用分层回退机制：

```text
新阶段专属参数
    ↓ 没有足够数据
同一任务类型的参数
    ↓ 仍然没有数据
相似任务阶段的参数
    ↓ 仍然没有数据
全局基础参数
```

例如新增“候选人背景调查”阶段时，可以先继承招聘任务的基础参数，再叠加外部查询和高可靠性阶段的修正。随着运行日志增加，再逐渐估计该阶段自己的参数。

#### 新增节点能力

节点能力应优先使用能力向量，而不是固定的节点类型：

```text
can_reason = true
can_call_tool = true
can_query_database = false
context_window = 128K
max_concurrency = 4
reasoning_level = high
```

新增节点实例通常只需要提供能力向量，不必重新训练完整模型。如果增加 `can_analyze_image` 这类能力，可以先将其映射到通用的 `CallTool` 分支，并通过 `tool_type=image_analysis` 区分具体流量和处理时间。

如果新增能力改变了通信过程，例如引入持续流式传输，则应扩展状态机：

```text
Think → StartStream → ReceiveChunk → Continue / Finish
```

#### 运行时的未知类别处理

仿真器遇到新任务、阶段或能力时，可以执行：

```text
检查类别是否有专属参数
→ 查找相似类别或读取特征参数
→ 使用上级分层参数进行回退
→ 标记参数来源和置信度
→ 收集运行数据并进行增量校准
```

例如：

```text
parameter_source = fallback
confidence = low
```

这可以避免把基于少量数据或默认参数得到的结果误认为高可信预测。

#### 泛化能力的边界

模型通常可以泛化到以下情况：

- 新任务由已有任务行为组合而成；
- 新阶段与已有阶段具有相似特征；
- 新节点只是已有能力的不同组合；
- 基本消息交互模式没有变化。

模型难以直接泛化到以下情况：

- 新任务产生完全不同的消息类型；
- 新阶段需要全新的状态和交互协议；
- 新能力改变了通信机制；
- 新规模下出现训练数据中没有的拥塞、热点竞争或重试放大。

因此，新增类别的处理原则是：先通过特征和分层参数继承已有行为，再用少量新数据进行增量校准；只有当交互模式本身发生变化时，才扩展状态机结构。

## 7. 队列模型

### 7.1 队列的实际含义

这里的“消息队列”不一定指 Kafka、RabbitMQ 或其他独立中间件。更准确地说，它表示：

> 消息已经到达某个节点或链路，但当前没有足够的处理能力，因此暂时等待的消息集合。

本模型将 `Q_v(t)` 定义为“已到达节点、但尚未分配到活跃处理资源的消息数”。正在 `Think`、`CallTool` 或 `Wait` 中的处理上下文不计入 `Q_v(t)`，但会计入节点的活跃并发数和资源占用 `r_v(t)`。链路传输中的消息不计入节点队列；若要建模链路缓冲区，则另设 `Q_e(t)`。

现实系统中，等待消息可能存在于独立消息中间件、服务内部、Agent mailbox、模型服务、网络缓冲区或外部服务请求队列中。因此，即使 Agent 之间采用直接同步调用，系统中仍可能存在隐性的等待位置：

```text
Agent A -> 网络缓冲区 -> Agent B服务队列 -> 线程池 -> Agent B执行器
```

在本模型中，队列是一个抽象概念，不要求系统必须部署某一种具体的消息队列产品。

### 7.2 为什么需要对队列建模

如果一个节点每秒收到 100 条消息，但每秒只能处理 60 条消息，那么剩余消息必须等待、被丢弃、被拒绝或触发限流。若系统选择等待，就需要用队列表示：

```text
原队列：20 条
新到达：100 条
已处理：60 条
新队列：20 + 100 - 60 = 60 条
```

队列增长会带来消息等待时间增加、节点处理延迟增加、请求超时、重试流量增加、限流或请求拒绝，以及热点节点和链路拥塞。

队列采用有界、按 `priority` 优先且同优先级按到达顺序处理的调度规则；具体优先级范围由系统配置决定。节点有 $C_v=\text{max\_concurrency}$ 个并发槽。只有当活跃上下文数小于 $C_v$ 时，队首消息才能从 `Queue` 进入 `Receive` 或 `Think`，并使活跃上下文数加一。默认情况下，进入 `Wait` 的上下文仍占用一个并发槽，因为它仍需要维护请求、超时和响应匹配；若实际系统允许等待期间释放资源，应配置 `wait_holds_slot=false`，并在恢复时重新申请并发槽。上下文进入 `Send` 完成、`Failed` 或其他终止状态后释放一个并发槽，并立即尝试调度队列中的下一条消息。

本文采用离散事件仿真作为正式实现方式。固定窗口公式只用于统计和校验，不作为状态推进的唯一机制。

### 7.3 队列动态

节点或链路通常不能立即处理所有消息，因此需要维护等待队列或缓冲区。对节点队列，在固定统计窗口中可以使用：

$$
Q_v(t+\Delta t)=\max\left(0, Q_v(t)+A_v(t,\Delta t)-D_v(t,\Delta t)\right)
$$

其中 $Q_v(t)$ 是等待队列消息数，$A_v$ 是窗口内到达并需要排队的消息数，$D_v$ 是窗口内从等待队列取出并开始处理的消息数。处理完成数不直接等同于队列减少数；消息开始处理时才离开等待队列。应满足 $D_v(t,\Delta t)\leq Q_v(t)+A_v(t,\Delta t)$。在离散事件仿真中，每次消息到达使 `Q_v` 加一（若无可用资源），每次分配处理资源使 `Q_v` 减一。

$$
Q_v(t)\leq Q_v^{max}
$$

达到上限时，系统可能丢弃、拒绝、限流、切换节点、返回错误或让发送方等待/重试。因此，状态机描述“处理一条消息需要经历什么”，队列描述“多条消息同时到来时如何等待”。

## 8. 节点和链路流量计算

如果节点 $v$ 每秒收到 $\lambda_v^{in}$ 条消息，每条平均大小为 $b_v^{in}$，则入站流量为：

$$
B_v^{in}=\lambda_v^{in}\times b_v^{in}
$$

出站流量为：

$$
B_v^{out}=\lambda_v^{out}\times b_v^{out}
$$

节点总流量为：

$$
B_v=B_v^{in}+B_v^{out}
$$

链路按有向边分别统计：$B_{u\rightarrow v}(T)$ 只包含从 $u$ 到 $v$ 的消息字节数；如果需要双向链路总量，则另定义 $B_{\{u,v\}}(T)=B_{u\rightarrow v}(T)+B_{v\rightarrow u}(T)$。节点的入站/出站流量默认包含外部系统通信；若只研究节点间通信，则必须将外部系统单独作为节点或单独统计，不能在同一结果中混用两种口径。

## 9. 状态机如何指导最终模拟

状态机不是直接给出最终流量，而是作为模拟器的行为规则。模拟器不断执行“读取事件、状态转移、生成消息、更新队列和统计流量”的循环。

### 9.1 初始化

模拟开始时，设置：

- 网络拓扑；
- 每个节点的能力和资源；
- 局部拓扑特征和邻居状态；
- 每个节点的初始状态；
- 每个节点的消息队列；
- 链路带宽和延迟；
- 从日志估计的概率、持续时间和消息大小分布。

例如：

```text
Node_A：具备拆分和协作能力，状态 = Idle
Node_B：具备推理能力，状态 = Idle
Node_C：具备工具执行能力，状态 = Idle
```

### 9.2 事件处理循环

模拟器按照时间顺序处理事件；同一时间戳下按“消息到达 → 状态完成/资源释放 → 响应匹配 → 超时检查 → 重试或失败”的顺序处理。已经匹配到响应的请求会取消其未触发的超时事件。

```text
1. 取出时间最早的事件
2. 找到相关节点、消息处理上下文和 `correlation_id`
3. 更新消息到达、节点队列和并发资源状态
4. 根据当前消息处理状态和参数选择下一状态
5. 从条件持续时间分布中抽取处理时间
6. 根据状态转移产生新的逻辑消息或发送尝试
7. 按实际 `next_hop` 更新节点和有向链路流量
8. 将到达消息放入目标节点队列，或在有资源时直接分配并发槽
9. 安排后续的状态完成、响应匹配、超时、重试或失败事件
```

### 9.3 一个任务的模拟过程

假设 Node_A 收到一个外部任务：

```text
Idle -> Receive -> Think -> Split
```

`Split` 状态根据参数 $F=3$ 产生三条子任务消息。每条消息根据局部拓扑和目标选择规则进入一个邻居节点的队列，同时记录出站消息数和字节流量。

拆分后的父上下文进入 `Wait` 后，必须记录待完成子任务集合。只有在所有必需子任务返回、某个可配置的部分完成条件满足，或任务因失败/超时达到终止条件时，父上下文才从 `Wait` 返回 `Think` 或进入 `Failed`。单个子任务返回不会自动使父上下文继续执行。

目标节点随后进入：

```text
Receive -> Queue -> Think
```

如果从结合节点能力和局部拓扑得到的状态转移概率中抽到 `Think -> CallTool`，模拟器生成工具请求；如果抽到 `Think -> Send`，模拟器直接生成结果消息。

工具请求继续触发目标节点的通用状态机：

```text
Receive -> Queue -> Think -> Send
```

工具结果返回后，目标节点从 `Wait` 回到 `Think`，继续执行后续转移。

### 9.4 状态转移如何变成流量

例如一次转移：

```text
Think -> CallTool
```

需要包含以下参数：

```text
发生概率：0.6
状态持续时间：从 D_toolcall 中抽取
产生消息数：1
消息类型：工具请求
消息大小：从 S_request 分布中抽取
目标节点：从目标选择规则中抽取
失败概率：0.05
```

模拟器根据这些参数创建一条具体消息。消息经过的每条链路都会增加对应的字节流量；消息到达目标节点后，又会触发目标节点的状态机。

### 9.5 队列对模拟的作用

状态机描述“处理一条消息需要经历什么”，队列描述“多条消息同时到来时如何等待”。如果节点正在处理其他消息，新消息进入队列，直到节点有可用处理资源后，才继续触发状态机。

例如：

```text
消息到达率：100 条/秒
节点处理能力：60 条/秒
```

那么队列长期趋势约为每秒增加 40 条消息。队列增长还会增加等待时间，并可能进一步提高超时和重试概率。

### 9.6 模拟输出

模拟运行一段时间后，统计：

- 每个节点的消息数、入站流量和出站流量；
- 每条链路的累计字节数和峰值速率；
- 各类消息的数量和平均大小；
- 队列长度和节点忙碌比例；
- 任务端到端完成时间；
- 超时率、失败率和重试次数。

## 10. 三节点完整示例

下面用三个节点说明一次任务从到达到完成的完整过程。这个例子同时展示外层自动机的节点间传播、内层自动机的节点内部处理，以及每次消息传输对流量和队列的影响。

### 10.1 示例配置

设网络中有三个节点：

```text
Node_A：具备推理、任务分发和结果汇总能力
Node_B：具备推理和工具调用能力
Node_C：提供工具执行服务
```

网络连接为：

```text
Node_A ↔ Node_B ↔ Node_C
```

本次任务使用以下参数：

| 参数                            | 示例值 |
| ------------------------------- | ------ |
| 外部任务消息大小                | 2 KB   |
| 工具请求大小 (S_{request})      | 1 KB   |
| 工具响应大小 (S_{response})     | 4 KB   |
| 最终结果大小 (S_{result})       | 2 KB   |
| (P(Think\rightarrow CallTool))  | 0.7    |
| (P(Think\rightarrow Send))      | 0.3    |
| 工具请求超时概率                | 0.05   |
| Node_A、Node_B、Node_C 初始队列 | 0      |

这里假设本次随机抽样结果为：Node_B 选择调用工具，工具请求没有超时。实际仿真中，每次状态转移都按照相应概率随机抽样。

### 10.2 初始状态

```text
Node_A：Idle，队列 = 0
Node_B：Idle，队列 = 0
Node_C：Idle，队列 = 0
```

当前没有在途消息，累计流量为 0。

### 10.3 三节点状态变化和流量时序图

本节图中的“Node_X 状态”表示该节点当前示例任务对应的消息处理上下文状态；如果节点同时处理其他任务，还应分别记录其他上下文，不能据此推断节点只有一个全局业务状态。图中的双向连线仅用于展示请求和响应方向，正式流量按第 8 节的有向链路口径统计。

下面用连续的网络快照展示一次任务的演化过程。每一个步骤都重新绘制相同的三节点拓扑，并在当前图中标注：

- 节点当前状态和队列长度；
- 当前步骤产生的消息及其流量方向；
- 节点入站/出站流量累计值；
- 链路的累计流量。

为避免图中信息过于拥挤，节点标签中的 `Q` 表示队列长度，`In` 和 `Out` 分别表示截至当前步骤的累计入站和出站字节数。

#### 步骤 0：初始拓扑

```mermaid
flowchart LR
    EXT[外部系统]
    A[Node_A<br/>状态：Idle<br/>Q=0<br/>In=0 KB，Out=0 KB]
    B[Node_B<br/>状态：Idle<br/>Q=0<br/>In=0 KB，Out=0 KB]
    C[Node_C<br/>状态：Idle<br/>Q=0<br/>In=0 KB，Out=0 KB]
    EXT -.->|外部任务入口| A
    A <-->|链路 A-B<br/>累计 0 KB| B
    B <-->|链路 B-C<br/>累计 0 KB| C
```

初始时三个节点都处于 `Idle`，没有等待消息，也没有产生流量。

#### 步骤 1：外部任务到达 Node_A

```mermaid
flowchart LR
    EXT[外部系统] ==>|M0：外部任务，2 KB| A[Node_A<br/>状态：Receive → Think<br/>Q=0<br/>In=2 KB，Out=0 KB]
    A <-->|链路 A-B<br/>累计 0 KB| B[Node_B<br/>状态：Idle<br/>Q=0<br/>In=0 KB，Out=0 KB]
    B <-->|链路 B-C<br/>累计 0 KB| C[Node_C<br/>状态：Idle<br/>Q=0<br/>In=0 KB，Out=0 KB]
```

变化：`Node_A` 接收 2 KB 外部任务，入站流量增加 2 KB，并从 `Receive` 进入 `Think`。

#### 步骤 2：Node_A 将任务发送给 Node_B

```mermaid
flowchart LR
    EXT[外部系统] -.->|M0 已到达| A[Node_A<br/>状态：Idle<br/>Q=0<br/>In=2 KB，Out=3 KB]
    A ==>|M1：任务请求，3 KB<br/>链路 A-B 累计 3 KB| B[Node_B<br/>状态：Receive → Queue → Think<br/>Q：0 → 1 → 0<br/>In=3 KB，Out=0 KB]
    B <-->|链路 B-C<br/>累计 0 KB| C[Node_C<br/>状态：Idle<br/>Q=0<br/>In=0 KB，Out=0 KB]
```

变化：`Node_A` 执行 `Think → Send → Idle`，发送 3 KB 的 (M_1)。`Node_B` 收到消息，队列暂时从 0 增加到 1，获得处理资源后进入 `Think`。链路 A-B 累计流量为 3 KB。

#### 步骤 3：Node_B 调用 Node_C 的工具

```mermaid
flowchart LR
    EXT[外部系统] -.->|M0 已到达| A[Node_A<br/>状态：Idle<br/>Q=0<br/>In=2 KB，Out=3 KB]
    A <-->|链路 A-B<br/>累计 3 KB| B[Node_B<br/>状态：CallTool → Wait<br/>Q=0<br/>In=3 KB，Out=1 KB]
    B ==>|M2：工具请求，1 KB<br/>链路 B-C 累计 1 KB| C[Node_C<br/>状态：Receive → Queue → Think<br/>Q：0 → 1 → 0<br/>In=1 KB，Out=0 KB]
```

变化：本次随机抽样进入 `Think → CallTool`，概率为 (p_{tool}=0.7)。`Node_B` 进入 `Wait`，发出 1 KB 工具请求。链路 B-C 累计流量为 1 KB。

#### 步骤 4：Node_C 返回工具结果

```mermaid
flowchart LR
    EXT[外部系统] -.->|M0 已到达| A[Node_A<br/>状态：Idle<br/>Q=0<br/>In=2 KB，Out=3 KB]
    A <-->|链路 A-B<br/>累计 3 KB| B[Node_B<br/>状态：Wait → Think<br/>Q=0<br/>In=7 KB，Out=1 KB]
    C[Node_C<br/>状态：Send → Idle<br/>Q=0<br/>In=1 KB，Out=4 KB] ==>|M3：工具响应，4 KB<br/>链路 B-C 累计 5 KB| B
```

变化：`Node_C` 完成工具处理并返回 4 KB 的 (M_3)。`Node_B` 入站流量增加 4 KB，从 `Wait` 返回 `Think`。链路 B-C 的累计流量为 (1+4=5) KB。

#### 步骤 5：Node_B 返回最终结果给 Node_A

```mermaid
flowchart LR
    EXT[外部系统] -.->|M0 已到达| A[Node_A<br/>状态：Receive → Think<br/>Q=0<br/>In=4 KB，Out=3 KB]
    B[Node_B<br/>状态：Think → Send → Idle<br/>Q=0<br/>In=7 KB，Out=3 KB] ==>|M4：最终结果，2 KB<br/>链路 A-B 累计 5 KB| A
    B <-->|链路 B-C<br/>累计 5 KB| C[Node_C<br/>状态：Idle<br/>Q=0<br/>In=1 KB，Out=4 KB]
```

变化：`Node_B` 发送 2 KB 的最终结果，`Node_A` 入站流量增加 2 KB，并开始处理返回结果。链路 A-B 的累计流量为 (3+2=5) KB。

#### 步骤 6：Node_A 完成任务

```mermaid
flowchart LR
    EXT[外部系统] -.->|任务已提交| A[Node_A<br/>状态：Think → Send → Idle<br/>Q=0<br/>In=4 KB，Out=3 KB]
    A <-->|链路 A-B<br/>累计 5 KB| B[Node_B<br/>状态：Idle<br/>Q=0<br/>In=7 KB，Out=3 KB]
    B <-->|链路 B-C<br/>累计 5 KB| C[Node_C<br/>状态：Idle<br/>Q=0<br/>In=1 KB，Out=4 KB]
```

变化：`Node_A` 完成结果处理并回到 `Idle`。本次任务的节点间流量最终为：

```text
外部系统 → Node_A：2 KB
Node_A → Node_B：3 KB
Node_B → Node_C：1 KB
Node_C → Node_B：4 KB
Node_B → Node_A：2 KB
```

### 10.4 外部任务到达 Node_A

外部任务消息 (M_0) 到达 `Node_A`，大小为 2 KB。外层自动机确定消息的起点为 `Node_A`，内层自动机触发：

```text
Node_A: Idle → Receive → Think
```

流量和队列更新为：

```text
Node_A 入站消息数 +1
Node_A 入站字节数 +2 KB
Node_A 队列：0 → 0       （假设立即获得处理资源）
```

### 10.5 Node_A 发送任务请求给 Node_B

Node_A 根据任务上下文决定由 Node_B 执行具体任务。外层自动机选择路径：

```text
Node_A → Node_B
```

Node_A 的内层状态转移为：

```text
Think → Send → Idle
```

生成任务请求消息 (M_1)，假设大小为 3 KB。更新结果为：

```text
Node_A 出站消息数 +1
Node_A 出站字节数 +3 KB
链路 A-B 流量 +3 KB
Node_B 队列：0 → 1
```

Node_B 收到消息后执行：

```text
Idle → Receive → Queue → Think
```

如果 Node_B 当时有空闲处理资源，`Queue` 状态可以是瞬时状态，消息直接从队列取出进入 `Think`。

### 10.6 Node_B 调用 Node_C 的工具

Node_B 在 `Think` 状态根据条件概率选择下一步：

```text
P(Think → CallTool) = 0.7
P(Think → Send) = 0.3
```

本次抽样进入 `CallTool`。由于 Node_B 具备工具调用能力，且邻居 `Node_C` 是可用工具服务，因此转移可行：

```text
Node_B: Think → CallTool → Wait
```

生成工具请求 (M_2)，大小为 1 KB，路径为：

```text
Node_B → Node_C
```

更新流量：

```text
Node_B 出站消息数 +1
Node_B 出站字节数 +1 KB
链路 B-C 流量 +1 KB
Node_C 队列：0 → 1
```

Node_C 收到请求后执行自己的内层状态机：

```text
Idle → Receive → Queue → Think → Send → Idle
```

Node_C 完成工具执行并生成响应 (M_3)，大小为 4 KB，返回路径为：

```text
Node_C → Node_B
```

因此：

```text
Node_C 入站字节数 +1 KB
Node_C 出站字节数 +4 KB
Node_B 入站字节数 +4 KB
链路 B-C 流量再增加 4 KB
```

Node_B 收到响应后从等待状态返回思考状态：

```text
Node_B: Wait → Think
```

### 10.7 Node_B 返回最终结果给 Node_A

Node_B 处理工具结果后完成任务，执行：

```text
Node_B: Think → Send → Idle
```

生成最终结果消息 (M_4)，大小为 2 KB，沿路径返回：

```text
Node_B → Node_A
```

更新流量：

```text
Node_B 出站消息数再 +1
Node_B 出站字节数再 +2 KB
Node_A 入站消息数再 +1
Node_A 入站字节数再 +2 KB
链路 A-B 流量再增加 2 KB
```

Node_A 收到结果后执行：

```text
Node_A: Idle → Receive → Think → Send → Idle
```

本次任务完成。

如果 `Node_A` 代表面向外部系统的入口节点，则任务完成后还应生成一条 `Node_A → 外部系统` 的最终结果消息。该消息大小必须单独配置；本节原有的数值汇总只统计外部输入和节点间通信，未把这条未给出大小的外部结果消息计入。若统计节点总出站流量，则应在 `Node_A` 出站流量中另加该消息，并单独标注外部通信。

### 10.8 一次任务的汇总结果

消息路径为：

```text
外部 → Node_A → Node_B → Node_C → Node_B → Node_A
```

各链路累计流量为：

```text
A→B：3 KB
B→A：2 KB
B→C：1 KB
C→B：4 KB
```

若汇总为无向链路总量，则：

```text
{A,B}：3 KB + 2 KB = 5 KB
{B,C}：1 KB + 4 KB = 5 KB
```

节点处理得到的通信流量为：

```text
Node_A：入站 4 KB，出站 3 KB
Node_B：入站 7 KB，出站 3 KB
Node_C：入站 1 KB，出站 4 KB
```

这里的节点流量包含外部系统与节点之间的通信：Node_A 的入站流量为外部任务 2 KB 加上 Node_B 返回结果 2 KB，共 4 KB。如果只统计节点间通信，则应另记为 Node_A 入站 2 KB、出站 3 KB，并将外部系统流量单独统计。

如果工具请求发生超时，状态路径将变为：

```text
Node_B: Wait → Retry → CallTool → Wait
```

每次重试都会额外产生 1 KB 的工具请求流量；如果超过重试次数，则进入 `Failed`，并可能产生错误消息。这说明状态转移概率、状态持续时间、消息大小和队列负载会共同决定最终流量。

### 10.9 扩展到连续任务流

如果外部任务到达率为 $\lambda_{ext}$，且每个任务都经过上述路径，则在不考虑失败和重试时：

```text
A→B 平均消息流量 ≈ λ × 3 KB
B→A 平均消息流量 ≈ λ × 2 KB
B→C 平均消息流量 ≈ λ × (0.7 × 1) KB
C→B 平均消息流量 ≈ λ × (0.7 × 4) KB
```

例如 $\lambda_{ext}=100$ 条/秒时：

```text
{A,B} 双向汇总 ≈ 100 × 5 KB = 500 KB/秒
{B,C} 双向汇总 ≈ 100 × 0.7 × 5 KB = 350 KB/秒
```

若考虑超时重试，则还需要乘以平均请求次数。若单次请求超时概率为 (p_{timeout})，且允许无限重试的理论平均请求次数为：

```text
平均请求次数 = 1 / (1 - p_timeout)
```

实际模型还应受到最大重试次数限制。


## 11. 最终模型定义

一个消息处理上下文或消息处理事件在时刻 $t$ 的完整状态可以表示为：

$$
s_m(t)=(v,q_v,q_m,x_v,z_v,c,m,path,h,Q_v(t),r_v,\tau_v,{retry\_count})
$$

其中：

- $v$：消息当前所在的节点；
- $q_v$：节点级资源状态，如 `Idle`、`Busy`、`Saturated` 或 `Failed`；
- $q_m$：当前消息或任务处理上下文的内部状态；
- $x_v$：节点能力和资源配置；
- $z_v$：从节点局部拓扑 $G_v$ 中提取的特征；
- $c$：任务类型、任务阶段和其他业务上下文；
- $m$：消息属性，包括消息类型、大小、优先级和消息标识；
- $path$：消息已经经过或计划经过的节点序列；
- $h$：消息已经完成的跳数；
- $Q_v(t)$：节点当前等待队列长度；
- $r_v$：节点当前并发数、处理资源占用和可用容量。它决定新的消息处理上下文能否从 `Queue` 进入活跃状态；
- $\tau_v$：节点或消息相关的时间信息，包括状态持续时间和等待时间；
- retry_count：当前消息已经重试的次数。

对于需要显式建模链路拥塞的场景，链路 $e$ 在时刻 $t$ 的状态还可以表示为：

$$
g_e(t)=(bandwidth_e,delay_e,utilization_e,congestion_e)
$$

状态转移可以概括为：

$$
(s_{t+\Delta t},M_{out},\Delta F)
=f(s_t,g_e(t),\xi_t)
$$

其中：

- $M_{out}$：本次状态转移产生的输出消息集合；
- $\Delta F$：本次状态转移产生的节点和链路流量变化；
- $\xi_t$：随机因素，包括状态转移、处理时间、消息大小、目标选择、失败和超时等随机变量。

推荐将整体系统定义为：

$$
\boxed{随机混合自动机+消息队列+动态通信图+事件调度器+路由与目标选择模型+流量统计模型}
$$

## 12. 参数总表

下表汇总本文模型中的主要参数。参数可以来自系统配置、网络拓扑、压测结果、小规模交互日志或大规模仿真校准。

| 符号或名称                                              | 含义                                     | 单位或取值形式         | 主要来源           | 在仿真中的用途                   |
| ------------------------------------------------------- | ---------------------------------------- | ---------------------- | ------------------ | -------------------------------- |
| $v$                                                   | 一个具体节点                             | 节点 ID                | 拓扑配置           | 标识 Agent、工具或服务           |
| $x_v$                                                 | 节点$v$ 的能力和资源                   | 能力向量、资源配置     | 系统配置或日志     | 判断哪些状态转移可用             |
| $G_v$                                                 | 节点$v$ 的局部拓扑子图                 | 局部有向图             | 拓扑配置或实时状态 | 确定邻居和可达目标                 |
| $z_v$                                                 | 节点$v$ 的局部拓扑特征                 | 度数、邻居、距离、负载 | 拓扑配置或实时状态 | 选择目标节点和调整转移概率       |
| $r_v$                                                 | 节点$v$ 的并发数、资源占用和可用容量   | 资源状态               | 仿真实时维护       | 判断处理能力和排队状态             |
| $\tau_v$                                              | 节点或消息相关的状态及等待时间         | 秒                     | 事件日志或仿真维护 | 安排状态完成和超时事件             |
| $V$                                                   | 网络中的所有节点集合                     | 节点集合               | 拓扑配置           | 构建仿真网络                     |
| $E$                                                   | 节点之间的通信连接集合                   | 有向边集合             | 拓扑配置           | 决定消息如何传播                 |
| $G=(V,E)$                                             | 网络拓扑图                               | 有向图                 | 拓扑配置           | 描述整体网络结构                 |
| $g_e(t)$                                              | 链路$e$的带宽、时延和拥塞状态           | 链路状态               | 拓扑配置或实时监控 | 计算传输时延和拥塞影响             |
| $m$                                                   | 一条逻辑消息                             | 消息对象               | 日志或仿真生成     | 作为传播和状态转移的基本事件     |
| $s_m(t)$                                              | 消息或消息处理事件的完整状态             | 状态向量               | 仿真状态维护       | 驱动状态转移和事件处理             |
| `message_type`                                        | 消息类型                                 | 任务、工具调用、结果等 | 日志统计           | 决定消息处理方式和大小分布       |
| `source`                                              | 消息的逻辑发送端，即产生消息的节点       | 节点 ID                | 日志或路由规则     | 确定端到端起点                   |
| `destination`                                         | 消息的逻辑接收端，即最终目标节点         | 节点 ID                | 日志或目标选择规则 | 确定端到端终点                   |
| `message_size` 或 $b$                               | 消息大小                                 | Byte、KB 或 MB         | 消息日志           | 计算字节流量                     |
| `priority`                                            | 消息优先级                               | 离散等级               | 系统配置或日志     | 决定队列调度顺序                 |
| `path`                                                | 消息计划经过或已经经过的节点序列         | 节点序列               | 路由规则或日志     | 确定并更新每一跳的链路流量       |
| $h$                                                   | 消息已经完成的跳数                       | 非负整数               | 根据路径实时更新   | 表示消息传播位置                 |
| $q_v$                                                 | 节点级资源状态                         | `Idle`、`Busy`、`Saturated`、`Failed` | 状态机定义和日志 | 判断节点整体资源状态 |
| $q_m$                                                 | 消息或任务处理上下文状态               | 状态枚举               | 状态机定义和日志   | 决定当前消息下一步行为         |
| $Q_v(t)$                                              | 节点$v$ 在时刻 $t$ 的等待消息数量    | 条数                   | 仿真实时维护       | 计算排队延迟和拥塞               |
| $Q_v^{max}$                                           | 节点队列容量上限                         | 条数                   | 系统配置或压测     | 判断丢弃、拒绝或限流             |
| $\lambda$                                             | 一般消息到达率                           | 条/秒                  | 日志或场景配置     | 生成输入消息                     |
| $\lambda_{ext}$                                       | 外部任务到达率                           | 条/秒                  | 日志或场景配置     | 生成外部任务                     |
| $\lambda_v^{in}$                                      | 节点$v$ 的入站消息率                   | 条/秒                  | 日志或仿真统计     | 计算节点入站流量                 |
| $\lambda_v^{out}$                                     | 节点$v$ 的出站消息率                   | 条/秒                  | 日志或仿真统计     | 计算节点出站流量                 |
| $F$                                                   | 一条消息平均触发的下游消息数量           | 条/消息                | 日志统计           | 模拟任务拆分和流量放大           |
| $\mu$                                                 | 节点消息处理速度                         | 条/秒                  | 压测或日志统计     | 判断节点是否形成排队             |
| $A_v$                                                 | 时间窗口内到达节点$v$ 的消息数量       | 条                     | 仿真实时统计       | 更新节点队列                     |
| $D_v$                                                 | 时间窗口内节点$v$ 处理完成的消息数量   | 条                     | 仿真实时统计       | 更新节点队列                     |
| $p_{tool}$                                            | 思考后调用工具的概率                     | $0\sim1$             | 小规模日志统计     | 决定是否产生工具请求             |
| $p_{timeout}$                                         | 请求超时概率                             | $0\sim1$             | 日志或压测         | 触发超时和重试                   |
| $p_{fail}$                                            | 请求或节点处理失败概率                   | $0\sim1$             | 日志或压测         | 触发错误处理流程                 |
| $D_q$                                                 | 状态$q$ 的持续时间分布                 | 秒的概率分布           | 状态日志           | 安排状态完成事件                 |
| $\Delta t_q$                                          | 一次状态$q$ 的实际持续时间             | 秒                     | 从$D_q$ 抽样     | 推进仿真时间                     |
| $N_{out}$                                             | 一次状态转移产生的消息数量               | 条                     | 日志统计           | 创建新的消息事件                 |
| $M_{out}$                                             | 一次状态转移产生的输出消息集合           | 消息集合               | 日志统计或仿真生成 | 创建和传播输出消息               |
| $P(q'\mid q)$                                         | 从状态$q$ 转移到状态 $q'$ 的概率     | $0\sim1$             | 状态转移日志       | 选择下一内部状态                 |
| $P(q',\Delta t,N_{out},M_{out}\mid q,x_v,z_v,上下文)$ | 考虑能力、局部拓扑和上下文的状态转移模型 | 条件概率和分布         | 分组日志或模型估计 | 选择下一状态、持续时间和输出消息 |
| $P(destination\mid 上下文)$                           | 选择目标节点的概率                       | $0\sim1$             | 路由日志或配置     | 决定消息发往哪个节点             |
| $S_{request}$                                         | 请求消息大小分布                         | Byte 的概率分布        | 消息日志           | 生成请求流量                     |
| $S_{response}$                                        | 响应消息大小分布                         | Byte 的概率分布        | 消息日志           | 生成返回流量                     |
| $S_{result}$                                          | 最终结果消息大小分布                     | Byte 的概率分布        | 消息日志           | 生成任务结束流量                 |
| $B_v^{in}$                                            | 节点入站字节流量                         | Byte/秒                | 由消息统计         | 评价节点入站带宽需求             |
| $B_v^{out}$                                           | 节点出站字节流量                         | Byte/秒                | 由消息统计         | 评价节点出站带宽需求             |
| $B_e(T)$                                              | 链路$e$ 在时间窗口 $T$ 内的累计流量  | Byte                   | 由路径上的消息累加 | 评价链路总流量                   |
| $R_e(T)$                                              | 链路$e$ 的平均流量速率                 | Byte/秒                | $B_e(T)/T$       | 评价链路带宽利用情况             |
| `task_id`                                             | 一次完整任务的标识                       | ID                     | 运行日志           | 还原任务级调用链                 |
| `message_id`                                          | 一条消息的标识                           | ID                     | 运行日志           | 追踪消息生命周期                 |
| `parent_message_id`                                   | 当前消息的父消息标识                     | ID                     | 运行日志           | 分析消息触发关系                 |
| `timestamp`                                           | 事件发生时间                             | 秒或毫秒时间戳         | 运行日志           | 计算延迟和状态持续时间           |
| `retry_count`                                         | 当前消息已经重试的次数                   | 非负整数               | 日志或仿真维护     | 控制重试上限和统计重试流量       |
