线上 Go 服务调用 OpenAI Responses 时,最容易踩的坑不是“模型不准”,而是链路抖动:连接池不稳、超时预算乱配、重试叠加把自己打挂。
这篇给一套可落地的基线配置:HTTP/2 连接复用、分层超时、错误预算和退避重试,目标是把 5xx 与超时比例压到可控范围,并且能快速定位瓶颈。
先给结论:生产默认基线
如果你还没有一套标准配置,先用下面这组:
- 强制开启 HTTP/2(默认支持 TLS 场景)
- 全链路超时预算:
请求总超时 > 单次调用超时 > 传输超时 - 只在可重试错误上重试(429/5xx/网络瞬断)
- 重试次数 2~3 次,指数退避 + 抖动
- 用并发信号量限制每实例同时在飞请求
一、Transport:先把连接复用配对
很多“随机慢请求”其实是连接层问题。先固定一版可控 Transport:
tr := &http.Transport{
MaxIdleConns: 512,
MaxIdleConnsPerHost: 128,
MaxConnsPerHost: 256,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 5 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
ForceAttemptHTTP2: true,
}
client := &http.Client{
Transport: tr,
Timeout: 25 * time.Second, // 单次调用硬上限
}
建议从 MaxConnsPerHost=CPU核数*16 起步,按实际 p95 延迟和 QPS 再调。
二、超时预算:别把所有超时都塞进一个 Timeout
推荐三层预算:
- 请求总预算(业务层):比如 30 秒
- 单次 OpenAI 调用预算(HTTP Client):比如 25 秒
- 每次重试的剩余预算:自动按 context 截断
ctx, cancel := context.WithTimeout(parentCtx, 30*time.Second)
defer cancel()
resp, err := callOpenAIWithRetry(ctx, client, payload)
如果你把业务层和调用层都写成 30 秒,一旦有重试就必然超预算,尾延迟会很难看。
三、重试策略:只重试“值得重试”的错误
可重试:
- HTTP 429
- HTTP 500/502/503/504
context deadline exceeded(且总预算仍有剩余)- 临时网络错误(reset/timeout)
不可重试:
- 400/401/403/404
- 参数校验失败
- 明确的配额耗尽且短期不可恢复
func backoff(attempt int) time.Duration {
base := 200 * time.Millisecond
max := 2 * time.Second
d := base * time.Duration(1<<attempt)
if d > max { d = max }
jitter := time.Duration(rand.Int63n(int64(120 * time.Millisecond)))
return d + jitter
}
四、并发与熔断:防止雪崩
给每个实例一层轻量并发闸门,避免突发流量把上游和自己一起拖死:
sem := make(chan struct{}, 64) // 每实例最多 64 个在飞请求
func withLimit(fn func() error) error {
sem <- struct{}{}
defer func(){ <-sem }()
return fn()
}
再加一层简单熔断指标:
- 最近 1 分钟错误率 > 20%
- 且样本量 > 100
触发后短暂降级(比如降模型、降并发、返回兜底响应)。
五、观测面板:最少要盯这 6 个指标
openai_requests_total(按 status_code 分组)openai_request_latency_ms(p50/p95/p99)openai_retries_totalopenai_timeout_totalopenai_inflightopenai_error_budget_burn_rate
一条经验:先看 timeout_total 和 inflight,比盯单个报错字符串更快定位。
常见错误与排查路径
1) p95 延迟突然翻倍
先查:
netstat -an | grep ESTABLISHED | wc -l
lsof -iTCP -sTCP:ESTABLISHED -n -P | grep <your-service-name> | wc -l
如果连接数异常升高,优先检查 MaxConnsPerHost、重试风暴、上游限流。
2) 429 激增
排查顺序:
- 是否多个服务共享同一 API key
- 是否批量任务与在线流量抢额度
- 是否重试策略没有抖动,导致同步重试
3) deadline exceeded 占比高
优先看调用链预算是否冲突:网关 20s、服务 25s、客户端 30s 这种配置会直接制造“假超时”。
最小可行上线方案(MVP)
如果你今天就要上线,至少做这四件事:
- 固化 Transport + HTTP/2 参数
- 设置三层超时预算(30s/25s/重试剩余)
- 重试只覆盖 429/5xx/瞬断,最多 2 次
- 接 Prometheus 的 6 个核心指标
做到这一步,稳定性通常就能从“偶发雪崩”变成“可观测、可预期、可回滚”。
总结
Go 调 OpenAI Responses 的核心,不是单点参数,而是“连接复用 + 超时预算 + 错误预算”三件套。
把这三件事先做扎实,再谈更复杂的多供应商路由和成本优化,你的线上系统会省很多夜里报警。