Multi-Model Panel

Combine perspectives from multiple LLMs into a single selectable model

Run multiple models as advisors and one as the actor — all selectable as a single LLM.

python
from praisonaiagents import Agent

agent = Agent(
    name="Assistant",
    instructions="Answer thoughtfully.",
    llm={
        "provider": "panel",
        "references": ["gpt-4o", "anthropic/claude-3-5-sonnet"],
        "aggregator": "anthropic/claude-3-5-sonnet",
    },
)
agent.start("What are the trade-offs of this design?")

The user asks once; reference models advise and the aggregator produces the final answer.

Diagram

Multi-Model Panel

💬 User Prompt

🔍 Reference: gpt-4o

🔍 Reference: Claude

🧠 Aggregator

🔧 Tool Loop

✅ Final Answer

Quick Start

  1. Inline descriptor

    Describe the panel inline — no registration needed. The references advise, the aggregator writes the final answer.

    python
    from praisonaiagents import Agent
    
    agent = Agent(
        name="Assistant",
        instructions="Answer thoughtfully.",
        llm={
            "provider": "panel",
            "references": ["gpt-4o", "anthropic/claude-3-5-sonnet"],
            "aggregator": "anthropic/claude-3-5-sonnet",
        },
    )
    
    agent.start("Design a migration plan for moving from REST to GraphQL.")
  2. Named preset (reusable)

    Register a preset once and reference it by name — works from Python, YAML, CLI, and bots.

    python
    from praisonaiagents import Agent
    from praisonaiagents.llm import register_panel_preset
    
    register_panel_preset("deep", {
        "references": ["gpt-4o", "anthropic/claude-3-5-sonnet"],
        "aggregator": "anthropic/claude-3-5-sonnet",
    })
    
    agent = Agent(name="Researcher", llm="panel:deep")
    agent.start("What are the trade-offs of event sourcing?")

How It Works

Diagram
ToolsAggregator (acting model)References (tool-free)AgentUserToolsAggregator (acting model)References (tool-free)AgentUser“Design X”trimmed view (parallel)advisory text (cached per turn)prompt + reference guidance (tail-appended)tool calls (normal loop)resultsfinal answer

On every user turn the references run once (tool-free, trimmed view) and their advisory text is appended to the tail of the latest user turn — never to the system prompt, so Anthropic prompt caching on the system prefix stays intact. The aggregator then runs the normal tool loop with full tools, hooks, and sessions.

When To Use This vs. Other Model Features

Diagram

No

Yes, one model per task

Yes, backup on failure

Yes, score outputs

Yes, one synthesized answer per turn

Need multi-model perspective?

Use single model

Use model-router

Use model-fallback

Use llm-as-judge

Use multi-model-panel ✅

| Feature | What it does | What it does NOT do | |—Run multiple models as advisors and one as the actor — all selectable as a single LLM.

python
from praisonaiagents import Agent

agent = Agent(
    name="Assistant",
    instructions="Answer thoughtfully.",
    llm={"provider": "panel", "references": ["gpt-4o", "anthropic/claude-3-5-sonnet"], "aggregator": "anthropic/claude-3-5-sonnet"},
)
agent.start("Design a migration plan for moving from REST to GraphQL.")

The user prompts once; reference models advise and the aggregator produces the final answer.

|—|—| | model-router | Picks ONE model per task | Does not ensemble | | model-fallback | Backup on failure | Not parallel perspectives | | llm-as-judge | Scores outputs after-the-fact | Does not act as a model | | multi-model-panel | Multiple references advise + one aggregator acts as a single LLM | — |

Configuration Options

Agent(llm=...) accepts the panel in two equivalent forms:

python
# 1. Named preset (must register first)
agent = Agent(name="assistant", llm="panel:deep")

# 2. Inline dict descriptor (no registration needed)
agent = Agent(
    name="assistant",
    llm={
        "provider": "panel",
        "references": ["gpt-4o", "anthropic/claude-3-5-sonnet"],
        "aggregator": "anthropic/claude-3-5-sonnet",
        "enabled": True,
    },
)

Panel descriptor keys

KeyTypeDefaultDescription
aggregator (required)str—Model string that acts in the loop (e.g. "gpt-4o", "anthropic/claude-3-5-sonnet"). Inherits the full tool loop, hooks, and session.
references`list[str] \None`NoneAdvisory model strings called first, tool-free, with a trimmed view. Empty list = aggregator-alone.
enabledboolTrueWhen False, references are skipped entirely — behaves identically to selecting the aggregator directly (no added cost).
reference_temperaturefloat0.0Temperature passed to the advisory reference calls (kept deterministic by default for caching).
base_url`str \None`NoneBase URL forwarded to the underlying LLM and propagated to reference LLMs so they hit the same backend.
api_key`str \None`NoneAPI key forwarded to the underlying LLM and propagated to reference LLMs.
api_version`str \None`NoneAPI version forwarded to the underlying LLM and propagated to reference LLMs.
auth`object \None`NoneAuth object forwarded to the underlying LLM and propagated to reference LLMs.

Module helpers

Common Patterns

With tools (aggregator gets full tool loop)

python
from praisonaiagents import Agent
from praisonaiagents.tools import duckduckgo

agent = Agent(
    name="Research Assistant",
    llm="panel:deep",
    tools=[duckduckgo],
)

agent.start("Research the latest Anthropic releases and summarize.")

YAML

yaml
agent:
  name: assistant
  llm: panel:deep
  tools:
    - duckduckgo

Local models (Ollama, with base_url)

python
agent = Agent(
    name="Local Panel",
    llm={
        "provider": "panel",
        "references": ["ollama/llama3", "ollama/mistral"],
        "aggregator": "ollama/llama3",
        "base_url": "http://localhost:11434",
    },
)

Disabled panel (escape hatch)

python
agent = Agent(
    name="Assistant",
    llm={
        "provider": "panel",
        "references": ["gpt-4o"],
        "aggregator": "anthropic/claude-3-5-sonnet",
        "enabled": False,  # skip references; aggregator acts alone
    },
)

Behavioral Guarantees

  • Selectable like any model — flows through CLI --model panel:deep, YAML llm: panel:deep, bot /model panel:deep, and Python Agent(llm=...).
  • Prompt-cache safe — reference outputs are injected at the tail of the latest user turn, never on the system prompt or history.
  • Per-turn reference caching — references run once per user turn, cached across tool-loop iterations by a deterministic signature of the trimmed view. Bounded FIFO cache (max 128 entries).
  • Partial-failure tolerance — if one reference fails (network, credentials), it becomes a labeled (unavailable: reference call failed) note and the turn continues. The whole turn never fails just because a reference did.
  • Strict-provider safety — references get a trimmed view: system prompt dropped, tool-role messages dropped, tool_calls payloads dropped. Strict providers won’t 400 on orphan tool messages.
  • Recursion guard — a panel preset cannot reference another panel preset (rejected at config-validation time with ValueError).
  • enabled=False collapses cleanly — same cost as selecting the aggregator directly.
  • Tool-free references — references never see the tool schema and cannot emit tool calls. Only the aggregator acts.

Best Practices

Keep reference_temperature at 0.0

Deterministic reference outputs maximize cache hits and keep the aggregator’s view stable across tool-loop iterations.

Use 2-3 references max

Each reference is an extra API call per turn. Marginal value drops fast beyond two or three references, while cost grows linearly.

Pick a strong aggregator

The aggregator writes the final answer and runs the tool loop. It should be the most capable model in your panel, not necessarily the cheapest.

Don't nest panels

A panel preset can’t reference another panel preset — the config validator rejects it with ValueError. Keep panels flat.

Related