Skip to main content
Every agent records its token usage; read the running total whenever you need it. Token accounting is on for every agent that runs through the native OpenAI path — the default when you pass a bare model name like "gpt-4o-mini". You don’t turn it on, you just read it back.

Quick Start

1

Run an agent and read the total

A bare Agent(llm="gpt-4o-mini") records its usage automatically. Read it back with the global collector:
The numbers are real spend — no metrics=True, no verbose, no display flag required.
2

Break usage down per agent

Pass a name to each agent and the collector rolls usage up under by_agent:
Agents built with a real LLM instance can also carry a stable agent_id alongside the display name. The collector’s by_agent keying matches whichever attribution the runtime installed (current_agent_name today; scoped team views still filter by Agent.name).

How It Works

Accounting happens inside the native OpenAIClient after every successful completion — one record per tool-loop iteration — and lands in the global TokenCollector.
Token accounting is on by default and does not depend on output="verbose", metrics=True, or any display flag. A quiet default agent still records real spend — display flags gate rendering only, never accounting.

Session Summary Shape

get_session_summary() returns a plain dict you can read or serialise:
In the example above total_tokens is 320 because it is input_tokens (200) + output_tokens (120) — nothing else. Each metrics block also carries cached_tokens, reasoning_tokens, audio_input_tokens, and audio_output_tokens for visibility, but those are subsets of the input/output counts, so they are not added into the total.
How total_tokens is computed. total_tokens is input_tokens + output_tokens. cached_tokens are a subset of input_tokens, and reasoning_tokens / audio tokens are subsets of the totals the provider already reports — they are broken out for visibility, not added on top. Adding them would double-count and inflate cached-prompt and o-series (reasoning) usage by up to ~1.8×.
Concrete illustration you can compare against:
The 1500 is the provider’s own reported total. The cached_tokens (800) sit inside the 1000 input tokens, and the reasoning_tokens (400) sit inside the 500 output tokens — summing all four would report 2700, which is wrong.

Scoping to one team (concurrent instances)

The get_token_collector() singleton is process-wide: every agent in every PraisonAIAgents instance writes into the same collector. Reading it directly gives you a combined total across the whole process. Since PraisonAI PR #4462 (finalized in PR #4470, which closes issue #4446), PraisonAIAgents exposes instance-scoped views that filter the singleton to the team’s own agents — so two concurrent teams never see each other’s spend.
The scoped methods:
Scoping key = agent name. Filtering matches Agent.name against the collector’s by_agent map. Give each agent a unique name for accurate per-team accounting. Agents with name=None fall back to the unfiltered summary so an unnamed team still sees real numbers rather than zeros.
total_interactions and by_model are best-effort in the scoped view. The collector caps its per-interaction log (_max_recent), so scoped total_interactions and by_model reflect only interactions still in that retained window. The token totals (total_metrics, by_agent) come from the full aggregate and stay exact.

Common Patterns

Reset before, read the summary after — you get the spend for just this run:
by_agent gives a per-agent rollup so you can attribute spend to the right worker:
In multi-agent teams the executor’s LLM instance (executor_agent.llm_instance) is the one wired into set_current_agent() / last_token_metrics, so per-agent accounting is accurate for agents built with a real LLM object — not just a bare model-name string. That instance exposes set_current_agent(name, agent_id=None) plus current_agent_name and current_agent_id, so you can read back which agent a completion was attributed to.
Concurrent agents sharing one LLM. Since PR #5310 (fix for issue #5052), LLM.current_agent_name is a task-local contextvars.ContextVar, not a plain attribute. When two agents share one LLM instance and their completions overlap, each task reads its own current_agent_name — mid-completion writes from one agent no longer clobber the other’s attribution in last_token_metrics. Reading llm.current_agent_name inside a task returns whatever the last set_current_agent(...) in that task’s contextvars.Context set; different tasks see different values. See also Thread-Safe Agent State — Concurrent token/cost attribution on a shared LLM.
Deep-copying an LLM. copy.deepcopy(llm) gives the clone a fresh current_agent_name ContextVar — the raw ContextVar cannot be pickled, so a naive deep copy used to raise. The clone starts with no attribution set and only its own tasks can write to it.
A single LLM instance shared by concurrent agents (gateway channels, asyncio.gather) previously risked one agent’s set_current_agent() clobbering another’s mid-completion (issues #5052 and #1746). Since PraisonAI PR #5359, attribution lives in per-instance context variables and set_current_agent() also accepts an agent_id, so downstream aggregation keys stay stable even when two agents share a display name.
An Agent (and the LLM it uses) is now safely deep-copyable, so cloning an agent with copy.deepcopy for parallel runs no longer raises.
When an agent calls a tool and then completes, each model call is its own paid iteration. A single tool-using turn therefore records total_interactions == 2 — one for the tool-call step and one for the final answer — and both are summed into the totals.

Latest Call Only

For CLI or Harbor envelopes that need the most recent completion’s usage — not the session total — read OpenAIClient.last_token_metrics. It exposes the latest completion’s TokenMetrics and is cleared when a response carries no usable usage.

Gateway

Unified control plane for agents, tools, and delivery.

Observability

Trace and monitor agent runs end to end.

Output Config

Control what an agent renders vs what it records.