Skip to content

简介 ​

本章节主要介绍 java-openai(GitHub:litongjava/java-openai)库的核心能力、目录结构与统一调用方式,并展示如何将第三方大模型 API(OpenAI / Google / Anthropic / OpenRouter 等)以一致的请求与响应模型接入业务系统。

java-openai 的设计目标不是“只对接某一家模型厂商”,而是提供一套统一的抽象层:

  • 业务侧只需要组装 UniChatRequest
  • 统一通过 UniChatClient 发起调用
  • 得到统一结构的 UniChatResponse
  • 底层根据平台与模型自动完成协议转换与返回结构归一化
  • 同时支持非流式与流式文本输出,便于在 Web、SSE、WebSocket 等场景使用

快速入门 ​

1. 添加依赖 ​

xml
<dependency>
  <groupId>nexus.io</groupId>
  <artifactId>java-openai</artifactId>
  <version>1.3.9</version>
</dependency>

2. 最小可运行示例 ​

在项目依赖管理中统一定义 java-openai.version,使用与当前工程兼容的依赖。

下面示例使用 DeepSeek 平台,通过统一接口请求并返回内容。先在服务端配置 DEEPSEEK_API_KEY;可通过 DEEPSEEK_MODEL 指定账户可用的模型。密钥不要写入浏览器、小程序或示例源码。

java
package nexus.io.tio.web.hello.handler;

import java.util.ArrayList;
import java.util.List;

import nexus.io.chat.PlatformInput;
import nexus.io.chat.UniChatClient;
import nexus.io.chat.UniChatMessage;
import nexus.io.chat.UniChatRequest;
import nexus.io.chat.UniChatResponse;
import nexus.io.consts.ModelPlatformName;
import nexus.io.tio.utils.environment.EnvUtils;
import nexus.io.tio.boot.http.TioRequestContext;
import nexus.io.tio.http.common.HttpRequest;
import nexus.io.tio.http.common.HttpResponse;
import nexus.io.tio.http.server.handler.HttpRequestHandler;

public class PredictHandler implements HttpRequestHandler {

  @Override
  public HttpResponse handle(HttpRequest httpRequest) throws Exception {
    PlatformInput platform = new PlatformInput(
        ModelPlatformName.DEEPSEEK,
        EnvUtils.get("DEEPSEEK_MODEL", "deepseek-flash")
    );

    List<UniChatMessage> messges = new ArrayList<>();
    messges.add(UniChatMessage.buildUser("just say hi"));

    UniChatRequest uniChatRequest = new UniChatRequest(platform);
    uniChatRequest.setApiKey(EnvUtils.get("DEEPSEEK_API_KEY"));
    uniChatRequest.setMessages(messges);

    UniChatResponse uniChatResponse = UniChatClient.generate(uniChatRequest);

    String content = uniChatResponse.getMessage().getContent();

    HttpResponse response = TioRequestContext.getResponse();
    return response.setBody(content);
  }
}

调用:

bash
curl http://localhost/predict

可能输出:

text
Hi! How can I help you today?

服务端应在加载配置后再初始化模型客户端。UniChatClient 的默认平台密钥和 API 地址在类初始化时读取;上面的示例通过请求显式设置 Key,避免依赖隐式默认值。模型可用性以 DeepSeek 官方文档 为准。

业务使用 JSON 输出时,可设置 uniChatRequest.setResponseFormat("json_object"),并在提示词中明确要求 JSON、给出字段示例。JSON 输出不等于业务字段已校验,还需检查空结果、字段类型和长度。需要识别截断时,应检查原始 Chat Completions 响应的 choices[0].finish_reason,不能仅凭 JSON 能解析就视为成功。

OpenAiClient 的同步请求实现使用共享 HTTP 客户端。网页交互需要独立的总超时限制时,应显式设置请求截止时间,并让前端等待时间略长于后端;不要仅延长前端等待而忽略上游连接占用。第三方错误响应不要直接暴露给用户。


