# ChatWatsonx

> **Class** in `langchain_ibm`

📖 [View in docs](https://reference.langchain.com/python/langchain-ibm/chat_models/ChatWatsonx)

`IBM watsonx.ai` chat models integration.

???+ info "Setup"

    To use, you should have `langchain_ibm` python package installed,
    and the environment variable `WATSONX_API_KEY` set with your API key, or pass
    it as a named parameter `api_key` to the constructor.

    ```bash
    pip install -U langchain-ibm

    # or using uv
    uv add langchain-ibm
    ```

    ```bash
    export WATSONX_API_KEY="your-api-key"
    ```

    !!! deprecated
        `apikey` and `WATSONX_APIKEY` are deprecated and will be removed in
        version `2.0.0`. Use `api_key` and `WATSONX_API_KEY` instead.

??? info "Instantiate"

    Create a model instance with desired params. For example:

    ```python
    from langchain_ibm import ChatWatsonx
    from ibm_watsonx_ai.foundation_models.schema import TextChatParameters

    parameters = TextChatParameters(
        top_p=1, temperature=0.5, max_completion_tokens=None
    )

    model = ChatWatsonx(
        model_id="meta-llama/llama-3-3-70b-instruct",
        url="https://us-south.ml.cloud.ibm.com",
        project_id="*****",
        params=parameters,
        # api_key="*****"
    )
    ```

??? info "Invoke"

    Generate a response from the model:

    ```python
    messages = [
        (
            "system",
            "You are a helpful translator. Translate the user sentence to French.",
        ),
        ("human", "I love programming."),
    ]
    model.invoke(messages)
    ```

    Results in an `AIMessage` response:

    ```python
    AIMessage(
        content="J'adore programmer.",
        additional_kwargs={},
        response_metadata={
            "token_usage": {
                "completion_tokens": 7,
                "prompt_tokens": 30,
                "total_tokens": 37,
            },
            "model_name": "ibm/granite-4-h-small",
            "system_fingerprint": "",
            "finish_reason": "stop",
        },
        id="chatcmpl-529352c4-93ba-4801-8f1d-a3b4e3935194---daed91fb74d0405f200db1e63da9a48a---7a3ef799-4413-47e4-b24c-85d267e37fa2",
        usage_metadata={"input_tokens": 30, "output_tokens": 7, "total_tokens": 37},
    )
    ```

??? info "Stream"

    Stream a response from the model:

    ```python
    for chunk in model.stream(messages):
        print(chunk.text)
    ```

    Results in a sequence of `AIMessageChunk` objects with partial content:

    ```python
    AIMessageChunk(content="", id="run--e48a38d3-1500-4b5e-870c-6313e8cff775")
    AIMessageChunk(content="J", id="run--e48a38d3-1500-4b5e-870c-6313e8cff775")
    AIMessageChunk(content="'", id="run--e48a38d3-1500-4b5e-870c-6313e8cff775")
    AIMessageChunk(content="ad", id="run--e48a38d3-1500-4b5e-870c-6313e8cff775")
    AIMessageChunk(content="or", id="run--e48a38d3-1500-4b5e-870c-6313e8cff775")
    AIMessageChunk(
        content=" programmer", id="run--e48a38d3-1500-4b5e-870c-6313e8cff775"
    )
    AIMessageChunk(content=".", id="run--e48a38d3-1500-4b5e-870c-6313e8cff775")
    AIMessageChunk(
        content="",
        response_metadata={
            "finish_reason": "stop",
            "model_name": "ibm/granite-4-h-small",
        },
        id="run--e48a38d3-1500-4b5e-870c-6313e8cff775",
    )
    AIMessageChunk(
        content="",
        id="run--e48a38d3-1500-4b5e-870c-6313e8cff775",
        usage_metadata={"input_tokens": 30, "output_tokens": 7, "total_tokens": 37},
    )
    ```

    To collect the full message, you can concatenate the chunks:

    ```python
    stream = model.stream(messages)
    full = next(stream)
    for chunk in stream:
        full += chunk

    full
    ```

    ```python
    AIMessageChunk(
        content="J'adore programmer.",
        response_metadata={
            "finish_reason": "stop",
            "model_name": "ibm/granite-4-h-small",
        },
        id="chatcmpl-88a48b71-c149-4a0c-9c02-d6b97ca5dc6c---b7ba15879a8c5283b1e8a3b8db0229f0---0037ca4f-8a74-4f84-a46c-ab3fd1294f24",
        usage_metadata={"input_tokens": 30, "output_tokens": 7, "total_tokens": 37},
    )
    ```

??? info "Async"

    Asynchronous equivalents of `invoke`, `stream`, and `batch` are also available:

    ```python
    # Invoke
    await model.ainvoke(messages)

    # Stream
    async for chunk in model.astream(messages):
        print(chunk.text)

    # Batch
    await model.abatch([messages])
    ```

    Results in an `AIMessage` response:

    ```python
    AIMessage(
        content="J'adore programmer.",
        additional_kwargs={},
        response_metadata={
            "token_usage": {
                "completion_tokens": 7,
                "prompt_tokens": 30,
                "total_tokens": 37,
            },
            "model_name": "ibm/granite-4-h-small",
            "system_fingerprint": "",
            "finish_reason": "stop",
        },
        id="chatcmpl-5bef2d81-ef56-463b-a8fa-c2bcc2a3c348---821e7750d18925f2b36226db66667e26---6396c786-9da9-4468-883e-11ed90a05937",
        usage_metadata={"input_tokens": 30, "output_tokens": 7, "total_tokens": 37},
    )
    ```

    For batched calls, results in a `list[AIMessage]`.

??? info "Tool calling"

    ```python
    from pydantic import BaseModel, Field

    class GetWeather(BaseModel):
        '''Get the current weather in a given location'''

        location: str = Field(
            ..., description="The city and state, e.g. San Francisco, CA"
        )

    class GetPopulation(BaseModel):
        '''Get the current population in a given location'''

        location: str = Field(
            ..., description="The city and state, e.g. San Francisco, CA"
        )

    model_with_tools = model.bind_tools(
        [GetWeather, GetPopulation]
        # strict = True  # Enforce tool args schema is respected
    )
    ai_msg = model_with_tools.invoke(
        "Which city is hotter today and which is bigger: LA or NY?"
    )
    ai_msg.tool_calls
    ```

    ```python
    [
        {
            "name": "GetWeather",
            "args": {"location": "Los Angeles, CA"},
            "id": "chatcmpl-tool-59632abcee8f48a18a5f3a81422b917b",
            "type": "tool_call",
        },
        {
            "name": "GetWeather",
            "args": {"location": "New York, NY"},
            "id": "chatcmpl-tool-c6f3b033b4594918bb53f656525b0979",
            "type": "tool_call",
        },
        {
            "name": "GetPopulation",
            "args": {"location": "Los Angeles, CA"},
            "id": "chatcmpl-tool-175a23281e4747ea81cbe472b8e47012",
            "type": "tool_call",
        },
        {
            "name": "GetPopulation",
            "args": {"location": "New York, NY"},
            "id": "chatcmpl-tool-e1ccc534835945aebab708eb5e685bf7",
            "type": "tool_call",
        },
    ]
    ```

??? info "Reasoning output"

    ```python
    from langchain_ibm import ChatWatsonx
    from ibm_watsonx_ai.foundation_models.schema import TextChatParameters

    parameters = TextChatParameters(
        include_reasoning=True, reasoning_effort="medium"
    )

    model = ChatWatsonx(
        model_id="openai/gpt-oss-120b",
        url="https://us-south.ml.cloud.ibm.com",
        project_id="*****",
        params=parameters,
        # api_key="*****"
    )

    response = model.invoke("What is 3^3?")

    # Response text
    print(f"Output: {response.content}")

    # Reasoning summaries
    print(f"Reasoning: {response.additional_kwargs['reasoning_content']}")
    ```

    ```txt
    Output: 3^3 = 27
    Reasoning: The user asks "What is 3^3?" That's 27. Provide answer.
    ```

    !!! version-added "Added in version 0.3.19: Updated `AIMessage` format"
        [`langchain-ibm >= 0.3.19`](https://pypi.org/project/langchain-ibm/#history)
        allows users to set Reasoning output parameters and will format output from
        reasoning summaries into `additional_kwargs` field.

??? info "Structured output"

    ```python
    from pydantic import BaseModel, Field

    class Joke(BaseModel):
        '''Joke to tell user.'''

        setup: str = Field(description="The setup of the joke")
        punchline: str = Field(description="The punchline to the joke")
        rating: int | None = Field(description="How funny the joke is, 1 to 10")

    structured_model = model.with_structured_output(Joke)
    structured_model.invoke("Tell me a joke about cats")
    ```

    ```python
    Joke(
        setup="Why was the cat sitting on the computer?",
        punchline="To keep an eye on the mouse!",
        rating=None,
    )
    ```

    See `with_structured_output` for more info.

??? info "JSON mode"

    ```python
    json_model = model.bind(response_format={"type": "json_object"})
    ai_msg = json_model.invoke(
        “Return JSON with 'random_ints': an array of 10 random integers from 0-99.”
    )
    ai_msg.content
    ```

    ```txt
    '{\n  "random_ints": [12, 34, 56, 78, 10, 22, 44, 66, 88, 99]\n}'
    ```

??? info "Image input"

    ```python
    import base64
    import httpx
    from langchain.messages import HumanMessage

    image_url = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg"
    image_data = base64.b64encode(httpx.get(image_url).content).decode("utf-8")
    message = HumanMessage(
        content=[
            {"type": "text", "text": "describe the weather in this image"},
            {
                "type": "image_url",
                "image_url": {"url": f"data:image/jpeg;base64,{image_data}"},
            },
        ]
    )

    ai_msg = model.invoke([message])
    ai_msg.content
    ```

    ```txt
    "The weather in the image presents a clear, sunny day with good visibility
    and no immediate signs of rain or strong winds. The vibrant blue sky with
    scattered white clouds gives the impression of a tranquil, pleasant day
    conducive to outdoor activities."
    ```

??? info "Token usage"

    ```python
    ai_msg = model.invoke(messages)
    ai_msg.usage_metadata
    ```

    ```txt
    {'input_tokens': 30, 'output_tokens': 7, 'total_tokens': 37}
    ```

    ```python
    stream = model.stream(messages)
    full = next(stream)
    for chunk in stream:
        full += chunk
    full.usage_metadata
    ```

    ```txt
    {'input_tokens': 30, 'output_tokens': 7, 'total_tokens': 37}
    ```

??? info "Logprobs"

    ```python
    logprobs_model = model.bind(logprobs=True)
    ai_msg = logprobs_model.invoke(messages)
    ai_msg.response_metadata["logprobs"]
    ```

    ```txt
    {
        'content': [
            {
                'token': 'J',
                'logprob': -0.0017940393
            },
            {
                'token': "'",
                'logprob': -1.7523613e-05
            },
            {
                'token': 'ad',
                'logprob': -0.16112353
            },
            {
                'token': 'ore',
                'logprob': -0.0003091811
            },
            {
                'token': ' programmer',
                'logprob': -0.24849245
            },
            {
                'token': '.',
                'logprob': -2.5033638e-05
            },
            {
                'token': '<|end_of_text|>',
                'logprob': -7.080781e-05
            }
        ]
    }
    ```

??? info "Response metadata"

    ```python
    ai_msg = model.invoke(messages)
    ai_msg.response_metadata
    ```

    ```txt
    {
        'token_usage': {
            'completion_tokens': 7,
            'prompt_tokens': 30,
            'total_tokens': 37
        },
        'model_name': 'ibm/granite-4-h-small',
        'system_fingerprint': '',
        'finish_reason': 'stop'
    }
    ```

## Signature

```python
ChatWatsonx()
```

## Extends

- `BaseChatModel`

## Properties

- `model_id`
- `model`
- `deployment_id`
- `project_id`
- `space_id`
- `url`
- `apikey`
- `api_key`
- `token`
- `password`
- `username`
- `instance_id`
- `version`
- `params`
- `frequency_penalty`
- `logprobs`
- `top_logprobs`
- `max_tokens`
- `max_completion_tokens`
- `n`
- `presence_penalty`
- `temperature`
- `response_format`
- `top_p`
- `time_limit`
- `logit_bias`
- `seed`
- `stop`
- `chat_template_kwargs`
- `reasoning_effort`
- `include_reasoning`
- `repetition_penalty`
- `length_penalty`
- `verify`
- `validate_model`
- `streaming`
- `watsonx_model`
- `watsonx_model_gateway`
- `watsonx_client`
- `model_config`
- `lc_secrets`

## Methods

- [`is_lc_serializable()`](https://reference.langchain.com/python/langchain-ibm/chat_models/ChatWatsonx/is_lc_serializable)
- [`validate_environment()`](https://reference.langchain.com/python/langchain-ibm/chat_models/ChatWatsonx/validate_environment)
- [`bind_tools()`](https://reference.langchain.com/python/langchain-ibm/chat_models/ChatWatsonx/bind_tools)
- [`with_structured_output()`](https://reference.langchain.com/python/langchain-ibm/chat_models/ChatWatsonx/with_structured_output)

---

[View source on GitHub](https://github.com/langchain-ai/langchain-ibm/blob/629c50b31dcb6369911ae60a84348719053d9172/libs/ibm/langchain_ibm/chat_models.py#L412)