Skip to content
LangChain4j 文档版本 1.22.0 源快照 f86582b8 更新于 2026-10-14

watsonx.ai

本集成构建于 IBM watsonx.ai Java SDK 之上。下文每个模型都包装它的某个服务。当你需要了解某个非 LangChain4j 专有行为的细节——令牌缓存、重试、HTTP 客户端调优——SDK 文档即是参考。

Maven 依赖

xml
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-watsonx</artifactId>
    <version>1.22.0-beta32</version>
</dependency>

身份认证

Watsonx.ai 支持通过 Authenticator 接口进行身份验证。

这使你可以根据部署方式使用不同的认证机制:

  • IBMCloudAuthenticator —— 使用 API 密钥向 IBM Cloud 认证。这是最简单的方式,在你提供 apiKey(...) builder 方法时使用。
  • CP4DAuthenticator —— 向 Cloud Pak for Data 部署认证。
  • 自定义认证器 —— 可使用 Authenticator 接口的任意实现。

WatsonxChatModel、WatsonxStreamingChatModel 及其他服务 builder 既接受通过 .apiKey(...) 的快捷方式,也接受通过 .authenticator(...) 的完整 Authenticator 实例。

令牌缓存与续期会被透明地处理。令牌在首次请求时获取、被缓存、并在过期前刷新,因此你从不管理它的生命周期。把同一个 Authenticator 实例传给多个模型,能让它们共享一个缓存令牌。认证器及其参数的完整列表见 SDK 认证指南。

Example

java
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.watsonx.WatsonxChatModel;
import com.ibm.watsonx.ai.core.auth.cp4d.CP4DAuthenticator;
import com.ibm.watsonx.ai.core.auth.cp4d.AuthMode;
import com.ibm.watsonx.ai.CloudRegion;

WatsonxChatModel.builder()
    .baseUrl(CloudRegion.FRANKFURT)
    .apiKey("your-api-key") // Simple IBM Cloud authentication
    .projectId("your-project-id")
    .modelName("ibm/granite-4-h-small")
    .build();

WatsonxChatModel.builder()
    .baseUrl("https://my-instance-url")
    .authenticator( // For Cloud Pak for Data deployments
        CP4DAuthenticator.builder()
            .baseUrl("https://my-instance-url")
            .username("username")
            .apiKey("api-key")
            .authMode(AuthMode.LEGACY)
            .build()
    )
    .projectId("my-project-id")
    .modelName("ibm/granite-4-h-small")
    .build();

自定义 HttpClient 与 SSL 配置

使用自定义 HttpClient

所有服务与认证器都通过 builder 模式支持自定义的 HttpClient 实例。这在 Cloud Pak for Data 环境中特别有用——你可能需要配置自定义 TLS/SSL 设置、代理配置或其他 HTTP 客户端属性。

java
HttpClient httpClient = HttpClient.newBuilder()
    .sslContext(createCustomSSLContext())
    .executor(ExecutorProvider.ioExecutor())
    .build();

EmbeddingModel embeddingModel = WatsonxEmbeddingModel.builder()
    .baseUrl("https://my-instance-url")
    .modelName("ibm/granite-embedding-278m-multilingual")
    .projectId("project-id")
    .httpClient(httpClient) // Custom HttpClient
    .authenticator(
        CP4DAuthenticator.builder()
            .baseUrl("https://my-instance-url")
            .username("username")
            .apiKey("api-key")
            .httpClient(httpClient) // Custom HttpClient
            .build()
    )
    .build();

注: 在 Cloud Pak for Data 中使用自定义 HttpClient 时,请确保同时在服务 builder 和认证器 builder 上设置它,以保证所有请求的 HTTP 行为一致。

🔗 SDK 关于 HTTP 客户端的指南,包括如何从一个私有信任库构建 SSLContext。

禁用 SSL 验证

如果你只需禁用 SSL 证书验证,可以使用 verifySsl(false) 选项,而不必提供自定义 HttpClient:

java
EmbeddingModel embeddingModel = WatsonxEmbeddingModel.builder()
    .baseUrl("https://my-instance-url")
    .modelName("ibm/granite-embedding-278m-multilingual")
    .projectId("project-id")
    .verifySsl(false) // Disable SSL verification
    .authenticator(
        CP4DAuthenticator.builder()
            .baseUrl("https://my-instance-url")
            .username("username")
            .apiKey("api-key")
            .verifySsl(false) // Disable SSL verification
            .build()
    )
    .build();

如何创建 IBM Cloud API 密钥

