OpenAI-Compatible Endpoints

Point PraisonAI at any /v1 host with base_url + api_key — no provider prefix needed

Point PraisonAI at any OpenAI-compatible /v1 host by setting base_url and api_key on the Agent — bare catalog model ids are fine, no provider/ prefix required.

Diagram

OpenAI-Compatible Routing

📝 Agent
llm=’deepseek-v4-flash’
base_url=’Unsupported markdown: link’

🔌 Auto-prefix
openai/deepseek-v4-flash

🌐 /v1/chat/completions
on your host

✅ Response

Quick Start

  1. Simplest form

    Pass base_url and api_key at the top level with a bare model id.

    python
    from praisonaiagents import Agent
    
    agent = Agent(
        name="assistant",
        instructions="You are a helpful assistant",
        llm="deepseek-v4-flash",
        base_url="https://api.pzero.studio/v1",
        api_key="your-key-or-empty-if-public",
    )
    agent.start("Explain what an OpenAI-compatible endpoint is in one paragraph.")
  2. Environment-variable variant

    Set the host once with environment variables, then keep the code clean.

    bash
    export OPENAI_API_BASE=https://api.pzero.studio/v1
    export OPENAI_API_KEY=your-key
    python
    from praisonaiagents import Agent
    
    agent = Agent(
        name="assistant",
        instructions="You are a helpful assistant",
        llm="deepseek-v4-flash",
    )
    agent.start("Hi")
  3. Dict form (equivalent)

    The dict form does the same thing when you prefer to bundle connection settings inside llm.

    python
    from praisonaiagents import Agent
    
    agent = Agent(
        name="assistant",
        instructions="You are a helpful assistant",
        llm={
            "model": "deepseek-v4-flash",
            "api_base": "https://api.pzero.studio/v1",
            "api_key": "",
        },
    )
    agent.start("Hello")

How It Works

PraisonAI routes a bare model id plus a base_url through the OpenAI-compatible client.

Diagram
Your /v1 hostPraisonAI LLMAgentUserYour /v1 hostPraisonAI LLMAgentUserBare model + base_url →route as openai/deepseek-v4-flashagent.start(“…”)model=’deepseek-v4-flash’, base_url setPOST /v1/chat/completionschoices[0].messagetextresponse
SituationWhat happens
Bare model + base_url setRouted as openai/<model> to <base_url>
Prefixed model (e.g. anthropic/…, ollama/…, openai/…)Passed through unchanged
Bare model with no base_url and no OPENAI_API_BASEUses OpenAI default (api.openai.com/v1)

Configuration Options

Set these top-level Agent parameters for any OpenAI-compatible host.

OptionTypeDefaultDescription
llmstr \dictrequiredCatalog model id (e.g. "deepseek-v4-flash") or a full dict {model, api_base, api_key}
base_urlstrNoneOpenAI-compatible /v1 root, e.g. https://api.pzero.studio/v1
api_keystrNoneAPI key for the host (may be empty for public catalogs)
Agent SDK Reference

Full parameter surface for the Agent class.


Common Patterns

Every host uses the same 5-line pattern — only base_url and the catalog id change.

P0 / pzero.studio

python
from praisonaiagents import Agent

agent = Agent(
    name="assistant",
    llm="deepseek-v4-flash",
    base_url="https://api.pzero.studio/v1",
    api_key="",
)
agent.start("Hello")

DeepInfra

python
from praisonaiagents import Agent

agent = Agent(
    name="assistant",
    llm="meta-llama/Meta-Llama-3-8B-Instruct",
    base_url="https://api.deepinfra.com/v1/openai",
    api_key="your-deepinfra-key",
)
agent.start("Hello")

Fireworks

python
from praisonaiagents import Agent

agent = Agent(
    name="assistant",
    llm="accounts/fireworks/models/llama-v3-8b-instruct",
    base_url="https://api.fireworks.ai/inference/v1",
    api_key="your-fireworks-key",
)
agent.start("Hello")

Together AI

python
from praisonaiagents import Agent

agent = Agent(
    name="assistant",
    llm="meta-llama/Llama-3-8b-chat-hf",
    base_url="https://api.together.xyz/v1",
    api_key="your-together-key",
)
agent.start("Hello")

vLLM

You can also use the vllm/… / hosted_vllm/… prefix directly — see Local prefix route for the adapter with tool-call repair.

python
from praisonaiagents import Agent

agent = Agent(
    name="assistant",
    llm="meta-llama/Meta-Llama-3-8B-Instruct",
    base_url="http://localhost:8000/v1",
    api_key="not-needed",
)
agent.start("Hello")

LM Studio

You can also use the lm_studio/… prefix directly — see Local prefix route for the adapter with tool-call repair.

python
from praisonaiagents import Agent

agent = Agent(
    name="assistant",
    llm="local-model",
    base_url="http://localhost:1234/v1",
    api_key="not-needed",
)
agent.start("Hello")

Company gateway

python
from praisonaiagents import Agent

agent = Agent(
    name="assistant",
    llm="your-catalog-id",
    base_url="https://gateway.company.internal/v1",
    api_key="your-key",
)
agent.start("Hello")

Local prefix route (tool-call repair)

For a locally-served OpenAI-compatible server — LM Studio, vLLM, llama.cpp’s llama-server — use a dedicated prefix instead of base_url + bare model. PraisonAI recognises these prefixes and selects a LocalOpenAIAdapter that keeps the standard OpenAI message shape and adds a tool-call repair budget of 2 — a safety net for the malformed JSON tool calls small local models occasionally emit.

