Python with AI Gateway: OpenAI and Anthropic SDKs
To get started with Python and AI Gateway, you can either call the OpenAI Chat Completions, OpenAI Responses, or Anthropic Messages API directly, or use the official OpenAI and Anthropic Python SDKs, which are covered below.
Install your preferred SDK:
pip install openaipip install anthropicpip install openaiimport os
from openai import OpenAI
client = OpenAI(
api_key=os.getenv('AI_GATEWAY_API_KEY'),
base_url='https://ai-gateway.vercel.sh/v1'
)
response = client.chat.completions.create(
model='anthropic/claude-opus-5',
messages=[
{'role': 'user', 'content': 'Explain quantum computing in one paragraph.'}
]
)
print(response.choices[0].message.content)import os
import anthropic
client = anthropic.Anthropic(
api_key=os.getenv('AI_GATEWAY_API_KEY'),
base_url='https://ai-gateway.vercel.sh'
)
message = client.messages.create(
model='anthropic/claude-opus-5',
max_tokens=1024,
messages=[
{'role': 'user', 'content': 'Explain quantum computing in one paragraph.'}
]
)
for block in message.content:
if block.type == "text":
print(block.text)import os
from openai import OpenAI
client = OpenAI(
api_key=os.getenv('AI_GATEWAY_API_KEY'),
base_url='https://ai-gateway.vercel.sh/v1',
)
response = client.responses.create(
model='anthropic/claude-opus-5',
input='Explain quantum computing in one paragraph.',
)
print(response.output_text)All SDKs support the same authentication methods. Use an API key for local development or OIDC tokens for Vercel deployments.
import os
# Option 1: API key (recommended for local development)
api_key = os.getenv('AI_GATEWAY_API_KEY')
# Option 2: OIDC token (automatic on Vercel deployments)
api_key = os.getenv('VERCEL_OIDC_TOKEN')
# Fallback pattern for code that runs both locally and on Vercel
api_key = os.getenv('AI_GATEWAY_API_KEY') or os.getenv('VERCEL_OIDC_TOKEN')Stream responses for real-time output in chat applications or long-running generations.
import os
from openai import OpenAI
client = OpenAI(
api_key=os.getenv('AI_GATEWAY_API_KEY'),
base_url='https://ai-gateway.vercel.sh/v1'
)
stream = client.chat.completions.create(
model='anthropic/claude-opus-5',
messages=[
{'role': 'user', 'content': 'Write a short story about a robot.'}
],
stream=True
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end='', flush=True)import os
import anthropic
client = anthropic.Anthropic(
api_key=os.getenv('AI_GATEWAY_API_KEY'),
base_url='https://ai-gateway.vercel.sh'
)
with client.messages.stream(
model='anthropic/claude-opus-5',
max_tokens=1024,
messages=[
{'role': 'user', 'content': 'Write a short story about a robot.'}
]
) as stream:
for text in stream.text_stream:
print(text, end='', flush=True)import os
from openai import OpenAI
client = OpenAI(
api_key=os.getenv('AI_GATEWAY_API_KEY'),
base_url='https://ai-gateway.vercel.sh/v1',
)
stream = client.responses.create(
model='anthropic/claude-opus-5',
input='Write a short story about a robot.',
stream=True,
)
for event in stream:
if event.type == 'response.output_text.delta':
print(event.delta, end='', flush=True)Both the OpenAI and Anthropic SDKs provide async clients for use with asyncio.
import os
import asyncio
from openai import AsyncOpenAI
client = AsyncOpenAI(
api_key=os.getenv('AI_GATEWAY_API_KEY'),
base_url='https://ai-gateway.vercel.sh/v1'
)
async def main():
response = await client.chat.completions.create(
model='anthropic/claude-opus-5',
messages=[
{'role': 'user', 'content': 'Hello!'}
]
)
print(response.choices[0].message.content)
asyncio.run(main())import os
import asyncio
import anthropic
client = anthropic.AsyncAnthropic(
api_key=os.getenv('AI_GATEWAY_API_KEY'),
base_url='https://ai-gateway.vercel.sh'
)
async def main():
message = await client.messages.create(
model='anthropic/claude-opus-5',
max_tokens=1024,
messages=[
{'role': 'user', 'content': 'Hello!'}
]
)
for block in message.content:
if block.type == "text":
print(block.text)
asyncio.run(main())import os
import asyncio
from openai import AsyncOpenAI
client = AsyncOpenAI(
api_key=os.getenv('AI_GATEWAY_API_KEY'),
base_url='https://ai-gateway.vercel.sh/v1',
)
async def main():
response = await client.responses.create(
model='anthropic/claude-opus-5',
input='Hello!',
)
print(response.output_text)
asyncio.run(main())Enable models to call functions you define. This example shows a weather tool that the model can invoke.
import os
import json
from openai import OpenAI
client = OpenAI(
api_key=os.getenv('AI_GATEWAY_API_KEY'),
base_url='https://ai-gateway.vercel.sh/v1'
)
tools = [{
'type': 'function',
'function': {
'name': 'get_weather',
'description': 'Get the current weather for a location',
'parameters': {
'type': 'object',
'properties': {
'location': {
'type': 'string',
'description': 'City name, e.g. San Francisco'
}
},
'required': ['location']
}
}
}]
response = client.chat.completions.create(
model='anthropic/claude-opus-5',
messages=[
{'role': 'user', 'content': "What's the weather in Tokyo?"}
],
tools=tools
)
# Check if the model wants to call a tool
if response.choices[0].message.tool_calls:
tool_call = response.choices[0].message.tool_calls[0]
args = json.loads(tool_call.function.arguments)
print(f"Model wants to call: {tool_call.function.name}")
print(f"With arguments: {args}")import os
import anthropic
client = anthropic.Anthropic(
api_key=os.getenv('AI_GATEWAY_API_KEY'),
base_url='https://ai-gateway.vercel.sh'
)
tools = [{
'name': 'get_weather',
'description': 'Get the current weather for a location',
'input_schema': {
'type': 'object',
'properties': {
'location': {
'type': 'string',
'description': 'City name, e.g. San Francisco'
}
},
'required': ['location']
}
}]
message = client.messages.create(
model='anthropic/claude-opus-5',
max_tokens=1024,
messages=[
{'role': 'user', 'content': "What's the weather in Tokyo?"}
],
tools=tools
)
# Check if the model wants to call a tool
for block in message.content:
if block.type == 'tool_use':
print(f"Model wants to call: {block.name}")
print(f"With arguments: {block.input}")import os
from openai import OpenAI
client = OpenAI(
api_key=os.getenv('AI_GATEWAY_API_KEY'),
base_url='https://ai-gateway.vercel.sh/v1',
)
response = client.responses.create(
model='openai/gpt-6-astra',
input='What is the weather in Tokyo?',
tools=[
{
'type': 'function',
'name': 'get_weather',
'description': 'Get the current weather for a location',
'parameters': {
'type': 'object',
'properties': {
'location': {'type': 'string'},
},
'required': ['location'],
},
},
],
)
for item in response.output:
if item.type == 'function_call':
print(f'Call: {item.name}({item.arguments})')See Chat Completions tool calls, OpenAI Responses API tool calling, or Anthropic Messages tool calls for more examples.
Generate responses that conform to a JSON schema for reliable parsing.
import os
from openai import OpenAI
client = OpenAI(
api_key=os.getenv('AI_GATEWAY_API_KEY'),
base_url='https://ai-gateway.vercel.sh/v1'
)
response = client.chat.completions.create(
model='anthropic/claude-opus-5',
messages=[
{'role': 'user', 'content': 'Extract: John is 30 years old and lives in NYC'}
],
response_format={
'type': 'json_schema',
'json_schema': {
'name': 'person',
'schema': {
'type': 'object',
'properties': {
'name': {'type': 'string'},
'age': {'type': 'integer'},
'city': {'type': 'string'}
},
'required': ['name', 'age', 'city']
}
}
}
)
import json
data = json.loads(response.choices[0].message.content)
print(data) # {'name': 'John', 'age': 30, 'city': 'NYC'}See structured outputs for more details.
Each surface takes attachments as an array of content parts in place of a plain string, but the part names differ. Read the file, base64-encode it, and use the shape for your surface:
import base64
import os
from openai import OpenAI
client = OpenAI(
api_key=os.getenv('AI_GATEWAY_API_KEY'),
base_url='https://ai-gateway.vercel.sh/v1'
)
with open('diagram.png', 'rb') as f:
image_base64 = base64.b64encode(f.read()).decode()
completion = client.chat.completions.create(
model='anthropic/claude-opus-5',
messages=[
{
'role': 'user',
'content': [
{'type': 'text', 'text': 'Describe this image in one sentence.'},
{
'type': 'image_url',
'image_url': {'url': f'data:image/png;base64,{image_base64}'}
}
]
}
]
)
print(completion.choices[0].message.content)import base64
import os
import anthropic
client = anthropic.Anthropic(
api_key=os.getenv('AI_GATEWAY_API_KEY'),
base_url='https://ai-gateway.vercel.sh'
)
with open('diagram.png', 'rb') as f:
image_base64 = base64.b64encode(f.read()).decode()
message = client.messages.create(
model='anthropic/claude-opus-5',
max_tokens=1024,
messages=[
{
'role': 'user',
'content': [
{'type': 'text', 'text': 'Describe this image in one sentence.'},
{
'type': 'image',
'source': {
'type': 'base64',
'media_type': 'image/png',
'data': image_base64
}
}
]
}
]
)
for block in message.content:
if block.type == "text":
print(block.text)import base64
import os
from openai import OpenAI
client = OpenAI(
api_key=os.getenv('AI_GATEWAY_API_KEY'),
base_url='https://ai-gateway.vercel.sh/v1'
)
with open('diagram.png', 'rb') as f:
image_base64 = base64.b64encode(f.read()).decode()
response = client.responses.create(
model='anthropic/claude-opus-5',
input=[
{
'role': 'user',
'content': [
{'type': 'input_text', 'text': 'Describe this image in one sentence.'},
{
'type': 'input_image',
'image_url': f'data:image/png;base64,{image_base64}'
}
]
}
]
)
print(response.output_text)PDFs work the same way with a different part type. On Anthropic Messages that is a document part:
import base64
import os
import anthropic
client = anthropic.Anthropic(
api_key=os.getenv('AI_GATEWAY_API_KEY'),
base_url='https://ai-gateway.vercel.sh'
)
with open('report.pdf', 'rb') as f:
pdf_base64 = base64.b64encode(f.read()).decode()
message = client.messages.create(
model='anthropic/claude-opus-5',
max_tokens=1024,
messages=[
{
'role': 'user',
'content': [
{'type': 'text', 'text': 'What total does this document state?'},
{
'type': 'document',
'source': {
'type': 'base64',
'media_type': 'application/pdf',
'data': pdf_base64
}
}
]
}
]
)For the per-surface reference, see Chat Completions file attachments, Responses file attachments, and Anthropic file attachments.
Reasoning models work through a problem before answering. On the Responses API, pass reasoning with an effort level:
import os
from openai import OpenAI
client = OpenAI(
api_key=os.getenv('AI_GATEWAY_API_KEY'),
base_url='https://ai-gateway.vercel.sh/v1',
)
response = client.responses.create(
model='openai/gpt-6-astra',
input='Explain the Monty Hall problem step by step.',
reasoning={'effort': 'medium'},
max_output_tokens=2048,
)
print(response.output_text)The Chat Completions API takes the same idea through extra_body, since the OpenAI Python client does not have a typed field for it:
import os
from openai import OpenAI
client = OpenAI(
api_key=os.getenv('AI_GATEWAY_API_KEY'),
base_url='https://ai-gateway.vercel.sh/v1',
)
completion = client.chat.completions.create(
model='openai/gpt-6-astra',
messages=[{'role': 'user', 'content': 'Explain the Monty Hall problem.'}],
extra_body={'reasoning': {'effort': 'medium'}},
)
print(completion.choices[0].message.reasoning)
print(completion.choices[0].message.content)Each surface names and shapes this differently, and Anthropic models have their own constraints. See Responses reasoning, Chat Completions reasoning, and Anthropic extended thinking.
Python frameworks with dedicated AI Gateway support:
| Framework | Integration |
|---|---|
| Pydantic AI | Native VercelProvider for type-safe agents |
| LlamaIndex | llama-index-llms-vercel-ai-gateway package |
| LiteLLM | Use vercel_ai_gateway/ model prefix |
| LangChain | Configure via Chat Completions endpoint |
See Framework Integrations for the complete list and setup guides.
For complete API documentation, see:
- OpenAI Chat Completions API: Chat completions, embeddings, streaming, tool calls, structured outputs, image inputs, and provider routing
- OpenAI Responses API: Streaming, tool calling, structured output, and reasoning
- Anthropic Messages API: Streaming, tool calls, extended thinking, web search, and file attachments
Was this helpful?