free-code-dotnet/docs/核心模块设计/核心模块设计-API提供商路由.md
应文浩wenhao.ying@xiaobao100.com e25ac591a7 init easy-code
2026-04-06 07:24:24 +08:00

7.8 KiB
Raw Blame History

核心模块设计 — API 多提供商路由

所属项目: free-code .NET 10 重写 原始代码来源: ../../src/services/api/ 原始设计意图: 支持五种 API 提供商Anthropic、OpenAI Codex、AWS Bedrock、Google Vertex、Anthropic Foundry的统一路由通过环境变量自动检测活跃提供商并为每个提供商实现 SSE 流式解析 上级文档: 核心模块设计总览


概述

API 多提供商路由模块是 free-code 多后端能力的核心。它将具体 API 调用细节从 QueryEngine 中解耦出来,使查询引擎无需关心当前使用的是哪家服务商的 API。

原始 TypeScript 实现通过 ../../src/services/api/ 目录下的多个文件分别实现各提供商的客户端。.NET 重写引入 IApiProvider 接口统一抽象,通过 ApiProviderRouter 在运行时选择具体实现。


9.1 提供商枚举

public enum ApiProviderType
{
    Anthropic,          // 默认,直连 Anthropic API
    OpenAICodex,        // CLAUDE_CODE_USE_OPENAI=1
    AwsBedrock,         // CLAUDE_CODE_USE_BEDROCK=1
    GoogleVertex,       // CLAUDE_CODE_USE_VERTEX=1
    AnthropicFoundry    // CLAUDE_CODE_USE_FOUNDRY=1
}

9.2 IApiProvider 接口

/// <summary>API提供商抽象接口</summary>
public interface IApiProvider
{
    /// <summary>发起流式 API 请求,返回 SSE 消息流</summary>
    IAsyncEnumerable<SDKMessage> StreamAsync(
        ApiRequest request,
        CancellationToken ct = default);
}

public record ApiRequest(
    string SystemPrompt,
    IReadOnlyList<ApiMessage> Messages,
    IReadOnlyList<ITool> Tools,
    string? Model = null
);

9.3 ApiProviderRouter — 路由器

ApiProviderRouter 在构造时检测环境变量,确定活跃提供商,后续每次调用 GetActiveProvider() 都返回对应的实例。

原始设计意图: 原始代码通过 process.env 检查选择不同的 API 客户端模块。.NET 版本将这一逻辑集中在路由器的构造函数中,避免散布在代码各处的条件判断。

public class ApiProviderRouter : IApiProviderRouter
{
    private readonly IServiceProvider _services;
    private ApiProviderType _activeProvider;

    public ApiProviderRouter(IServiceProvider services)
    {
        _services = services;
        _activeProvider = DetectProvider(); // 从环境变量自动检测
    }

    private static ApiProviderType DetectProvider()
    {
        if (Env("CLAUDE_CODE_USE_OPENAI") == "1") return ApiProviderType.OpenAICodex;
        if (Env("CLAUDE_CODE_USE_BEDROCK") == "1") return ApiProviderType.AwsBedrock;
        if (Env("CLAUDE_CODE_USE_VERTEX") == "1") return ApiProviderType.GoogleVertex;
        if (Env("CLAUDE_CODE_USE_FOUNDRY") == "1") return ApiProviderType.AnthropicFoundry;
        return ApiProviderType.Anthropic;
    }

    public IApiProvider GetActiveProvider() => _activeProvider switch
    {
        ApiProviderType.Anthropic => _services.GetRequiredService<AnthropicProvider>(),
        ApiProviderType.OpenAICodex => _services.GetRequiredService<CodexProvider>(),
        ApiProviderType.AwsBedrock => _services.GetRequiredService<BedrockProvider>(),
        ApiProviderType.GoogleVertex => _services.GetRequiredService<VertexProvider>(),
        ApiProviderType.AnthropicFoundry => _services.GetRequiredService<FoundryProvider>(),
        _ => throw new InvalidOperationException()
    };