你可以在 https://cloud.ibm.com/iam/apikeys 点击 Create + 创建 API 密钥。

如何找到你的 Project ID

  1. 访问 https://dataplatform.cloud.ibm.com/projects/?context=wx
  2. 打开你的项目
  3. 进入 Manage 标签
  4. 从 Details 部分复制 Project ID

WatsonxChatModel

WatsonxChatModel 类让你能创建一个完全封装在 LangChain4j 内的 ChatModel 接口实例。要创建一个实例,你必须指定以下必填参数:

  • baseUrl(...) —— IBM Cloud 端点 URL(以 String、URI 或 CloudRegion 形式)
  • apiKey(...) —— IBM Cloud IAM API 密钥
  • projectId(...) —— IBM Cloud Project ID(或使用 spaceId(...))
  • modelName(...) —— 用于推理的基础模型 ID

你可以用 .apiKey(...) 或通过 .authenticator(...) 提供一个完整 Authenticator 实例来认证。

要调用你已按需部署的模型,请改用 WatsonxDeploymentChatModel。

Example

java
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.watsonx.WatsonxChatModel;
import com.ibm.watsonx.ai.CloudRegion;

ChatModel chatModel = WatsonxChatModel.builder()
    .baseUrl(CloudRegion.FRANKFURT)
    .apiKey("your-api-key")
    .projectId("your-project-id")
    .modelName("ibm/granite-4-h-small")
    .temperature(0.7)
    .maxOutputTokens(0)
    .build();

String answer = chatModel.chat("Hello from watsonx.ai");
System.out.println(answer);

🔗 查看可用模型

WatsonxStreamingChatModel

WatsonxStreamingChatModel 在 LangChain4j 内为 IBM watsonx.ai 提供流式支持。当你想在词元生成之际就处理它们时它很有用,非常适合聊天 UI 或长文本生成这类实时应用。

流式使用与非流式 WatsonxChatModel 相同的配置结构与参数。主要区别在于响应通过一个处理器接口增量交付。

要调用你已按需部署的模型,请改用 WatsonxDeploymentStreamingChatModel。

Example

java
import dev.langchain4j.model.chat.StreamingChatModel;
import dev.langchain4j.model.chat.StreamingChatResponseHandler;
import dev.langchain4j.model.chat.ChatResponse;
import dev.langchain4j.model.watsonx.WatsonxStreamingChatModel;
import com.ibm.watsonx.ai.CloudRegion;

StreamingChatModel model = WatsonxStreamingChatModel.builder()
    .baseUrl(CloudRegion.FRANKFURT)
    .apiKey("your-api-key")
    .projectId("your-project-id")
    .modelName("ibm/granite-4-h-small")
    .maxOutputTokens(0)
    .build();

model.chat("What is the capital of Italy?", new StreamingChatResponseHandler() {

    @Override
    public void onPartialResponse(String partialResponse) {
        System.out.println("Partial: " + partialResponse);
    }

    @Override
    public void onCompleteResponse(ChatResponse completeResponse) {
        System.out.println("Complete: " + completeResponse);
    }

    @Override
    public void onError(Throwable error) {
        error.printStackTrace();
    }
});

🔗 查看可用模型

已部署模型(按需部署)

IBM watsonx.ai 允许你在专用硬件上按需部署基础模型,供你的组织独占使用。这些已部署模型以其 deploymentId 寻址,并由一个不同于基础模型目录的 watsonx.ai 端点服务,因此 LangChain4j 通过它们各自的一对类 WatsonxDeploymentChatModel 与 WatsonxDeploymentStreamingChatModel 暴露它们。

要创建一个实例,你必须指定:

  • baseUrl(...) —— IBM Cloud 端点 URL(以 String、URI 或 CloudRegion 形式)
  • apiKey(...) —— IBM Cloud IAM API 密钥
  • deploymentId(...) —— 按需部署模型的 Deployment ID

一个部署已经指向某个项目或空间内的特定模型,因此这些 builder 既不暴露 modelName(...),也不暴露 projectId(...)/spaceId(...)。其他每个生成参数(temperature、maxOutputTokens、thinking、工具、responseFormat……)的工作方式与在 WatsonxChatModel 上完全一致。

注: deploymentId 是一个连接级的设置,在构建模型时固定——它选择部署端点,因此不能通过 WatsonxChatRequestParameters 逐次请求覆盖。

WatsonxDeploymentChatModel

java
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.watsonx.WatsonxDeploymentChatModel;
import com.ibm.watsonx.ai.CloudRegion;

