快速结论:当多轮 /v1/responses 请求被 encrypted_content_affinity 钉在某个 deployment 上,而该 deployment 因为 cooldown/限流/瞬时故障被移出 healthy_deployments,且同一 model group 内每个 deployment 的 (api_base, api_key) 都唯一(多区域 PrivateLink/Azure/Bedrock 拓扑)时,检查逻辑找不到任何 peer,会直接抛 RateLimitError/ServiceUnavailableError。报错原文中的关键信息是:[Bug]: encrypted_content_affinity has no fallback when the pinned deployment is unavailable or removed, permanently bricking multi-turn Resp。优先排查你的 model group 是否存在“每个 deployment 一个独立 api_base”的架构,以及被钉住的那个 deployment 当前是否在健康池里。
适用环境:Issue 讨论基于 LiteLLM 仓库 main 分支提交 e484a7c 验证;未提供操作系统、Python、CUDA、显卡版本信息。文中提到的拓扑为多区域 PrivateLink、多区域 Azure/Bedrock,示例模型为 gpt-6-sol/gpt-6-luna,客户端为 Codex 及任何实现 previous_response_id/reasoning replay 的客户端。
最快修复方案:暂无确认的一步修复方案。Issue 目前状态是:Case 1(deployment 被彻底移除/改配,不再属于 routed group)在 main(e484a7c)已通过 strip-and-dispatch 分支修复;Case 2(origin 仍是 routed group 成员但被排除出 healthy_deployments)仍是有意设计的 fail-fast,社区建议的“配置逃生开关(把 member-but-unavailable + 零 boundary peer 按非成员处理,strip 后派发)”属于可优先尝试的方向,但 Issue 中未确认落地。
注意事项:Case 2 的 fail-fast 是官方文档化的契约,强行 strip 后派发到非 peer deployment 有概率触发上游 invalid_encrypted_content 400;Issue 作者认为这一次 400 严格优于客户端必然收到的 429/503,但这只是该 Issue 中的论证,不是已验证结论。如果你的环境关闭了 disable_cooldowns,故障可能持续较长时间。另外不要混淆相关但不同的 Issue:#41792/#41793 讲的是共享凭据下有意切换模型,被跨模型 reasoning 拒绝;#40364 讲的是 Chat Completions→Responses 桥接从未被 affinity 钉住。
问题场景
用户在 LiteLLM 代理上使用原生 /v1/responses 接口进行多轮对话(典型客户端是 Codex,或任何回放 previous_response_id/encrypted_content 的 agentic 客户端)。当 model group 的部署被设计成每个 deployment 拥有独立的 api_base(多区域 PrivateLink、多区域 Azure/Bedrock,或任何“负载均衡存在的前提就是每个后端是独立资源/区域”的拓扑)时,EncryptedContentAffinityCheck.async_filter_deployments 会把请求钉在产生 encrypted_content 的那个 deployment 上。一旦该 deployment 因为 cooldown、限流或瞬时容量节流被移出 healthy_deployments,由于 (api_base, api_key) 在本地拓扑下只能唯一标识一个 deployment,检查逻辑结构性地找不到任何 peer,于是抛出 hard 503。即使配置了 disable_cooldowns: true,同一 model group 内其他具备 reasoning 能力的健康 deployment 也无法接管这一轮。
报错原文
[Bug]: encrypted_content_affinity has no fallback when the pinned deployment is unavailable or removed, permanently bricking multi-turn Resp
ServiceUnavailableError (503)
RateLimitError
BadRequestError: re-issue the request without the stale encrypted_content items
原因分析
最可能的原因有两个分支,Issue 中已明确区分:
- Case 1(origin 已不属于 routed group):被钉住的
model_id被移除或重新配置(例如运行期/model/new+/model/{id}/update/delete 注册,常见于在values.yaml之外做 day-0 模型支持),router.get_deployment(model_id=...)返回None。在较新的main(e484a7c)上,代码会通过_routed_group_candidate_model_ids(encrypted_content_affinity_check.pyL205-214)判断 origin 不是 routed group 的候选,从而剥离input/messages里的加密 reasoning,保留可读历史并派发到 routed group(L367-389)。所以“永久移除导致会话彻底报废”这一半在近期main上已不成立。 - Case 2(origin 仍是 routed group 当前成员,但被排除出
healthy_deployments):这是有意的 fail-fast,会抛与 cooldown 镜像的RateLimitError/ServiceUnavailableError,并把Retry-After设为剩余 cooldown 窗口(L391-397;docstring L299-310)。文档化理由是:把被钉住的请求派发到非 peer deployment 会保证上游 400,所以快速失败并期望客户端在 cooldown 后重试。
结构性问题在于:当每个 deployment 的 api_base 都不同时,(api_base, api_key) peer 永远是空的,于是 Case 2 不是罕见的边角情况,而是多区域拓扑的常态——任何一次瞬时 cooldown 都会变成客户端可见的硬失败,且整个 cooldown 期间没有 strip-and-dispatch 逃生路径。Issue 作者进一步指出,“fail fast 让客户端重试”这个默认假设并不安全,因为 Codex 这类 agentic 客户端通常不会针对这种错误形态做 retry-after 退避,而是原样重放并撞同一堵墙。
环境排查
- 确认 LiteLLM 版本/提交:Issue 讨论基于
main分支e484a7c,先确认你的部署是否包含该提交之后的代码。 - 确认 model group 拓扑:每个 deployment 的
api_base是否互不相同(多区域 PrivateLink、多区域 Azure/Bedrock 等)。 - 确认
disable_cooldowns配置状态:Issue 作者提到“某些环境关闭了disable_cooldowns”,故障可能持续较长时间。 - 确认被钉住的
model_id当前是否仍注册、是否仍属于该 routed group 的候选。 - 确认客户端类型:是否为 Codex 或实现了
previous_response_id/reasoning replay 的客户端,这类客户端不会自行剥离encrypted_content。 - Issue 未提供操作系统、Python、CUDA、PyTorch、显卡、依赖版本信息,无法据此判断。
解决步骤
- 先定位报错属于哪个 Case。检查日志中被钉住的
model_id:如果它已不在 routed group 候选内(被移除/改配/层级变更/伪造标记),在含e484a7c之后的main上应自动走 strip-and-dispatch 分支,升级到该版本可优先尝试。 - 如果
model_id仍是 routed group 的当前成员,只是被排除出healthy_deployments(cooldown/限流/节流),那么你现在遇到的就是尚未修复的 Case 2。 - 临时缓解可优先尝试:调整拓扑,让同一 model group 内的 deployment 共享
(api_base, api_key),从而让 encryption-boundary peer 存在,使检查能找到 fallback 目标。 - 另一条可优先尝试的缓解:确保
disable_cooldowns按预期生效,减少 deployment 被移出健康池的概率;但注意 Issue 指出这并不能覆盖 provider 侧的瞬时问题。 - 如果希望跟进上游修复:Issue 中社区提议的方向是增加配置逃生开关,把“member-but-unavailable + 零 boundary peer”按非成员处理(strip 后派发),复用 L387-389 的 strip 机制。该方案在 Issue 中未确认落地,可优先尝试向上游提交/关注此需求,不要在生产中假设它已可用。
- 在 Case 2 未修复期间,对于已经进入故障会话的 Codex 客户端,Issue 作者确认客户端没有恢复路径,实际只能由用户开启全新对话来绕过。
验证方法
在含 main(e484a7c 及之后)的版本上,构造 Case 1 场景:把某个曾经产生过 encrypted_content 的 deployment 从注册中删除,然后继续多轮 /v1/responses 对话。如果请求不再抛 BadRequestError,而是正常返回并继续对话(加密 reasoning 被剥离、可读历史保留),说明 Case 1 的修复生效。对于 Case 2,目前没有已验证的“修复后”行为可对照;只能确认在 deployment 被排除出 healthy_deployments 期间是否仍稳定抛 RateLimitError/ServiceUnavailableError。Issue 未提供具体的集成测试命令或断言,建议以实际拓扑复现为准。
参考来源
AI 工具推荐
想把多个 AI 模型放在一个入口?
GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。
推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。
这个方案解决了吗?
可以继续搜索完整报错,或查看同一工具的其他排查指南。
![[Security] Memory content injected into system prompt without sanitization enables indirect prompt injection](https://www.chat-gpts.plus/wp-content/uploads/2026/09/5057-ee12e05b-768x403.jpg)

![[Bug]: --gpu-device-id has no effect when used with --directml on an AMD GPU](https://www.chat-gpts.plus/wp-content/uploads/2026/09/4024-b3734cdf-768x403.jpg)