python
from praisonaiagents import Agent

def get_weather(city: str) -> str:
    return f"{city}: 21°C"

agent = Agent(llm="lm_studio/qwen2.5-7b-instruct", tools=[get_weather])
agent.start("What is the weather in Paris?")

Every local prefix works the same way — swap the prefix, keep your tools:

python
from praisonaiagents import Agent

def get_weather(city: str) -> str:
    return f"{city}: 21°C"

# LM Studio
agent = Agent(llm="lm_studio/qwen2.5-7b-instruct", tools=[get_weather])

# vLLM (self-hosted)
agent = Agent(llm="vllm/meta-llama/Llama-3.1-8B-Instruct", tools=[get_weather])

# OpenAI-compatible vLLM (LiteLLM's hosted_vllm/ spelling)
agent = Agent(llm="hosted_vllm/Qwen2.5-7B", tools=[get_weather])

# llama.cpp
agent = Agent(llm="llamacpp/qwen2.5", tools=[get_weather])
PrefixServerAdaptermax_tool_repairsText-based tool-call recoveryApplies on
lm_studio/…, lmstudio/…LM StudioLocalOpenAIAdapter2✅sync, async
vllm/…, hosted_vllm/…vLLMLocalOpenAIAdapter2✅sync, async
llamacpp/…, llama_cpp/…llama.cpp llama-serverLocalOpenAIAdapter2✅sync, async
ollama_chat/…Ollama (tool-calling)OllamaAdapter2✅sync, async
ollama/…OllamaOllamaAdapter2✅sync, async
huggingface/…Hosted Inference API (not local)DefaultAdapter0❌—
Hosted OpenAI-compatible via base_urlHosted /v1 APIDefaultAdapter0❌—

Local-server prefixes (lm_studio/, vllm/, hosted_vllm/, llamacpp/, llama_cpp/) also inherit text-based tool-call recovery: when the model emits a tool call as JSON text — common after a repair prompt on a small local model — the adapter parses it and dispatches the tool call anyway. A hosted OpenAI-compatible endpoint (a base_url pointing at a hosted API) deliberately does not get this behaviour: a hosted model returning JSON prose must never have it silently interpreted as a tool call. Recovery fires on both sync and async response paths as of PraisonAI PR #4940. Before that release, only agent.start() / agent.chat() recovered a text-emitted tool call — agent.astart() / agent.achat() would silently ignore it. The streaming path does not yet have this recovery on any adapter. See Tool Call Self-Repair → Text-based tool-call recovery.

Explicit max_tool_repairs on the Agent always wins:

python
from praisonaiagents import Agent

agent = Agent(llm="lm_studio/qwen", max_tool_repairs=5)  # ends up as 5

Streaming with tools keeps working on LM Studio, vLLM, and llama.cpp — the LocalOpenAIAdapter deliberately does not inherit Ollama’s stream-disabling behaviour, because these servers stream tool calls correctly.

Diagram

Same host across many agents
or non-standard /v1 path

One-off script + tool calling
on a small local model

Local OpenAI-compatible server?

Use base_url + bare model

Use lm_studio/… vllm/… llamacpp/…
gets LocalOpenAIAdapter + repair budget


Choosing Which Style to Use

Pick the routing style that matches what you connect to.

Diagram

Named provider
OpenAI, Anthropic, Gemini

OpenAI-compatible /v1 host

Generic host

Local server + tool calling

Self-hosted LiteLLM Proxy
as a gateway

Custom Python provider class

What are you connecting to?

Use provider prefix
e.g. anthropic/claude-sonnet-4-5

Local server?
LM Studio · vLLM · llama.cpp

Use base_url + bare model

Use local prefix
lm_studio/… vllm/… llamacpp/…

Use litellm-proxy/model
with LITELLM_PROXY_* env

Register in Custom Provider Registry


Which Adapter Am I Getting?

A base_url says where the server is, not what it serves — so a local URL only implies Ollama for a model a local runtime could plausibly host.

Diagram

Yes

No

Yes

No

Yes

No

Yes

No

📝 model + base_url

ollama/ prefix?

✅ OllamaAdapter

Closed-weights name?
gpt-* o1-* claude* gemini-*

✅ Native adapter
Default · Anthropic · Gemini

Local base_url?
ollama or :11434

claude / gemini
in name?

✅ DefaultAdapter


Best Practices

Use base_url at the top level for one-off hosts

The top-level base_url is cleaner than the dict form for single-agent scripts. Reach for the dict form only when you want connection settings bundled inside llm.

Use env vars when the host is fixed

Set OPENAI_API_BASE and OPENAI_API_KEY when the host stays the same across runs. This keeps code portable across environments.

Keep embeddings on their own provider

Most OpenAI-compatible chat hosts don’t serve embeddings. Configure embeddings separately — see the Embeddings docs.

Don't add openai/ yourself

PraisonAI adds the openai/ prefix internally when base_url is set. Adding it manually is harmless but unnecessary.

Mixing base_url with hosted model names is safe

Closed-weights models — gpt-, o1-, o3-, chatgpt-, claude, gemini- — keep their native adapter regardless of base_url. Setting a local base_url (even http://localhost:11434/v1) no longer reassigns them to Ollama.

The exception is open-weights families — llama, gemma, mistral, qwen, deepseek, phi — which a local server can actually host. Behind a local base_url these are treated as Ollama, unlocking the tool-call repair budget. See Mixing local and hosted models for the full rules.


Related