OpenAI 接口协议是普通话,其他大模型是方言,Java 视角拆字段与流式调用

简介: OpenAI 接口协议是大模型世界的普通话,国内模型多是方言。用 Java 视角讲清关键字段、流式调用与 Anthropic Messages API 差异。

大家好,我是晚安code。

一、为什么说它是"普通话"

OpenAI 接口协议不是某家厂商写进标准文档的规范,它是被生态"投"出来的事实标准。

OpenAI 接口协议(OpenAI API Protocol):以 POST /v1/chat/completions 为核心的一组请求/响应约定。请求体按它的字段名发,服务端就按它的结构回。你可以理解成"跟模型说话用的普通话"——不是官方钦定的,是大家都这么说,说的人多了就成了标准。

最有意思的地方在于,国内几乎每家都开了"兼容模式"。

厂商 兼容端点 base_url 认证方式
OpenAI https://api.openai.com/v1 Authorization: Bearer
DeepSeek https://api.deepseek.com/v1 同上
智谱 GLM https://open.bigmodel.cn/api/paas/v4 同上
Kimi https://api.moonshot.cn/v1 同上
通义千问 https://dashscope.aliyuncs.com/compatible-mode/v1 同上

(2026 年 10 月核对,各家地址可能调整,用之前建议再扫一眼官方文档。)

注意通义千问那行的路径里带着 compatible-mode 四个字——这就是明牌告诉你:我们说的是方言,但给你配了个翻译。

对 Java 开发者来说,这件事的现实收益很直接:你不用为每家模型写一套 SDK。一个 OpenAI 风格的客户端,改 base_url 和 model 就能横着走。

左边是各说各话,右边是统一接口——协议的价值不在谁写得优雅,在于插头能对上孔。

二、一条请求里到底装了什么

真正需要背下来的字段不超过八个,剩下的都是调优。

先看最小可用的一条请求,别看文档,看这个就够了:

{
   
  "model": "deepseek-chat",
  "messages": [
    {
   "role": "system", "content": "你是严谨的 Java 助手"},
    {
   "role": "user", "content": "HashMap 扩容为什么是 2 倍"}
  ],
  "temperature": 0.3,
  "stream": false
}

Java 侧用 OpenAI 官方出的 openai-java,写法是把这些字段装进一个 builder:

// 非流式:一次拿全量
ChatCompletionCreateParams params = ChatCompletionCreateParams.builder()
        .model("deepseek-chat")
        .addSystemMessage("你是严谨的 Java 助手")
        .addUserMessage("HashMap 扩容为什么是 2 倍")
        .temperature(0.3)
        .build();

ChatCompletion res = client.chat().completions().create(params);
String text = res.choices().get(0).message().content().orElse("");

params 那个对象,就是你跟协议打交道的地方。字段看着几十个,日常真正常用的就这几个:

字段 作用 我的建议
model 指定用哪个模型 必填,别名写错直接 404
messages 对话历史 必填,接口无状态,每次带全
temperature 0~2 的随机性 写代码给 0.2~0.3,别用默认
max_tokens 输出长度上限 别抠,给够;不够会被截断
stream 流式开关 见下一节,这是重点
tools 工具/函数定义 Agent 场景必用
response_format 强制 JSON 输出 要解析结构化结果时开
seed 复现种子 只是"尽力",别指望完全一致

往下再挖一层,messages 里每条消息都带一个 role,四种:

  • system:人设和规则,放数组第一条;
  • user:用户说的话;
  • assistant:模型上一轮的回答,多轮对话时回填;
  • tool:工具执行的结果,配合 tools 用。

有个坑要先说:这个接口是无状态的。它不记得你上一句说了啥,所谓"多轮对话"是你自己把历史消息一条条塞回 messages 数组。上下文越长,token 越贵——这不是模型贵,是你每次都在重发。

可能有人会问:max_tokens 到底填多少才合适?

看你要它输出多长。写一段代码注释,512 够用;让它生成一个完整类,给 4096;做长文总结,直接拉满。填小了最典型的症状是回答说到一半硬生生断掉,finish_reason 会告诉你是 length 而不是 stop——看到这个值就该调大了。

