agentic_huge_data_base / wiki
页面 RAGFlow · 5.3 错误处理与重试逻辑·DeepWiki 中文全文译文

5.3 · 错误处理与重试逻辑

复杂文档理解与引用检索 · 聚焦本章的模块关系、源码依据与实现要点。

项目RAGFlow 章节5.3 状态全文译文 模块接口与服务契约、测试、发布与运维、模型调用与提供方适配、认证、权限与安全
源码线索
  • api/apps/llm_app.py
  • conf/llm_factories.json
  • rag/llm/__init__.py
  • rag/llm/chat_model.py
  • rag/llm/cv_model.py
  • rag/llm/embedding_model.py
  • rag/llm/rerank_model.py
  • rag/llm/sequence2txt_model.py
  • rag/llm/tts_model.py
  • web/src/components/svg-icon.tsx
模块标签
  • 接口与服务契约
  • 测试、发布与运维
  • 模型调用与提供方适配
  • 认证、权限与安全
  • 系统架构

章节正文

错误处理与重试逻辑

错误处理与重试逻辑

相关源文件

本章引用的主要源码文件:

  • api/apps/llm_app.py
  • conf/llm_factories.json
  • rag/llm/__init__.py
  • rag/llm/chat_model.py
  • rag/llm/cv_model.py
  • rag/llm/embedding_model.py
  • rag/llm/rerank_model.py
  • rag/llm/sequence2txt_model.py
  • rag/llm/tts_model.py
  • web/src/components/svg-icon.tsx
  • web/src/constants/llm.ts
  • web/src/pages/user-setting/setting-model/constant.ts
  • web/src/utils/common-util.ts

本文档详细介绍了 RAGFlow 大语言模型(LLM)集成系统中实现的复杂错误处理与重试机制。该系统提供了带有指数退避策略的自动重试逻辑、错误分类以及可配置的重试策略,用于处理与外部大语言模型(LLM)提供商通信时出现的瞬时故障。

关于大语言模型(LLM)抽象层和模型类型的信息,请参阅 5.1 LLMBundle 与模型类型。关于特定提供商的实现,请参阅 5.2 提供商实现

概述

RAGFlow 在所有大语言模型(LLM)类型(包括对话、嵌入向量、重排序、计算机视觉(CV)、文本转语音(TTS)等)中实现了统一的错误处理与重试系统。该系统会自动将错误分类为可重试和不可重试两类,使用随机化指数退避策略重试瞬时故障,并提供细粒度的错误信息用于诊断。

核心的横切逻辑主要存在于每个模型领域的抽象 Base 类中,例如 rag/llm/chat_model.py(第 113-125 行)中的 Base 类以及 rag/llm/cv_model.py(第 42-51 行)中的计算机视觉(CV)模型。

来源: rag/llm/chat_model.py:39-51rag/llm/chat_model.py:113-125rag/llm/cv_model.py:42-51

错误分类系统

LLMErrorCode 枚举

系统定义了一个 LLMErrorCode 字符串枚举,用于分类与大语言模型(LLM)提供商通信时返回或遇到的常见错误条件。这套标准化的错误码使得跨提供商和模型类型的统一错误处理逻辑成为可能。

错误码描述
ERROR_RATE_LIMIT速率限制超出(例如 HTTP 429 或限流)
ERROR_AUTHENTICATIONAPI 密钥无效或授权错误(例如 HTTP 401)
ERROR_INVALID_REQUEST请求格式错误或参数无效(例如 HTTP 400)
ERROR_SERVER提供商端服务器错误(HTTP 500、502、503、504 等)
ERROR_TIMEOUT客户端或服务器端请求超时
ERROR_CONNECTION网络问题,如 DNS 故障或端点不可达
ERROR_CONTENT_FILTER因策略或安全规则导致内容被过滤/屏蔽
ERROR_MODEL模型未找到、不可用或超过最大轮次
ERROR_QUOTA配额/计费问题,如余额不足
ERROR_MAX_RETRIES达到最大重试次数
ERROR_GENERIC未分类或未知的错误类型
class LLMErrorCode(StrEnum):
    ERROR_RATE_LIMIT = "RATE_LIMIT_EXCEEDED"
    ERROR_AUTHENTICATION = "AUTH_ERROR"
    ERROR_INVALID_REQUEST = "INVALID_REQUEST"
    ERROR_SERVER = "SERVER_ERROR"
    ERROR_TIMEOUT = "TIMEOUT"
    ERROR_CONNECTION = "CONNECTION_ERROR"
    ERROR_MODEL = "MODEL_ERROR"
    ERROR_MAX_ROUNDS = "ERROR_MAX_ROUNDS"
    ERROR_CONTENT_FILTER = "CONTENT_FILTERED"
    ERROR_QUOTA = "QUOTA_EXCEEDED"
    ERROR_MAX_RETRIES = "MAX_RETRIES_EXCEEDED"
    ERROR_GENERIC = "GENERIC_ERROR"

