首页
/ Headroom Rust 代理 Phase D 详解:原生 Bedrock 与 Vertex 信封、SigV4 签名与二进制 EventStream 流式转发

Headroom Rust 代理 Phase D 详解:原生 Bedrock 与 Vertex 信封、SigV4 签名与二进制 EventStream 流式转发

2026-09-05 11:49:27作者:薛曦旖Francesca

Headroom 的 Rust 代理(headroom-proxy)在 Phase D 阶段用原生路由替换了原本基于 LiteLLM 的"假"Bedrock/Vertex 路径——后者会在 Anthropic↔OpenAI 两种消息格式之间做有损转换。本文以 REALIGNMENT/06-phase-D-bedrock-vertex.md 为主线,完整还原该阶段 4 个 PR(D1 非流式 Bedrock Invoke、D2 EventStream 流式、D3 可观测性与 auth-mode 集成、D4 原生 Vertex publisher)的设计目标、验收标准与回滚策略,并结合仓库中实际落地的 Rust 源码(信封解析、SigV4 签名、EventStream 增量解析器、GCP ADC token 缓存、Prometheus 指标)逐层印证关键实现,帮助你理解"压缩之后再做签名""字节保真契约""无静默回退"等工程约束如何在代码里兑现。

一、Phase D 的目标、节奏与四个 PR 的分工

Phase D 的总目标是:让 Anthropic-on-Bedrock 与 Anthropic-on-Vertex 在穿过 Headroom 代理时,完整保留 thinkingredacted_thinkingdocumentsearch_resultimageserver_tool_usemcp_tool_use 这些内容块,同时接入 live-zone 压缩引擎(与直接调用 Anthropic 时一致)。原始文档给出的节奏与拆分如下:

  • 日历:2 周,SigV4 与 EventStream 是主要工作量。
  • 形态:4 个 PR。D1+D2+D3 面向 AWS Bedrock,D4 面向 GCP Vertex。
  • 依赖链:D1 依赖 Phase C 的 PR-C1(Anthropic SSE 状态机),D2 依赖 D1,D3 依赖 D2 与 PR-F1(auth-mode 助手),D4 依赖 C1 与 D1(信封模式)。D2/D3/D4 均阻塞 Phase H 的 PR-H2(删除 Python LiteLLM 转换路径)。
PR 分支 风险 新增 LOC 核心内容
PR-D1 realign-D1-bedrock-native-invoke HIGH +1500 原生 Bedrock /model/{model}/invoke 非流式路由 + SigV4
PR-D2 realign-D2-bedrock-event-stream HIGH +1100 /invoke-with-response-stream,二进制 EventStream 解析/转 SSE
PR-D3 realign-D3-bedrock-observability LOW +400 按模型/区域指标、IAM 归因、auth-mode 集成
PR-D4 realign-D4-vertex-native HIGH +1300 Vertex :rawPredict / :streamRawPredict + ADC bearer

Phase D 完成后的验收清单(来自文档"Phase D acceptance summary"):

  • Rust 中原生 Bedrock /model/{model}/invoke 路由;
  • /model/{model}/invoke-with-response-stream(二进制 EventStream 被解析并翻译);
  • 压缩后做 SigV4 签名(signing post-compression);
  • 所有 Anthropic 块类型穿过 Bedrock 不被破坏;
  • stop_sequence: null 不再硬编码;
  • tool_calls.function.arguments 保持字符串形态;
  • 原生 Vertex :rawPredict:streamRawPredict 路由;
  • ADC bearer token 解析;
  • Bedrock/Vertex 均被归类为 AuthMode::OAuth(passthrough-prefer 压缩);
  • 按 Bedrock 模型、Vertex 模型的 Prometheus 指标。

文档同时声明:Phase D 淘汰 bug 清单里的 P4-37/38/39/43;此后 Bedrock/Vertex 请求路径上不再经过 LiteLLM Python 转换器,该转换器将在 Phase H 被删除。

