Skip to main content
model= is the canonical name for the model on every agent class; llm= is a deprecated alias for it.

Quick Start

1

Use the canonical name

2

The deprecated alias still works

llm= still works but emits a DeprecationWarning. Move to model= at your convenience.
3

Passing both is refused


How It Works

Every agent class routes llm= and model= through one resolver so the rule is identical everywhere.

Where It Applies

The llm= / model= pair resolves the same way on every class below.
manager_llm= on AgentTeam / AgentFlow is separate and unchanged — it is the hierarchical manager’s model and never touches the members.

Custom LLM objects

Pass any object with a get_response or get_response_async method to llm= and the agent uses it as its backend instead of the OpenAI default. The tool loop calls llm_instance.get_response(**kwargs) (or its async twin), so those are the two surfaces the agent detects on.
An async-only backend works too — expose get_response_async and the async tool loop drives it. Either method alone is enough; you do not need both.
The agent detects on get_response and get_response_async, so any backend exposing either works — including the ScriptedModel test double from Offline Testing.
What is not adopted. praisonaiagents/llm/protocols.py also defines LLMProviderProtocol (chat / achat) and UnifiedLLMProtocol (chat_completion / achat_completion). Those are provider-side protocols for other subsystems — the Agent tool loop drives get_response / get_response_async only. A backend exposing only chat / chat_completion is not picked up by Agent(llm=<obj>); wrap it in a small class that exposes get_response, or use it as a plain provider.
Before PraisonAI #4929, passing your own model object fell through every branch to the plain OpenAI path: self.llm became the object itself and _using_custom_llm stayed False, so every turn went to OpenAI under a model name that was really a repr(). #4929 adopted get_response-shaped backends; #4959 refined the detection to get_response and get_response_async and pinned it to the surface the tool loop can actually drive.

Migration

No code change is required — llm= still works. Move to model= at your convenience; it is the canonical name.
Pick one. model= is the canonical name. Passing both now raises TypeError because the two are the same parameter and guessing a winner could change which vendor is billed.
On VisionAgent, AudioAgent, OCRAgent, VideoAgent, EmbeddingAgent, CodeAgent, RealtimeAgent, ImageAgent, and ContextAgent you no longer need to unwrap an LLMConfig yourself. The class stores its .model string and keeps its own base_url= / api_key=.
AgentTeam(llm=LLMConfig(...)) and AgentFlow(llm=LLMConfig(...)) unwrap the config to its .model string before filling in members. Before this fix, the raw LLMConfig was pushed into every member and each member’s chat() returned None silently. base_url, api_key, auth, and fallback_models on the config are dropped for containers today — pin those on the individual member Agent(s) if you need them.
Those four now also accept model= (canonical). The alias llm= still works.
Passing LLMConfig(...) to AgentTeam or AgentFlow today keeps only .model — base_url, api_key, auth, and fallback_models are dropped. Pin those on the individual member Agent(s) when you need a custom endpoint, alternate credentials, or a fallback chain per member.

LLM Config

Pass an LLMConfig object to model= for base_url, api_key, and fallbacks.

Legacy Agent Parameters

Other deprecated Agent() parameters and their replacements.