ChatModel chatModel = WatsonxDeploymentChatModel.builder()
    .baseUrl(CloudRegion.FRANKFURT)
    .apiKey("your-api-key")
    .deploymentId("your-deployment-id")
    .temperature(0.7)
    .maxOutputTokens(0)
    .build();

String answer = chatModel.chat("Hello from watsonx.ai");
System.out.println(answer);

WatsonxDeploymentStreamingChatModel

java
import dev.langchain4j.model.chat.StreamingChatModel;
import dev.langchain4j.model.chat.StreamingChatResponseHandler;
import dev.langchain4j.model.chat.ChatResponse;
import dev.langchain4j.model.watsonx.WatsonxDeploymentStreamingChatModel;
import com.ibm.watsonx.ai.CloudRegion;

StreamingChatModel model = WatsonxDeploymentStreamingChatModel.builder()
    .baseUrl(CloudRegion.FRANKFURT)
    .apiKey("your-api-key")
    .deploymentId("your-deployment-id")
    .maxOutputTokens(0)
    .build();

model.chat("What is the capital of Italy?", new StreamingChatResponseHandler() {

    @Override
    public void onPartialResponse(String partialResponse) {
        System.out.println("Partial: " + partialResponse);
    }

    @Override
    public void onCompleteResponse(ChatResponse completeResponse) {
        System.out.println("Complete: " + completeResponse);
    }

    @Override
    public void onError(Throwable error) {
        error.printStackTrace();
    }
});

🔗 进一步了解按需部署模型

模型网关(Model Gateway)

IBM watsonx.ai 的 Model Gateway 暴露一个兼容 OpenAI 的聊天端点,能在单个 watsonx.ai 入口之后,将请求路由到由多家提供者(例如 OpenAI、Anthropic,或你注册的第三方提供者)托管的模型。LangChain4j 通过 WatsonxGatewayChatModel 与 WatsonxGatewayStreamingChatModel 与之集成。

注: 该网关须由管理员在使用前配置——你传入的每个 modelName 都必须是网关中已注册的 id。

WatsonxGatewayChatModel

要创建一个实例,指定:

  • baseUrl(...) —— IBM Cloud 端点 URL(以 String、URI 或 CloudRegion 形式)
  • apiKey(...) —— IBM Cloud IAM API 密钥(或通过 .authenticator(...) 提供完整 Authenticator)
  • modelName(...) —— 网关中注册的、OpenAI 风格的模型 id
java
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.watsonx.WatsonxGatewayChatModel;
import com.ibm.watsonx.ai.CloudRegion;

ChatModel chatModel = WatsonxGatewayChatModel.builder()
    .baseUrl(CloudRegion.FRANKFURT)
    .apiKey("your-api-key")
    .modelName("gpt-4o")
    .temperature(0.7)
    .build();

String answer = chatModel.chat("Hello from the watsonx.ai Model Gateway");
System.out.println(answer);

WatsonxGatewayStreamingChatModel

WatsonxGatewayStreamingChatModel 为网关提供流式支持。它使用与 WatsonxGatewayChatModel 相同的配置。响应通过一个处理器增量交付。

java
import dev.langchain4j.model.chat.StreamingChatModel;
import dev.langchain4j.model.chat.StreamingChatResponseHandler;
import dev.langchain4j.model.chat.ChatResponse;
import dev.langchain4j.model.watsonx.WatsonxGatewayStreamingChatModel;
import com.ibm.watsonx.ai.CloudRegion;

StreamingChatModel model = WatsonxGatewayStreamingChatModel.builder()
    .baseUrl(CloudRegion.FRANKFURT)
    .apiKey("your-api-key")
    .modelName("gpt-4o")
    .build();

model.chat("What is the capital of Italy?", new StreamingChatResponseHandler() {

    @Override
    public void onPartialResponse(String partialResponse) {
        System.out.println("Partial: " + partialResponse);
    }

    @Override
    public void onCompleteResponse(ChatResponse completeResponse) {
        System.out.println("Complete: " + completeResponse);
    }

    @Override
    public void onError(Throwable error) {
        error.printStackTrace();
    }
});

仅网关支持的参数

每个 watsonx.ai 聊天服务都有自己的 ChatRequestParameters 实现,只暴露该服务接受的参数,别无其他:

类被谁使用
WatsonxChatRequestParametersWatsonxChatModel、WatsonxStreamingChatModel、WatsonxDeploymentChatModel、WatsonxDeploymentStreamingChatModel
WatsonxGatewayChatRequestParametersWatsonxGatewayChatModel、WatsonxGatewayStreamingChatModel

