news 2026/9/6 4:09:49

大模型混合部署实战:路由层与多Agent编排的高可用架构

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
大模型混合部署实战:路由层与多Agent编排的高可用架构

1. 混合部署的动机:别在选边站上折腾了

1.1 全本地和全云端的苦,我都吃过

做混合大模型架构之前,我先在"全云端"和"全本地"这两个极端方案里各待过一段时间,两边的问题都很真实。

全云端部署的时候,接入成本确实低,注册账号开个Key就能调,模型能力也强,今天GPT级别的推理水平很难用本地小模型直接替代。但真正放到业务里跑起来,问题就接踵而至:首先是数据链路,内部系统的工单、代码片段、客户信息一旦过云端API,隐私合规这道坎就绕不过去,很多企业不是不想用,是根本不敢把数据送出去。其次是成本,你以为按Token计费很灵活,但当Agent在复杂任务里来回调用、反复推理的时候,账单增长是肉眼可见的。再一个是延迟,每一次调用跨公网走一圈,正常情况一两秒,高峰期排队起来就完全不可控了,这对实时性要求高的场景非常致命。

全本地部署则是另一个极端。模型确实私有化了,延迟也低了,数据也不用出境了。但团队很快就发现,本地部署的模型在复杂推理、代码生成、长文本理解上的表现和云端商用模型有实质差距。业务方会说"这个模型回答的答案没法用",技术方则被困在硬件维护、模型迭代、显存管理的泥潭里。我们当时部署了一台8卡A800的机器跑开源模型,为了达到还不错的推理效果,光是量化精度、vLLM参数、并发策略就调了好几周,最后效果也只是"勉强能用"。更要命的是模型本身的迭代速度,云端大模型可能隔几个月就有一次能力跃迁,而本地方案从选型、评估到上线,一个版本跑半年很正常。

所以"全部上云"和"全部本地"都不是最优解。真正跑过业务之后你会发现,大部分实际需求是分层的:一部分数据敏感、对延迟有硬性要求的任务,适合留在本地;另一部分需要强推理能力、对创造性要求高的任务,完全可以放云端。混合部署不是炫技,而是被业务逼出来的必然选择。

1.2 什么场景真的需要混合架构

不是所有团队都需要混合部署。我见过不少项目,明明业务量很小,硬要搭一套复杂的混合架构,结果维护成本比模型调用成本还高。判断要不要走这条路,我一般看三个条件:

  • 数据条目分级:业务里是否有明确区分"可出域"和"不可出域"的数据类型,且不可出域的数据量占比够大、任务够重。
  • 延迟敏感度:用户交互链路中是否存在"必须几百毫秒内返回"的关键路径,比如对话中间件、实时助手、流程控制节点。
  • 能力分层需求:业务任务是否能按复杂度、推理深度、专业领域做明确分层,低难度高频任务与高难度低频任务的比例是否明显。

如果三条都不沾,直接全云端就完事了。如果三条里有两条成立,混合架构的价值就很明显。

下表是我踩过很多坑之后整理的一个简单判断矩阵,可以直接拿去对照自己的业务场景:

判断维度适合全云端适合全本地适合混合架构
数据敏感度低,基本都是公开信息极高,完全不能出境有明显分层,部分敏感部分不敏感
延迟要求秒级可接受毫秒级硬性要求关键路径毫秒级,非关键路径秒级可接受
任务复杂度简单问答、文本分类有限领域的重复性任务高复杂度与高频低难度任务并存
成本预算充足,可接受Token费用一次性硬件投入可承受需要平衡硬件与Token成本
运维能力几乎为零有专业算法与运维团队有基础运维能力和代码能力

混合架构真正适配的是那种"既不想被云端绑定,又不想被本地模型能力卡死"的中间态团队,这个中间态范围其实比很多人想象的要大。

1.3 混合架构的分层视图

在设计阶段,我习惯把整个系统拆成四层,每一层只关心自己的事:

  • 接入层:接收用户请求或业务系统触发的任务,做基础鉴权和参数校验。这一层不关心背后是哪个模型在回答,也不关心有多少Agent在同时干活。
  • 路由层:整个架构里最核心的决策层。它拿到请求后,根据预设策略判断"这个任务应该走本地模型还是云端模型""走哪个模型""要不要切换Agent",同时负责负载均衡、故障转移、灰度支持。
  • 编排层(多Agent层):处理任务拆解、Agent调度、工具调用、状态同步。这一层相当于团队的"项目经理"。
  • 模型层:底部实际执行推理的模型资源,既包括本地私有化部署的开源模型,也包括云端的商用模型API。

