发布时间:2026/7/24 15:49:09
LLM网关项目复盘:多模型统一接入层的架构设计与工程挑战 LLM网关项目复盘多模型统一接入层的架构设计与工程挑战一、多模型的巴别塔问题一个AI应用同时使用了5个LLM ProviderOpenAI、Anthropic、DeepSeek、通义千问、Moonshot。每个Provider有自己的SDK、请求格式、响应格式、错误码——代码中散落着5套if-else逻辑。更麻烦的是需要做A/B对比同一问题发给两个模型、故障切换OpenAI挂了自动切Anthropic、成本控制优先用便宜模型复杂问题才用贵的。这些都指向同一个需求多模型的统一接入层——不关心用什么模型只关心得到了什么回答。二、统一抽象层的设计核心接口Provider抽象type LLMProvider interface { Name() string Chat(ctx context.Context, req ChatRequest) (*ChatResponse, error) StreamChat(ctx context.Context, req ChatRequest) (-chan StreamEvent, error) ListModels(ctx context.Context) ([]Model, error) } // 统一的请求/响应——屏蔽Provider差异 type ChatRequest struct { Model string Messages []Message Temperature float64 MaxTokens int Stream bool } type ChatResponse struct { ID string Model string Content string FinishReason string Usage Usage Latency time.Duration } // OpenAI Adapter type OpenAIProvider struct { client *openai.Client config ProviderConfig } func (p *OpenAIProvider) Chat(ctx context.Context, req ChatRequest) (*ChatResponse, error) { // 内部格式转换统一格式 → OpenAI格式 resp, err : p.client.CreateChatCompletion(ctx, openai.ChatCompletionRequest{ Model: req.Model, Messages: toOpenAIMessages(req.Messages), Temperature: req.Temperature, MaxTokens: req.MaxTokens, }) if err ! nil { return nil, p.mapError(err) // 错误码标准化 } // 响应标准化OpenAI格式 → 统一格式 return toChatResponse(resp), nil } // Anthropic Adapter type AnthropicProvider struct { client *anthropic.Client } func (p *AnthropicProvider) Chat(ctx context.Context, req ChatRequest) (*ChatResponse, error) { // Claude格式转换 msg, err : p.client.Messages.Create(ctx, anthropic.MessageNewParams{ Model: req.Model, Messages: toAnthropicMessages(req.Messages), MaxTokens: int64(req.MaxTokens), Temperature: anthropic.Float(req.Temperature), }) // ... }三、智能路由策略基于内容的路由type Router struct { rules []RouteRule defaultProvider string } type RouteRule struct { Matcher func(req ChatRequest) bool Provider string } func (r *Router) Route(req ChatRequest) string { // 代码相关 → DeepSeek代码能力好且便宜 // 长文本 → Claude200K上下文 // 默认 → GPT-4o for _, rule : range r.rules { if rule.Matcher(req) { return rule.Provider } } return r.defaultProvider } // 路由规则配置 var defaultRules []RouteRule{ { Matcher: func(req ChatRequest) bool { return containsKeyword(req.Messages, 代码, bug, function) }, Provider: deepseek, }, { Matcher: func(req ChatRequest) bool { return estimateTokenCount(req.Messages) 100000 }, Provider: claude, // 大上下文场景 }, }基于优先级的故障切换func (g *Gateway) Chat(ctx context.Context, req ChatRequest) (*ChatResponse, error) { primary : g.router.Route(req) fallbacks : g.getFallbackChain(primary) // [primary, fallback1, fallback2] var lastErr error for _, providerName : range fallbacks { provider : g.providers[providerName] if !g.circuitBreaker.IsOpen(providerName) { resp, err : provider.Chat(ctx, req) if err nil { return resp, nil } lastErr err g.circuitBreaker.RecordFailure(providerName) } } return nil, fmt.Errorf(所有Provider都不可用: %w, lastErr) }四、成本控制与可观测性成本追踪每个请求记录实际消耗的Token和费用func (g *Gateway) Chat(ctx context.Context, req ChatRequest) (*ChatResponse, error) { start : time.Now() resp, err : g.routeAndExecute(ctx, req) // 记费用——不管成功失败 cost : g.calculateCost(resp) g.metrics.RecordRequest(MetricRecord{ Provider: resp.Provider, Model: req.Model, Tokens: resp.Usage.TotalTokens, Cost: cost, Latency: time.Since(start), Error: err, }) return resp, err } func (g *Gateway) calculateCost(resp *ChatResponse) float64 { // 各模型定价 pricing : map[string]float64{ gpt-4o: 0.005 / 1000, // $0.005/1K tokens gpt-4o-mini: 0.00015 / 1000, claude-3-opus: 0.015 / 1000, deepseek-chat: 0.00014 / 1000, } rate, ok : pricing[resp.Model] if !ok { return 0 } return float64(resp.Usage.TotalTokens) * rate }月费用报表基于记录的数据自动生成各Provider的费用分布。DeepSeek处理了65%的请求但仅占总费用的12%GPT-4o仅15%的请求却占总费用的72%。五、总结LLM网关的核心价值统一接入层屏蔽了5个Provider的SDK差异——调用方不感知底层用哪个模型智能路由节省了约40%的LLM费用——简单问题用便宜模型复杂问题才用贵的故障切换让整体可用性从单Provider的99.5%提升到99.9%成本追踪让每个请求花了多少钱从黑盒变成白盒Provider接口抽象让新增模型接入成本从改全局代码降到实现一个适配器当前网关日均处理约2万次LLM调用月费用约$1800。智能路由策略将DeepSeek/GPT-4o-mini等低成本模型的使用率从初始的40%提升到65%月节省约$700。最大的架构取舍流式响应streaming要求Provider适配器支持SSE推送复杂度是指令式非流式的3倍。如果不需要流式输出如后台批量处理适配器实现可以大幅简化。网关的流式和非流式两套路径独立维护是当前架构的主要技术债。