这两个类是 ChatRequestParameters 的相互独立实现。每一个都精确声明其服务支持什么,因此谁也不知道对方的参数。把一个服务的参数传给另一个——无论是通过 builder 上的 defaultRequestParameters(...),还是通过单个 ChatRequest 的参数——因此只贡献 DefaultChatRequestParameters 所涵盖的部分(modelName、temperature、topP、maxOutputTokens……),而它们携带的每个 watsonx.ai 专有参数都会被忽略。请使用与你所调用模型相匹配的那个类。

除通用聊天参数外,WatsonxGatewayChatRequestParameters 还暴露网关专有参数:

参数描述
serviceTier(...)服务层级,AUTO、DEFAULT、FLEX 或 PRIORITY 之一。
reasoningEffort(...)推理模型的推理精力,LOW、MEDIUM 或 HIGH 之一。
router(...) / cache(...)路由器配置,含一个提示词 Cache。
modalities(...)输出模态(例如 ["text"])。
store(...)提供者是否应持久化请求/响应。
parallelToolCalls(...)启用/禁用并行工具调用。
user(...)转发给提供者的终端用户标识。
metadata(...)转发给提供者的自由格式元数据 map。
logitBias(...)、logprobs(...)、topLogprobs(...)、seed(...)兼容 OpenAI 的采样控制。
java
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.model.chat.request.ChatRequest;
import dev.langchain4j.model.watsonx.WatsonxGatewayChatRequestParameters;
import com.ibm.watsonx.ai.gateway.chat.ModelGatewayParameters.ReasoningEffort;
import com.ibm.watsonx.ai.gateway.chat.ModelGatewayParameters.ServiceTier;

ChatRequest request = ChatRequest.builder()
    .messages(UserMessage.from("Solve this step by step."))
    .parameters(
        WatsonxGatewayChatRequestParameters.builder()
            .serviceTier(ServiceTier.FLEX)
            .reasoningEffort(ReasoningEffort.HIGH)
            .build()
    ).build();

String answer = chatModel.chat(request).aiMessage().text();

响应元数据

每个 watsonx.ai 聊天响应都携带一个 WatsonxChatResponseMetadata。它的三个字段只由 Model Gateway 填充,对其他服务保持 null:

java
import dev.langchain4j.model.chat.response.ChatResponse;
import dev.langchain4j.model.watsonx.WatsonxChatResponseMetadata;

ChatResponse response = chatModel.chat(request);
var metadata = (WatsonxChatResponseMetadata) response.metadata();

metadata.serviceTier();       // service tier that served the request (gateway only)
metadata.systemFingerprint(); // provider system fingerprint (gateway only)
metadata.cached();            // whether the response was served from cache (gateway only)

内联审核

WatsonxChatModel 与 WatsonxStreamingChatModel 能在答案生成的同时筛查聊天请求的输入与输出,而无需额外调用任何审核服务。筛查通过 moderations(...) builder 方法启用。

java
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.watsonx.WatsonxChatModel;
import com.ibm.watsonx.ai.CloudRegion;
import com.ibm.watsonx.ai.chat.ChatModeration;

ChatModel chatModel = WatsonxChatModel.builder()
    .baseUrl(CloudRegion.FRANKFURT)
    .apiKey("your-api-key")
    .projectId("your-project-id")
    .modelName("ibm/granite-4-h-small")
    .moderations(
        ChatModeration.builder()
            .pii(pii -> pii.input(true).output(true))
            .hap(hap -> hap.output(0.8f))
            .graniteGuardian(guardian -> guardian.input(0.85f))
            .build()
    )
    .build();

有三个检测器可用。pii 与 hap 可在输入、输出或两者上启用,而 graniteGuardian 只筛查输入。

检测器用途通过何者启用
pii检测个人数据,例如电话号码、邮箱与信用卡。.pii(pii -> pii.input(true).output(true))
hap检测高于某置信度阈值的仇恨与脏话。.hap(hap -> hap.input(0.8f).output(0.9f))
graniteGuardian通用的有害内容分类器。.graniteGuardian(guardian -> guardian.input(0.85f))

inputRanges(...) 会把对输入的筛查收窄到给定范围,其中起点含、终点不含。

java
import com.ibm.watsonx.ai.chat.ChatModeration.InputRanges;

ChatModeration.builder()
    .pii(pii -> pii.input(true))
    .inputRanges(List.of(InputRanges.of(0, 50), InputRanges.of(100, 150)))
    .build();

读取匹配项

匹配项会在响应的 WatsonxChatResponseMetadata 上上报。