四层之间的关系是单向依赖的:接入层只依赖路由层,路由层依赖编排层和模型层,编排层通过路由层获取模型资源。没有这种清晰分层的时候,系统会变成一团乱麻——Agent里直接写死"调用GPT-4"、"调用本地Llama",一旦模型服务变更,代码跟着改,风险极大。

我见过有些团队的代码里到处散落着对不同模型的直接调用,没有一层统一的"模型入口",这就导致每次模型升级、Key轮换、本地服务重启都必须动业务代码。路由层就是解决这个问题的最短路径——把"用哪个模型"从业务逻辑里抽出来,变成一个可配置、可观测、可运维的独立服务。

2. 路由层设计:把"模型选择"从代码里拆出来

2.1 路由到底在解决什么问题

很多人一听"路由"这个词,第一反应是网络设备里的路由表,或者是前端框架里的URL路由。在大模型架构上下文里,"路由"解决的其实是同一个本质问题:把一个请求分发到最合适的目标去处理。只不过这里的目标从一个IP地址变成了一组模型实例(本地模型服务、云端API、不同规格的模型)。

路由层需要决策的维度比网络路由复杂得多,不仅要看"哪个目标可用",还要看"哪个目标更适合当前任务"。同样一段推理请求,本地7B模型处理耗时可能只要800毫秒,但回答质量一般;云端满血模型处理可能要5秒,但回答质量高。路由层就要根据场景做平衡:这个请求是给用户看的最终答案,还是中间过程中的一个判断?如果只是做实体抽取、意图识别这类中间任务,本地小模型完全够用。

我把路由层要解决的几个核心问题总结如下:

  • 可达性路由:哪些模型服务当前健康可用,被限流了没有,队列长度是否超标。
  • 能力路由:当前请求需要什么样的模型能力,代码生成、复杂推理、多模态理解还是简单文本处理。
  • 策略路由:数据是否敏感、预算是否充足、是否有特定模型要求,这些条件在什么优先级下生效。
  • 成本路由:同样的任务,本地模型的边际成本远低于云端,能否在效果损失可控的前提下优先走本地。

2.2 路由维度的落地配置

路由策略如果写在代码里,很快就会变成一团无法维护的意大利面。我建议从一开始就把它做成独立的配置项,用结构化配置来描述"什么条件下路由到哪"。下面这个YAML示例是我在实际项目里用过的简化版本,字段基本可以覆盖多数场景:

router: default_policy: local_first # 默认策略:尽量走本地 targets: - name: local_vllm_7b type: local endpoint: http://127.0.0.1:8000/v1/chat/completions max_concurrency: 16 cost_per_1k_tokens: 0.0001 health_check_interval: 15s - name: local_vllm_32b type: local endpoint: http://127.0.0.1:8001/v1/chat/completions max_concurrency: 8 cost_per_1k_tokens: 0.0005 health_check_interval: 15s - name: cloud_gpt4o type: cloud endpoint: https://api.example.com/v1/chat/completions model_name: gpt-4o max_concurrency: 50 cost_per_1k_tokens: 0.03 health_check_interval: 30s routes: # 带敏感信息的任务,强制走本地 - name: sensitive_data when: tags_include: ["sensitive"] target: local_vllm_7b priority: 100 # 需要强推理能力的任务,走云端 - name: complex_reasoning when: task_type: "reasoning" complexity: "high" target: cloud_gpt4o priority: 80 # 中间过程判断,走本地小模型 - name: intermediate_judgement when: task_type: "extract" # 实体抽取、意图识别 target: local_vllm_7b priority: 60 # 长文本生成或代码补全,走本地32B - name: code_generation when: task_type: "code" target: local_vllm_32b priority: 50 # 默认兜底:如果上面的规则都没匹配,走本地 - name: fallback when: all_else: true target: local_vllm_7b priority: 1

这个配置的核心思想是:每条路由规则由条件、目标、优先级三部分组成,运行时执行顺序按优先级降序匹配,命中即返回。这样每次模型上线、下架、调整策略,不需要改代码,只需要改配置并热加载。

2.3 动态路由与状态感知

