agentscope-ai / agentscope-ai/agentscope-java

[Bug]:主agent停止子agent不停

Abierto
#1,577 0 comentarios 0 reacciones 0 asignados Ver en GitHub
area/harness bug
Lenguaje dominante
Java
Estrellas
5.6k
Forks
1.3k
Merge medio
4 d 12 h
PR fusionados (30 d)
77

Descripción

你的判断是对的。这是一个**真实存在的取消传播断裂问题**。

## 问题本质

Reactor 的取消信号传播依赖于**完整的订阅链**——从下游 `Subscriber` 到上游 `Publisher`,`cancel()` 信号沿 `Subscription` 逐级回传。一旦链中任何环节调用了 `.subscribe()` 且未保存 `Disposable`,就等于开了一个"脱管的火", cancel 信号无法穿越这个边界。

在 [AgentSpawnTool.execLocalSync](agentscope-harness/src/main/java/io/agentscope/harness/agent/tool/AgentSpawnTool.java#L454-L507) 中,子 Agent 的调用链设计为:

```
父 Mono 链 → execLocalSync (deferContextual) → invokeAgentStream → doOnNext(bus::emit) → .last() → .map()
```

这条链本身是纯响应式操作符组合,cancel 信号**理论上**可以传播。但问题出在 `AgentBase.createEventStream()`——根据其 Javadoc(见 [AgentSpawnTool.java#L60-L67](agentscope-harness/src/main/java/io/agentscope/harness/agent/tool/AgentSpawnTool.java#L60-L67)):

> *"When a `SubagentEventBus` is present in the Reactor Context (injected by `AgentBase.createEventStream`)..."*

`createEventStream()` 是设置 `SubagentEventBus` 并注入到 Reactor Context 的入口。如果它内部对 Flux 做了 `.subscribe()` 来桥接事件而**没保存 Disposable**,那么:

1. 父 Agent 响应式链被 cancel → 信号传到 `execLocalSync` 的 `deferContextual`
2. 但 `invokeAgentStream` 内部如果已经通过 `.subscribe()` 消费了子 Agent 的事件流
3. 那个 `.subscribe()` 创建了**独立的订阅**,与父链无关
4. **cancel 信号无法到达子 Agent 的实际执行流** → 子 Agent 继续运行

## 影响范围

| 场景 | 是否受影响 |
|---|---|
| `call()` 模式(非 streaming) | ⚠️ 不受影响——走 `invokeAgent` 非流式路径,没有 `.subscribe()` 桥接 |
| `stream()` 模式 + 子 Agent | ❌ **受影响**——`createEventStream` 内部的 `.subscribe()` 打断链路 |
| 异步子 Agent(timeout=0) | ❌ 本来就不在链上,不受影响(需 `task_cancel`) |

## 修复方向

要修复这个问题,有两个思路:

**思路 A:保存 Disposable,在父链 cancel 时主动 dispose**

```java
// createEventStream 内部应类似:
Disposable childSub = childFlux.subscribe(sink::next);
// 在父链的 onCleanup/doFinally 中:
childSub.dispose();
```

**思路 B:避免手动 subscribe,用响应式操作符桥接**

```java
// 不用 .subscribe(),而是将子 Flux 直接嵌入父链:
childFlux.doOnNext(bus::emit)
.then(mainChain); // 通过操作符组合保持链路完整
```

思路 B 更符合 Reactor 的编程范式——**能用操作符就不要手动 subscribe**。手动 subscribe 是响应式编程中的"goto",一旦用了就得自己管生命周期。

---

你抓到了一个值得提 issue 的 bug。子 Agent 不随父 Agent 停止,在生产环境下不仅是资源泄漏,还可能导致幽灵任务持续消耗 token。

建议深入阅读:
- [钩子系统与事件](9-hook-system-and-events) — Hook 中可注入清理逻辑作为临时缓解方案
- [子 Agent 管理](24-subagent-management) — 子 Agent 生命周期完整文档
- [中断与人机协同](10-interruption-and-human-in-the-loop) — interrupt 机制与 cancel 传播的交互

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.