java
import dev.langchain4j.model.chat.response.ChatResponse;
import dev.langchain4j.model.watsonx.WatsonxChatResponseMetadata;

ChatResponse response = chatModel.chat(request);
var metadata = (WatsonxChatResponseMetadata) response.metadata();

metadata.moderations(); // matches keyed by detector name, "pii", "hap" or "granite_guardian"
metadata.detections();  // Granite Guardian detections keyed by position, "input" or "output"

当审核被禁用、或没有任何检测器匹配时,两个 map 都为 null。每个匹配都会说明它来自输入还是输出、检测器赋给的分数、被识别出的实体类型,以及越界词在文本中的位置。用 WatsonxStreamingChatModel 时,每个块的匹配会被合并,并在传给 onCompleteResponse(...) 的响应元数据上上报。

字段类型描述
score()float匹配的置信度。
input()boolean匹配来自输入时为 true,来自输出时为 false。
position()Position匹配在文本内的起始(含)与结束(不含)偏移。
entity()String被识别实体的类型,例如 PhoneNumber。
word()String匹配到的文本。

该服务上报输出的匹配却从不改写答案,因此对文本的脱敏交由调用方完成,调用方可利用每个匹配的偏移。每个检测器也接受 mask(true),请求服务移除被检测实体的值,而聊天服务的答案仍原样返回。

java
import com.ibm.watsonx.ai.chat.TextChatResponse.ModerationResult;

static String mask(String text, ModerationResult result) {
    var position = result.position();
    return text.substring(0, position.start())
        + "*".repeat(position.end() - position.start())
        + text.substring(position.end());
}

输入被检测器拦截

匹配某个检测器的输入会阻断生成。LangChain4j 会把它报告为一个 ContentFilteredException,其 cause 是 SDK 抛出的 ModerationException,因此每个触发拦截的检测器的匹配仍可访问。

java
import com.ibm.watsonx.ai.chat.exception.ModerationException;
import dev.langchain4j.exception.ContentFilteredException;

try {
    chatModel.chat(request);
} catch (ContentFilteredException e) {
    var cause = (ModerationException) e.getCause();
    System.out.println(cause.moderations());
}

在 WatsonxStreamingChatModel 上,同一个异常会被投递到 onError(...)。

单个请求的审核

WatsonxChatRequestParameters 携带同样的设置,优先于在 builder 上配置的那个。

java
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.model.chat.request.ChatRequest;
import dev.langchain4j.model.watsonx.WatsonxChatRequestParameters;

ChatRequest request = ChatRequest.builder()
    .messages(UserMessage.from("Contact me at john@example.com."))
    .parameters(
        WatsonxChatRequestParameters.builder()
            .moderations(ChatModeration.builder().pii(pii -> pii.output(true)).build())
            .build()
    ).build();

注: 内联审核只在基础模型上可用。WatsonxDeploymentChatModel 与 WatsonxDeploymentStreamingChatModel 会以 UnsupportedFeatureException 拒绝它,而 Model Gateway 不支持它。要在聊天流之外筛查一段文本,请使用 WatsonxModerationModel。

🔗 SDK 内容审核,了解每个检测器选项的完整列表。

工具集成

所有 watsonx.ai 聊天模型——WatsonxChatModel、WatsonxStreamingChatModel、WatsonxDeploymentChatModel、WatsonxDeploymentStreamingChatModel、WatsonxGatewayChatModel 与 WatsonxGatewayStreamingChatModel——都支持 LangChain4j 工具,让模型能调用用 @Tool 注解的 Java 方法。

这里是一个使用同步模型(WatsonxChatModel)的示例,但同样的方式适用于流式以及部署/网关变体。

java
static class Tools {

    @Tool
    LocalDate currentDate() {
        return LocalDate.now();
    }

    @Tool
    LocalTime currentTime() {
        return LocalTime.now();
    }
}

interface AiService {
    String chat(String userMessage);
}

ChatModel chatModel = WatsonxChatModel.builder()
    .baseUrl(CloudRegion.FRANKFURT)
    .apiKey("your-api-key")
    .projectId("your-project-id")
    .modelName("mistralai/mistral-small-3-1-24b-instruct-2503")
    .maxOutputTokens(0)
    .build();

AiService aiService = AiServices.builder(AiService.class)
        .chatModel(chatModel)
        .tools(new Tools())
        .build();

String answer = aiService.chat("What is the date today?");
System.out.println(answer);

注: 请确保你所选的模型支持工具使用。


结构化输出

