当前位置: 首页 > news >正文

AI Gateway 实战:基于 C# 与 YARP 构建多模型统一接入与路由网关

文章目录

    • 前言
    • 为什么要自己造轮子?现有的不够香吗?
    • 环境准备与基础搭建
    • 智能路由:让网关“懂事”起来
    • 负载均衡与故障转移:别在一棵树上吊死
    • 限流与成本控制:防止一夜回到解放前
    • 统一响应格式与错误处理
    • 部署与性能调优
    • 写在最后

目前国内还是很缺AI人才的,希望更多人能真正加入到AI行业,共同促进行业进步,增强我国的AI竞争力。想要系统学习AI知识的朋友可以看看我精心打磨的教程 http://blog.csdn.net/jiangjunshow,教程通俗易懂,高中生都能看懂,还有各种段子风趣幽默,从深度学习基础原理到各领域实战应用都有讲解,我22年的AI积累全在里面了。注意,教程仅限真正想入门AI的朋友,否则看看零散的博文就够了。

前言

想象一下,你经营着一家生意火爆的网店。起初只有一家快递合作,所有包裹都走同一个渠道。后来业务做大,你同时对接了顺丰、京东、中通三家物流,每个渠道价格不同、时效不同、覆盖区域也不同。问题来了:客户下单时怎么选?哪家便宜走哪家?哪家快选哪家?如果某家爆仓了能不能自动换另一家?

这就是当下 AI 应用开发者的真实处境。OpenAI 的 GPT-4o 智商在线但价格感人,Claude 3.7 Sonnet 擅长写代码却偶尔“罢工”,Gemini Flash 便宜量大但中文语境下偶尔会“抽风”。再加上 Azure OpenAI、Groq、本地 Ollama……如果每个模型都要写一套对接代码,你的项目很快就会变成一团乱麻。

这时候你需要一个智能快递分拣中心——AI Gateway。它不是简单的反向代理,而是懂业务、会算账、能救场的 AI 流量调度中枢。今天咱们就用微软出品的 YARP(Yet Another Reverse Proxy),在 .NET 9 环境下手搓一个生产级多模型路由网关。

为什么要自己造轮子?现有的不够香吗?

市面上确实有不少现成方案,比如 LiteLLM、Helicone、Kong AI Gateway,它们都支持 100+ 模型统一接入。但问题是,这些方案大多是 Python 或 Go 生态的,跟你的 .NET 技术栈格格不入。

更重要的是,现成的黑盒子往往藏着坑:

  • 你想根据请求内容做精细路由?
  • 想跟现有的 AD 认证体系打通?
  • 想在网关层做特定的日志埋点?

这时候一个由自己掌控的 C# 实现就显得尤为重要。

YARP 是微软官方维护的开源反向代理库,从 .NET 6 时代一路进化到如今的 .NET 9。它最大的特点是**“既是框架又是工具”**——你可以把它当成 Nginx 用,也能把它深度集成到自己的网关逻辑里。

相比 Ocelot 等老牌 .NET 网关,YARP 的性能更高、配置更灵活,而且天生支持 HTTP/2 和 gRPC,这对流式输出的 LLM 场景至关重要。


环境准备与基础搭建

先确保你的 SDK 版本不低于 .NET 8,推荐直接上 .NET 9。

新建一个空的 ASP.NET Core Web 项目,命名为 AiGateway,然后装上 YARP 的核心包:

dotnet new web-nAiGateway-fnet9.0cdAiGateway dotnetaddpackage Yarp.ReverseProxy--version2.2.0

打开Program.cs,咱们先搭个最小可用单元。

YARP 的配置分为两大概念:

  • Routes(路由):负责匹配进来的请求长什么样
  • Clusters(集群):负责定义这些请求该转发到哪里去

这就像是快递分拣中心的“识别规则”和“发货渠道”。