二、PR-D1:非流式 Bedrock Invoke 与"压缩后签名"

2.1 信封(Envelope)形状:为什么 Bedrock 体里没有 model

Bedrock 的 InvokeModel 对任意 anthropic.claude-* 模型期望的请求体形如:

{
  "anthropic_version": "bedrock-2023-05-31",
  "messages": [...],
  "max_tokens": 1024,
  "...其余 Anthropic 字段": "..."
}

与直接调用 Anthropic /v1/messages 的关键差异是:model 在 URL 路径里/model/{model}/invoke),而不在 body 中;anthropic_version 是必需字段且必须是 Bedrock 认可的版本字符串(如 "bedrock-2023-05-31")。

这一点在源码 crates/headroom-proxy/src/bedrock/envelope.rs 中被精确落地。BedrockEnvelope 结构持有 anthropic_version 与完整解析后的 Value,并提供两类关键操作:

  • BedrockEnvelope::parse(body):只解析、不改写字节;校验顶层是对象、anthropic_version 存在且为字符串,否则返回 MissingAnthropicVersion / AnthropicVersionNotString / NotObject / NotJson 结构化错误。
  • BedrockEnvelope::ensure_anthropic_version_first(body):仅当压缩器返回 Modified 需要重组 body 时调用;借助 serde_jsonpreserve_order(工作区默认开启)保留键序,仅在 anthropic_version 不是第一个键时才重排。

源码注释中明确了一条缓存安全契约(对应 REALIGNMENT/02-architecture.md 的 I1):压缩器若返回 NoChange,代理原封不动转发最初缓冲的字节——绝不重新序列化;若返回 Modified,其产出的字节切片已通过 preserve_order 保持键序,ensure_anthropic_version_first 在正常路径上几乎总是 no-op,只是作为"防御性断言"确保字节序正确后再签名。

2.2 关键约束:SigV4 必须在压缩改写之后签名

原始文档在 Notes 中强调:签名范围覆盖 hostx-amz-datex-amz-content-sha256 头 + 规范化请求体;body 哈希必须在任何压缩改写之后计算。源码 crates/headroom-proxy/src/bedrock/sigv4.rs 用一段模块级注释把这条策略写成不变量:

失败签名尝试返回结构化错误;处理器返回 5xx 并记录事件。我们绝不把未签名请求转发给 Bedrock。 body 字节在压缩之后被哈希。签名输入包含的 &[u8] 就是转发器将要发送的精确字节切片;不存在"哈希压缩前 body"的单独代码路径。

sign_request 的核心实现细节:

  • 服务名固定为 bedrockBEDROCK_SERVICE_NAME),用于 SigV4 string-to-sign。
  • 通过 PayloadChecksumKind::XAmzSha256 强制把 x-amz-content-sha256 纳入规范化请求。源码解释原因:若用 crate 默认的 NoHeader,签名器会跳过该头,任何真正检查该头的下游网关都会 403。
  • aws-sigv4SignableRequest::new(method, url, extra_signed_headers, SignableBody::Bytes(body)) 构造签名输入,body 必须恰好是即将发送的字节(压缩后)。
  • 签名器固定输出 authorizationx-amz-datex-amz-content-sha256 三个头,调用方还需把 extra_signed_headers(如 content-typeaccept)一起纳入签名列表。
  • 每次签名成功都会发出 event = "sigv4_signed" 的结构化日志(含 region、method、host、body_bytes、headers_added),便于运维确认签名发生。

该模块还声明了几条"刻意不做"的边界:不解析凭证(那是 aws-config 的职责,在应用启动时解析一次,让每请求签名保持廉价);不缓冲 body(调用方在压缩门处缓冲,是同一片字节);不处理 SigV4a(跨区变体),因为 Bedrock 每区使用标准 SigV4。

单元测试覆盖了四条性质:固定输入产生确定性签名、改变 body 会改变签名、改变 region 会改变签名、最小请求必然产出 authorization/x-amz-date/x-amz-content-sha256 三头且签名是 64 位十六进制(32 字节)。