相关新闻

2026/7/24 15:49:09

UnityEditor命名空间报错全解析:从编译原理到项目结构优化

1. 项目概述:当UnityEditor“消失”时 如果你在Unity编辑器里写脚本,尤其是那些用来扩展编辑器功能、创建自定义工具窗口或者自动化流程的脚本,那么“not exist in the namespace ‘UnityEditor‘”这个报错,大概率是你绕不开的一…

2026/7/24 17:14:18

3分钟掌握:用开源工具解锁你的加密音乐收藏

3分钟掌握:用开源工具解锁你的加密音乐收藏 【免费下载链接】unlock-music-electron Unlock Music Project - Electron Edition 在Electron构建的桌面应用中解锁各种加密的音乐文件 项目地址: https://gitcode.com/gh_mirrors/un/unlock-music-electron 你是…

2026/7/24 17:14:18

模型路由技术:智能调度多AI模型提升应用效率与成本控制

1. 模型路由到底解决了什么问题 如果你同时用过多个大模型 API,肯定遇到过这种选择困难:写代码用 GPT-4 效果最好但成本高,日常对话 Claude 更自然但编程弱,处理长文本时又要换专用模型。每次都要手动判断该调哪个接口&#xff0c…

2026/7/24 17:09:18

打车系统的定价算法:动态调价背后的供需模型

打车系统的定价算法:动态调价背后的供需模型 一、深度引言与场景痛点:为什么下雨天打车价格翻倍? 下雨天打车时的价格跳涨,是大多数用户对"动态定价"的直观体验。在用户视角,这是平台在趁火打劫。但在系统视…

2026/7/23 12:54:51

Unity与Python本地通信:基于Flask的跨语言数据交换实战

1. 项目概述:为什么我们需要一个本地通信服务器?在游戏开发、数字孪生、仿真训练等众多领域,Unity作为强大的实时3D内容创作平台,其核心逻辑通常由C#驱动。然而,当我们需要进行复杂的数据分析、机器学习推理、科学计算…

2026/7/24 0:03:10

不同品牌斜齿行星减速机如何替换?以PX与PAG系列为例

不同品牌斜齿行星减速机如何替换?以 PX 与 PAG 系列为例 一、系列对应不等于型号直接互换 PX 与 PAG 都属于斜齿、方法兰、输出轴式精密行星减速机,结构形式和应用方向具有对应关系。 原设备使用PX系列时,可以优先从PAG系列中寻找替换型号。但…

2026/7/24 0:03:10

jdk8 把list 扁平化成String 多个以逗号分隔

在 JDK 8 中&#xff0c;将 List 扁平化为以逗号分隔的 String&#xff0c;有几种非常简洁且高效的方法。&#x1f680; 推荐方案&#xff1a;使用 Collectors.joining()这是最标准的 Java 8 写法&#xff0c;适用于 List<String>。javaimport java.util.stream.Collecto…

2026/7/24 0:03:10

java 两个 long id 怎么合并成一个long id 并且不重复

“把两个 Long ID 合并成一个唯一的 Long ID&#xff0c;且保证不重复”这个需求&#xff0c;在 Java 里直接做数学上的“完美合并”是不可能的。因为两个 Long&#xff08;各 64 位&#xff09;要合并成一个 Long&#xff08;64 位&#xff09;&#xff0c;在信息论上是有损压…

2026/7/23 23:42:43

3个高效策略:快速掌握Axure中文界面配置

3个高效策略&#xff1a;快速掌握Axure中文界面配置 【免费下载链接】axure-cn Chinese language file for Axure RP. Axure RP 简体中文语言包。支持 Axure 11、10、9。不定期更新。 项目地址: https://gitcode.com/gh_mirrors/ax/axure-cn 还在为Axure RP的英文界面感…