fix(llm): classify "network connection error" as retryable SERVER_ERROR (#179)

Some providers (notably SiliconFlow) return "network connection error" in the response body when their backend is overloaded or the upstream model connection is disrupted. classifyError() had no pattern for this string, so it fell through to UNKNOWN (non-retryable), surfacing the raw error to the user on the first failure instead of running the exponential-backoff recovery. Adds the pattern to the SERVER_ERROR classifier and a friendly message mapping in extractUserFriendlyError(); bumps MAX_RETRIES from 5 to 10 so sustained wiki batch load can ride out provider flaps without surfacing an error to the channel user.

Closes #178
This commit is contained in:
倪程伟 2026-05-20 16:49:54 +08:00 committed by GitHub
parent 43136fc663
commit d7378273b2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -333,7 +333,7 @@ public class NodeStreamingChatHelper {
*/
private static final int CONTENT_REPEAT_CHECK_INTERVAL = 200;
private static final int MAX_RETRIES = 5;
private static final int MAX_RETRIES = 10;
// RATE_LIMIT: fail fast to failover chain staying on the same
// provider during a rate-limit window wastes time without recovery.
// SERVER_ERROR keeps MAX_RETRIES (upstream flaps often self-heal).
@ -449,7 +449,12 @@ public class NodeStreamingChatHelper {
// Reactor Netty wraps the raw socket cause in WebClientRequestException;
// surface that wrapper too so retries fire even when the cause chain
// string is "WebClientRequestException ...; nested ... SSLException".
|| msg.contains("WebClientRequestException")) {
|| msg.contains("WebClientRequestException")
// SiliconFlow and some other providers return "network connection error"
// in the response body when their backend is under high load or the
// upstream connection to the model server is disrupted. This is a
// transient server-side failure classify as retryable.
|| msg.contains("network connection error")) {
return ErrorType.SERVER_ERROR;
}
return ErrorType.UNKNOWN;
@ -1502,6 +1507,11 @@ public class NodeStreamingChatHelper {
if (msg.contains("rate_limit") || msg.contains("429")) return "Rate limit exceeded, please retry later";
if (msg.contains("timeout") || msg.contains("Timeout")) return "Request timeout, please retry";
if (msg.contains("502") || msg.contains("503") || msg.contains("504")) return "Model service temporarily unavailable";
// SiliconFlow and similar providers surface "network connection error" when their
// backend is under high load or the upstream model connection is disrupted.
// Treat this as a transient failure so the user gets a retry-oriented message.
if (combined.contains("network connection error"))
return "Model service network error, please retry in a moment";
// 截断过长的原始消息
return msg.length() > 100 ? msg.substring(0, 100) + "..." : msg;
}