Skip to main content

Running Agents

Once an agent is configured in the App Panel, you run it by calling get_agent() to look it up and agent.run() to execute it. This page covers every way to call an agent, from the simplest one-liner to files, memory sessions, JSON output, and background tasks.

The basics

from zango.ai import get_agent

agent = get_agent("your-agent-name")
response = agent.run(input="Summarise the latest orders.")

print(response.content) # str: the LLM's text response
print(response.cost_usd) # float: cost of this invocation in USD
print(response.usage.input_tokens)
print(response.usage.output_tokens)

get_agent() looks up the agent by name in the current tenant's schema. It raises AgentNotFound if the name does not match or the agent is disabled. agent.run() always returns an LLMResponse, and every invocation is logged automatically. See Invocation Logs.

Input modes

There are three ways to provide input to agent.run(). The first non-None value wins.

Plain string (input=)

The simplest call. Pass a string directly as the user message. Use this when the agent has a system prompt but no user prompt template.

agent = get_agent("support-agent")
response = agent.run(input="What are the refund policies?")
print(response.content)

Prompt variables (variables= and system_variables=)

When the agent has a User Prompt template with {{placeholders}}, pass a dict to render it via variables=. If the System Prompt also has placeholders, pass those via system_variables=. The two dicts are independent.

agent = get_agent("patient-summary-agent")
response = agent.run(
variables={"patient_id": 42, "question": "Summarise this patient's recent visits."},
system_variables={"department": "cardiology", "protocol_version": "2026-Q1"},
triggered_by="user",
)
print(response.content)

If system_variables is omitted, the system prompt is used as-is.

Full message list (messages=)

For multi-turn conversations or manual history injection, pass a list of LLMMessage objects directly. This bypasses the agent's prompt template.

from zango.ai import get_agent, LLMMessage

agent = get_agent("chat-agent")
response = agent.run(
messages=[
LLMMessage(role="user", content="What's the capital of France?"),
LLMMessage(role="assistant", content="Paris."),
LLMMessage(role="user", content="And what's its population?"),
],
triggered_by="user",
)

File attachments

Pass one or more LLMFile objects via files= to send documents or images alongside the prompt. Files work with all three input modes.

from zango.ai import get_agent, LLMFile

agent = get_agent("report-analyser")

# From a Django model file field (the most common case)
response = agent.run(
input="Summarise the key findings from this report.",
files=[LLMFile.from_django_file(report.report_file)],
triggered_by="user",
)

# From raw bytes in memory
response = agent.run(
input="Extract the total and line items from this invoice.",
files=[LLMFile.from_bytes(pdf_bytes, media_type="application/pdf")],
triggered_by="system",
)

# From a public URL (the provider fetches it directly)
response = agent.run(
input="Describe this image and suggest tags.",
files=[LLMFile.from_url("https://cdn.example.com/product-photo.jpg")],
triggered_by="user",
)

Pass a list to send multiple attachments in one call. Other constructors include LLMFile.from_django_file(request.FILES["prescription"]) for request uploads.

Memory sessions

When an agent has Short-term memory enabled, it retains conversation history across agent.run() calls within the same session.

agent = get_agent("support-agent")

# First turn: omit session_id, the agent generates one
response = agent.run(input="I need help resetting my password.", triggered_by="user")
session_id = response.session_id # save for subsequent turns

# Continuing: pass the same session_id to load prior history
response = agent.run(
input="The reset link says it's expired.",
session_id=session_id,
triggered_by="user",
)
print(response.content)

Persist response.session_id (in the browser session, a database record, or an API response) and pass it back on the next call. Call agent.clear_session(session_id) to deactivate a session and delete its stored messages.

note

Memory stores text content only. File attachments are replaced with [file: attachment] placeholders in the session history to avoid storing large base64 blobs.

JSON output

When an agent's Output Schema is JSON, the response includes a parsed_content attribute with the already-parsed dict.

agent = get_agent("structured-extractor")
response = agent.run(variables={"document_id": 7}, triggered_by="user")

# response.content is the raw JSON string
# response.parsed_content is the parsed dict (validated against the schema if configured)
data = response.parsed_content
print(data["total_amount"], data["line_items"])

If the response cannot be parsed, OutputParseError is raised. If a schema is configured and the response does not match, OutputValidationError is raised.

from zango.ai.exceptions import OutputParseError, OutputValidationError

try:
response = agent.run(variables={"document_id": 7}, triggered_by="user")
data = response.parsed_content
except OutputParseError:
... # LLM returned invalid JSON
except OutputValidationError as e:
print(e.errors) # JSON didn't match the configured schema

Running from an async task

Use triggered_by="task" when running an agent from a background job. Zango's tenant context is set automatically inside task execution, turning agent.run() into an autonomous worker.

from zango.apps.tasks.base import BaseTask


class NightlyPatientSummaryTask(BaseTask):
name = "nightly_patient_summary"

def run(self):
from zango.ai import get_agent
from .models import Patient

agent = get_agent("patient-summary-agent")
for patient in Patient.objects.filter(flagged_for_review=True):
response = agent.run(
variables={"patient_id": patient.id,
"question": "Summarise recent activity and flag concerns."},
triggered_by="task",
)
patient.ai_summary = response.content
patient.save(update_fields=["ai_summary"])

The triggered_by parameter

Every agent.run() call requires a triggered_by value. It is stored in invocation history for auditing.

ValueWhen to use
"user"HTTP request triggered by a logged-in user
"task"Background job or scheduled task
"system"Programmatic call with no direct user action

The response object

response.content # str: final text response from the LLM
response.parsed_content # dict | None: parsed JSON (when output_schema=JSON)
response.session_id # str | None: memory session ID (when memory is enabled)
response.cost_usd # float: total cost of this invocation
response.usage.input_tokens # int
response.usage.output_tokens # int
response.model # str: actual model used
response.latency_ms # int: total request time in milliseconds

Error handling

All exceptions inherit from ZangoAIError and import from zango.ai.exceptions.

ExceptionRaised byWhenUseful attributes
AgentNotFoundget_agent()No agent with that name exists, or it is inactivee.name
AgentDisabledagent.run()Agent exists but is toggled offe.name
PromptRenderErroragent.run()A {{variable}} placeholder was not suppliede.missing_vars
BudgetExceededagent.run()The provider's monthly spend limit was reachede.provider_name, e.budget_limit
RateLimitExceededagent.run()The provider's rate limit was hite.retry_after_seconds
LLMTimeoutErroragent.run()The LLM request timed outn/a
LLMAPIErroragent.run()The provider returned an API errore.status_code, e.original_error
OutputParseErroragent.run()Output is JSON but could not be parsedn/a
OutputValidationErroragent.run()Parsed JSON does not match the schemae.field, e.errors
from zango.ai import get_agent
from zango.ai.exceptions import AgentNotFound, ZangoAIError

try:
agent = get_agent("my-agent")
response = agent.run(variables={"patient_id": 42}, triggered_by="user")
except AgentNotFound:
... # name doesn't exist or agent is inactive
except ZangoAIError:
... # any other AI framework error (see table above)

Next steps

Every agent.run() call is recorded automatically. Use Invocation Logs to inspect prompts, tool calls, costs, and debug failures.