工程目录结构与模块说明 ​

java-openai 按“平台/能力域”组织代码,每个目录大体代表一个厂商平台、一个能力模块或一个业务通用层。给出的目录如下(节选说明):

  • chat统一聊天抽象层所在位置。通常包含:

    • UniChatRequest / UniChatResponse 等统一 DTO
    • UniChatClient 统一入口
    • 消息结构、流式 delta、usage 归一化等
  • openai / claude / gemini / google 对应不同厂商协议与实现细节:

    • OpenAI 风格的 Chat/Responses
    • Anthropic/Claude 风格的 messages / content blocks
    • Google/Gemini 风格的 contents / parts 这些模块对上层隐藏协议差异,供 UniChatClient 做自动转换与路由。
  • openrouter / groq / deepseek / moonshot / minimax / tencent / volcengine / byteplus / siliconflow / cerebras … 代表不同聚合平台或模型服务商的适配层,通常包含:

    • 模型常量(如 xxxModels)
    • API 地址与鉴权适配
    • 请求/响应结构映射
  • consts / exception / utils / vo / model 基础设施与通用能力:

    • 常量与枚举(平台名、模型名等)
    • 异常封装与错误处理
    • 工具类(序列化、HTTP、签名、字符串等)
    • 通用 VO 与数据模型
  • image / tts / fishaudio / textin 多模态或特定能力域扩展:图像生成、语音合成、音频能力、OCR/文档等。

  • search / searchapi / searxng / tavily / supadata 与搜索/数据检索相关的能力与第三方服务整合,常用于:

    • 开启检索增强(RAG)
    • 外部搜索工具调用
    • 结果引用(citations)等
  • proxy / linux / libreoffice 偏工程化、运行环境与系统工具集成的模块:

    • 代理与网络访问
    • 服务器环境工具封装
    • 文档转换等
  • prompt Prompt 模板与提示词组织方式,通常用于统一系统提示词、模板复用与版本管理。

  • mcp 一般用于“工具协议/工具调用”的扩展模块(若这里指的是 Model Context Protocol 或类似思想),用来把外部能力以统一方式暴露给模型或业务。

整体上可以理解为两层:

  1. 业务统一层:chat(统一输入输出、统一调用方式)
  2. 平台适配层:openai/claude/gemini/openrouter/...(负责协议差异与细节)

UniChatRequest:统一请求结构 ​

UniChatRequest 是业务侧与 UniChatClient 之间的统一契约。可以把它当作“跨平台 Chat 请求 DTO”。

给出的字段如下(节选):

java
public class UniChatRequest {
  private String domain;
  private String apiPrefixUrl;
  private Long groupId;
  private String groupName;
  private Long taskId;
  private String taskName;

  private boolean useSystemPrompt = true;
  private String apiKey;
  private String platform;
  private String model;
  private String systemPrompt;
  private boolean cacheSystemPrompt;
  private Boolean stream;
  private List<UniChatMessage> messages;
  private Float temperature;
  private String cachedId;
  private Integer max_tokens;
  private Boolean enable_thinking;
  private UniThinkingConfig thinkingConfig;
  private String responseFormat;
  private UniResponseSchema responseSchema;
  private ChatProvider provider;
  private List<String> responseModalities;
  private Boolean enable_search;
  private List<ChatRequestTool> tools;
}

1. 业务标识字段(不会发送给大模型) ​

以下字段仅用于业务表达与链路追踪,不会进入最终发给模型的 payload:

  • domain
  • groupId
  • groupName
  • taskId
  • taskName

典型用途包括:

  • 多租户/多业务域隔离:按 domain 做配置路由或日志分桶
  • 分组维度统计:按 groupId/groupName 汇总调用量、成本、成功率
  • 任务维度管理:按 taskId/taskName 关联某条业务流程(比如“客服质检”“合同摘要”“代码审查”)
  • 日志与审计:在不污染模型上下文的前提下,保留业务语义