静态配置只能解决"把请求按固定规则分发"的问题,真正让路由层变得可靠的是动态状态感知。模型服务的健康状况是实时变化的,路由层必须有能力动态调整目标权重,而不是死板地按配置走。

健康检查要做两层。第一层是基础探测,定期向模型的health接口发心跳请求,确认进程是否活着、显存是否够、是否会OOM。第二层是"流量感知",一个模型端点的历史成功率、平均响应时间、Token生成速度会实时写入一个滑动窗口,路由决策时会参考这些指标。

具体的动态调整逻辑我用过一个相对实用的方案:

全局状态维护: 1. 每个模型端点维护一个 HealthScore(0~100) 2. 健康检查成功:+10,失败:-30,连续失败3次置0 3. 端点置0后进入冷却时间,冷却期内不分配流量 4. 冷却期结束后进入半开状态,放少量探针请求,成功则恢复 路由判定逻辑: 1. 根据请求元信息(任务类型、敏感标签、复杂程度)匹配静态路由规则 2. 对候选目标按 HealthScore 过滤,低于阈值的直接剔除 3. 多个同等级候选目标之间,按权重负载均衡

这个方案实现成本不高,但对高可用性的提升非常明显。有一次我们的本地模型服务因为显存碎片问题导致推理质量下降,但进程本身没挂,基础健康检查完全看不出来。后来是流量感知发现平均Token生成速度从60 tokens/s降到15 tokens/s,自动降低了它的权重,把新请求导向了备用端点,才避免了故障扩散。

3. 多Agent编排:让Agent当一个有组织的工作组

3.1 三种协作模式的取舍

多Agent架构不是简单地把多个Agent实例启动起来就算完事,关键在"协作"两个字。一个负责拆任务、一个负责执行、一个负责校验、一个负责汇总,它们之间怎么通信、怎么避免重复劳动、怎么处理互相依赖,这才是架构设计中最耗精力的部分。

实践下来,Agent之间的协作模式有三种相对成熟的选择:

  • 主管-工人模式(Supervisor-Worker):用一个主管Agent负责任务分解、派发和结果汇总,工人Agent只负责执行具体的子任务。这种模式最容易理解和实现,适合"目标任务明确、子任务之间没有复杂依赖"的场景。
  • 流水线模式(Pipeline):Agent A的输出是Agent B的输入,任务按固定顺序流转。适合重写、翻译、内容生产这类"后一步依赖前一步结果"的任务。
  • 网状模式(Mesh/Graph):Agent之间可以互相通信、动态决定下一步谁执行。灵活度最高,但状态管理复杂度也随之指数级上升,适合高度动态的任务编排场景。

我个人的建议是:能用主管-工人模式解决的问题,绝不上网状模式。网状模式听起来很酷,但工程上对状态同步、死锁处理、任务重试的要求非常高,一旦链路复杂了,排查问题会非常痛苦。多数业务场景下,主管-工人加上流水线就已经能覆盖90%以上的需求了。

3.2 Agent并发与上下文管理

Agent并发的问题在本地部署场景下会被无限放大。云端API的并发上限通常由服务商控制,有明确的配额管理;而本地模型服务的并发能力受限于GPU显存和推理引擎配置,一旦并发过高,请求会在模型层排队,响应时间急剧恶化,甚至触发OOM。

我们当时给Agent配置并发的参数体系大致是这样设计的:

agent_concurrency: max_agents_per_task: 5 # 单个任务最多拆出多少个并行子Agent max_concurrent_tasks: 8 # 全局最多同时处理多少个任务 # 每个Agent处理时的模型调用限制 model_call_limits: local_small: 20 # 本地7B模型:Agent每秒最多调用20次 local_medium: 10 # 本地32B模型:Agent每秒最多调用10次 cloud_api: 5 # 云端API:Agent每秒最多调用5次 # Agent内模型调用的并发信号量 semaphore_pool: local_small_max_wait: 30s local_medium_max_wait: 60s cloud_api_max_wait: 90s

这套配置的本质是三层限流:Agent级别限制"一个Agent内并行的模型调用数",任务级别限制"一个任务内并行的Agent数",全局限制"同一时间运行的任务数"。三层配合,才能保证底层模型服务不会因为Agent的突发请求而被打爆。