三、流式和非流式,Java 里差在哪

流式调用不是让总耗时变短,而是让用户更早看到第一个字。

SSE(Server-Sent Events,服务端事件推送):一种基于 HTTP 的单向流式传输格式,服务端可以持续往同一个响应里"推"文本行。大模型的逐字输出用的就是它。

非流式的逻辑特别简单:请求发出去,服务端在那边憋着,把整段话生成完,一次性把 JSON 甩给你。中间那几秒到几十秒,你的 Java 线程就是在等。

流式就热闹了。stream: true 之后,服务端回的不是一个大 JSON,而是一串以 data: 开头的行:

data: {"object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}

data: {"object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"因为"},"finish_reason":null}]}

data: {"object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

data: [DONE]

关键差别只有一个:非流式读 choices[0].message,流式读 choices[0].delta。最后收到一个带 finish_reason 的块,再收到 data: [DONE],流就结束了。

Java 侧接流式,官方 SDK 已经把 SSE 解析包好了:

// 流式:逐块吐字
StreamResponse<ChatCompletionChunk> stream =
        client.chat().completions().createStreaming(params);

stream.stream()
      .flatMap(chunk -> chunk.choices().stream())
      .map(choice -> choice.delta().content())
      .flatMap(Optional::stream)
      .forEach(System.out::print);

如果你还想在流结束之后拿到那个"完整的" ChatCompletion 对象(比如要读最终的 usage),SDK 提供累加器:

ChatCompletionAccumulator acc = ChatCompletionAccumulator.create();
stream.stream().forEach(acc::accumulate);
ChatCompletion full = acc.chatCompletion();

顺手提一句:流式模式下 usage 字段默认可能不返回。要统计 token 消耗,请求里得显式加 stream_options: {"include_usage": true},服务端会在 [DONE] 之前额外补一个只带用量的块。这个细节我第一次踩的时候排查了挺久。

下面这张图把两种模式的往返过程放在一起看:

OpenAI 接口协议流式与非流式调用的请求时序对比

那到底该选哪个?我的判断标准是"用户能不能等"。

场景 选哪个 理由
后台批处理、定时任务 非流式 代码简单,异常处理干净
网页/App 对话 流式 首字 1 秒内出现,体感完全不同
长文生成、报告 流式 顺便规避 HTTP 超时
要严格 JSON 结构 非流式 整段好校验,增量拼 JSON 很痛苦

说真的,第 2 行的差别大到什么程度:同一个模型、同样的回复,非流式转 8 秒圈圈用户会以为卡了,流式一秒开始吐字用户觉得"挺快"。总耗时可能一样,甚至流式更长一点点,但没人会去掐表。

四、方言登场:Anthropic Messages API

所谓兼容,大多数只兼容到你的 demo 跑通为止。

Anthropic Messages API:Claude 的原生接口协议,端点是 POST /v1/messages。它和 OpenAI 的字段语义高度接近,但位置、必填性、读取路径都不一样,可以理解成"同一门语言的另一套方言"——能听懂,但你不能按普通话的语法说。

一条最简请求长这样:

{
   
  "model": "claude-sonnet-5",
  "max_tokens": 1024,
  "system": "你是严谨的 Java 助手",
  "messages": [{
   "role": "user", "content": "HashMap 扩容为什么是 2 倍"}],
  "stream": true
}

看出来了吗?system 不在 messages 里,它是顶层一个独立字段。这是最容易踩的一个差异。

其余的差异我列成一张表,接 Claude 之前扫一眼:

维度 OpenAI 接口协议 Anthropic Messages API
端点 /v1/chat/completions /v1/messages
认证 Authorization: Bearer x-api-key + anthropic-version
system 提示 messages 里的一条 顶层独立 system 字段
max_tokens 可选 必填
读取结果 choices[0].message.content content[] 数组,按 type 挑块
结束原因 finish_reason stop_reason
用量字段 usage.prompt_tokens / completion_tokens usage.input_tokens / output_tokens

头部的两个差异得单独拎出来说。第一,认证头不叫 Authorization,叫 x-api-key;第二,它有个必须带的 anthropic-version 头(当前值是 2023-06-01),少一个直接 400。写过 HTTP 客户端的人可能觉得这没什么,但你如果用的是"OpenAI 兼容"的通用客户端,它压根不会帮你加这个头。

流式返回的结构也完全不同。它不是统一的 delta.content,而是一串有名字的事件,顺序大致是:

message_start → 若干组(content_block_start → content_block_delta → content_block_stop)→ message_delta → message_stop。

中间那个 content_block_delta 里还有细分:文本是 text_delta,工具参数是 input_json_delta,思考过程是 thinking_delta。你不能粗暴地按"第 0 个块就是文本"来取值,得先看 type。

下面这张图把两套协议里最容易混淆的四组字段一一对上,接新模型前扫一眼能少查半天文档:

OpenAI 接口协议与 Anthropic Messages API 字段对应关系对比

可能有人会问:既然都说"兼容 OpenAI",为什么换个模型还是报错?

因为兼容的通常只是最基础的文本对话部分。一旦用到工具调用、结构化输出、多模态、stream_options 这些进阶字段,各家实现就开始分叉了。典型的一个:DeepSeek、Qwen 在流式工具调用里每块都会重发完整的工具调用 ID,而 LangChain4j 默认是按块累积 ID 的——这时候得把 accumulateToolCallId 显式设成 false,不设的话你会拿到一串被拼起来的、根本对不上的 ID。

厂商承诺的"兼容",通常只覆盖露出水面的那一小块。

五、Java 落地时的三个真坑

Java 侧对接大模型,九成的报错不是模型的问题,是 base_url 的问题。

第一,/v1 到底加不加。 有些客户端要求你填的 base_url 以 /v1 结尾,有些会自动帮你拼 /chat/completions。如果你填了完整路径又碰上会自动拼的客户端,最后发出去的就是 .../v1/chat/completions/chat/completions,返回 404 还不告诉你为什么。我的习惯是:只填到版本号那一层,https://api.deepseek.com/v1,后面交给客户端。

第二,max_tokens 和 max_completion_tokens。 新版 OpenAI 模型在推 max_completion_tokens,老参数在部分模型上已经不认了;而国内兼容端大多还在用 max_tokens。这两个不是完全等价——切模型的时候如果报"未知参数",先想想是不是这里。

第三,流式接口在 Spring 里要单独配。 如果你用 Spring AI 的 ChatClient,返回类型得是 Flux,而且响应体的 content type 要声明成事件流,不然前端接不到:

@GetMapping(value = "/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> chat(@RequestParam String q) {
   
    return chatClient.prompt().user(q).stream().content();
}

少写 produces 那行,浏览器侧就是一直 pending 到超时,日志里干干净净什么都不报。

六、收个尾

学一套协议对付十家模型,这是 OpenAI 接口协议带来的最大红利;但它给你的只是"能通",不是"全通"。

以 2026 年 10 月这个时间点看,我的实际做法是:主链路统一走 OpenAI 风格的接口,用 base_url + model 两个变量切换;只有确实需要 Claude 那些原生能力——比如思考块、服务端工具——才单独走 Messages API,并且老老实实按它的规矩写一套客户端。

别指望"兼容"两个字能替你做所有事。真正的兼容层是你自己写的那层适配代码,不是厂商文档里的一句承诺。


参考链接


我是晚安code,持续分享编程干货。觉得有用的话记得点赞收藏和关注~也欢迎在评论区聊聊:你项目里是直接照着 OpenAI 接口协议写,还是被哪家方言坑过?

目录
相关文章
|
15天前
|
弹性计算 人工智能 数据库
阿里云优惠活动大全:阿里云活动怎么参与?新客户云产品特惠推荐
初次接触上云的个人开发者、初创团队,最关心的就是如何用更低成本获取云资源。阿里云优惠活动包含新客户首购特价、免费试用资源、代金券、算力补贴等多种福利,覆盖 阿里云轻量应用服务器、阿里云ECS云服务器、阿里云GPU云服务器、阿里云大模型服务平台 、数据库、对象存储、AI大模型服务等产品,大幅降低新手入门门槛。本文完整梳理活动参与方法、新客户特惠产品清单,搭配命令行实操示例,同时整理选购避坑要点,帮助大家顺利领取优惠,挑选匹配自身业务的云产品。
116 3
|
2月前
|
人工智能 安全 调度
DeepSeek Harness,为什么国内海外的评价两极分化?
老金来给你讲讲DeepSeek Harness到底是什么,应该怎么看带他。
|
3月前
|
人工智能 缓存 监控
【新版】阿里云 百炼 Token Plan 功能介绍及配置价格表
阿里云百炼Token Plan是面向个人开发者与企业团队推出的AI大模型订阅服务,以Credits为统一计量单位,实现多模型、多工具、多场景的统一调用与计费管理。新版Token Plan全面升级个人版与团队版能力,覆盖文本生成、图像生成、视频生成等多模态能力,兼容主流AI编程与智能体工具,提供灵活档位套餐与企业级管理功能,实现包月预算可控、多用户隔离、高峰不降速的稳定服务。本文将系统梳理Token Plan的核心功能、个人版与团队版配置、Credits计费规则、套餐价格明细、开通订阅流程、代码调用示例、团队管理与成本控制方案,帮助用户全面了解并高效使用Token Plan服务。
738 4
|
23天前
|
缓存 算法 Oracle
JVM 垃圾回收全流程拆解:可达性分析、四种算法与五种收集器选型
JVM 垃圾回收到底管哪块内存?本文从可达性分析与四种引用讲起,拆解四大收集算法,对比五种收集器,并讲清 CMS 工作流程与内存泄漏排查思路。
102 1
JVM 垃圾回收全流程拆解:可达性分析、四种算法与五种收集器选型
|
21天前
|
人工智能 安全
装修公司老板裁光员工利润反涨30%:装修设计行业OPC案例深度拆解
本文是「OPC一人公司通关手册」第23篇,深度拆解一位装修设计师转型AI驱动一人公司的实战案例:十年经验者裁掉7名员工,专注纯设计,借AI实现获客、谈单、交付、沉淀全链路提效——效率↑40%,利润↑20%-30%,早九晚六轻松运转。核心不在AI,而在狠砍施工、材料、售后三座成本大山,重构轻资产盈利结构。(239字)
|
21天前
|
定位技术 Python
0.8MB 跑通 Qwen|第 3-2 篇:推理引擎的字节序与十六进制纪律——一个字节序错误,引擎当场翻脸
本文以RK3588真机实测为基础,深入剖析字节序陷阱:揭示VQF格式中小端落盘导致魔数“VQFW”在磁盘呈现为“FQFW”,并用篡改version字段的实验直观展示——小端机器误读大端数据会直接拒载(报错33554432≠2)。强调“先问字节序,再读数字”的十六进制读法铁律。(239字)
102 1
0.8MB 跑通 Qwen|第 3-2 篇:推理引擎的字节序与十六进制纪律——一个字节序错误,引擎当场翻脸
|
23天前
|
缓存 安全 Java
JVM 类加载机制详解:双亲委派模型的原理、优势与三种打破方式
JVM 类加载机制到底怎么走?本文从生命周期七阶段讲起,把双亲委派模型的原理、优势与三种打破方式讲透,再补一张类初始化时机的主动 / 被动引用对照表。
114 4
JVM 类加载机制详解:双亲委派模型的原理、优势与三种打破方式
|
22天前
|
人工智能 文字识别 算法
浏览器本地 AI 视频去水印实践:从矩形补丁到笔画级修复
Timeline Studio 开源视频编辑器基于 MI-GAN 与 WebGPU 实现浏览器端本地去水印,无需上传素材。创新采用笔画级遮罩、局部泊松融合与保守跨帧辅助,精准保留皮肤、阴影等真实细节,显著改善矩形色块与帧间不一致问题。欢迎体验或贡献代码!
|
24天前
|
弹性计算 缓存 运维
阿里云上跑 dsh-free-search 的四条收敛实践
dsh-free-search 是阿里云ECS上轻量部署的多引擎搜索插件,支持Bing等免费引擎及百度、豆包等额度型引擎,通过引擎分层、出网收敛、凭据集中与数据边界管控,实现低成本、高可控的长期稳定运行。(239字)
146 2

热门文章

最新文章