2. 平台与鉴权 ​

  • platform:平台标识(如 OpenAI / Google / Anthropic / OpenRouter 等)
  • model:模型名或模型常量
  • apiKey:平台 API Key
  • apiPrefixUrl:可选,自定义 API 前缀(私有化网关、代理、内网镜像等)
  • provider:可选,某些平台下用于进一步指定提供方(例如聚合平台路由到具体供应商)

3. Prompt 与消息 ​

  • useSystemPrompt:是否启用系统提示词
  • systemPrompt:系统提示词内容
  • cacheSystemPrompt:是否缓存系统提示词(用于减少重复传输或复用同一系统提示词配置)
  • messages:对话消息列表(UniChatMessage),业务侧统一用它来表达 user/assistant/system/tool 等角色内容

对于只想发送一条或几条用户消息的简单场景,可以直接使用快捷方法:

java
UniChatRequest request = new UniChatRequest(platformInput);
request.setUserPrompts("how are you?");

setUserPrompts(String...) 会将每个非空字符串包装为一条 user 角色的 UniChatMessage,免去手工构造 messages 列表。

4. 生成参数 ​

  • temperature:随机性/发散程度
  • max_tokens:最大输出 token 限制(不同平台命名不同,此处归一)
  • responseFormat:响应格式类型(例如 text/json 等,按内部枚举 ChatResponseFormatType 组织)
  • responseSchema:当需要结构化输出时,可提供 schema(用于 JSON Schema 或类似约束)

5. 思考与推理控制(可选) ​

  • enable_thinking
  • thinkingConfig

用于对接支持“思考/推理配置”的平台或模型能力。即便底层不同平台字段不同,上层也仍然用统一开关与配置表达意图。