2.3 Invoke 处理器的完整管线

处理器入口 crates/headroom-proxy/src/bedrock/invoke.rshandle_invoke 完整实现了文档描述的 6 步管线:

  1. 从路径提取 {model_id}(Bedrock 约定形如 anthropic.claude-3-haiku-20240307-v1:0)。
  2. 若厂商是 anthropic,把 body 当作 Bedrock 信封解析,并对 body 字节跑 live-zone Anthropic 压缩调度器——这个调度器与 /v1/messages 用的是同一个,Bedrock 的 body 只是"没有 model 字段的 Anthropic"。
  3. 重新发出(可能被压缩的)body,保证 anthropic_version 是第一个键。
  4. 构造上游 URL:https://bedrock-runtime.{region}.amazonaws.com/model/{model}/invoke,或运维覆盖端点。
  5. 用 AWS SigV4 对(压缩后的)body 字节签名;签名头覆盖 hostx-amz-datex-amz-content-sha256 以及额外头(content-typeaccept)。
  6. 转发到 Bedrock,把响应流式回给客户端。

处理器的失败模式在源码注释里被明确列举,与文档的"无静默回退"项目规则一致:

  • 凭证缺失event=bedrock_credentials_missing(WARN),返回 500,绝不转发未签名请求;
  • 信封解析失败event=bedrock_envelope_parse_error,原字节透传,Bedrock 自己拒绝,失败归属于客户而非代理(与 Anthropic 压缩路径 Outcome::Passthrough 行为一致);
  • 非 Anthropic 模型:跳过压缩,但仍然签名 + 转发(Amazon Titan、Cohere、AI21、Meta 等厂商的 body 形状代理尚不理解,做不透明透传);
  • SigV4 签名失败event=bedrock_sigv4_failed,返回 500,绝不转发未签名。

值得留意的实现细节:

  • 动作解析:处理器同时挂载在 /invoke/converse 上(extract_invoke_action 从入站路径推断 action),以避免 /converse 请求被错误转发到上游 /invoke。这是文档中"PR-D1 修改 lib.rs 路由 /model/{model}/invoke/model/{model}/converse"的落地。
  • 压缩调度run_anthropic_compression 里对压缩器显式传入 AuthMode::OAuth——源码注释解释,Bedrock 下游使用 IAM 签名的 AWS SigV4,入站请求可能有也可能没有自己的鉴权,但 Bedrock 是 subscription/IAM 通道(而非 PAYG),所以硬编码 RequestAuthMode::OAuth 以跳过 PR-E3 的 cache_control 自动放置,保持 Bedrock 字节契约稳定,live-zone 压缩本身照常运行。
  • 可观测性:RAII 守卫 LatencyGuard 在进入处理器时启动,无论走哪条返回路径都在 Drop 时观测 bedrock_invoke_latency_seconds 直方图;record_bedrock_invoke(&model_id, &region, auth_mode) 在处理器入口就计数一次(在任何错误路径 early-return 之前),与结构化日志通过 request_id 关联。
  • 凭证来源:从 state.bedrock_credentials 读取(应用启动时通过 aws-config 默认链解析)。aws_profile 配置项允许指定 AWS profile 名;未设置时走默认链(env → [default] profile → IMDS)。

2.4 配置项:region、endpoint、profile 与开关

文档要求 D1 在 crates/headroom-proxy/src/config.rs 添加 --bedrock-region(默认 us-east-1)与 AWS 凭证配置。实际配置源码把这些做成了完整的一套 CLI + 环境变量:

参数 CLI flag 环境变量 默认值 说明
Bedrock 原生路由开关 --enable-bedrock-native HEADROOM_PROXY_ENABLE_BEDROCK_NATIVE 由 rollout 决定(测试默认开) 特性门控(Feature::NativeBedrock
区域 --bedrock-region HEADROOM_PROXY_BEDROCK_REGION us-east-1 用于 SigV4 签名与(未显式指定端点时)推导上游 URL
端点覆盖 --bedrock-endpoint HEADROOM_PROXY_BEDROCK_ENDPOINT 无(由 region 推导) 优先级:CLI → 环境变量 → 由 region 推导;FIPS/VPC/本地 mock 场景使用
AWS profile --aws-profile None None 时使用默认凭证链
EventStream CRC 校验 --bedrock-validate-eventstream-crc HEADROOM_PROXY_BEDROCK_VALIDATE_EVENTSTREAM_CRC true 仅调试可关闭

上游 URL 推导逻辑在 build_bedrock_upstream 中:若 state.config.bedrock_endpoint 有值则直接作为 base;否则用模板 bedrock-runtime.{region}.amazonaws.com 拼接 https://。路径与 query 部分从原始 URI 原样保留——Bedrock 的路径 schema(/model/{id}/{action})与代理对外暴露的路径完全一致。

2.5 D1 的验收标准、阻塞关系与回滚

  • 验收:新增的集成测试全部通过;在开发者真实 AWS 账号下手动测试成功;既有的假 Bedrock 路径(Python 端 headroom/backends/litellm.py)继续可用——本 PR 是在其旁路并行添加 Rust 路径。
  • 阻塞:D1 依赖 PR-C1;阻塞 D2、D3 与 Phase H 的 H2。
  • 回滚git revert。Bedrock 请求回落到 Python LiteLLM 转换器(即"假"路径)。未使用 Rust Bedrock 的用户没有回归。

文档列出的 D1 集成测试(位于 crates/headroom-proxy/tests/integration_bedrock_invoke.rs)覆盖了信封回环字节相等、压缩后 SigV4 正确签名、thinking/redacted_thinking/document 块保留、带图像的 tool_result 数组保留、stop_sequence: null 仅当存在时出现、tool_use.input 字节相等保留键序等。

三、PR-D2:二进制 EventStream 流式——不是 SSE

3.1 EventStream 线格式

Bedrock 的流式面 /model/{id}/invoke-with-response-stream 返回 application/vnd.amazon.eventstream 分帧消息,不是 Server-Sent Events。源码 crates/headroom-proxy/src/bedrock/eventstream.rs 用 ASCII 图描述了帧布局:

+------------------+----------------------+------------------+
|  prelude (12B)   |    headers (N1 B)    |   payload (N2 B) |  +  4-byte CRC32
+------------------+----------------------+------------------+

Prelude 是三个大端 u32:total_length(消息起点到含尾部 CRC32 的长度)、headers_length(headers 块字节数)、prelude_crc32(prelude 前 8 字节的 CRC32)。payload 长度按 total_length - 12 - headers_length - 4 计算。每个 header 为 [name_len: u8][name (UTF-8)][value_type: u8][value];AWS 定义了 10 种值类型,Bedrock 实践中只用类型 7(字符串,[u16 BE 长度][字节])与类型 6(字节数组)。

3.2 增量解析器:状态化、无 panic、无回退

TCP 分块在不可预测的边界交付——一条 EventStream 消息可能分散在任意数量的片段中到达,一个 chunk 也可能含多条完整消息加一条残缺尾巴。解析器必须以状态化结构跨 chunk 恢复、不丢字节:EventStreamParser 累积到内部 BytesMut,在完整消息成形时通过 next_message 吐出;API 形状刻意与 sse::framing::SseFramer(Phase C)保持一致,熟悉 SSE 侧的调用方可以直接迁移心智模型。

解析器的关键工程约束(对应项目规则 feedback_no_silent_fallbacks.md):永远返回 Result,从不 panic、从不用零值静默填充ParseError 的变体覆盖了每一种可诊断的畸形:

  • ImplausiblePreludeLengths { total_length, headers_length }total_length 小于最小合法值(12B prelude + headers + 4B CRC),是线格式违例;
  • MessageTooLarge { total_length, cap }:超过 max_message_bytes 上限(默认 32 MiB = AWS 文档最大值 16 MiB 的 2 倍余量,防止损坏流解码出垃圾长度后分配 GB 级内存;可用 with_max_message_bytes 覆盖);
  • PreludeCrcMismatch { expected, got } / MessageCrcMismatch { expected, got }:CRC 不匹配,指示在途比特翻转、chunk 截断或线格式版本漂移;
  • TruncatedHeader { offset, needed }HeaderNameNotUtf8HeaderValueNotUtf8UnsupportedHeaderType { value_type, offset }:头解析的逐点失败。

CrcValidation 枚举(默认 Yes)与 --bedrock-validate-eventstream-crc=false 调试 flag 联动,运维可在排查时关闭 CRC 校验——但源码明确注释"生产必须校验"。

3.3 EventStream → SSE 翻译与客户端选择

文档要求 D2 新增 eventstream_to_sse.rs:对 Anthropic 形状的 Bedrock 响应,每个 :event-typechunkEventStreamMessage,其 payload 携带一个 Anthropic SSE 事件,代理把它重新作为 SSE 发出给客户端;也可以原样透传 EventStream——具体走哪条由客户端 Accept 头决定。源码中 EventStreamMessage 提供 event_type()message_type() 便捷访问器,message_type 区分 event(数据帧)与 exception(同步错误)。

D2 的验收:测试通过 + 真实 Bedrock 流式端点手动测试成功;阻塞 H2;回滚为 git revert,流式 Bedrock 回落 Python LiteLLM。

D2 的测试矩阵(crates/headroom-proxy/tests/integration_bedrock_streaming.rs)包含 eventstream_parses_correctlyeventstream_translated_to_sseusage_extracted_from_translated_streamclient_can_choose_eventstream_or_sse,以及一条属性测试:proptest! { fn eventstream_parser_no_panic(bytes in any::<Vec<u8>>()) { let _ = parse(bytes); } }——用任意字节流验证解析器不 panic。

四、PR-D3:Bedrock 侧可观测性与 auth-mode 集成

D3 目标:按 Bedrock 模型的指标、区域标记、IAM role 归因,以及与 auth-mode 策略的集成(Bedrock IAM 默认视为 "oauth" 模式,压缩采用 passthrough-prefer)。

文档列出的 Prometheus 指标在 crates/headroom-proxy/src/observability/prometheus.rs 中被完整注册:

指标 类型 标签 语义
bedrock_invoke_count_total Counter {model, region, auth_mode} 每次 invoke 入口 +1
bedrock_invoke_latency_seconds Histogram {model, region} 处理器入口到 Drop 的墙钟时间(含上游 RTT + 签名 + 压缩)
bedrock_eventstream_message_count_total Counter {model, region, event_type} 解析出的 EventStream 消息数,按事件类型分桶

源码注释解释了 RAII 设计:LatencyGuard 保证所有返回路径(成功、签名失败、上游错误、响应构建失败)都观测直方图,避免未来有人新增错误路径时忘加埋点;计数器在 handler 入口就增加(一次请求一次,在任何 early-return 之前),与结构化日志通过 request_id 关联。

auth-mode 分类:文档要求把入站 /model/.../invoke 归类为 AuthMode::OAuth。源码里这一动作不在处理器内重复分类——处理器通过 Extension<AuthMode> 提取中间件预先填好的值(见 crates/headroom-proxy/src/bedrock/invoke.rs 顶部对 PR-F1 + PR-D3 的注释):"中间件提供的值是单一真相源——处理器不重新分类,那会与中间件的解析 + WARN 日志产生漂移。"Bedrock 专用分类逻辑位于 crates/headroom-proxy/src/bedrock/auth_mode_layer.rs

D3 的验收:测试通过;Prometheus scrape 包含 Bedrock 指标。回滚:git revert,丢失 Bedrock 可观测性,功能路径不变。文档还要求新增 docs/bedrock.md 运维文档(AWS 凭证配置、支持的模型——任意 anthropic.claude-*、期望的压缩行为——仅 live-zone、偏好无损)。

五、PR-D4:原生 Vertex publisher 路径

5.1 路由与信封

D4 添加两条路由:

POST /v1beta1/projects/{project}/locations/{loc}/publishers/anthropic/models/{model}:rawPredict
POST /v1beta1/projects/{project}/locations/{loc}/publishers/anthropic/models/{model}:streamRawPredict

信封同样使用 anthropic_version body 字段、无 model 字段,但鉴权头换成 GCP 的 Authorization: Bearer <jwt>。Vertex 的流式与 Bedrock 相反——使用 SSE,所以 PR-C1 的 AnthropicStreamState 可以直接工作,无需 EventStream 解析器。

5.2 GCP ADC → bearer token 解析

Vertex 的 :rawPredict/:streamRawPredict 期望 Authorization: Bearer <jwt>,其中 JWT 是短生命周期的 Google 签名访问令牌,来自 ADC provider 链(gcloud 用户凭证、GCE/GKE metadata server、GOOGLE_APPLICATION_CREDENTIALS 服务账号 JSON、workload-identity federation 等),并在过期前刷新。

源码 crates/headroom-proxy/src/vertex/adc.rs 的实现要点:

  • 抽象而非直连TokenSource trait 只有两个显式实现——生产 GcpAdcTokenSource 与测试 StaticTokenSource。源码注释解释理由:测试绝不能真打 GCP("无静默回退"项目规则),必须有一个显式且与生产区分的 mock;gcp_auth 每次调用都取 token,缓存 + 过期前刷新的策略放在这一层,使其独立可测可调。
  • 刷新策略:令牌剩余寿命低于 REFRESH_AHEAD_SECS(60 秒)时刷新,避免"请求恰好在过期时发出、与上游时钟竞争"的悬崖失败;60 秒足以覆盖慢上游与钟漂。gcp_auth 内部虽缓存,但仍要包一层以控制刷新前窗口(gcp_auth 的内部默认是实现定义、可能变动的)并每次刷新发出 event = "vertex_adc_token_refreshed" 结构化日志。
  • 默认 scopehttps://www.googleapis.com/auth/cloud-platformgcloud 为 ADC 默认输出的最宽 scope)。
  • 懒加载 providerGcpAdcTokenSource::new() 不解析 provider——推迟到首次 .bearer() 调用,让未实际接入 Vertex 路由的运维启动廉价。provider 缓存在 Mutex<Option<Arc<dyn TokenProvider>>>(而非 OnceCell),因为初始化可能失败,我们希望下次调用在瞬态失败后重试而非把 cell 永久锁死成错误。
  • 失败模式:ADC 获取失败(无凭证、metadata 不可达、IAM 拒绝等)时,处理器把 TokenSourceError 转成结构化 5xx(502,event = "vertex_adc_fetch_failed")——绝不静默无 token 转发,因为上游 401 比代理自己的 502 更难调试。

5.3 rawPredict 处理器管线

crates/headroom-proxy/src/vertex/raw_predict.rsforward_vertex_request 同时被 :rawPredict:streamRawPredict 复用,管线步骤与注释一一对应:

  1. 缓冲 body:受 compression_max_body_bytes 限制,超限返回 413(event = "vertex_body_too_large");
  2. 信封解析:确认 anthropic_version 存在、model 不存在;不匹配返回 400(event = "vertex_envelope_invalid");
  3. live-zone 压缩(开启时):body 就是 /v1/messages 接受的 Anthropic Messages 形状,只是 anthropic_version 替代了 model。调度器用基于 RawValue 的手术只改写 messages[*] 条目,anthropic_version 与其他非 messages 顶层字段字节相等回环。压缩器同样硬编码 AuthMode::OAuth(Vertex 下游用 GCP ADC bearer 而非 Anthropic 凭证,PAYG/OAuth/subscription 分类不适用),跳过 E3 cache_control 自动放置;
  4. ADC bearer token:解析(缓存、过期前刷新)并附 Authorization: Bearer <token>。ADC 失败 → 502,绝不静默未鉴权转发;
  5. 转发到配置好的 Vertex 端点(https://{region}-aiplatform.googleapis.com/<path>);
  6. 流式回写响应 body 不变。流式 SSE 字节原样回客户端。

VertexCallContext 载体结构从 URL 路径中解析出 projectlocationmodel_idverb,日志与错误路径共用一致字段。

5.4 D4 的验收与回滚

验收:测试通过;真实 Vertex 端点手动测试成功。阻塞 H2。回滚:git revert,Vertex 请求回落 LiteLLM Python。测试矩阵(crates/headroom-proxy/tests/integration_vertex_raw_predict.rs):native_envelope_round_trip_byte_equaladc_bearer_token_signed_correctlythinking_block_preservedstream_raw_predict_sse_handled

六、把 4 个 PR 串起来:字节保真、无静默回退与 auth-mode 统一

从源码结构看,Phase D 的四个 PR 共享三条贯穿始终的工程不变量,这也是理解整个阶段设计的关键:

  1. 字节保真契约(I1):压缩器 NoChange → 原字节透传,从不重新序列化;Modified → 借助 preserve_order 保键序,ensure_anthropic_version_first 作为防御性断言。这条契约让"未修改字节字节相等回环"成为可测试的性质,D1/D4 的集成测试都以 ..._byte_equal 命名。
  2. 无静默回退:SigV4 失败、ADC 失败、信封解析失败、EventStream CRC 不匹配——每一种失败都转为结构化 5xx + 明确 event 日志,绝不转发未签名请求、绝不静默用零值填充、绝不把解析失败吞掉。EventStream 解析器"永远返回 Result"、TokenSource "无 blanket impl"、GcpAdcTokenSourceMutex<Option> 而非 OnceCell 以便失败重试,都是这条规则的体现。
  3. auth-mode 统一为 OAuth:Bedrock(IAM 签名)与 Vertex(GCP ADC bearer)都不是 PAYG 通道,因此压缩器在两条路径上都硬编码 AuthMode::OAuth,跳过 E3 cache_control 自动放置,保证字节契约稳定,而 live-zone 压缩照常运行。auth-mode 分类由中间件(PR-F1 + D3)统一完成,处理器只提取、不重新分类,避免漂移。

七、如何在仓库中继续深入

八、适用范围与前提

  • 以上实现均对应当前仓库中已落地的 Rust 代理代码;Phase D 的 4 个 PR 在文档中规划为 HIGH/LOW 风险、合计约 +4300 LOC,当前代码已包含 D1–D4 对应的全部源文件与集成测试。
  • Bedrock 路径要求配置 AWS 凭证(--bedrock-region + 默认凭证链或 --aws-profile);未配置时非流式 invoke 会以 500 bedrock_credentials_missing 拒绝转发,而不是透传。
  • Vertex 路径要求可解析的 GCP ADC(gcloud 登录、GOOGLE_APPLICATION_CREDENTIALS 或 metadata server);解析失败返回 502 vertex_adc_fetch_failed
  • 压缩行为:Bedrock 与 Vertex 都只启用 live-zone Anthropic 压缩(偏好无损、passthrough-prefer),不执行 PAYG 专属的 cache_control 自动放置;非 Anthropic 厂商的 Bedrock 模型不做压缩、仅签名转发。
  • 流式差异:Bedrock 用二进制 EventStream(需 D2 的解析/翻译),Vertex 用 SSE(直接复用 PR-C1 的 AnthropicStreamState)。

掌握以上内容后,你可以独立定位 Bedrock/Vertex 请求在 Headroom Rust 代理中的完整生命周期——从路径路由、信封校验、live-zone 压缩、压缩后签名(SigV4 / ADC bearer)、EventStream 或 SSE 流式回写,到按模型/区域的 Prometheus 可观测性,以及每条失败路径的结构化错误与"无静默回退"边界。

登录后查看全文
热门项目推荐
相关项目推荐