实际运行中比并发更隐性的问题往往出在上下文上。多Agent协同的上下文膨胀比单Agent更严重。一个主管Agent要记住所有子Agent的返回结果,如果每个子Agent都返回几千Token的内容,几个子Agent跑完,主管的上下文窗口就被撑爆了。我们当时的处理办法是规定子Agent回传主管的内容必须是"结构化摘要而非原文",比如让子Agent用JSON格式只回传"结论、关键依据、置信度、所需资源",把大段原始输出落盘保存,而不是塞进主管上下文。

3.3 Agent与路由层的通信契约

多Agent和路由层之间必须有一个清晰的通信契约,否则两边各写各的,最终对接时必然是一堆临时补丁。我的实践是让Agent在发起模型调用时带上明确的路由元信息,路由层根据这些元信息做决策:

{ "agent_id": "worker_code_review_01", "agent_role": "code_reviewer", "task_id": "task_xxx_001", "request_meta": { "task_type": "code_span", "complexity": "medium", "tags": ["code", "internal"], "data_sensitivity": "sensitive", "requires_reasoning": false }, "model_preference": "local_vllm_32b", "timeout_ms": 45000 }

路由层拿到这份元数据后,先按data_sensitivity过滤可用的目标集合,再按task_typecomplexity匹配路由规则,最后在可用的目标里做负载均衡。如果model_preference指向的目标当前不健康,路由层需要有能力自动降级到能力相近的其他目标,而不是直接返回失败。

这里有个原则特别重要:Agent的model_preference只是"偏好",不是"强制要求"。如果把这个字段设计成硬绑定关系,路由层就失去了存在的意义。我在架构评审时经常遇到这样的情况:Agent开发者觉得自己对模型能力最了解,坚持指定模型,但从系统角度看,指定模型完全没必要——明明本地小模型就能干的活,非要声明"必须用云端大模型",成本一下就上去了。正确的做法是Agent声明任务需求,路由层做决策。

任务状态同步方面,我推荐用独立的中间存储(比如Redis或PostgreSQL)来保存Agent状态,而不是依赖各Agent的内存。主要原因是Agent实例可能随时被重启、迁移、扩容,如果状态只存在于内存,一旦实例挂掉,整个任务链就断了。共享状态存储虽然会引入一些序列化开销,但换来的是可靠性和可观测性,这笔账怎么算都划算。

4. 高可用设计:模型挂了不是灾难,没有预案才是

4.1 故障类型清单

模型服务和其他基础设施的高可用设计有很大不同。普通Web服务的故障通常是"服务不可达",表现很直接;而模型服务的故障形态要复杂得多。我把实际运维中遇到的故障类型整理成了一张表:

故障类型典型表现检测方式危害程度
服务超时请求长时间无响应,直到超时调用超时统计高,直接拖垮用户体验
限流拒绝返回429状态码或错误码状态码监控中,触发重试就容易雪崩
上下文溢出请求内容超过模型上下文上限调用前长度检查中,返回异常或截断
本地OOM推理引擎崩溃或重启健康检查探针高,需要自动拉起
显存碎片化推理速度断崖式下降吞吐量滑动窗口中,需要重启恢复
生成质量劣化模型输出明显变差,但指标正常结果评估采样低,难以自动发现
密钥/配额失效云端API鉴权失败错误码监控高,需要快速轮换

每种故障类型对应的处理策略不同,但整体思路是统一的:尽早发现、自动隔离、按预案降级、快速恢复。

4.2 降级策略:本地和云端的双向兜底

混合部署最有价值的优势就是"双活"——本地模型和云端模型可以互为备份。这个优势必须通过精心设计的降级策略才能兑现。

最常见的第一种场景是本地模型故障,自动切云端。本地模型因为GPU故障、容器重启、显存溢出等原因不可用时,路由层应该在一两次失败探测后就把新的请求全部导向云端API。但这里有个细节:切换到云端后,请求的模型参数可能要变一下。本地模型的temperature、top_p等参数和云端模型不一定适合用同一套,切换时最好连参数一起切换。

第二种场景是云端限流或不可用,降级回本地。云端API在大促、流量突增时很容易429,这时如果本地有能力兜底,路由层应该把它纳入候选。但要注意,本地模型的容量有限,云端流量突然全部压过来,可能导致本地模型直接过载。所以云端切本地的时候要做好限流保护,比如只允许把核心请求切到本地,非核心请求直接排队或返回"稍后重试"。

