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·Models

Python

LangChain talks to UplinkSwitch through its OpenAI integration. Install it, create a key in the 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, 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

ModelModel idInput / 1MOutput / 1MDeveloper list, in / out
Claude Sonnet 5.5claude-sonnet-5-5$1.20$3.00$2.00 / $10.00
GPT-6.1 Solgpt-6.1-sol$0.60$3.00$2.00 / $10.00
DeepSeek V4 Pro 0813deepseek-v4-pro-0813$0.792$1.188$1.32 / $3.96
Claude Opus 5.5claude-opus-5-5$2.80$10.00$4.00 / $20.00
Gemini 3.1 Pro Previewgemini-3.1-pro-preview$1.20$7.20$2.00 / $12.00
Grok 4.6grok-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.
  • 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.