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.
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.
| Value | When 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.
| Exception | Raised by | When | Useful attributes |
|---|---|---|---|
AgentNotFound | get_agent() | No agent with that name exists, or it is inactive | e.name |
AgentDisabled | agent.run() | Agent exists but is toggled off | e.name |
PromptRenderError | agent.run() | A {{variable}} placeholder was not supplied | e.missing_vars |
BudgetExceeded | agent.run() | The provider's monthly spend limit was reached | e.provider_name, e.budget_limit |
RateLimitExceeded | agent.run() | The provider's rate limit was hit | e.retry_after_seconds |
LLMTimeoutError | agent.run() | The LLM request timed out | n/a |
LLMAPIError | agent.run() | The provider returned an API error | e.status_code, e.original_error |
OutputParseError | agent.run() | Output is JSON but could not be parsed | n/a |
OutputValidationError | agent.run() | Parsed JSON does not match the schema | e.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.