所有 watsonx.ai 聊天模型都能把响应约束到一个 JSON Schema。通用的 LangChain4j 文档在这里,而本节描述 watsonx.ai 专有的行为。

strictJsonSchema(...) builder 方法控制 schema 如何发送给服务,默认为 true。在严格模式下,模型被要求遵循该 schema,每个属性都被标记为 required,additionalProperties 被设为 false,而未被列入 required 的属性会被置为可空。

java
import static dev.langchain4j.model.chat.Capability.RESPONSE_FORMAT_JSON_SCHEMA;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.watsonx.WatsonxChatModel;
import com.ibm.watsonx.ai.CloudRegion;

ChatModel chatModel = WatsonxChatModel.builder()
    .baseUrl(CloudRegion.FRANKFURT)
    .apiKey("your-api-key")
    .projectId("your-project-id")
    .modelName("ibm/granite-4-h-small")
    .supportedCapabilities(RESPONSE_FORMAT_JSON_SCHEMA)
    .strictJsonSchema(true) // default value
    .build();

使用 strictJsonSchema(false) 会把 schema 作为提示而非约束发送。模型仍会尝试产生一个遵循该 schema 的响应,但当响应偏离它时请求不会失败,required 列表按声明发送,且 additionalProperties 被略去。当可选字段必须保持可选时,就该用这个模式。

只有当模型通过 AI 服务使用、JSON Schema 由 AI 服务方法的返回类型生成时,才需要 supportedCapabilities(RESPONSE_FORMAT_JSON_SCHEMA)。

JSON Schema 的根元素必须是一个 JsonObjectSchema 或一个 JsonRawSchema。任何其他根元素都会让请求以 IllegalArgumentException 失败。

启用思考 / 推理输出

一些基础模型能把内部推理(也被称为思考)步骤作为其响应的一部分包含进来。取决于模型,这种推理可能与最终响应的文本内嵌在一起,也可能在 watsonx.ai 的一个专有的字段中单独返回。

要正确地启用并捕获这一行为,你必须根据模型的输出格式配置 thinking(...) builder 方法。这确保 LangChain4j 能从模型输出中自动抽取推理与响应内容。

主要有两种配置模式:

  • ExtractionTags → 用于把推理与响应在同一文本块中返回的模型(例如 ibm/granite-3-3-8b-instruct)。
  • ThinkingEffort → 用于已自动分离推理与响应的模型(例如 openai/gpt-oss-120b)。

thinking(...) builder 方法在 WatsonxChatModel、WatsonxStreamingChatModel、WatsonxDeploymentChatModel 与 WatsonxDeploymentStreamingChatModel 上可用。Model Gateway 不接受它,因此在网关模型上请改用 reasoningEffort(...)。

一起返回推理与响应的模型

当模型在同一文本字符串中输出推理与响应时,使用 ExtractionTags。这些标签定义了用于把推理与最终响应分离的类 XML 标记。

示例标签:

  • 推理标签: <think> —— 包含模型的内部推理。
  • 响应标签: <response> —— 包含面向用户的答案。

行为

  • 若两个标签都指定,就直接用它们抽取推理与响应片段。
  • 若只指定推理标签,该标签之外的一切都视为响应。

ibm/granite-3-3-8b-instruct 的示例

java
ChatModel chatModel = WatsonxChatModel.builder()
    .baseUrl(CloudRegion.FRANKFURT)
    .apiKey("your-api-key")
    .projectId("your-project-id")
    .modelName("ibm/granite-3-3-8b-instruct")
    .maxOutputTokens(0)
    .thinking(ExtractionTags.of("think", "response"))
    .build();

ChatResponse chatResponse = chatModel.chat(
    UserMessage.userMessage("Why is the sky blue?")
);

AiMessage aiMessage = chatResponse.aiMessage();

System.out.println(aiMessage.thinking());
System.out.println(aiMessage.text());

分开返回推理与响应的模型。

对于已经把推理与响应作为独立字段返回的模型,使用 ThinkingEffort 来控制模型在生成时投入多少推理。或者,用一个布尔标志启用它。

openai/gpt-oss-120b 的示例

java
ChatModel chatModel = WatsonxChatModel.builder()
    .baseUrl(CloudRegion.DALLAS)
    .apiKey("your-api-key")
    .projectId("your-project-id")
    .modelName("openai/gpt-oss-120b")
    .thinking(ThinkingEffort.HIGH)
    .build();

or

java
ChatModel chatModel = WatsonxChatModel.builder()
    .baseUrl(CloudRegion.DALLAS)
    .apiKey("your-api-key")
    .projectId("your-project-id")
    .modelName("openai/gpt-oss-120b")
    .thinking(true)
    .build();

