日期:2026-09-11(按独立评审意见修订)。面向 Claude Code / Codex / Cline / Gemini CLI:关心的是首字延迟与流式顺滑,不是压测吞吐。
编程工具场景优先保证协议完整、计量可靠和首字 / 流式体验。先使用与客户端实际入口匹配的上游协议,减少业务不需要的外部调用,再通过统一口径的分段计时定位瓶颈。同协议请求体复用与跳过无用提取是候选优化,但收益需在真实大小请求和代表性并发下验证。响应头时间不等于客户端首字,写入耗时不能独立判定反代缓冲,tok/s 也不能单独证明转发更快。代理、重试和 fsync 按可达性、成功率与持久性要求选择,不能为跑分统一关闭或降低。
同协议 Anthropic 流式直连零延迟 mock,curl 的首个响应字节时间中位数(20 次,本机,代理变量已清除):
| 请求体 | 直连 mock | 经网关 | 网关多出 |
|---|---|---|---|
| 4 KB | 0.6 ms | 0.9 ms | 0.3 ms |
| 200 KB | 1.7 ms | 4.6 ms | 2.9 ms |
| 1 MB | 6.1 ms | 19.0 ms | 12.9 ms |
多出的部分主要是整包读入、JSON 扫描、模型名改写后的重编码和合规 / 路由用的文本提取。以真实模型首字 500 ms 到数秒计,200 KB 会话体上的 3 ms 低于 1%;1 MB 上下文约 13 ms。这是"不先改热路径"的依据;如果实际会话体普遍在 1 MB 以上,同协议直传请求体值得做,但要用这一组数据做 A/B。
| 优先级 | 做什么 | 依据 |
|---|---|---|
| 1 | 每个客户端用上游的原生协议账号:Claude Code → Anthropic 兼容入口(anthropic-messages);Codex → OpenAI(openai-responses);OpenAI 兼容工具 → openai-completions;Gemini CLI → 原生 Gemini(gemini-generate) |
同协议只改模型名(Chat 流式还会注入 stream_options)再转发;跨协议要整包转换,流式逐事件编解码,Anthropic ↔ Responses / Gemini 走两跳串联 |
| 2 | 业务不需要就保持「内容合规」关闭;coding 请求不要走虚拟模型 yz-auto |
语义审核与智能路由会调用向量服务;是否真的触发,看路由决策记录和向量调用次数,不要凭请求体大小推断 |
| 3 | 「最多尝试次数」按需设置,注意它是含首次的总次数 | 设为 1 表示失败后不切号;调整时对比成功率、重试次数和失败原因,不只看成功请求的平均耗时 |
| 4 | 出站代理按可达性实测决定;YZAPI_JOURNAL_FSYNC 沿用既定持久性要求;正文审计不需要就关 |
强制代理会给每跳加延迟,但直连是否可达要实测;fsync 不是性能开关,改它就是改丢失边界 |
| 5 | 个别供应商流式卡顿时再试 YZAPI_UPSTREAM_HTTP2=0,逐个对照 |
这是诊断开关;先确认该链路确实协商了 HTTP/2 |
| 字段 | 含义 |
|---|---|
queue_wait_ms |
等并发槽的时间;不为 0 说明在排队,先查上游慢或账号冷却,不要先加队列 |
first_byte_ms |
成功那次上游尝试的响应头到达;含排队和之前失败的尝试 |
first_content_ms |
首个真正的正文 / 思考 / 工具调用增量写向客户端;这才是用户感受的首字 |
client_write_ms |
向客户端写入被阻塞的累计时间;高了查写入路径(下游接收、网络),结合客户端事件时间线定位,不能直接归咎反代 |
| attempts | 先有超时 / 5xx 再成功,说明重试在吃首字;看具体失败类型 |
first_content_ms − first_byte_ms 大:上游在响应头之后才出字(推理模型常见),与网关无关。first_byte_ms − queue_wait_ms 明显大于直连该供应商:再看请求体大小与是否跨协议。
- 同协议、模型名已是上游名、无需注入字段时直接传
req.body;保留完整解析与授权检查。 - 合规与路由都不使用时跳过文本提取;需确认审计、路由与消息数没有其他依赖。
- 再往后才是请求体全流式转发,它牵涉鉴权、模型授权、重试、审核和内存预算,改动范围大。
- SSE 写出的临时缓冲、转换路径逐 token 编码属于微优化,排在最后。
不建议用字符串替换改 JSON,也不建议为了省一次 flush 攒 token。
gin 包装、并发槽、配额读锁、快照原子指针,相对大 body 和上游耗时可以忽略。README 的吞吐数字来自零延迟 mock 加小请求,不代表大上下文流式。MaxConcurrency 512 / 队列 1024 对几路 IDE 足够。