    private static string? Env(string name) => Environment.GetEnvironmentVariable(name);
}

检测优先级为OpenAI > Bedrock > Vertex > Foundry > Anthropic默认。若同时设置多个环境变量优先级靠前的生效。


9.4 AnthropicProvider — SSE 流式解析

AnthropicProvider 实现直连 Anthropic Messages API 的 SSE 流式解析,是五个提供商中最核心的实现。

原始设计意图: 原始 claude.ts 使用 Anthropic TypeScript SDK 处理流式响应。.NET 版本直接使用 HttpClient 发送 HTTP 请求,手动解析 SSE 事件行,避免引入额外 SDK 依赖。

public class AnthropicProvider : IApiProvider
{
    private readonly HttpClient _httpClient;

    public async IAsyncEnumerable<SDKMessage> StreamAsync(
        ApiRequest request, [EnumeratorCancellation] CancellationToken ct = default)
    {
        var payload = new {
            model = request.Model ?? "claude-sonnet-4-6",
            max_tokens = 16384,
            stream = true,
            system = request.SystemPrompt,
            messages = request.Messages,
            tools = request.Tools
        };

        var httpReq = new HttpRequestMessage(HttpMethod.Post,
            $"{GetBaseUrl()}/v1/messages")
        {
            Content = JsonContent.Create(payload)
        };
        httpReq.Headers.Add("x-api-key", GetApiKey());
        httpReq.Headers.Add("anthropic-version", "2023-06-01");

        using var response = await _httpClient.SendAsync(
            httpReq, HttpCompletionOption.ResponseHeadersRead, ct);
        response.EnsureSuccessStatusCode();

        // SSE 流式解析
        using var stream = await response.Content.ReadAsStreamAsync(ct);
        using var reader = new StreamReader(stream);

        while (!reader.EndOfStream && !ct.IsCancellationRequested)
        {
            var line = await reader.ReadLineAsync(ct);
            if (string.IsNullOrEmpty(line) || !line.StartsWith("data: ")) continue;

            var json = line[6..];
            var doc = JsonDocument.Parse(json);
            var type = doc.RootElement.GetProperty("type").GetString();

            switch (type)
            {
                case "content_block_delta":
                    yield return new SDKMessage.StreamingDelta(
                        doc.RootElement.GetProperty("delta")
                            .GetProperty("text").GetString()!);
                    break;
                case "content_block_start":
                    var block = doc.RootElement.GetProperty("content_block");
                    if (block.GetProperty("type").GetString() == "tool_use")
                        yield return new SDKMessage.ToolUseStart(
                            block.GetProperty("id").GetString()!,
                            block.GetProperty("name").GetString()!,
                            block.GetProperty("input"));
                    break;
                case "message_stop":
                    yield break;
            }
        }
    }
}

SSE 事件类型映射

SSE type 映射到 SDKMessage 子类 说明
content_block_delta SDKMessage.StreamingDelta 文本流式增量
content_block_start (tool_use) SDKMessage.ToolUseStart 工具调用开始
message_stop yield break 流结束
其他 忽略 pingmessage_start 等元数据事件

HttpCompletionOption.ResponseHeadersRead 确保在响应头返回后立即开始读取流,而不是等待整个响应体下载完成,这是 SSE 流式解析的关键设置。


9.5 提供商配置汇总

提供商 环境变量 认证方式 端点
Anthropic 默认 ANTHROPIC_API_KEY 或 OAuth https://api.anthropic.com
OpenAI Codex CLAUDE_CODE_USE_OPENAI=1 OAuth via OpenAI https://api.openai.com
AWS Bedrock CLAUDE_CODE_USE_BEDROCK=1 AWS 标准凭证链 AWS_REGION 对应端点
Google Vertex CLAUDE_CODE_USE_VERTEX=1 GCP ADC GCP 项目对应端点
Anthropic Foundry CLAUDE_CODE_USE_FOUNDRY=1 ANTHROPIC_FOUNDRY_API_KEY 自定义部署端点

参考资料