共计 2096 个字符,预计需要花费 6 分钟才能阅读完成。
背景痛点
在传统 HTTP 请求处理大模型 API 时,我们经常会遇到几个典型问题:

- 长文本截断:ChatGPT 的 API 有 token 限制(通常 4096 tokens),直接发送长文本会导致截断
- 流式响应解析:大模型的生成式响应可能持续 10-30 秒,传统同步请求会导致客户端超时
- 配额管理:免费账号每分钟仅有 3 次调用限额,突发流量会触发 429 错误
技术选型对比
针对不同场景的 HTTP 客户端选择建议:
- Spring WebClient(推荐)
- 响应式非阻塞 IO
- 内置重试机制
-
完美支持 SSE(Server-Sent Events)
-
Retrofit
- 接口声明式调用
- 适合固定格式的 REST API
-
需要额外配置流式解析
-
HttpURLConnection
- JDK 原生支持
- 需要手动处理连接池
- 流式读取较繁琐
核心实现
基础封装类
public class ChatGPTClient {
private final WebClient webClient;
private final Semaphore rateLimiter;
// 初始化带速率限制的客户端
public ChatGPTClient(String apiKey, int permits) {this.rateLimiter = new Semaphore(permits);
this.webClient = WebClient.builder()
.baseUrl("https://api.openai.com/v1")
.defaultHeader("Authorization", "Bearer" + apiKey)
.build();}
// 异步流式调用
public Flux<String> streamCompletion(ChatRequest request) {return webClient.post()
.uri("/chat/completions")
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(request)
.retrieve()
.bodyToFlux(String.class)
.timeout(Duration.ofSeconds(30))
.doOnSubscribe(sub -> acquirePermit());
}
private void acquirePermit() {
try {if (!rateLimiter.tryAcquire(1, TimeUnit.SECONDS)) {throw new RuntimeException("Rate limit exceeded");
}
} catch (InterruptedException e) {Thread.currentThread().interrupt();}
}
}
生产环境优化
- Token 计算优化
- 中文 1 个 token≈2 个字符
- 英文 1 个 token≈4 个字符
-
建议使用
tiktoken库精确计算 -
监控埋点示例
@Bean
public MeterBinder chatGPTPMetrics(ChatGPTClient client) {
return registry -> {
Gauge.builder("chatgpt.permits",
() -> client.availablePermits())
.register(registry);
Timer.builder("chatgpt.latency")
.publishPercentiles(0.5, 0.95)
.register(registry);
};
}
常见问题排查
403 错误触发条件
- API 密钥过期
- 终端 IP 被封锁
- 请求头缺失
Content-Type: application/json
线程安全实践
// 使用 ThreadLocal 管理对话上下文
private static final ThreadLocal<Deque<Message>> contextHolder =
ThreadLocal.withInitial(ArrayDeque::new);
public void addContext(Message message) {contextHolder.get().addLast(message);
// 防止内存泄漏
if(contextHolder.get().size() > 10) {contextHolder.get().removeFirst();}
}
进阶方向
推荐尝试 Spring AI 框架的多模型切换能力:
@Bean
public AiClient aiClient(@Value("${openai.key}") String apiKey) {return new OpenAiChatClient(apiKey);
}
// 随时切换模型
aiClient.setModel("gpt-4-turbo");
实践心得
经过三个月的生产环境验证,我们总结出几个关键经验:
- 流式响应必须设置合理的超时时间(建议 20-30 秒)
- 企业级应用建议购买预留容量(Provisioned Throughput)
- 对话历史采用滚动窗口管理最有效
- 监控面板需要重点关注 token 消耗速率
完整示例代码已开源在 GitHub(伪代码),欢迎开发者交流优化建议。
正文完