第三种场景容易被忽略,叫服务降级而不是降模型。当路有层发现所有模型目标都不可用时,系统不能直接报错,而是要有一个"降级输出"的预案。比如一个客服问答Agent,在模型全挂的情况下,可以通过兜底服务返回知识库里的标准答案,或者返回一个预设的"系统繁忙"模板。这个兜底可能是很朴素的规则匹配,但在真实的可靠性场景里,它的价值不亚于模型本身。

重试机制需要特别注意。模型调用和普通HTTP请求不同,Token生成是动态的,重试的代价非常高。如果请求在云端API已经执行了一半才超时,重试意味着同样的钱要花两遍。所以我的建议是:只在幂等Agent任务中启用自动重试,且重试次数最多一次,重试时选择不同的目标端点。核心任务宁可让上层做补偿,也不要依赖底层盲目重试。

4.3 会话状态与Agent执行状态的持久化

高可用不只是"请求能返回结果",更重要的是"任务在故障后能恢复"。一个复杂Agent任务可能拆成几十个子步骤,执行到一半模型挂了、Agent挂了,如果状态没有持久化,整个任务就要从头再来。这在真实业务里是不可接受的。

我们在生产环境用PostgreSQL保存Agent执行状态,表结构大概是这样的思路:

CREATE TABLE agent_task_state ( task_id VARCHAR(64) PRIMARY KEY, parent_task_id VARCHAR(64), -- 父任务ID,用于复杂任务嵌套 agent_id VARCHAR(128), -- 当前执行Agent status VARCHAR(16), -- pending/running/success/failed/paused input_summary JSONB, -- 输入摘要 output_summary JSONB, -- 输出摘要 current_step INTEGER, -- 当前执行步骤 total_steps INTEGER, -- 总步骤数 retry_count INTEGER DEFAULT 0, route_targets JSONB, -- 本次使用的路由目标 created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); CREATE INDEX idx_agent_task_state_status ON agent_task_state(status); CREATE INDEX idx_agent_task_state_parent ON agent_task_state(parent_task_id);

每个Agent在开始执行、执行中、执行结束三个阶段都有明确的落库动作。一旦某个Agent实例挂了,调度器从数据库里找到status='running'updated_at超过阈值的任务,把它重新入队,由另一个Agent实例拉起并恢复执行。恢复时通过current_stepoutput_summary恢复上下文,而不是从零开始。

这个机制做扎实之后,整个系统就有了"从故障中自愈"的能力。模型挂了、Agent挂了、机器重启了,任务都在数据库里留着,随时可以恢复。这是高可用方案中最容易被忽略,但价值最大的一块。

5. 工程化落地:一套可以照抄的最小实现

5.1 目录结构与核心模块

理论说了那么多,最终还是要落到工程实现上。我整理了一套经过生产环境验证的最小目录结构,新项目可以直接按这个骨架搭:

model-gateway/ ├── config/ │ ├── router.yaml # 路由策略配置 │ ├── agents.yaml # Agent定义与并发参数 │ └── high_availability.yaml # 高可用降级策略配置 ├── gateway/ │ ├── main.py # 服务主入口,基于FastAPI │ ├── router/ │ │ ├── engine.py # 路由判定核心逻辑 │ │ ├── health.py # 健康检查与状态管理 │ │ ├── weights.py # 动态权重调整 │ │ └── target_pool.py # 模型目标池管理 │ ├── agents/ │ │ ├── supervisor.py # 主管Agent实现 │ │ ├── worker.py # 工人Agent通用实现 │ │ ├── context.py # 上下文管理 │ │ └── message_queue.py # Agent间消息通信 │ └── providers/ │ ├── base.py # 模型Provider抽象接口 │ ├── vllm_local.py # 本地vLLM适配 │ ├── openai_compatible.py # 云端OpenAI兼容API适配 │ └── fallback.py # 降级输出Provider ├── storage/ │ ├── postgres.py # 任务状态存储 │ └── redis.py # 分布式锁、限流计数器 ├── observability/ │ ├── metrics.py # 指标采集 │ ├── tracing.py # 全链路追踪 │ └── alerting.py # 告警规则 └── deploy/ ├── docker-compose.yml └── k8s/ ├── gateway-deployment.yaml ├── gateway-service.yaml └── configmap.yaml

这个结构的核心思路是:gateway/providers是一层抽象,任何模型服务只要能转成OpenAI兼容协议就能接进来;gateway/router负责决策逻辑,与具体模型解耦;storageobservability作为横切支撑,不掺入业务逻辑。

