拓冰建站拓冰建站
首页 / 资讯中心 / 正文

OmniRoute Context Relay 上下文中继策略:跨账户轮换时的会话连续性保障

OmniRoute Context Relay 上下文中继策略跨账户轮换时的会话连续性保障【免费下载链接】OmniRouteNever stop coding. Free MIT AI gateway: one endpoint, 352 providers (150 free), 1200 models Kimi, Claude, GPT, Gemini, GLM, DeepSeek, MiniMax. Works with Claude Code, Codex, Cursor, OpenCode, Cline Copilot. Quota-aware auto-fallback, RTKCaveman compression saves 15-95% tokens, MCP/A2A, Desktop/PWA. Built by 550 contributors项目地址: https://gitcode.com/GitHub_Trending/om/OmniRoutecontext-relay是 OmniRoute 提供的一种 Combo组合路由策略用于解决多账户轮换场景下的会话断裂问题当活跃账户因配额耗尽而在对话结束前被切换时OmniRoute 会预先生成一份紧凑的结构化摘要并在确认账户真正切换后将摘要作为系统消息注入下一次请求让新账户无缝承接未完成的任务。本文基于 docs/i18n/ru/docs/features/context-relay.md 展开并结合 open-sse/services/contextHandoff.ts、src/sse/handlers/chat.ts 等源码讲清其运行时流程、交接载荷结构、配置字段与底层实现原理。核心概念在优先级路由之上叠加一层交接从模型选择的角度看context-relay的行为与普通优先级路由priority routing一致先按路由策略挑选目标账户。区别在于它在此基础上增加了一个交接层handoff layer其完整生命周期包含三步生成在活跃账户配额耗尽之前OmniRoute 在后台生成一份紧凑的结构化会话摘要注入当身份认证为同一会话选择了不同账户后OmniRoute 将该摘要作为系统消息system message注入到下一次请求中消费交接被成功消费后立即从存储中移除避免过期内容被重复注入。这三步分别对应仓库中的三处实现生成逻辑位于 open-sse/services/contextHandoff.tsmaybeGenerateHandoff注入逻辑位于 src/sse/handlers/chat.tsgetHandoffinjectHandoffIntoBody持久化与删除位于 src/lib/db/contextHandoffs.ts。适用场景原文档明确指出只有以下条件全部满足时才建议启用context-relayCombo 预期会在同一服务商的多个账户之间轮换丢失短期会话连续性会损害任务质量服务商暴露了足够的配额信息能够预测即将到达的账户上限。最典型的用例是超长编程或研究会话一次任务可能跨越单个账户的额度窗口需要在账户间接力完成。反之如果任务很短、单个账户完全够用或者服务商不提供配额探针则这个策略带来的收益有限。运行时流程按配额水位分阶段工作context-relay的行为被刻意拆分为两个运行时层级Combo 循环负责何时生成摘要认证与注入层负责何时注入摘要。整个流程按配额使用率分为四个阶段配额用量 0%84%不生成交接此时请求行为与普通优先级路由完全一致不产生任何摘要请求无额外开销。配额用量 85%94%后台预生成交接当配额使用率进入预警区间且活跃服务商在handoffProviders白名单中已启用时OmniRoute 会在账户完全耗尽前在后台生成一份结构化的交接摘要。几个关键细节默认警告阈值warning threshold为0.85对应源码中的HANDOFF_WARNING_THRESHOLD见 open-sse/services/contextHandoff.ts生成摘要的硬停止线为0.95对应HANDOFF_EXHAUSTION_THRESHOLD同文件 L13超过该水位不再调度新的摘要请求每个sessionId comboName只允许一个进行中的交接生成源码通过模块级SetstringinflightHandoffGenerations记录在途任务重复触发会被直接忽略见 maybeGenerateHandoff如果该会话/Combo 已存在活跃交接hasActiveHandoff命中也不会生成重复摘要。摘要生成采用setImmediate异步调度不阻塞主请求路径调用前还会执行cleanupExpiredHandoffs()清理过期记录。配额用量 95% 及以上不再生成此时系统已处于或接近耗尽状态运行时会避免再调度一个摘要请求——因为为生成摘要而消耗的配额可能进一步加剧耗尽。账户轮换后注入交接当同一会话的下一次请求经过身份认证后解析到的实际账户与生成交接时的账户不同时OmniRoute 将存储的交接作为系统消息前置注入到请求体中。注入只在实际账户切换被确认后发生——这是本策略正确性的关键前提详见下文架构说明。交接载荷与消息格式持久化结构context_handoffs 表持久化的交接载荷存储在context_handoffs表中字段与 src/lib/db/contextHandoffs.ts 中HandoffPayload接口一一对应字段说明sessionId会话标识与comboName共同构成交接的作用域与唯一键comboName产生交接的 Combo 名称fromAccount生成交接时活跃的账户connectionIdsummary紧凑摘要正文最大 2000 字符keyDecisions关键决策列表最多 8 项单项最长 240 字符taskProgress任务进度描述最大 1200 字符activeEntities活跃上下文实体文件、功能、服务商等最多 10 项messageCount参与摘要的消息条数model实际生成摘要所用的模型warningThresholdPct触发摘要的警告阈值默认 0.85generatedAt生成时间ISO 字符串expiresAt过期时间默认 TTL 为 5 小时DEFAULT_TTL_MS 5 * 60 * 60 * 1000写入使用INSERT ... ON CONFLICT(session_id, combo_name) DO UPDATE的 upsert 语义见 contextHandoffs.ts即同一会话同一 Combo 永远只保留一份交接新生成的会覆盖旧的。交接天然带过期时间并按sessionId comboName隔离不会串到其他会话。摘要模型的 JSON 输出契约摘要模型被提示词HANDOFF_PROMPT_TEMPLATE要求只返回一个结构固定的 JSON 对象不可附带 markdown 或解释{ summary: 对连续性重要内容的紧凑摘要, keyDecisions: [决策 1, 决策 2], taskProgress: 已完成项、待完成项以及下一步, activeEntities: [fileA.ts, 功能 X, 服务商 Y] }源码中的parseHandoffJSON会先剥除 markdown 代码围栏与omniModel标签再尝试JSON.parse若解析失败会退化为截取第一个{到最后一个}之间的片段。解析成功但summary为空时返回null该次生成被判定为 unparseable不会写入任何数据。生成摘要的请求本身带有内部标记_omnirouteInternalRequest: context-handoff与_omnirouteSkipContextRelay: true防止摘要请求自身再次触发交接逻辑或配额监控形成递归。摘要请求使用temperature: 0.1、max_tokens: 800且为非流式stream: false见 contextHandoff.ts。注入时的 context_handoff 系统消息注入时OmniRoute 将载荷转换为带 XML 语义的context_handoff系统消息见buildHandoffSystemMessagecontextHandoff.tscontext_handoff transfer_reasonAccount quota transfer - continuing from previous session/transfer_reason session_summary对连续性重要内容的紧凑摘要/session_summary task_progress已完成项、待完成项以及下一步/task_progress key_decisions - 决策 1 - 决策 2 /key_decisions active_contextfileA.ts, 功能 X, 服务商 Y/active_context messages_processed42/messages_processed /context_handoff所有动态内容都会经过 XML 转义、、、引号并追加一段指令You are continuing a conversation that was transferred from another account due to quota limits...引导新账户从上次会话结束的位置无缝继续。injectHandoffIntoBody对两类请求做了区分Responses 协议请求请求体含input或instructions字段会把交接文本拼接到instructions之前Chat Completions 请求则把交接作为role: system的消息插入messages数组头部见 contextHandoff.ts。配置字段context-relay支持以下配置字段全局默认值可在 Settings 中配置Combo 特定值可在 Combos 页面覆盖Combo 级配置优先于全局配置字段类型默认值说明handoffThresholdnumber0.85摘要生成的警告阈值必须在(0, 0.95)区间内否则回退到默认值handoffModelstring空可选模型覆盖仅用于摘要生成为空时使用当前请求的模型handoffProvidersstring[][codex]允许触发交接生成的服务商白名单未显式配置时默认仅codex此外源码中的ContextRelayConfig还暴露了两个扩展字段见 contextHandoff.tsmaxMessagesForSummary参与摘要的最大消息数默认30合法范围[5, 100]relayModeschema-locked | standard默认standard。schema-locked模式下摘要输入严格排除 system/developer 消息仅取最近的非系统消息适配对消息结构有严格要求的服务商。resolveContextRelayConfig的解析逻辑contextHandoff.ts值得注意handoffThreshold若不在(0, 0.95)内会被静默回退为0.85handoffProviders只有显式传入数组时才按白名单处理否则默认[codex]——这也是当前运行时支持集中于 codex 配额轮换的直接原因。架构说明为什么交接生成与注入被拆到两个文件原文档特别强调当前实现没有独立的handleContextRelayCombo处理器而是刻意采用分层设计open-sse/services/combo 决定成功的回合是否应生成交接。以 executeTargetAttempt.ts 为例当strategy context-relay、服务商在handoffProviders白名单中且为codex时Combo 层会通过fetchCodexQuota拉取账户配额信息计算使用率然后调用maybeGenerateHandoff决定是否触发后台摘要生成src/sse/handlers/chat.ts 负责注入在认证解析出本次请求实际使用的账户credentials.connectionId之后调用getHandoff(sessionId, comboName)仅当handoff.fromAccount ! credentials.connectionId即确认发生了真实账户切换时才调用injectHandoffIntoBody并把交接写入请求体同时打印CONTEXT_RELAY日志记录账户切换方向。这种分离是刻意的Combo 循环本身并不知道请求最终停留在同一账户还是切换了账户——账户选择发生在认证环节内部。如果把注入放在 Combo 层可能把交接注入到根本没切换账户的请求里浪费载荷且污染上下文。注入后交接并不会立即删除而是等该请求成功消费后才移除一次性消费语义。该行为在 tests/unit/chat-context-relay.test.ts 中有完整验证测试同时 seed 两个 Codex OAuth 账户codex-a配额 87%、codex-b配额 20%创建一个strategy: context-relay的 Combo断言首次请求触发摘要生成并写入context_handoffs下一次请求解析到不同账户时上游请求体中出现context_handoff且消费后getHandoff返回null。另一个测试还覆盖了 Responses 原生 Codex 请求在 live failover 期间的注入路径并回归验证账户切换后交接必须被注入、注入后必须被消费删除这一核心不变量。补充通用交接Universal Handoff需要说明的是contextHandoff.ts 中还实现了面向任意模型/服务商切换的通用交接maybeGenerateUniversalHandoff特性开关UNIVERSAL_CONTEXT_HANDOFF_ENABLED其触发时机可以是always每次回合、on-switch模型变化时默认或on-error错误回退后。这与context-relay的配额驱动路径共享同一套摘要生成、JSON 解析、存储与注入基建selectMessagesForSummary、parseHandoffJSON、upsertHandoff、context_handoff消息模板但作用域与触发依据不同前者按配额水位后者按模型切换。若配置了providerAllowlist通用交接还会校验摘要模型所属服务商是否在白名单内。当模型输出不可解析时系统会按(session, combo)维度记录退避冷却从 5 分钟指数增长到最长 1 小时避免在每次切换时反复发起注定被丢弃的上游摘要请求。局限性有效运行时支持目前集中于codex配额轮换handoffProviders虽然已建模为通用配置面但实际交接生成仍依赖服务商特定的配额管道目前主要是 codex 的 quota 接口摘要刻意保持紧凑并基于近期历史它不是完整对话回放机制。源码中的selectMessagesForSummary默认只取最近 30 条消息并通过estimateTokens将摘要输入裁剪到 8000 token 预算内交接作用域限定于sessionId comboName并自动过期默认 TTL 5 小时清理由cleanupExpiredHandoffs按节流30 分钟执行如果会话没有切换账户存储的交接不会被注入会一直保留到过期或被覆盖。推荐使用模式为同一服务商配置多个账户并放入同一 Combo在整个会话中保持稳定的sessionId因为交接按sessionId comboName索引sessionId 漂移会导致摘要无法命中将handoffThreshold设置得足够早例如 0.70.85为后台摘要请求留出执行时间——太接近 0.95 硬停止线时摘要可能来不及生成账户就已耗尽把context-relay当作连续性辅助工具而不是持久记忆的替代品摘要只承载当前任务做到哪、下一步做什么的短期上下文长期事实仍应依赖 OmniRoute 的记忆Memory或外部上下文机制。通过理解配额水位、交接载荷契约与双层架构你可以针对自己的多账户轮换场景精确调优context-relay让长会话在账户切换时真正无缝接力。【免费下载链接】OmniRouteNever stop coding. Free MIT AI gateway: one endpoint, 352 providers (150 free), 1200 models Kimi, Claude, GPT, Gemini, GLM, DeepSeek, MiniMax. Works with Claude Code, Codex, Cursor, OpenCode, Cline Copilot. Quota-aware auto-fallback, RTKCaveman compression saves 15-95% tokens, MCP/A2A, Desktop/PWA. Built by 550 contributors项目地址: https://gitcode.com/GitHub_Trending/om/OmniRoute创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门