来源: rag/llm/chat_model.py:39-51

错误分类方法

在对话模型的 Base 类(rag/llm/chat_model.py)中,_classify_error 方法使用一组与错误码关联的关键词列表来分类异常的错误消息。错误消息字符串会被转换为小写,并通过正则表达式与已知模式进行匹配:

  • 配额相关关键词包括 "quota""capacity""billing""欠费"
  • 速率限制关键词包括 "rate limit""429""too many requests"
  • 认证检查关键词包括 "auth""apikey""401""permission"
  • 服务器错误检测关键词包括 "503""500""unavailable"
  • 超时检查关键词包括 "timeout""timed out"
  • 连接问题检查关键词包括 "connect""network""dns"
  • 内容过滤检查关键词包括 "content""policy""blocked"
  • 模型错误检查关键词包括 "model""not found"

如果以上均不匹配,则错误默认为 ERROR_GENERIC

def _classify_error(self, error):
    error_str = str(error).lower()
    keywords_mapping = [
        (["quota", "capacity", "credit", "billing", "balance", "欠费"], LLMErrorCode.ERROR_QUOTA),
        (["rate limit", "429", "tpm limit", "too many requests", "requests per minute"], LLMErrorCode.ERROR_RATE_LIMIT),
        (["auth", "key", "apikey", "401", "forbidden", "permission"], LLMErrorCode.ERROR_AUTHENTICATION),
        (["invalid", "bad request", "400", "format", "malformed", "parameter"], LLMErrorCode.ERROR_INVALID_REQUEST),
        (["server", "503", "502", "504", "500", "unavailable"], LLMErrorCode.ERROR_SERVER),
        (["timeout", "timed out"], LLMErrorCode.ERROR_TIMEOUT),
        (["connect", "network", "unreachable", "dns"], LLMErrorCode.ERROR_CONNECTION),
        (["filter", "content", "policy", "blocked", "safety", "inappropriate"], LLMErrorCode.ERROR_CONTENT_FILTER),
        (["model", "not found", "does not exist", "not available"], LLMErrorCode.ERROR_MODEL),
        (["max rounds"], LLMErrorCode.ERROR_MODEL),
    ]
    for words, code in keywords_mapping:
        if re.search("({})".format("|".join(words)), error_str):
            return code
    return LLMErrorCode.ERROR_GENERIC
错误分类决策树
RAGFlow · 错误分类决策树 · 图 1
RAGFlow · 错误分类决策树 · 图 1

来源: rag/llm/chat_model.py:130-149

重试配置参数

重试机制通过参数化来提供对不同环境和使用场景的灵活性。这些参数可以在模型实例化时提供,也可以从环境变量中读取,支持全局默认值与每个实例的覆盖值。

参数环境变量默认值描述
max_retriesLLM_MAX_RETRIES5对瞬时错误的最大重试次数
base_delayLLM_BASE_DELAY2.0重试退避的基础延迟(秒)
max_rounds不适用5ReAct/工具的最大推理轮次
timeoutLLM_TIMEOUT_SECONDS600OpenAI 客户端的请求超时时间

这些参数在公共 Base 类的构造函数中设置,例如在对话模型(rag/llm/chat_model.py 第 114-122 行)中:

class Base(ABC):
    def __init__(self, key, model_name, base_url, **kwargs):
        timeout = int(os.environ.get("LLM_TIMEOUT_SECONDS", 600))
        self.client = OpenAI(api_key=key, base_url=base_url, timeout=timeout)
        # ...
        self.max_retries = kwargs.get("max_retries", int(os.environ.get("LLM_MAX_RETRIES", 5)))
        self.base_delay = kwargs.get("retry_interval", float(os.environ.get("LLM_BASE_DELAY", 2.0)))
        self.max_rounds = kwargs.get("max_rounds", 5)

来源: rag/llm/chat_model.py:113-125rag/llm/cv_model.py:44-47

重试策略与退避

带抖动的指数退避

RAGFlow 采用随机化延迟计算来进行重试尝试,以减轻同步重试导致的负载峰值问题(即"惊群"问题)。延迟的计算方式是将基础延迟乘以一个介于 10 到 150 之间的随机浮点数因子。

def _get_delay(self):
    return self.base_delay * random.uniform(10, 150)

这会产生一个较宽的延迟范围:如果 base_delay 为 2 秒,则实际重试延迟在 20 到 300 秒之间,引入了显著的抖动。

重试延迟计算流程
RAGFlow · 重试延迟计算流程 · 图 2
RAGFlow · 重试延迟计算流程 · 图 2

重试会在尝试之间等待计算出的延迟时间。

来源: rag/llm/chat_model.py:127-129

可重试错误与不可重试错误

