Model Parameter

One model parameter, one canonical name — model=

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

Diagram

One parameter, one name

✅ model=”gpt-4o”

🤖 Agent runs

⚠️ llm=”gpt-4o”

❌ llm= and model=

🚫 TypeError

Quick Start

  1. Use the canonical name
    python
    from praisonaiagents import Agent
    
    agent = Agent(
        instructions="Summarise the given article in three bullets.",
        model="gpt-4o",
    )
    
    agent.start("<article text>")
  2. The deprecated alias still works
    python
    from praisonaiagents import Agent
    
    agent = Agent(
        instructions="Summarise the given article.",
        llm="gpt-4o",
    )
  3. Passing both is refused
    python
    from praisonaiagents import Agent
    
    # ❌ Passing both is refused
    Agent(instructions="…", llm="gpt-4o", model="gpt-3.5-turbo")
    # TypeError: Agent() received both llm= and model=. They are the same
    #   parameter, so passing both is ambiguous. Pass only one; model= is
    #   the canonical name (llm= is a deprecated alias).

How It Works

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

Diagram

Yes

No

Yes — AgentTeam, AgentFlow,
or a media/specialist agent

No — bare Agent

Both llm= and model= set?

🚫 raise TypeError

Pick the non-None one

LLMConfig on a container
or media/specialist agent?

Unwrap to the bare .model string

Store the LLMConfig as-is

CallResult
Agent(model="gpt-4o")✅ Canonical. Preferred everywhere.
Agent(llm="gpt-4o")⚠️ Deprecated alias. Works, emits a DeprecationWarning.
Agent(llm="gpt-4o", model="gpt-3.5-turbo")❌ TypeError — same parameter, so passing both is ambiguous.
Agent(model=LLMConfig(model="gpt-4o", …))✅ Accepted. Stored as the LLMConfig object (bare Agent uses it directly).
VisionAgent(model=LLMConfig(model="gpt-4o", …)) (or any media/specialist agent)✅ Accepted. Unwrapped to the bare "gpt-4o" string; base_url / api_key on the config are dropped.
AgentTeam(model=LLMConfig(model="gpt-4o", …)) / AgentFlow(model=LLMConfig(model="gpt-4o", …))✅ Accepted. Unwrapped to the bare "gpt-4o" string before it fills in members. base_url / api_key / fallback_models on the config are dropped for containers today.

Where It Applies

The llm= / model= pair resolves the same way on every class below.

ClassAccepts model=Accepts llm= (deprecated)
Agent✅✅
AgentTeam✅✅
AgentFlow✅✅
VisionAgent✅✅
AudioAgent✅✅
OCRAgent✅✅
VideoAgent✅✅
EmbeddingAgent✅✅
ImageAgent✅✅
ContextAgent✅✅
CodeAgent✅✅
RealtimeAgent✅✅
python
from praisonaiagents import Agent, AgentTeam, Task

# Default model for members that did not name one themselves
team = AgentTeam(
    agents=[Agent(instructions="Researcher"), Agent(instructions="Writer")],
    tasks=[Task(description="Write a two-paragraph brief on quantum sensing.")],
    model="gpt-4o-mini",
)

team.start()

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.

python
from praisonaiagents import Agent

class MyBackend:
    model = "my-backend"
    def get_response(self, prompt, **kwargs):
        return "answer from my backend"

agent = Agent(instructions="Use my backend.", llm=MyBackend())
agent.start("hello")   # routed to MyBackend, not OpenAI

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.

python
from praisonaiagents import Agent

class MyAsyncBackend:
    model = "my-async-backend"
    async def get_response_async(self, prompt, **kwargs):
        return "answer from my async backend"

agent = Agent(instructions="Use my async backend.", llm=MyAsyncBackend())
agent.start("hello")

The agent detects on get_response and get_response_async, so any backend exposing either works — including the ScriptedModel test double from Offline Testing.

Diagram

Yes

No

Yes

No

🧩 Agent(llm=<object>)

Has get_response
or get_response_async?

✅ Adopted as backend
_using_custom_llm = True

Only chat / achat /
chat_completion / achat_completion?

⚠️ Not adopted
wrap it to expose get_response

❌ Falls through to string/dict path


Migration

I use llm= in every example

No code change is required — llm= still works. Move to model= at your convenience; it is the canonical name.

I pass both llm= and model= today

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.

I pass an LLMConfig to a specialised agent

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=.

I pass an LLMConfig to a container (AgentTeam / AgentFlow)

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.

I use CodeAgent(llm=…), RealtimeAgent(llm=…), AgentTeam(llm=…), or AgentFlow(llm=…)

Those four now also accept model= (canonical). The alias llm= still works.


Related