流式示例

java
StreamingChatModel model = WatsonxStreamingChatModel.builder()
    .baseUrl(CloudRegion.FRANKFURT)
    .apiKey("your-api-key")
    .projectId("your-project-id")
    .modelName("ibm/granite-3-3-8b-instruct")
    .thinking(ExtractionTags.of("think", "response"))
    .build();

List<ChatMessage> messages = List.of(
    UserMessage.userMessage("Why is the sky blue?")
);

ChatRequest chatRequest = ChatRequest.builder()
    .messages(messages)
    .build();

model.chat(chatRequest, new StreamingChatResponseHandler() {

    @Override
    public void onPartialResponse(String partialResponse) {
        ...
    }

    @Override
    public void onPartialThinking(PartialThinking partialThinking) {
        ...
    }
});

注:

  • 请确保所选模型支持推理输出。
  • 对把推理与响应嵌在同一文本字符串中的模型,使用 ExtractionTags。
  • 对已自动分离推理与响应的模型,使用 ThinkingEffort 或 thinking(true)。

WatsonxModelCatalog

WatsonxModelCatalog 提供了一种以编程方式发现并列出 IBM watsonx.ai 上所有可用基础模型的途径。它实现了 LangChain4j 的 ModelCatalog 接口,让你能检索每个模型的详细信息。

Example

java
import dev.langchain4j.model.catalog.ModelCatalog;
import dev.langchain4j.model.catalog.ModelDescription;
import dev.langchain4j.model.watsonx.WatsonxModelCatalog;
import com.ibm.watsonx.ai.CloudRegion;

ModelCatalog modelCatalog = WatsonxModelCatalog.builder()
    .baseUrl(CloudRegion.FRANKFURT)
    .build();

var models = modelCatalog.listModels();

🔗 SDK 基础模型服务

WatsonxGatewayModelCatalog

WatsonxGatewayModelCatalog 是 WatsonxModelCatalog 对应的 Model Gateway 版本。它不列出 watsonx.ai 托管的基础模型,而是列出网关中配置的、跨其注册的所有提供者聚合而来的模型。它也实现了 LangChain4j 的 ModelCatalog 接口。

每个返回的 ModelDescription 的 name(),就是要传给 WatsonxGatewayChatModel.modelName(...) 与 WatsonxGatewayStreamingChatModel.modelName(...) 的标识符。当网关管理员定义了别名时,它是模型的别名,否则是提供者侧的模型 id。

Example

java
import dev.langchain4j.model.catalog.ModelCatalog;
import dev.langchain4j.model.catalog.ModelDescription;
import dev.langchain4j.model.watsonx.WatsonxGatewayModelCatalog;
import com.ibm.watsonx.ai.CloudRegion;

ModelCatalog modelCatalog = WatsonxGatewayModelCatalog.builder()
    .baseUrl(CloudRegion.FRANKFURT)
    .apiKey("your-api-key")
    .build();

for (ModelDescription model : modelCatalog.listModels()) {
    System.out.println(model.name() + " (" + model.owner() + ")");
}
// → gpt-4o (openai)
// → claude-3-5-sonnet (anthropic)

网关模型如何映射

ModelDescription网关字段备注
name()alias,无别名时为 id与网关聊天模型一起使用的 id
displayName()与 name() 相同网关没有单独的名称标签
description()description用户定义,除非管理员设置了否则为 null
owner()owned_by提供者,例如 openai
createdAt()created网关配置的 Unix 时间戳,而非模型发布时间
type()-始终为 ModelType.CHAT,因为网关不暴露模型能力
maxInputTokens()metadata.context_window当管理员未配置 metadata 时为 null
maxOutputTokens()-始终为 null,网关不返回它

WatsonxTokenCountEstimator

WatsonxTokenCountEstimator 通过调用 watsonx.ai 的分词端点实现了 LangChain4j 的 TokenCountEstimator 接口,因此计数来自模型自身的分词器,而非本地近似。正因如此,modelName(...) 是必填的。

Example

java
import dev.langchain4j.model.TokenCountEstimator;
import dev.langchain4j.model.watsonx.WatsonxTokenCountEstimator;
import com.ibm.watsonx.ai.CloudRegion;

TokenCountEstimator tokenCountEstimator = WatsonxTokenCountEstimator.builder()
    .baseUrl(CloudRegion.FRANKFURT)
    .apiKey("your-api-key")
    .projectId("your-project-id")
    .modelName("ibm/granite-4-h-small")
    .build();