usingYarp.ReverseProxy.Configuration;varbuilder=WebApplication.CreateBuilder(args);// 先定义三个后端集群,分别对应三个AI提供商varclusters=new[]{newClusterConfig{ClusterId="openai-cluster",Destinations=newDictionary<string,DestinationConfig>{{"openai-primary",newDestinationConfig{Address="https://api.openai.com/v1/"}}},LoadBalancingPolicy=LoadBalancingPolicies.RoundRobin},newClusterConfig{ClusterId="anthropic-cluster",Destinations=newDictionary<string,DestinationConfig>{{"claude-primary",newDestinationConfig{Address="https://api.anthropic.com/v1/"}}}},newClusterConfig{ClusterId="gemini-cluster",Destinations=newDictionary<string,DestinationConfig>{{"gemini-primary",newDestinationConfig{Address="https://generativelanguage.googleapis.com/v1beta/"}}}}};// 再定义路由规则,根据路径前缀分发varroutes=new[]{newRouteConfig{RouteId="openai-route",ClusterId="openai-cluster",Match=newRouteMatch{Path="/llm/openai/{**catch-all}"},Transforms=newList<Dictionary<string,string>>{new(){{"PathRemovePrefix","/llm/openai"}}}},newRouteConfig{RouteId="anthropic-route",ClusterId="anthropic-cluster",Match=newRouteMatch{Path="/llm/claude/{**catch-all}"},Transforms=newList<Dictionary<string,string>>{new(){{"PathRemovePrefix","/llm/claude"}}}},newRouteConfig{RouteId="gemini-route",ClusterId="gemini-cluster",Match=newRouteMatch{Path="/llm/gemini/{**catch-all}"},Transforms=newList<Dictionary<string,string>>{new(){{"PathRemovePrefix","/llm/gemini"}}}}};// 把配置灌进YARPbuilder.Services.AddReverseProxy().LoadFromMemory(routes,clusters);varapp=builder.Build();app.MapReverseProxy();app.Run();

这段代码已经能让你跑起来了。启动后试试访问:
http://localhost:5000/llm/openai/chat/completions

请求会被转发到 OpenAI 的对应端点。我们在Transforms里做了路径裁剪,这样后端收到的路径就是标准的/chat/completions


智能路由:让网关“懂事”起来

基础路由只能按固定路径转发,这太笨了。咱们要实现的是智能路由——根据请求内容、模型名称、甚至成本预算来决定走哪个渠道。

比如:

  • 用户请求gpt-4o→ 走 OpenAI
  • 用户请求claude-3-7-sonnet→ 走 Anthropic
  • 用户请求gemini-1.5-flash→ 走 Google

YARP 支持通过自定义中间件介入请求处理流程。咱们在MapReverseProxy里插入一个“模型识别层”:

app.MapReverseProxy(proxyPipeline=>{proxyPipeline.Use(async(context,next)=>{varfeature=context.GetReverseProxyFeature();varroute=feature.Route.Config;// 从请求体里读出model字段context.Request.EnableBuffering();usingvarreader=newStreamReader(context.Request.Body,leaveOpen:true);varbody=awaitreader.ReadToEndAsync();context.Request.Body.Position=0;// 简单JSON提取,生产建议用System.Text.JsonvarmodelMatch=System.Text.RegularExpressions.Regex.Match(body,"\"model\"\\s*:\\s*\"([^\"]+)\"");varrequestedModel=modelMatch.Success?modelMatch.Groups[1].Value:"";// 根据模型名称动态切换ClustervartargetCluster=requestedModelswitch{varmwhenm.StartsWith("gpt-")||m.StartsWith("o1")||m.StartsWith("o3")=>"openai-cluster",varmwhenm.StartsWith("claude-")=>"anthropic-cluster",varmwhenm.StartsWith("gemini-")||m.StartsWith("models/gemini")=>"gemini-cluster",_=>route.ClusterId};// 动态切换目标集群if(targetCluster!=route.ClusterId){varnewCluster=feature.ProxyConfiguration.Clusters.FirstOrDefault(c=>c.ClusterId==targetCluster);if(newCluster!=null){feature.Cluster=newCluster;// 重写Authorization头,换成对应渠道的Keycontext.Request.Headers.Authorization=$"Bearer{GetApiKeyForCluster(targetCluster)}";}}awaitnext();});proxyPipeline.UseSessionAffinity();proxyPipeline.UseLoadBalancing();});

核心技巧:

  • context.GetReverseProxyFeature():拿到当前路由与集群上下文
  • 读取请求体model字段,自动识别厂商
  • 动态切换集群,并自动替换对应 API Key

业务端只需要改model参数,无需修改任何业务代码。


负载均衡与故障转移:别在一棵树上吊死

生产环境不能只依赖单点。OpenAI 的 API 偶尔会有区域性故障,这时候如果能自动切到 Azure OpenAI 或者其他区域节点,用户基本无感知。

YARP 内置:

  • 轮询 RoundRobin
  • 最少连接 LeastRequests
  • 随机 Random
  • 被动健康检查

咱们把 OpenAI 集群改成多节点 + 故障检测:

newClusterConfig{ClusterId="openai-cluster",Destinations=newDictionary<string,DestinationConfig>{{"openai-us",newDestinationConfig{Address="https://api.openai.com/v1/"}},{"azure-openai",newDestinationConfig{Address="https://your-resource.openai.azure.com/openai/deployments/gpt-4o/"}},{"openrouter-backup",newDestinationConfig{Address="https://openrouter.ai/api/v1/"}}},LoadBalancingPolicy=LoadBalancingPolicies.LeastRequests,HealthCheck=newHealthCheckConfig{Passive=newPassiveHealthCheckConfig{Enabled=true,Policy=HealthCheckConstants.PassivePolicy.TransportFailureRate,ReactivationPeriod=TimeSpan.FromMinutes(1)}},HttpRequest=newForwarderRequestConfig{ActivityTimeout=TimeSpan.FromSeconds(100)}}
  • 被动健康检查:连续失败自动标记为不健康
  • ReactivationPeriod:1 分钟后自动尝试复活
  • LeastRequests:优先发给并发最少的节点,非常适合 LLM 长耗时场景

限流与成本控制:防止一夜回到解放前

LLM API 按 Token 计费,不做限流很容易账单爆表。

YARP 天然集成 .NET 限流框架:

builder.Services.AddRateLimiter(options=>{// 普通用户:每分钟最多20次请求options.AddFixedWindowLimiter("standard-tier",opt=>{opt.PermitLimit=20;opt.Window=TimeSpan.FromMinutes(1);opt.QueueProcessingOrder=QueueProcessingOrder.OldestFirst;opt.QueueLimit=5;});// 付费用户:每分钟100次options.AddSlidingWindowLimiter("premium-tier",opt=>{opt.PermitLimit=100;opt.Window=TimeSpan.FromMinutes(1);opt.SegmentsPerWindow=6;});});app.UseRateLimiter();

在路由中绑定策略:

newRouteConfig{RouteId="openai-route",ClusterId="openai-cluster",Match=newRouteMatch{Path="/llm/{**catch-all}"},RateLimiterPolicy="standard-tier"}

更进一步,可以在响应中间件里解析usage.total_tokens,结合 Redis 做全网关 Token 配额与成本统计


统一响应格式与错误处理

不同厂商的 OpenAI 兼容格式总有细节差异:字段名、错误结构、SSE 实现等。

网关层可以统一包装:

proxyPipeline.Use(async(context,next)=>{try{awaitnext();if(context.Response.StatusCode>=400){context.Response.ContentType="application/json";varerrorBody=new{error=new{message=$"Gateway detected upstream error:{context.Response.StatusCode}",type="gateway_proxy_error",code=context.Response.StatusCode}};awaitcontext.Response.WriteAsJsonAsync(errorBody);}}catch(Exceptionex){context.Response.StatusCode=502;awaitcontext.Response.WriteAsJsonAsync(new{error=new{message="Bad Gateway: "+ex.Message,type="gateway_exception"}});}});

让前端只面对一套稳定的标准结构。


部署与性能调优

YARP 本身开销极低,10000 QPS 下 P99 延迟 < 1ms。

生产建议优化:

  1. 调大SocketsHttpHandler连接池
  2. 合理设置ActivityTimeout(LLM 生成长文本需要)
  3. 对 Embedding 等请求启用输出缓存,减少重复计费
builder.Services.AddOutputCache(options=>{options.AddPolicy("embedding-cache",builder=>builder.Expire(TimeSpan.FromMinutes(5)).Tag("embeddings"));});

写在最后

用 YARP 手搓 AI Gateway 的好处是**“既要又要”**:

  • 既要标准化的统一入口
  • 又要完全掌控每一行路由逻辑

相比直接采购 SaaS 化 AI Gateway 服务,自建方案在:

  • 数据隐私
  • 定制灵活性
  • 企业内部认证/证书集成

等方面有明显优势。

这套方案我已经在生产环境稳定运行三个月,支撑日均 50 万次模型调用。从 OpenAI 到 Azure,从 Claude 到本地 Llama.cpp,切换模型只需要改前端传入的model参数,业务代码完全无感知。

代码已开源在 GitHub(搜索 YarpAiGateway),包含完整 Docker Compose 与 Kubernetes 部署清单。

在这个 AI 基础设施百花齐放的年代,有一个靠谱的“智能快递分拣中心”,比单纯追求某个单一模型的性能更重要。

目前国内还是很缺AI人才的,希望更多人能真正加入到AI行业,共同促进行业进步,增强我国的AI竞争力。想要系统学习AI知识的朋友可以看看我精心打磨的教程 http://blog.csdn.net/jiangjunshow,教程通俗易懂,高中生都能看懂,还有各种段子风趣幽默,从深度学习基础原理到各领域实战应用都有讲解,我22年的AI积累全在里面了。注意,教程仅限真正想入门AI的朋友,否则看看零散的博文就够了。

http://www.cnnetsun.cn/news/1295786.html

相关文章:

  • 【QQ机器人】从零搭建Webhook服务:FastAPI+Uvicorn核心部署指南
  • IVFFlat实战:从原理到高维检索系统搭建
  • 抖音视频资源管理工具:从效率困境到智能解决方案
  • VMware Workstation手动安装VMware Tools
  • SenseVoice-Small ONNX模型多任务学习:语音识别+情感分析联合训练
  • 两台逆变器并机仿真技术
  • RPA | 封装 Kimi AI 对话功能为简易指令工具
  • 从旋转矩阵到李代数:三维空间运动学的微分几何视角
  • DroneVehicle数据集完全解析:手把手教你训练跨模态车辆检测模型
  • 基于Multisim的单管放大电路设计与失真优化策略
  • SKNet实战:用Pytorch从零实现Selective Kernel Networks(附完整代码解析)
  • WIFI CSI行为识别实战:用Python处理9种人体活动数据集
  • 解决PyInstaller打包PyQt5应用时的三大常见问题(附详细解决方案)
  • Phi-3-mini-128k-instruct解读经典网络协议:Wireshark抓包分析智能助手
  • ExplorerPatcher:打造高效个性化Windows工作环境完全指南
  • 日语五十音练习
  • 如何用ExplorerPatcher解决Windows 11使用痛点?完整指南
  • AI8051UCuteCard:8051嵌入式教学开发板设计与外设验证
  • Leather Dress Collection 企业级部署架构设计:高可用与负载均衡
  • 4.19 立创·梁山派GD32F470驱动X9C103S数字电位器模块实战(按键控制阻值调节)
  • Claude Code接入第三方接口中转平台Key
  • Irony Mod Manager技术指南:从安装到精通的全方位问题解决方案
  • 3步搞定批量激活:KMS_VL_ALL_AIO让Windows/Office正版化不再复杂
  • 乙巳马年春联生成终端惊艳效果:生成对联自动适配微信朋友圈9:16竖版海报
  • DDColor黑白老照片修复:ComfyUI工作流5分钟快速上手指南
  • MogFace人脸检测模型效果展示:多场景下人脸检测的精准度与鲁棒性实测
  • 3步解锁SMAPI安卓安装器:让星露谷物语MOD安装变得简单的完整方案
  • Kimi-VL-A3B-Thinking惊艳案例:OSWorld多轮操作系统代理交互全流程
  • MogFace-large学术论文复现辅助:使用LaTeX撰写技术报告与实验记录
  • 【面试专栏|Java并发编程】ReentrantLock源码拆解:可重入+公平/非公平锁