资讯动态

hermesllm 多供应商 LLM 网关统一抽象:在 Plano 中构建类型安全的跨 Provider 请求/响应转换层

发布时间:2026/9/17 3:40:49 来源:尧图企业网站定制
hermesllm 多供应商 LLM 网关统一抽象在 Plano 中构建类型安全的跨 Provider 请求/响应转换层【免费下载链接】planoPlano is an AI-native proxy server and data plane for agentic apps. Smart LLM routing, observability, agent orchestration, and guardrails so you stay focused on your agents core logic.项目地址: https://gitcode.com/GitHub_Trending/ar/planohermesllm 是 PlanoAI 原生代理服务器与数据面核心仓库中的一个 Rust 库用于在 OpenAI、AnthropicClaude、Amazon Bedrock、Groq、Mistral 等多家 LLM 供应商之间提供统一的请求/响应抽象与格式互转能力。本文以 crates/hermesllm/README.md 为主干结合src/providers、src/clients/endpoints.rs、src/apis与src/transforms等源码实现讲解如何在 Plano 中解析、转换、流式转发多供应商 LLM 流量读完你将掌握其核心类型、trait 体系、流式缓冲机制与可扩展的供应商接入方式。hermesllm 是什么hermesllm 是一个处理 LLM API 请求与响应的 Rust 库核心目标是用统一抽象抹平不同供应商的 API 差异。它提供统一的请求/响应类型并支持供应商特定的解析同时支持流式streaming与非流式响应类型安全的供应商标识ProviderId以 OpenAI 兼容 API 结构为基准、可扩展的供应商支持。在 Plano 整体架构中hermesllm 承担协议翻译层的职责客户端无论以 OpenAI Chat Completions、OpenAI Responses 还是 Anthropic Messages 格式发起请求hermesllm 都能将其解析为统一的ProviderRequestType再根据目标供应商转换为对应的上游格式OpenAI / Anthropic / Amazon Bedrock Converse 等并转发返回时再做逆向转换。支持的供应商README 中列出的核心供应商为OpenAI、Mistral、Groq、Deepseek、Gemini、Claude、GitHub。从 src/providers/id.rs 的实际枚举看当前代码库已扩展出远多于 README 列表的供应商集合包括pub enum ProviderId { OpenAI, Xiaomi, Mistral, Deepseek, Groq, Gemini, Anthropic, GitHub, Plano, AzureOpenAI, XAI, TogetherAI, Ollama, Moonshotai, Zhipu, Qwen, AmazonBedrock, ChatGPT, DigitalOcean, Vercel, OpenRouter, Astraflow, AstraflowCN, Meta, Minimax, EdenAI, }ProviderId实现了TryFromstrid.rs支持字符串到枚举的解析且内置了若干别名例如google→Gemini、together→TogetherAI、amazon→AmazonBedrock、do/do_ai→DigitalOcean。从 src/lib.rs 的test_provider_id_conversion测试可以看到assert_eq!(ProviderId::try_from(openai).unwrap(), ProviderId::OpenAI); assert_eq!(ProviderId::try_from(google).unwrap(), ProviderId::Gemini); assert_eq!(ProviderId::try_from(unknown_provider).is_err(), true);此外ProviderId还提供models()方法id.rs从内嵌的provider_models.yaml加载各供应商可用模型列表并自动去除供应商前缀如openai/gpt-4→gpt-4。安装与引入在Cargo.toml中添加依赖即可这是 Plano workspace 内的 crate[dependencies] hermesllm { path ../hermesllm } # 或 workspace 中的合适路径该 crate 的元信息见 crates/hermesllm/Cargo.toml当前版本0.1.0依赖serde/serde_json/serde_yaml、aws-smithy-eventstream用于 Amazon Bedrock 的 Event Stream 二进制帧解码、bytes、uuid等model-fetch特性依赖ureq与chrono用于编译可选的模型拉取二进制fetch_models。基本用法请求解析从 JSON 字节解析请求use hermesllm::providers::{ProviderRequestType, ProviderRequest, ProviderId}; // 从 JSON 字节解析请求 let request_bytes r#{model: gpt-4, messages: [{role: user, content: Hello!}]}#; // 携带供应商上下文解析 let request ProviderRequestType::try_from((request_bytes.as_bytes(), ProviderId::OpenAI))?; // 访问请求属性 println!(Model: {}, request.model()); println!(User message: {:?}, request.get_recent_user_message()); println!(Is streaming: {}, request.is_streaming());从 src/providers/request.rs 看ProviderRequestType是一个枚举包装类型覆盖五种请求形态pub enum ProviderRequestType { ChatCompletionsRequest(ChatCompletionsRequest), // OpenAI /v1/chat/completions MessagesRequest(MessagesRequest), // Anthropic /v1/messages BedrockConverse(ConverseRequest), // Amazon Bedrock Converse BedrockConverseStream(ConverseStreamRequest), // Amazon Bedrock ConverseStream ResponsesAPIRequest(ResponsesAPIRequest), // OpenAI /v1/responses }它实现的ProviderRequesttraitrequest.rs定义了统一访问接口model()、set_model()、is_streaming()、extract_messages_text()、get_recent_user_message()、get_tool_names()、to_bytes()、metadata()、remove_metadata_key()、get_temperature()、get_messages()/set_messages()以 OpenAIMessage作为跨格式消息历史的中间表示。实际解析入口有两套TryFromTryFrom([u8], SupportedAPIsFromClient)request.rs根据客户端 API 形态决定解析成哪种子类型TryFrom(ProviderRequestType, SupportedUpstreamAPIs)request.rs把已解析的请求转换成目标上游 API 格式例如ChatCompletionsRequest → MessagesRequest、ResponsesAPIRequest → ChatCompletionsRequest、ResponsesAPIRequest → ConverseRequest经 ChatCompletions 中转等并明确拒绝不支持的反向转换如 Responses API 作为上游。发送上游前的归一化normalize_for_upstream()request.rs负责按供应商做请求字段修正例如xAI在 chat/completions 上清除已废弃的web_search_optionsMoonshot kimi-for-coding / kimi-k3剥离上游不支持的采样字段temperature、top_p、n、stream_options等K3 保留reasoning_effortChatGPTCodex强制注入基础指令、设置storefalse、强制streamtrue拒绝非流式请求并将input规范为列表形式。这些行为均有对应单元测试佐证例如 request.rs 中的test_normalize_for_upstream_xai_clears_chat_web_search_options与 Kimi 系列归一化测试。处理响应与 Token 用量解析供应商响应use hermesllm::providers::{ProviderResponseType, ProviderResponse}; // 从供应商解析响应 let response_bytes /* JSON response from LLM */; let response ProviderResponseType::try_from((response_bytes, ProviderId::OpenAI))?; // 提取 token 用量 if let Some((prompt, completion, total)) response.extract_usage_counts() { println!(Tokens used: {}/{}/{}, prompt, completion, total); }ProviderResponseTypesrc/providers/response.rs同样是一个 untagged 枚举包含ChatCompletionsResponse、MessagesResponse、ResponsesAPIResponse三种形态。更细粒度的用量拆解TokenUsagetraitresponse.rs在基础的三元组之外还通过带默认实现的方法暴露了缓存与推理相关的细分指标cached_input_tokens()提示词缓存命中的 token 数OpenAIprompt_tokens_details.cached_tokens、Anthropiccache_read_input_tokens、Googlecached_content_token_countcache_creation_tokens()写入缓存条目消耗的 token 数Anthropiccache_creation_input_tokensreasoning_tokens()推理模型的推理 token 数OpenAIcompletion_tokens_details.reasoning_tokens、Googlethoughts_token_count。ProviderResponsetrait 进一步提供extract_usage_details()返回结构化的 UsageDetails便于观测层直接消费。响应跨格式转换ProviderResponseType的TryFrom([u8], SupportedAPIsFromClient, ProviderId)response.rs实现了完整的响应转换矩阵例如 OpenAI 上游返回的响应可以转换成 Anthropic Messages 格式返回给客户端Anthropic 上游响应可转成 OpenAI 格式Bedrock Converse 响应可转成 OpenAI 或 Anthropic 格式复杂的链式转换如 Anthropic → ChatCompletions → ResponsesAPI、Bedrock → ChatCompletions → ResponsesAPI也都有实现。流式响应处理从 SSE 数据创建流式迭代器use hermesllm::providers::{ProviderStreamResponseIter, ProviderStreamResponse}; // 从 SSE 数据创建流式迭代器 let sse_data /* Server-Sent Events data */; let mut stream ProviderStreamResponseIter::try_from((sse_data, ProviderId::OpenAI))?; // 处理流式分片 for chunk_result in stream { match chunk_result { Ok(chunk) { if let Some(content) chunk.content_delta() { print!({}, content); } if chunk.is_final() { break; } } Err(e) eprintln!(Stream error: {}, e), } }底层实现SSE 解析与流式缓冲流式链路的核心在 src/providers/streaming_response.rs 与 src/apis/streaming_shapesSseStreamIter/SseEvent负责把原始 SSE 字节流解析成事件对象data: [DONE]会被标记为终止事件ping 等消息会被过滤见 lib.rs 的test_provider_streaming_response与 streaming_response.rs 中的test_sse_stream_iter_filters_ping_messages。needs_buffering(client_api, upstream_api)streaming_response.rs当客户端 API 与上游 API 一致时走 passthrough无需缓冲不一致时必须缓冲并按目标格式重组。SseStreamBuffer::try_from((client_api, upstream_api))streaming_response.rs工厂方法按客户端 API 选择 OpenAI / Anthropic / Responses 对应的流缓冲器。ProviderStreamResponseTypestreaming_response.rs统一四种流事件形态其 trait 提供content_delta()、is_final()、role()、event_type()。值得注意的是OpenAI ChatCompletions 的流事件没有event_type返回NoneAnthropic / Responses API 的流事件在线缆上使用event:data:成对格式OpenAI → Anthropic 转换时[DONE]会被特殊转换为 Anthropic 的message_stop事件见test_done_marker_handled_in_stream_response_transformation。Amazon Bedrock 二进制事件流Amazon Bedrock 的 ConverseStream 不是 SSE而是 AWS Event Stream 二进制帧协议。hermesllm 使用aws-smithy-eventstream的MessageFrameDecoder解析帧并通过 BedrockBinaryFrameDecoder 处理分块到达chunked arrival场景。lib.rs 的test_amazon_bedrock_streaming_response展示了完整流程模拟 50~1000 字节不等的数据块到达 → 循环decode_frame()→ 遇到Incomplete继续等待下一块 → 从:event-type头识别事件 → 从contentBlockDelta提取文本增量并拼接出完整回复测试数据来自 tests/e2e/response.hex。供应商兼容性判断README 中的兼容性示例use hermesllm::providers::{ProviderId, has_compatible_api, supported_apis}; // 检查 API 兼容性 let provider ProviderId::Groq; if has_compatible_api(provider, /v1/chat/completions) { println!(Provider supports chat completions); } // 列出支持的 API let apis supported_apis(provider); println!(Supported APIs: {:?}, apis);从当前源码结构看这一能力的具体落地实现位于 src/clients/endpoints.rsSupportedAPIsFromClient客户端侧三种 APIOpenAI ChatCompletions / Anthropic Messages / OpenAI Responses与SupportedUpstreamAPIs上游侧五种 API含 Bedrock Converse 与 ConverseStream双枚举体系加上ProviderId::compatible_api_for_client(client_api, is_streaming)id.rs完成客户端 API × 供应商 → 上游 API的映射决策例如Anthropic 供应商原生支持 Messages APIOpenRouter / DigitalOcean 等网关把 Anthropic 客户端请求翻译为上游 ChatCompletionsOpenAI、xAI、ChatGPT、Vercel 原生支持 Responses API其余供应商回退到 ChatCompletionsAmazon Bedrock 无论客户端是什么形态均映射到 Converse / ConverseStream流式与否决定具体端点。端点路径的最终生成由target_endpoint_for_provider()endpoints.rs完成它内置了 Groq 的/openai/v1/...、Zhipu 的/api/paas/v4/...、Qwen 的/compatible-mode/v1/...、Azure OpenAI 的/openai/deployments/{model}/...?api-version2025-01-01-preview、Gemini 的/v1beta/openai/...、Bedrock 的/model/{id}/converse[-stream]等供应商特殊路径规则并支持base_url_path_prefix覆盖与无版本号路径use_unversioned_paths两种模式。核心类型一览供应商类型ProviderId标识供应商的枚举OpenAI、Mistral、Groq 等当前已扩展到 27 个ProviderRequestType包装各供应商请求类型的枚举ProviderResponseType包装各供应商响应类型的枚举ProviderStreamResponseIter/ProviderStreamResponseType流式响应分片的迭代器与类型。TraitsProviderRequest所有请求类型的统一接口ProviderResponse所有响应类型的统一接口ProviderStreamResponse流式响应分片的接口TokenUsagetoken 用量信息的接口含缓存命中/写入与推理 token 的扩展方法。OpenAI API 类型ChatCompletionsRequestChat Completion 请求结构ChatCompletionsResponseChat Completion 响应结构Message、Role、MessageContent消息构建基础件。对应的请求、响应、流事件结构定义位于 src/apis/openai.rs、src/apis/anthropic.rs、src/apis/amazon_bedrock.rs 与 src/apis/openai_responses.rs。所有 API 枚举都实现统一的ApiDefinitiontraitsrc/apis/mod.rs提供endpoint()、from_endpoint()、supports_streaming()、supports_tools()、supports_vision()、all_variants()。架构设计hermesllm 采用类型安全的枚举驱动设计编译期类型安全所有供应商操作都在编译期检查运行时供应商选择供应商可从请求头或配置中动态确定干净的抽象层公共 trait 隐藏供应商细节可扩展性新增供应商只需扩展枚举即可接入。所有请求都会被解析为统一的ProviderRequestType枚举并实现ProviderRequesttrait从而无论底层是哪种供应商格式都能统一访问请求属性。类似的响应与流事件也各自收敛到ProviderResponseType/ProviderStreamResponseType通过 src/transforms 下的request、response、response_streaming、lib四个子模块如from_openai.rs、to_anthropic.rs、to_openai_streaming.rs、output_to_input.rs完成格式互转transforms/lib.rs 中的ContentUtils/ExtractText等工具负责消息内容块文本、图片、工具调用、工具结果在 OpenAI 与 Anthropic 形态之间的映射例如将 Anthropic 的ToolUse/ToolResult内容块转换为 OpenAI 的tool_calls消息。端到端请求流转客户端请求到达SupportedAPIsFromClient::from_endpoint()endpoints.rs根据路径如/v1/chat/completions、/v1/messages、/v1/responses识别客户端 API 形态ProviderRequestType::try_from((bytes, client_api))解析请求体ProviderId::compatible_api_for_client()确定目标上游 APItarget_endpoint_for_provider()生成供应商特定端点ProviderRequestType::try_from((request, upstream_api))完成请求格式转换必要时经normalize_for_upstream()做字段修正流式场景下needs_buffering()判断是否需要缓冲SseStreamBuffer按目标客户端 API 重组 SSE 输出Bedrock 则走MessageFrameDecoder二进制帧解码链路。完整示例与测试src/lib.rs 内置了大量端到端测试可作为完整可运行示例test_provider_id_conversion供应商字符串解析与别名test_provider_streaming_responseSSE 流解析、content_delta()、[DONE]终止与迭代器收尾test_amazon_bedrock_streaming_response分块到达下的事件流解码与内容重建request.rs 与 response.rs 中的往返转换测试Anthropic ↔ OpenAI请求 roundtrip模型、system prompt、消息角色与内容、max_tokens 均保持一致、Responses API → ChatCompletions 转换、供应商特定归一化等endpoints.rs 中的端点测试覆盖 Groq / Zhipu / Qwen / Azure / Gemini / Bedrock 的路径生成与自定义前缀行为。运行测试cargo test -p hermesllm扩展新供应商的路径结合源码结构接入一家新供应商通常只需要四步在ProviderId枚举id.rs与TryFromstr匹配中登记新供应商在compatible_api_for_client()id.rs中声明它支持的上游 API 映射如端点路径特殊在target_endpoint_for_provider()endpoints.rs中补充路由规则若存在专属请求/响应字段差异在normalize_for_upstream()与 transforms 模块中添加归一化或转换逻辑并补充单元测试。许可证hermesllm 采用 MIT License与 Plano 仓库整体开源协议保持一致。适用前提说明以上示例均针对当前仓库crates/hermesllm实际代码编写Cargo.toml中的路径依赖写法适用于 Plano workspace 内部引用。若在独立项目中使用需将path指向本仓库crates/hermesllm目录并确保 rust toolchain 支持 edition 2021。【免费下载链接】planoPlano is an AI-native proxy server and data plane for agentic apps. Smart LLM routing, observability, agent orchestration, and guardrails so you stay focused on your agents core logic.项目地址: https://gitcode.com/GitHub_Trending/ar/plano创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价