5.2 路由与降级的骨架实现

路由判定核心逻辑用Python写大概就是这样(生产版会复杂一些,但核心链路是清晰的):

# gateway/router/engine.py import time from typing import Optional class RouteEngine: def __init__(self, config, health_store, metrics): self.policies = sorted(config["routes"], key=lambda x: x["priority"], reverse=True) self.health_store = health_store self.metrics = metrics async def route(self, request_meta: dict) -> Optional[str]: # 1. 按配置规则匹配,得到候选目标列表 candidates = [] for policy in self.policies: if self._match_policy(policy, request_meta): candidates.append(policy["target"]) # 2. 剔除不健康的目标 healthy = [ t for t in candidates if self.health_store.get_score(t) >= 50 ] if not healthy: self.metrics.increase("route_no_healthy_target") return None # 3. 对剩余目标按健康分+权重排序 weighted = sorted( healthy, key=lambda x: self.health_store.get_score(x) * self._get_weight(x), reverse=True ) return weighted[0] def _match_policy(self, policy, request_meta) -> bool: when = policy.get("when", {}) for key, value in when.items(): if key == "all_else": return True if key == "tags_include": req_tags = set(request_meta.get("tags", [])) if not req_tags.intersection(value): return False else: if request_meta.get(key) != value: return False return True def _get_weight(self, target: str) -> float: # 基础权重 + 最近的错误率惩罚 history = self.health_store.get_recent_history(target, window=300) if len(history) < 10: return 1.0 error_rate = history.error_count / history.total_count return max(0.1, 1.0 - error_rate * 5)

降级策略的核心逻辑可以放在Provider层。每个Provider调用失败后,向上抛出一个标记了错误类型的异常,路由层捕获后自动尝试下一个可用目标:

# gateway/providers/base.py class ProviderError(Exception): def __init__(self, code: str, message: str): self.code = code # timeout / rate_limited / auth_error / server_error self.message = message # 调用入口的使用方式 async def call_with_failover(request_data, route_engine, provider_pool): target = await route_engine.route(request_data.meta) retry_targets = route_engine.get_alternative_targets(target) for endpoint in [target] + retry_targets: try: provider = provider_pool.get(endpoint) return await provider.chat(request_data) except ProviderError as e: route_engine.report_failure(endpoint, e.code) if e.code == "auth_error": continue # 密钥失效时,换其他云端端点试试 if e.code == "timeout": continue # 超时换一个端点 if e.code == "rate_limited": # 限流时不能立刻重试,先等一小段 await asyncio.sleep(0.5) continue raise ProviderError("no_available_target", "all model targets failed")

这里面最关键的设计是route_engine.report_failure,每一次失败都会实时更新健康状态,让后续请求自动避开故障端点。故障反馈和路由决策必须在同一条链路上闭环,否则路由层看到的永远是一个过期状态。

5.3 我自己在生产环境踩过的坑

工程实践到最后,拼的是细节。下面这几个坑是我真实在线上遇到过、花了不少时间才排查清楚的,分享出来帮你少走弯路。

坑一:本地模型冷启动被路由层误判为宕机。本地vLLM服务在刚启动或大量并发进入时需要加载模型权重、构建KV cache,这个阶段请求响应时间可能长达几十秒甚至更久。我们的健康检查超时时间最初设为5秒,结果一冷启动就误报宕机,路由层把所有流量切到了云端。等本地模型真正就绪后,又因为流量切回来太慢导致资源闲置。解决方法是健康检查分两个阶段:基础探测用短超时(3~5秒),只检查进程是否存活;能力探测用长超时(60秒以上),真正发一个简单推理请求验证模型能否正常工作。冷启动期间的路由权重也要单独处理,不能按正常状态计算。

坑二:云端API限流触发重试风暴。有段时间云端API偶发429,我们的重试逻辑是"收到429就自动重试一次",结果在高峰期多个Agent同时触发重试,瞬间把云端API的配额打满,随后所有请求持续429,形成恶性循环。后来把重试改成了带抖动的指数退避,并增加了"单窗口内重试次数上限"(比如30秒内最多重试3次),同时开启"降级开关",连续收到5次以上429就自动把对应流量切成备份端点。