系统区分了哪些错误码值得重试:

  • 可重试: 速率限制错误(ERROR_RATE_LIMIT)、瞬时服务器错误(ERROR_SERVER)。
  • 不可重试: 认证错误、无效请求错误、内容过滤、配额问题和通用错误。

对话模型 Base 类的内部重试逻辑(处理对话完成或流式传输期间的异常)应用此分类来决定重试行为。

捕获异常后的流程如下:

  1. 使用 _classify_error 分类错误。
  2. 如果重试次数超过 max_retries,返回 MAX_RETRIES_EXCEEDED 错误。
  3. 如果错误可重试,计算延迟并在休眠后重试。
  4. 否则,中止重试并返回一个以 "**ERROR**" 为前缀的错误消息字符串。
ChatModel 中的重试决策流程图
RAGFlow · ChatModel 中的重试决策流程图 · 图 3
RAGFlow · ChatModel 中的重试决策流程图 · 图 3

来源: rag/llm/chat_model.py:130-149rag/llm/chat_model.py:212-243

集成与实现细节

API 层超时保护

用于设置大语言模型(LLM)API 密钥的 API 端点(api/apps/llm_app.py)使用 asyncio.wait_for 实现了上限超时,以限制请求持续时间(默认为 10 秒)。这可以保护用户界面(UI)免受模型内部逻辑中长时间挂起重试的影响。

API 中的示例:

timeout_seconds = int(os.environ.get("LLM_TIMEOUT_SECONDS", 10))
# 使用示例测试嵌入编码
arr, tc = await asyncio.wait_for(
    asyncio.to_thread(mdl.encode, ["Test if the api key is available"]),
    timeout=timeout_seconds,
)

这会在交互式用户界面(UI)层对大语言模型(LLM)调用实施时间限制,补充了模型类中嵌入的重试逻辑。

API 超时与重试流程
RAGFlow · API 超时与重试流程 · 图 4
RAGFlow · API 超时与重试流程 · 图 4

来源: api/apps/llm_app.py:87api/apps/llm_app.py:101-104api/apps/llm_app.py:124

模型特定的错误处理注意事项
  • 内置嵌入模型rag/llm/embedding_model.py)使用带有线程锁的单例初始化,并相应地委托编码调用。它在内部处理错误。
  • Xinference ASR 模型rag/llm/sequence2txt_model.py)直接发起 HTTP 请求,使用标准异常处理,返回以 "**ERROR**" 为前缀的错误。
  • 计算机视觉(CV)模型rag/llm/cv_model.py)使用 try-except 包装对话调用,并在异常时生成错误字符串。
  • Fish Audio TTSrag/llm/tts_model.py)捕获 HTTP 错误并抛出带有 "**ERROR**" 消息格式的 RuntimeError

这些模型展示了 RAGFlow 如何在不同的交互模型中保持一致的错误消息和重试模式。

来源: rag/llm/embedding_model.py:123-157 rag/llm/sequence2txt_model.py:82-125, 176-210 rag/llm/cv_model.py:141-150, 152-173 rag/llm/tts_model.py:146-185

错误消息协议

终端错误始终作为以 "**ERROR**" 为前缀的字符串结果返回。这种模式有两个目的:

  1. 在编程上区分错误情况与正常响应。
  2. 允许下游组件(如前端用户界面(UI)或代理工作流引擎)检测失败并显示用户友好的消息或采取纠正措施。

此外,由于 Token 或上下文长度限制导致的截断响应会通过特殊的通知字符串指示(例如,中文的 "······\n由于大模型的上下文窗口大小限制,回答已经被大模型截断。" 或对应的英文消息),这些也在 rag/llm/chat_model.py 中定义。

来源: rag/llm/chat_model.py:59-61rag/llm/cv_model.py:150rag/llm/sequence2txt_model.py:123

总结图表:自然语言到代码实体的映射

大语言模型(LLM)错误处理组件与关键代码实体
RAGFlow · 大语言模型(LLM)错误处理组件与关键代码实体 · 图 5
RAGFlow · 大语言模型(LLM)错误处理组件与关键代码实体 · 图 5
跨大语言模型(LLM)模型的重试工作流
RAGFlow · 跨大语言模型(LLM)模型的重试工作流 · 图 6
RAGFlow · 跨大语言模型(LLM)模型的重试工作流 · 图 6

本文介绍了强大的错误分类与重试系统,该系统通过智能处理瞬时问题和故障,确保 RAGFlow 与多个大语言模型(LLM)提供商之间实现流畅且具有弹性的交互。

来源:

  • rag/llm/chat_model.py:39-51, 113-149, 212-243
  • rag/llm/cv_model.py:42-51,141-173
  • rag/llm/sequence2txt_model.py:32-125,176-210
  • rag/llm/tts_model.py:146-185
  • api/apps/llm_app.py:79-151