---
title: "LangChain OpenAI-compatible setup: ChatOpenAI base URL"
canonical: https://uplinkswitch.ai/guides/langchain
generated: 2026-11-04T07:22:41.892Z
source: https://uplinkswitch.ai/guides/langchain
base_url: https://api.uplinkswitch.com/v1
---

[›uplinkswitch](https://uplinkswitch.ai/)

[api.uplinkswitch.com/v1](https://uplinkswitch.ai/models)[Console](https://uplinkswitch.ai/console)

[›uplinkswitch](https://uplinkswitch.ai/)

# LangChain

ChatOpenAI with one base URL and one key, in Python and JavaScript. Claude, GPT, Gemini and DeepSeek through the same class.

Checked 2026-10-19

·[All guides](https://uplinkswitch.ai/guides)·[Models](https://uplinkswitch.ai/models)

## Python

LangChain talks to UplinkSwitch through its OpenAI integration. Install it, create a key in the [console](https://uplinkswitch.ai/console) and export it as `UPLINKSWITCH_API_KEY`.

shell

```
pip install langchain-openai
```

app.py

```
import os

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model="claude-sonnet-5-5",
    base_url="https://api.uplinkswitch.com/v1",
    api_key=os.environ["UPLINKSWITCH_API_KEY"],
    default_headers={
        "HTTP-Referer": "https://uplinkswitch.ai",
        "X-Title": "LangChain",
    },
)

print(llm.invoke("Explain what an API gateway does in one sentence.").content)
```

`base_url` stops at `/v1`. The model id is the one on the [Models page](https://uplinkswitch.ai/models), with no vendor prefix. Swap `claude-sonnet-5-5` for `gpt-6.1-sol` or `deepseek-v4-pro-0813` and nothing else changes. `default_headers` is optional: the gateway records `X-Title` as the client app against each request on the console's Usage page, so put your own app name there.

## JavaScript and TypeScript

In LangChain.js the base URL and the headers go inside `configuration`, which is passed to the OpenAI client.

shell

```
npm install @langchain/openai @langchain/core
```

app.ts

```
import { ChatOpenAI } from '@langchain/openai';

const llm = new ChatOpenAI({
  model: 'claude-sonnet-5-5',
  apiKey: process.env.UPLINKSWITCH_API_KEY,
  configuration: {
    baseURL: 'https://api.uplinkswitch.com/v1',
    defaultHeaders: {
      'HTTP-Referer': 'https://uplinkswitch.ai',
      'X-Title': 'LangChain',
    },
  },
});

const msg = await llm.invoke('Explain what an API gateway does in one sentence.');
console.log(msg.content);
```

## Tool calls

`bind_tools` sends OpenAI's tools schema, and the calls come back on `msg.tool_calls`. Claude Sonnet 5.5, GPT-6.1 Sol and DeepSeek V4 Pro each called the tool below with `{'city': 'Paris'}` in our run.

tools.py

```
from langchain_core.tools import tool

@tool
def get_weather(city: str) -> str:
    """Get the current weather for a city."""
    return f"Sunny in {city}"

msg = llm.bind_tools([get_weather]).invoke("What's the weather in Paris?")
print(msg.tool_calls)
# [{'name': 'get_weather', 'args': {'city': 'Paris'}, 'id': '...', 'type': 'tool_call'}]
```

## Agents

`create_agent` runs the tool loop for you: it calls the model, runs each tool the model asks for, sends the result back and stops when the model answers. Pass it the same `llm`.

shell

```
pip install langchain langchain-openai
```

agent.py

```
from langchain.agents import create_agent
from langchain_core.tools import tool

@tool
def word_count(text: str) -> int:
    """Count the words in a piece of text."""
    return len(text.split())

agent = create_agent(model=llm, tools=[word_count])
result = agent.invoke(
    {"messages": [{"role": "user", "content": "How many words are in 'the quick brown fox jumps'?"}]}
)
print(result["messages"][-1].text)
```

On Claude Sonnet 5.5, GPT-6.1 Sol and DeepSeek V4 Pro the agent called `word_count` once and answered 5, in two model calls. Each model call in the loop is a separate request, listed with its charge on the console's Usage page.

## Structured output

Pass `method="function_calling"` to `with_structured_output`. It turns the schema into a forced tool call, and Claude Sonnet 5.5, GPT-6.1 Sol and DeepSeek V4 Pro each returned a filled `Capital` object.

structured.py

```
from pydantic import BaseModel

class Capital(BaseModel):
    country: str
    capital: str

parser = llm.with_structured_output(Capital, method="function_calling")
print(parser.invoke("What is the capital of France?"))
# country='France' capital='Paris'
```

The default method is `json_schema`, which sends `response_format`. GPT-6.1 Sol returned the object with it; Claude Sonnet 5.5 and DeepSeek V4 Pro returned a plain sentence, and Pydantic raised `ValidationError: Invalid JSON`.

## Streaming

`stream` yields chunks as the model writes them. All three models streamed in our run.

stream.py

```
for chunk in llm.stream("Count from 1 to 5."):
    print(chunk.content, end="", flush=True)
```

## Models and prices

| Model | Model id | Input / 1M | Output / 1M | Developer list, in / out |
| --- | --- | --- | --- | --- |
| [Claude Sonnet 5.5](https://uplinkswitch.ai/models/claude-sonnet-5-5) | `claude-sonnet-5-5` | $1.20 | $3.00 | $2.00 / $10.00 |
| [GPT-6.1 Sol](https://uplinkswitch.ai/models/gpt-6.1-sol) | `gpt-6.1-sol` | $0.60 | $3.00 | $2.00 / $10.00 |
| [DeepSeek V4 Pro 0813](https://uplinkswitch.ai/models/deepseek-v4-pro-0813) | `deepseek-v4-pro-0813` | $0.792 | $1.188 | $1.32 / $3.96 |
| [Claude Opus 5.5](https://uplinkswitch.ai/models/claude-opus-5-5) | `claude-opus-5-5` | $2.80 | $10.00 | $4.00 / $20.00 |
| [Gemini 3.1 Pro Preview](https://uplinkswitch.ai/models/gemini-3.1-pro-preview) | `gemini-3.1-pro-preview` | $1.20 | $7.20 | $2.00 / $12.00 |
| [Grok 4.6](https://uplinkswitch.ai/models/grok-4.6) | `grok-4.6` | $0.60 | $1.80 | $2.00 / $6.00 |

USD per million tokens, live from GET /v1/catalog.

A chain call that sends 4,000 input tokens (prompt, retrieved context and history) and gets 500 back costs $0.0063 on Claude Sonnet 5.5, against $0.013 at Anthropic's list price. A thousand of them a day is $6.30. Credit is prepaid from $10 with no subscription.

## Check it

Confirm the key before you run a chain:

shell

```
curl https://api.uplinkswitch.com/v1/models \
  -H "Authorization: Bearer $UPLINKSWITCH_API_KEY" \
  -H "HTTP-Referer: https://uplinkswitch.ai" \
  -H "X-Title: LangChain"
```

A list of model ids means the key works. Every snippet on this page ran against the live API on 2026-10-19 with langchain 1.4.6, langchain-openai 1.7.2 and @langchain/openai 1.6.2: invoke, stream, bind\_tools, create\_agent and with\_structured\_output on Claude Sonnet 5.5, GPT-6.1 Sol and DeepSeek V4 Pro.

## Errors

-   `AuthenticationError: Error code: 401` with `The API key is not valid.` means the key is wrong or revoked. With no key at all the message is `No API key was sent.`
-   `NotFoundError: Error code: 404` with `No such route.` means `base_url` lost its `/v1`.
-   A 404 with `No such model` means the model id is not in the catalog. Copy it from the [Models page](https://uplinkswitch.ai/models).
-   A 402 with the code `insufficient_balance` means the prepaid balance ran out. Requests work again after a top-up.

## Questions

### 

Yes. ChatOpenAI from langchain-openai, and ChatOpenAI from @langchain/openai in JavaScript, take a base URL. Set it to https://api.uplinkswitch.com/v1 and every chat model on the Models page answers through the same class, Claude and Gemini included.

### 

https://api.uplinkswitch.com/v1, ending at /v1. The OpenAI client adds /chat/completions itself. Without /v1 the API answers 404 with "No such route."

### 

Yes. Pass a Claude model id such as claude-sonnet-5-5 or claude-opus-5-5 as model. The request and the reply stay in the OpenAI format, tool calls included. langchain-anthropic is not needed.

### 

Its default json\_schema method sends response\_format, and in our run only GPT-6.1 Sol returned the object with it; Claude Sonnet 5.5 and DeepSeek V4 Pro answered in plain text and Pydantic raised a ValidationError. method="function\_calling" returned the object on all three.

### 

Each AIMessage carries usage\_metadata with input\_tokens and output\_tokens. Multiply by the per-million prices in the table above, or read the charge for each request on the Usage page of the console.

### 

Yes. create\_agent in langchain 1.x, which replaces LangGraph’s create\_react\_agent, takes the ChatOpenAI instance above as its model. It ran the tool and answered on Claude Sonnet 5.5, GPT-6.1 Sol and DeepSeek V4 Pro.

## Related

-   [SDK setup](https://uplinkswitch.ai/guides/sdks)
-   [Strands Agents setup](https://uplinkswitch.ai/guides/strands-agents)
-   [LiteLLM setup](https://uplinkswitch.ai/guides/litellm)
-   [Vercel AI SDK setup](https://uplinkswitch.ai/guides/vercel-ai-sdk)
-   [Claude Sonnet 5.5](https://uplinkswitch.ai/models/claude-sonnet-5-5)
-   [GPT-6.1 Sol](https://uplinkswitch.ai/models/gpt-6.1-sol)
-   [DeepSeek V4 Pro](https://uplinkswitch.ai/models/deepseek-v4-pro-0813)
-   [Model catalog](https://uplinkswitch.ai/models)
-   [LLM API price index](https://uplinkswitch.ai/pricing-index)