int tokenCount = tokenCountEstimator.estimateTokenCountInText("Hello from watsonx.ai");

注: 每次估算都是一次远程调用。estimateTokenCountInMessage(...) 也会统计一个 AiMessage 的思考文本与工具执行请求。不支持图像、音频、PDF 与视频内容。

🔗 SDK 分词服务

WatsonxModerationModel

WatsonxModerationModel 使用 IBM watsonx.ai 提供了 ModerationModel 接口的 LangChain4j 实现。它让你能通过检测器自动检测并标记文本中敏感、不安全或违反策略的内容。

可以用一个或多个检测器来识别不同类型的内容,例如:

  • Pii – 检测个人身份信息(例如邮箱、电话号码)
  • Hap – 检测仇恨、辱骂或脏话
  • GraniteGuardian – 检测有风险或有害的语言

Example

java
ModerationModel model = WatsonxModerationModel.builder()
    .baseUrl(CloudRegion.FRANKFURT)
    .apiKey("your-api-key")
    .projectId("your-project-id")
    .detectors(Hap.ofDefaults(), GraniteGuardian.ofDefaults())
    .build();

Response<Moderation> response = model.moderate("...");

元数据

每次审核响应都包含一个 metadata map,提供关于检测的额外上下文。

键描述
detection检测器赋给的被检测标签或类别
detection_type触发标记的检测器类型
start被检测片段的起始字符索引
end被检测片段的结束字符索引
score检测的置信度分数

这些元数据值可通过 Response.metadata() 获取:

java
Map<String, Object> metadata = response.metadata();
System.out.println("Detection type: " + metadata.get("detection_type"));
System.out.println("Score: " + metadata.get("score"));

🔗 SDK 检测服务,了解检测器及其选项的完整列表。

通过环境变量配置

底层 SDK 的内部 HTTP 行为可以通过环境变量自定义,无需任何代码改动。这些设置是可选的,未显式定义变量时会使用合理的默认值。

重试配置

在发生瞬时故障或认证令牌过期时,HTTP 请求会被自动重试。重试行为可用以下环境变量自定义:

环境变量描述默认值
WATSONX_RETRY_TOKEN_EXPIRED_MAX_RETRIES认证令牌过期(HTTP 401 / 403)时的最大重试次数1
WATSONX_RETRY_STATUS_CODES_MAX_RETRIES瞬时 HTTP 状态码(429、503、504、520)的最大重试次数10
WATSONX_RETRY_STATUS_CODES_BACKOFF_ENABLED为瞬时重试启用指数退避true
WATSONX_RETRY_STATUS_CODES_INITIAL_INTERVAL_MS初始重试间隔(毫秒,作为指数退避的基数)20

HTTP IO 执行器配置

流式响应与 HTTP 响应处理由一个内部 IO 执行器处理。默认在 Java 21+ 上使用虚拟线程,在 Java 17–20 上使用一个缓存线程池。

该行为可通过以下环境变量自定义:

环境变量描述默认值
WATSONX_IO_EXECUTOR_THREADS把 IO 执行器上限设为固定大小、此线程数的线程池未设置

🔗 SDK 环境变量的完整参考

错误处理

SDK 抛出的 watsonx.ai 错误会被翻译为标准的 LangChain4j 异常,因此你可以像对待任何其他提供者那样处理它们。该映射由 watsonx.ai 返回的错误码驱动:

watsonx.ai 错误码LangChain4j 异常
authentication_token_expired、authorization_rejectedAuthenticationException
invalid_input_argument、invalid_request_entity、json_type_error、json_validation_errorInvalidRequestException
model_not_supportedModelNotFoundException
token_quota_reachedRateLimitException
任何其他错误码LangChain4jException

当响应不含错误体时,异常改由 HTTP 状态码选取。一个超出其 timeout(...) 的请求会被报告为 TimeoutException。一个拒绝作答的模型,以及一个被内联审核拦截的输入,会被报告为 ContentFilteredException。

java
try {
    String answer = chatModel.chat("Hello from watsonx.ai");
} catch (RateLimitException e) {
    // token quota reached
} catch (InvalidRequestException e) {
    // a request parameter was rejected by watsonx.ai
}

🔗 SDK 异常层级,了解底层的 WatsonxException 及其 statusCode()、errorCode() 与 traceId(),可通过 getCause() 获取。

Quarkus

更多细节见这里。

示例

BytesRouter 是社区翻译站点,所有译文仅供参考,一切以官方英文原文为准。