坑三:Agent的幂等设计没做好,重试时任务重复执行。一个Agent任务发给本地模型后,网络抖动导致响应超时,Agent自动重试,结果模型那边实际上已经生成完了第一次的结果。第二次重试等于白白多花一次推理成本。更严重的是,如果这个Agent任务是"写入数据库",重复执行就会产生脏数据。要根治这个问题,必须为每个Agent任务生成唯一标识,在模型调用和状态落库时都以这个标识做幂等键。模型Provider层收到重复标识的请求可以直接返回上一次缓存的结果,这需要每个Provider都支持简单的请求级缓存。

坑四:多Agent并发写同一个数据库导致锁竞争。Agent数量多起来之后,同时读写PostgreSQL状态表会出现明显的锁等待,任务状态更新延迟增加。我们当时一部分状态从PostgreSQL换到了Redis,只把最终结果和关键节点落PostgreSQL,中间过程全部放Redis的哈希表,配合TTL自动清理,锁问题基本消除。

5.4 可观测性:高可用的前提,是你能看见故障

没有可观测性的高可用方案是空中楼阁。混合大模型架构里链路特别长,从用户请求到接入层、到路由层、到Agent编排、再到模型Provider,任何一环出问题都可能导致整体表现异常。没有全链路追踪的话,排查问题完全靠猜,耗时极长。

我维护的三个核心观测指标是:

  • 路由决策分布:每个时间段内,路由到本地7B、本地32B、云端API的请求各占多少比例,这个指标能直接反映成本趋势和策略是否生效。
  • 每个目标端点的错误率与分位数延迟:P50、P95、P99分开看,尤其是P99,本地模型和云端模型在长尾延迟上的表现差异非常大。
  • Agent任务成功率与恢复次数:多少任务是一次成功的,多少任务经历了一次甚至多次恢复,这个指标直接体现整体架构的韧性。

告警规则也要围绕这几类核心指标来设置。延迟上去了不一定有故障,但延迟持续高位加上错误率上升,就需要人工介入了。全链路追踪方面,我建议给每个请求分配唯一的trace_id,从接入层一直透传到模型调用层,日志系统里只要保留trace_id,就能把整个过程串起来看。

写在最后

混合大模型架构工程实践,说到底不是模型选型的问题,而是系统工程的问题。多数团队在"用哪个模型"上纠结很久,却忽略了路由、编排、高可用这些真正决定系统上限的部分。

我个人在实际操作中最深的一个体会是:把路由策略当成一个可以随时调整的配置系统,而不是一段写死的代码。模型能力每周都在变,业务需求每月都在变,Token价格随时在变,如果你的架构不能快速响应这些变化,那今天搭好的"最优解"明天可能就成了拖累。

另一个体会是:路由层做薄,Agent业务做厚。路由层只需要关注分发、健康、降级这些纯技术问题,不要让业务规则渗入路由层;Agent层则要把业务逻辑做扎实,包括任务拆解质量、上下文管理、结果校验。这样两边都能独立演进,不会互相拖累。

最后,混合部署不是目的,稳定可用才是。每一次策略调整都值得做灰度验证,每一次模型切换都要留下可追溯的记录。这套架构能不能跑得好,靠的不是某一项高技术含量组件,而是无数个扎实的小决策叠加在一起的结果。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/6 4:09:40

盘式微孔曝气器采购:主流一线品牌甄选参考深度解析

一、行业现状复盘&#xff1a;2026 年赛道核心特征与数据支撑 作为污水处理好氧工艺的核心耗材&#xff0c;盘式微孔曝气器的市场需求&#xff0c;伴随国内污废水提标改造进程加快持续扩容。据中国环境保护产业协会 2026 年第一季度发布的最新数据&#xff0c;国内盘式微孔曝气…

作者头像 李华
网站建设 2026/9/6 4:09:32

Anthropic 150亿美元循环信贷与IPO时间表全面解析——从2万亿美元估值到史上最大科技IPO的资本路径

一、引言:AI资本市场的历史性时刻 2026年9月,全球科技资本市场正站在一个前所未有的节点上。据路透社2026年9月5日报道,人工智能公司Anthropic正在接近敲定将其循环信贷额度扩大至150亿美元,这标志着这家Claude模型开发商在通往史上最大规模IPO的道路上扫清了最后一道关键…

作者头像 李华
网站建设 2026/9/6 4:08:09

200万参数扩散模型植入树莓派Pico 2,1美元MCU实现离线图像生成

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/6 4:07:00

智能手表技术拆解:从BLE通信到消息推送的实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华