Headroom Rust 代理 Phase D 详解:原生 Bedrock 与 Vertex 信封、SigV4 签名与二进制 EventStream 流式转发
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 代理时,完整保留 thinking、redacted_thinking、document、search_result、image、server_tool_use、mcp_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_json的preserve_order(工作区默认开启)保留键序,仅在anthropic_version不是第一个键时才重排。
源码注释中明确了一条缓存安全契约(对应 REALIGNMENT/02-architecture.md 的 I1):压缩器若返回 NoChange,代理原封不动转发最初缓冲的字节——绝不重新序列化;若返回 Modified,其产出的字节切片已通过 preserve_order 保持键序,ensure_anthropic_version_first 在正常路径上几乎总是 no-op,只是作为"防御性断言"确保字节序正确后再签名。
2.2 关键约束:SigV4 必须在压缩改写之后签名
原始文档在 Notes 中强调:签名范围覆盖 host、x-amz-date、x-amz-content-sha256 头 + 规范化请求体;body 哈希必须在任何压缩改写之后计算。源码 crates/headroom-proxy/src/bedrock/sigv4.rs 用一段模块级注释把这条策略写成不变量:
失败签名尝试返回结构化错误;处理器返回 5xx 并记录事件。我们绝不把未签名请求转发给 Bedrock。 body 字节在压缩之后被哈希。签名输入包含的
&[u8]就是转发器将要发送的精确字节切片;不存在"哈希压缩前 body"的单独代码路径。
sign_request 的核心实现细节:
- 服务名固定为
bedrock(BEDROCK_SERVICE_NAME),用于 SigV4 string-to-sign。 - 通过
PayloadChecksumKind::XAmzSha256强制把x-amz-content-sha256纳入规范化请求。源码解释原因:若用 crate 默认的NoHeader,签名器会跳过该头,任何真正检查该头的下游网关都会 403。 - 用
aws-sigv4的SignableRequest::new(method, url, extra_signed_headers, SignableBody::Bytes(body))构造签名输入,body必须恰好是即将发送的字节(压缩后)。 - 签名器固定输出
authorization、x-amz-date、x-amz-content-sha256三个头,调用方还需把extra_signed_headers(如content-type、accept)一起纳入签名列表。 - 每次签名成功都会发出
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.rs 的 handle_invoke 完整实现了文档描述的 6 步管线:
- 从路径提取
{model_id}(Bedrock 约定形如anthropic.claude-3-haiku-20240307-v1:0)。 - 若厂商是
anthropic,把 body 当作 Bedrock 信封解析,并对 body 字节跑 live-zone Anthropic 压缩调度器——这个调度器与/v1/messages用的是同一个,Bedrock 的 body 只是"没有model字段的 Anthropic"。 - 重新发出(可能被压缩的)body,保证
anthropic_version是第一个键。 - 构造上游 URL:
https://bedrock-runtime.{region}.amazonaws.com/model/{model}/invoke,或运维覆盖端点。 - 用 AWS SigV4 对(压缩后的)body 字节签名;签名头覆盖
host、x-amz-date、x-amz-content-sha256以及额外头(content-type、accept)。 - 转发到 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, ®ion, 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 }、HeaderNameNotUtf8、HeaderValueNotUtf8、UnsupportedHeaderType { value_type, offset }:头解析的逐点失败。
CrcValidation 枚举(默认 Yes)与 --bedrock-validate-eventstream-crc=false 调试 flag 联动,运维可在排查时关闭 CRC 校验——但源码明确注释"生产必须校验"。
3.3 EventStream → SSE 翻译与客户端选择
文档要求 D2 新增 eventstream_to_sse.rs:对 Anthropic 形状的 Bedrock 响应,每个 :event-type 为 chunk 的 EventStreamMessage,其 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_correctly、eventstream_translated_to_sse、usage_extracted_from_translated_stream、client_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 的实现要点:
- 抽象而非直连:
TokenSourcetrait 只有两个显式实现——生产GcpAdcTokenSource与测试StaticTokenSource。源码注释解释理由:测试绝不能真打 GCP("无静默回退"项目规则),必须有一个显式且与生产区分的 mock;gcp_auth每次调用都取 token,缓存 + 过期前刷新的策略放在这一层,使其独立可测可调。 - 刷新策略:令牌剩余寿命低于
REFRESH_AHEAD_SECS(60 秒)时刷新,避免"请求恰好在过期时发出、与上游时钟竞争"的悬崖失败;60 秒足以覆盖慢上游与钟漂。gcp_auth内部虽缓存,但仍要包一层以控制刷新前窗口(gcp_auth的内部默认是实现定义、可能变动的)并每次刷新发出event = "vertex_adc_token_refreshed"结构化日志。 - 默认 scope:
https://www.googleapis.com/auth/cloud-platform(gcloud为 ADC 默认输出的最宽 scope)。 - 懒加载 provider:
GcpAdcTokenSource::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.rs 的 forward_vertex_request 同时被 :rawPredict 与 :streamRawPredict 复用,管线步骤与注释一一对应:
- 缓冲 body:受
compression_max_body_bytes限制,超限返回 413(event = "vertex_body_too_large"); - 信封解析:确认
anthropic_version存在、model不存在;不匹配返回 400(event = "vertex_envelope_invalid"); - 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 分类不适用),跳过 E3cache_control自动放置; - ADC bearer token:解析(缓存、过期前刷新)并附
Authorization: Bearer <token>。ADC 失败 → 502,绝不静默未鉴权转发; - 转发到配置好的 Vertex 端点(
https://{region}-aiplatform.googleapis.com/<path>); - 流式回写响应 body 不变。流式 SSE 字节原样回客户端。
VertexCallContext 载体结构从 URL 路径中解析出 project、location、model_id、verb,日志与错误路径共用一致字段。
5.4 D4 的验收与回滚
验收:测试通过;真实 Vertex 端点手动测试成功。阻塞 H2。回滚:git revert,Vertex 请求回落 LiteLLM Python。测试矩阵(crates/headroom-proxy/tests/integration_vertex_raw_predict.rs):native_envelope_round_trip_byte_equal、adc_bearer_token_signed_correctly、thinking_block_preserved、stream_raw_predict_sse_handled。
六、把 4 个 PR 串起来:字节保真、无静默回退与 auth-mode 统一
从源码结构看,Phase D 的四个 PR 共享三条贯穿始终的工程不变量,这也是理解整个阶段设计的关键:
- 字节保真契约(I1):压缩器
NoChange→ 原字节透传,从不重新序列化;Modified→ 借助preserve_order保键序,ensure_anthropic_version_first作为防御性断言。这条契约让"未修改字节字节相等回环"成为可测试的性质,D1/D4 的集成测试都以..._byte_equal命名。 - 无静默回退:SigV4 失败、ADC 失败、信封解析失败、EventStream CRC 不匹配——每一种失败都转为结构化 5xx + 明确
event日志,绝不转发未签名请求、绝不静默用零值填充、绝不把解析失败吞掉。EventStream 解析器"永远返回Result"、TokenSource"无 blanket impl"、GcpAdcTokenSource用Mutex<Option>而非OnceCell以便失败重试,都是这条规则的体现。 - auth-mode 统一为 OAuth:Bedrock(IAM 签名)与 Vertex(GCP ADC bearer)都不是 PAYG 通道,因此压缩器在两条路径上都硬编码
AuthMode::OAuth,跳过 E3cache_control自动放置,保证字节契约稳定,而 live-zone 压缩照常运行。auth-mode 分类由中间件(PR-F1 + D3)统一完成,处理器只提取、不重新分类,避免漂移。
七、如何在仓库中继续深入
- 信封与键序:crates/headroom-proxy/src/bedrock/envelope.rs(
BedrockEnvelope::parse、ensure_anthropic_version_first) - SigV4 签名:crates/headroom-proxy/src/bedrock/sigv4.rs(
sign_request、SigningInputs、PayloadChecksumKind::XAmzSha256) - 非流式 Invoke 处理器:crates/headroom-proxy/src/bedrock/invoke.rs(
handle_invoke、run_anthropic_compression、build_bedrock_upstream、LatencyGuard) - EventStream 增量解析:crates/headroom-proxy/src/bedrock/eventstream.rs(
EventStreamParser、ParseError、CrcValidation、帧布局注释) - EventStream → SSE:crates/headroom-proxy/src/bedrock/eventstream_to_sse.rs 与 crates/headroom-proxy/src/bedrock/invoke_streaming.rs
- Vertex ADC token 源:crates/headroom-proxy/src/vertex/adc.rs(
TokenSource、GcpAdcTokenSource、REFRESH_AHEAD_SECS) - Vertex rawPredict / streamRawPredict:crates/headroom-proxy/src/vertex/raw_predict.rs、crates/headroom-proxy/src/vertex/stream_raw_predict.rs、crates/headroom-proxy/src/vertex/envelope.rs
- Bedrock auth-mode 中间件:crates/headroom-proxy/src/bedrock/auth_mode_layer.rs
- Prometheus 指标:crates/headroom-proxy/src/observability/prometheus.rs(
record_bedrock_invoke、observe_bedrock_invoke_latency、record_bedrock_eventstream_message) - 配置项:crates/headroom-proxy/src/config.rs(
bedrock_region、bedrock_endpoint、aws_profile、bedrock_validate_eventstream_crc、enable_bedrock_native、vertex_region) - 集成测试:crates/headroom-proxy/tests/integration_bedrock_invoke.rs、crates/headroom-proxy/tests/integration_bedrock_streaming.rs、crates/headroom-proxy/tests/integration_bedrock_authmode.rs、crates/headroom-proxy/tests/integration_vertex_raw_predict.rs
- 阶段规划原文:REALIGNMENT/06-phase-D-bedrock-vertex.md
八、适用范围与前提
- 以上实现均对应当前仓库中已落地的 Rust 代理代码;Phase D 的 4 个 PR 在文档中规划为 HIGH/LOW 风险、合计约 +4300 LOC,当前代码已包含 D1–D4 对应的全部源文件与集成测试。
- Bedrock 路径要求配置 AWS 凭证(
--bedrock-region+ 默认凭证链或--aws-profile);未配置时非流式 invoke 会以 500bedrock_credentials_missing拒绝转发,而不是透传。 - Vertex 路径要求可解析的 GCP ADC(gcloud 登录、
GOOGLE_APPLICATION_CREDENTIALS或 metadata server);解析失败返回 502vertex_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 可观测性,以及每条失败路径的结构化错误与"无静默回退"边界。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00