agentscope-ai / agentscope-ai/agentscope-java

[Feature]: Expose typed model retry and fallback attempt events

未关闭
#2,136 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看
area/core/model enhancement
主要语言
Java
星标
5.6k
派生
1.3k
平均合并
4 天 12 小时
30 天内合并 PR
77

描述

## Motivation

AgentScope 2.0 supports model retry and fallback through `ExecutionConfig` / `ModelUtils` and `ReActAgent.Builder.maxRetries(...)` / `fallbackModel(...)`. The runtime behavior works, but `streamEvents()` currently exposes only one aggregate `MODEL_CALL_START` and `MODEL_CALL_END` boundary for the entire operation.

A product host therefore cannot answer, from typed runtime facts:

- which provider/model served the successful response;
- whether the primary was retried;
- whether fallback was activated;
- how many attempts occurred;
- whether the failure was rate-limit, timeout, authentication, network, or provider 5xx;
- which attempt consumed the reported usage/latency.

Parsing logs or synthesizing attempt facts in the host would create a second model-runtime truth source.

## Current behavior

`ReActAgent#modelCallStream(...)` emits:

```text
MODEL_CALL_START -> content block events -> MODEL_CALL_END
```

`modelForCall()` wraps primary/fallback internally. If the primary errors before its first signal, the wrapper switches to the fallback, but no typed event identifies that transition. Provider-level retry is applied inside model transport through `ModelUtils.applyTimeoutAndRetry(...)`, which is also not visible through `AgentEvent`.

A direct contract with a failing primary and successful fallback observes exactly one `MODEL_CALL_START`, one `MODEL_CALL_END`, and no retry/fallback event, even though the fallback completed the turn.

## Proposed contract

Please expose a typed attempt lifecycle owned by Core. Exact naming is open for discussion; one possible shape is:

```text
MODEL_ATTEMPT_START
MODEL_ATTEMPT_FAILED
MODEL_FALLBACK_ACTIVATED
MODEL_ATTEMPT_END
```

Suggested fields:

- logical model-call / reply id;
- attempt index and configured max attempts;
- provider id and model id/name;
- primary vs fallback role;
- typed failure category (`rate_limit`, `timeout`, `authentication`, `authorization`, `network`, `provider_5xx`, `invalid_request`, `unknown`);
- retryable flag and next action (`retry`, `fallback`, `fail`);
- sanitized status/error code without credential or response-body leakage;
- per-attempt latency and usage when available.

The existing aggregate `MODEL_CALL_START/END` can remain backward compatible around the full logical call.

## Required properties

- Events must come from Core/model transport, not product-host log parsing.
- No API keys, authorization headers, raw credential values, or sensitive response bodies.
- Works for both direct provider retries and `fallbackModel` transitions.
- Failed attempts do not create assistant messages or replay completed tool calls.
- Same behavior through `call()` and `streamEvents()` lifecycle.
- Provider implementations can map native errors into the shared failure taxonomy.

## Validation proposal

Tests should cover:

1. 429 and 5xx retry, followed by success.
2. 401/403 non-retryable classification.
3. timeout/network retry.
4. primary exhaustion followed by fallback success.
5. fallback failure.
6. fallback after a completed tool result without replaying the tool.
7. HITL approval continuation followed by fallback.
8. secret redaction in serialized events.

I have downstream contracts confirming fallback continuity, single execution of side-effecting tools, and the current aggregate-only event gap. I can prepare a focused PR after maintainers confirm the preferred event shape and whether retry events should originate in `ModelUtils`, middleware, or `ReActAgent`.

贡献指南

打开贡献指南

评估

这个 Issue 还没有评估数据。

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。