文章目录
目前国内还是很缺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 的核心包:
bash
dotnet new web -n AiGateway -f net9.0
cd AiGateway
dotnet add package Yarp.ReverseProxy --version 2.2.0
打开 Program.cs,咱们先搭个最小可用单元。
YARP 的配置分为两大概念:
- Routes(路由):负责匹配进来的请求长什么样
- Clusters(集群):负责定义这些请求该转发到哪里去
这就像是快递分拣中心的"识别规则"和"发货渠道"。
csharp
using Yarp.ReverseProxy.Configuration;
var builder = WebApplication.CreateBuilder(args);
// 先定义三个后端集群,分别对应三个AI提供商
var clusters = new[]
{
new ClusterConfig
{
ClusterId = "openai-cluster",
Destinations = new Dictionary<string, DestinationConfig>
{
{ "openai-primary", new DestinationConfig { Address = "https://api.openai.com/v1/" } }
},
LoadBalancingPolicy = LoadBalancingPolicies.RoundRobin
},
new ClusterConfig
{
ClusterId = "anthropic-cluster",
Destinations = new Dictionary<string, DestinationConfig>
{
{ "claude-primary", new DestinationConfig { Address = "https://api.anthropic.com/v1/" } }
}
},
new ClusterConfig
{
ClusterId = "gemini-cluster",
Destinations = new Dictionary<string, DestinationConfig>
{
{ "gemini-primary", new DestinationConfig { Address = "https://generativelanguage.googleapis.com/v1beta/" } }
}
}
};
// 再定义路由规则,根据路径前缀分发
var routes = new[]
{
new RouteConfig
{
RouteId = "openai-route",
ClusterId = "openai-cluster",
Match = new RouteMatch { Path = "/llm/openai/{**catch-all}" },
Transforms = new List<Dictionary<string, string>>
{
new() { { "PathRemovePrefix", "/llm/openai" } }
}
},
new RouteConfig
{
RouteId = "anthropic-route",
ClusterId = "anthropic-cluster",
Match = new RouteMatch { Path = "/llm/claude/{**catch-all}" },
Transforms = new List<Dictionary<string, string>>
{
new() { { "PathRemovePrefix", "/llm/claude" } }
}
},
new RouteConfig
{
RouteId = "gemini-route",
ClusterId = "gemini-cluster",
Match = new RouteMatch { Path = "/llm/gemini/{**catch-all}" },
Transforms = new List<Dictionary<string, string>>
{
new() { { "PathRemovePrefix", "/llm/gemini" } }
}
}
};
// 把配置灌进YARP
builder.Services.AddReverseProxy()
.LoadFromMemory(routes, clusters);
var app = 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 里插入一个"模型识别层":
csharp
app.MapReverseProxy(proxyPipeline =>
{
proxyPipeline.Use(async (context, next) =>
{
var feature = context.GetReverseProxyFeature();
var route = feature.Route.Config;
// 从请求体里读出model字段
context.Request.EnableBuffering();
using var reader = new StreamReader(context.Request.Body, leaveOpen: true);
var body = await reader.ReadToEndAsync();
context.Request.Body.Position = 0;
// 简单JSON提取,生产建议用System.Text.Json
var modelMatch = System.Text.RegularExpressions.Regex.Match(body, "\"model\"\\s*:\\s*\"([^\"]+)\"");
var requestedModel = modelMatch.Success ? modelMatch.Groups[1].Value : "";
// 根据模型名称动态切换Cluster
var targetCluster = requestedModel switch
{
var m when m.StartsWith("gpt-") || m.StartsWith("o1") || m.StartsWith("o3")
=> "openai-cluster",
var m when m.StartsWith("claude-")
=> "anthropic-cluster",
var m when m.StartsWith("gemini-") || m.StartsWith("models/gemini")
=> "gemini-cluster",
_ => route.ClusterId
};
// 动态切换目标集群
if (targetCluster != route.ClusterId)
{
var newCluster = feature.ProxyConfiguration.Clusters
.FirstOrDefault(c => c.ClusterId == targetCluster);
if (newCluster != null)
{
feature.Cluster = newCluster;
// 重写Authorization头,换成对应渠道的Key
context.Request.Headers.Authorization = $"Bearer {GetApiKeyForCluster(targetCluster)}";
}
}
await next();
});
proxyPipeline.UseSessionAffinity();
proxyPipeline.UseLoadBalancing();
});
核心技巧:
context.GetReverseProxyFeature():拿到当前路由与集群上下文- 读取请求体
model字段,自动识别厂商 - 动态切换集群,并自动替换对应 API Key
业务端只需要改 model 参数,无需修改任何业务代码。
负载均衡与故障转移:别在一棵树上吊死
生产环境不能只依赖单点。OpenAI 的 API 偶尔会有区域性故障,这时候如果能自动切到 Azure OpenAI 或者其他区域节点,用户基本无感知。
YARP 内置:
- 轮询 RoundRobin
- 最少连接 LeastRequests
- 随机 Random
- 被动健康检查
咱们把 OpenAI 集群改成多节点 + 故障检测:
csharp
new ClusterConfig
{
ClusterId = "openai-cluster",
Destinations = new Dictionary<string, DestinationConfig>
{
{ "openai-us", new DestinationConfig { Address = "https://api.openai.com/v1/" } },
{ "azure-openai", new DestinationConfig { Address = "https://your-resource.openai.azure.com/openai/deployments/gpt-4o/" } },
{ "openrouter-backup", new DestinationConfig { Address = "https://openrouter.ai/api/v1/" } }
},
LoadBalancingPolicy = LoadBalancingPolicies.LeastRequests,
HealthCheck = new HealthCheckConfig
{
Passive = new PassiveHealthCheckConfig
{
Enabled = true,
Policy = HealthCheckConstants.PassivePolicy.TransportFailureRate,
ReactivationPeriod = TimeSpan.FromMinutes(1)
}
},
HttpRequest = new ForwarderRequestConfig
{
ActivityTimeout = TimeSpan.FromSeconds(100)
}
}
- 被动健康检查:连续失败自动标记为不健康
ReactivationPeriod:1 分钟后自动尝试复活LeastRequests:优先发给并发最少的节点,非常适合 LLM 长耗时场景
限流与成本控制:防止一夜回到解放前
LLM API 按 Token 计费,不做限流很容易账单爆表。
YARP 天然集成 .NET 限流框架:
csharp
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();
在路由中绑定策略:
csharp
new RouteConfig
{
RouteId = "openai-route",
ClusterId = "openai-cluster",
Match = new RouteMatch { Path = "/llm/{**catch-all}" },
RateLimiterPolicy = "standard-tier"
}
更进一步,可以在响应中间件里解析 usage.total_tokens,结合 Redis 做全网关 Token 配额与成本统计。
统一响应格式与错误处理
不同厂商的 OpenAI 兼容格式总有细节差异:字段名、错误结构、SSE 实现等。
网关层可以统一包装:
csharp
proxyPipeline.Use(async (context, next) =>
{
try
{
await next();
if (context.Response.StatusCode >= 400)
{
context.Response.ContentType = "application/json";
var errorBody = new
{
error = new
{
message = $"Gateway detected upstream error: {context.Response.StatusCode}",
type = "gateway_proxy_error",
code = context.Response.StatusCode
}
};
await context.Response.WriteAsJsonAsync(errorBody);
}
}
catch (Exception ex)
{
context.Response.StatusCode = 502;
await context.Response.WriteAsJsonAsync(new
{
error = new
{
message = "Bad Gateway: " + ex.Message,
type = "gateway_exception"
}
});
}
});
让前端只面对一套稳定的标准结构。
部署与性能调优
YARP 本身开销极低,10000 QPS 下 P99 延迟 < 1ms。
生产建议优化:
- 调大
SocketsHttpHandler连接池 - 合理设置
ActivityTimeout(LLM 生成长文本需要) - 对 Embedding 等请求启用输出缓存,减少重复计费
csharp
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的朋友,否则看看零散的博文就够了。