6. 流式与多模态/搜索(可选) ​

  • stream:是否流式输出 为 true 时,期望底层以 SSE/Chunked 等方式输出增量内容,并映射到统一的 delta 结构。

  • responseModalities:期望的输出模态(例如仅文本,或文本+其他)

  • enable_search:是否开启搜索能力(对接支持检索增强的供应商或的 search/* 模块)

7. 缓存/复用(可选) ​

  • cachedId:用于复用某次缓存结果或上下文(具体语义由的实现定义,比如命中缓存直接返回、或复用某个会话上下文)

8. 工具/函数调用(可选) ​

  • tools:List<ChatRequestTool>,统一描述可供模型调用的工具/函数定义。 业务侧只需要按统一结构声明工具,底层适配层会根据目标平台(OpenAI / Claude / Gemini 等)转换为对应协议中的 tools / functions / tool_config 等字段。

配合 UniChatMessage 的工具消息构造方法,可以表达完整的多轮工具调用上下文:

  • UniChatMessage.buildAssistantWithToolCalls(List<ToolCall>) 模型在某轮发起的工具调用(assistant 消息携带 tool_calls)。

  • UniChatMessage.buildTool(toolCallId, name, content) 工具执行结果回填到对话上下文(tool 角色消息)。


UniChatResponse:统一响应结构 ​

UniChatResponse 是 UniChatClient 的统一输出,屏蔽不同平台返回字段差异。

给出的结构:

java
public class UniChatResponse {
  private transient String rawData;
  private String model;
  private ChatResponseMessage message;
  private ChatResponseDelta delta;
  private ChatResponseUsage usage;
  private List<String> citations;
}

逐字段说明:

  • rawData(transient) 原始响应字符串或原始数据快照,用于:

    • 调试与问题定位(查看平台原始返回)
    • 线上故障回溯(但一般不参与序列化持久化)
  • model 实际响应所使用的模型(部分平台可能会返回最终命中的模型名)

  • message 归一后的“完整消息结果”。非流式场景通常读取:

    • uniChatResponse.getMessage().getContent()
  • delta 用于流式场景的增量内容承载(一次 chunk/一次增量)。 在 SSE/WebSocket 场景中,通常会不断拿到 delta 并拼接成完整文本。

  • usage token 使用情况(输入/输出/总计等),用于成本统计、限额控制、计费等。

  • citations 引用列表,常见于:

    • 带搜索或检索增强的返回(RAG)
    • 平台返回引用链接/来源片段 业务可以直接展示“参考来源”,或用于审计与可追溯性。

UniChatClient:统一入口与协议自动转换 ​

UniChatClient 的核心价值是:业务只关心统一 DTO,不需要分别学习 OpenAI/Google/Anthropic 的协议细节。

它的行为可以概括为:

  1. 以 UniChatRequest 作为唯一输入

  2. 根据 platform + model (+ provider) 做路由

  3. 内部自动完成协议转换:

    • 将 UniChatRequest/messages/systemPrompt/... 映射为目标平台请求格式
    • 调用对应平台 API
    • 将目标平台响应映射回 UniChatResponse(message/delta/usage/citations 等统一结构)

支持的协议家族 ​

按要求,这里强调三类主协议:

  • OpenAI 协议(OpenAI 风格 Chat/Responses)
  • Google 协议(Gemini/Google 风格)
  • Anthropic 协议(Claude 风格)

无论底层字段如何变化,业务侧都以 UniChatRequest 描述意图。

当前支持的平台标识 ​

ModelPlatformName 中已经内置了大量平台常量,业务侧通过 PlatformInput(platform, model) 即可在它们之间无缝切换:

  • 三大原生协议:OPENAI / GOOGLE / ANTHROPIC
  • 谷歌云通道:VERTEX_AI
  • 国内/区域聚合或企业平台:VOLC_ENGINE、BAILIAN、TENCENT、MOONSHOT、MINIMAX、SILICONFLOW、CHAT_GLM、GITEE
  • 海外聚合平台:OPENROUTER、ZENMUX、CEREBRAS
  • 私有化/自托管推理引擎:OLLAMA、LLAMACPP、VLLM、SWIFT、TITANIUM
  • 中转/代理通道:EXCHANGE_TOKEN、EXCHANGE_TOKEN_GOOGLE、EXCHANGE_TOKEN_ANTHROPIC、EXCHANGE_TOKEN_US、EXCHANGE_TOKEN_US_GOOGLE、EXCHANGE_TOKEN_US_ANTHROPIC
  • 其他扩展:AIAPI、ELEVEN_LABS、AUTO

UniChatClient.generate(...) 与 UniChatClient.stream(...) 会根据 platform 自动路由到对应的适配实现,并自动从环境变量读取 API Key 与 API URL(例如 OPENROUTER_API_KEY / OPENROUTER_API_URL、VERTEX_AI_API_KEY / VERTEX_AI_API_URL 等),业务侧无需重复配置。

文本流式响应 ​

除普通一次性返回外,UniChatClient 也支持文本的流式输出能力。典型用途:

  • Web 前端逐字输出提升体验
  • 长文本生成时尽早得到结果
  • 降低超时风险并改善“首 token 延迟”

实现层面通常表现为:

  • uniChatRequest.setStream(true)
  • 服务端使用 SSE/Chunked/WebSocket 将 delta 持续推送给客户端
  • 业务侧使用 UniChatResponse.delta 拼接渲染,并在结束时读取 usage 等信息(具体以的实现为准)

推荐使用方式与实践建议 ​

  • 业务侧统一只依赖 chat 抽象层(UniChatRequest/Response/Client/Message),把平台差异留在 java-openai 内部。
  • 为不同业务域设置 domain/groupId/taskId 等标识,配合日志与用量统计做治理,但不要把这些字段塞进提示词。
  • 对需要“稳定结构化输出”的场景(如抽取字段、生成 JSON、生成表格数据),优先使用 responseFormat/responseSchema,减少靠 prompt 约束带来的不确定性。
  • 对交互型产品(聊天、写作助手、客服)优先考虑流式输出,显著提升体验。