Skip to content

AI Governance ​

Required Access Level

Super Admin

The AI Governance Dashboard is an exclusive tool for the Super Administrator of the Flowi Agentic platform. Its primary goal is to provide transparency and control over the financial consumption of Artificial Intelligence across the entire infrastructure.

Someone who administers a single tenant does not reach this screen: typing the address takes them back to the Dashboard.

Note

Flowi Agentic is designed on a Single-Client, Multi-Tenant architecture. This means the parent organization pays the Artificial Intelligence API bills (e.g., OpenAI, Google Gemini), and the governance dashboard serves to allocate, audit, and control the costs of each isolated department or client (Tenants).

The Quota System ​

To ensure that the AI bill does not spiral out of control, the system implements two levels of barriers:

1. Tenant Quota (Level 1) ​

Each Tenant receives a maximum limit of monthly tokens (or by configured period). When this limit is reached, the Tenant is immediately blocked from performing interactive operations with AI (such as chatting with agents or generating forms via AI).

Every Tenant is born with a quota of 1 million tokens, created along with it. Adjust the value under Tenants → (the tenant) → AI Token Quota.

A tenant with no quota gets no AI at all

The barrier is the quota existing, not only its value. A Tenant with no quota row is refused before its first call, with the same message as one that ran out. If an agent answers that no quota is configured, this is it — open the screen above and save.

2. User Quota (Level 2) ​

Within a Tenant, sub-limits can be defined for specific users, which prevents a single employee from consuming the entire monthly budget allocated to the whole department. Today it is the Super Admin who writes that sub-limit — the route that saves it (PUT /api/admin/users/{id}/ai-quota) requires that role, and a tenant Admin cannot reach it.

What counts towards a person's sub-limit: only the on-screen copilots. That is the spend they choose consciously — they opened the copilot, wrote the question, pressed send.

What an AI step spends belongs to the process, not to whoever pressed start. Whoever starts a process did not choose the model, did not write the prompt and cannot reduce that bill; besides, the step may run hours later, resumed by a timer, or be redone by the platform. That is why step usage goes to the Tenant quota — where the invoice comes from — and shows up in the report identified by the process that spent it, next to the people.

How to read the Usage by person and process table

Rows with a name and an e-mail are people, and what they spent on the copilots. Rows marked as Process are AI steps, summed per process. No person attributed is left only for usage that has no process either — usage that reached the model without declaring where it came from, which is an alert, not a normal category.

Soft Limits vs Hard Limits ​

  • Hard Limit (Automatic Blocking): Actions triggered manually by humans (interactions in the Copilot) are strictly blocked if the quota runs out.
  • Soft Limit (Overage): Scheduled or ongoing actions executed invisibly by the system (robots, Java Delegates, or background automations) are not interrupted when the quota runs out. This prevents vital company processes from failing halfway. Tokens spent beyond the limit enter the database as Overage Tokens, to be settled later.

AI BPMN validation is a Hard Limit, and only the tenant admin triggers it

The modeler's semantic validation button calls the model and spends the tenant's quota like any copilot. That is why the route (POST /a/ai-validation/bpmn) requires a tenant Admin or Super Admin — manager and ordinary user get 403. With no quota left, the call is refused with 402 and the message names the tenant; it does not come back disguised as an opinion about the diagram. If someone reports that validation "could not finish the analysis", that is a provider failure, not the quota.

Model evaluation (MODEL_EVALUATION) is a Hard Limit, but it waits in line

Compare models, on the agent's Reference cases tab, runs the cases on several models — see Agents → Evaluating models with reference cases. It is optional spend asked for by a person, so the quota is checked on every call: if it runs out midway, the remaining pairs do not run and the evaluation ends Partial; what was already spent stays counted. Unlike the copilots, an evaluation does not jump the model's queue — it waits like a process step. In the per-step usage it shows with the MODEL_EVALUATION feature, the agent's process key and the case name in place of the step; the tenant sees tokens only, the Super Admin also sees the cost.

Retrieval evaluation (RETRIEVAL_EVALUATION) is a Hard Limit and waits in line

Evaluate search, on the base's Reference questions tab, embeds each question once and measures search — see Knowledge Bases → Measuring search. The quota is checked on every question: if it runs out midway, the remaining ones do not run and the evaluation ends Partial; what was already spent stays counted, and a call that failed at the provider after it was sent also shows, with zero tokens. In the per-step usage it shows with the RETRIEVAL_EVALUATION feature, no process, and the question text in place of the step — it does not mix with RAG_EMBEDDING, which remains the embedding of ingestion and of the agents' search. The tenant sees tokens only; the Super Admin also sees the cost.

Robot generation (ROBOT_GENERATION) is a Hard Limit and interactive

Generating a robot from a description, and each Refine request, is one call to the copilot model, asked for by a tenant administrator. Without quota the request is refused before it reaches the provider and no revision is written. An answer that cannot be used (not the requested JSON) was already counted and uses up the click; a provider failure after the call was sent also shows, with zero tokens. If the primary model fails and the fallback answers, that is two rows of the same generation, not two generations. Editing the code by hand, approving, testing and activating call no model. In the per-step usage it shows with the ROBOT_GENERATION feature, no process, and Robô <name> (<key>) in place of the step — a discarded draft included. The tenant sees tokens only; the Super Admin also sees the cost.

A call that produces no answer is billed too ​

An agent can call the model and get an empty response — the provider refuses, or finishes without writing anything. The input tokens were billed anyway, because the prompt was processed. The platform records those calls and charges them to the tenant's quota, so that the dashboard's number does not sit below what the provider invoices.

In the audit list this shows up as consumption with no matching result. A tenant with high usage and few completed processes should be checked for barren calls first.

When the platform cannot count, the copilot refuses ​

Copilots answer as a stream, and the provider reports the token count only in the closing chunks of the response. If that count never arrives, the platform does not deliver the answer in the copilots or the playground: without a count there is no way to debit the quota, and a ceiling that never closes is not a ceiling. The user gets a message saying exactly that, and the call is recorded in the audit list with a zero count and the origin resposta-sem-contagem-de-tokens — its real spend is greater than zero.

For processes the decision is the opposite, for the usual reason: the step delivers its result and the gap is recorded. Stopping a process over a hole in a report would trade an accounting problem for a production outage.

If that warning shows up often, the provider configured under Platform → AI Settings is the first place to look.

The same holds for a step that ends in a blocking issue raised by the agent: the model read the document, concluded the work cannot be done and ended the step with a code. The step fails, nothing is written to the result variable — and the call is counted and debited like any other, because the provider charged for it. What the screen does not show is the blocking-issue code: that failure list is read through the API today, not from here.

A call cut short: billed by the provider, not measured here ​

There is a case where the platform knows it spent and does not know how much. When one of the agent's tools fails mid-conversation — database down, storage unavailable — the call is aborted. The prompt was already sent and the provider already charged for it, but the response that carries the token count never arrives, and there is nowhere to get the number from.

These calls appear in the report with zero tokens and no output produced. The zero is not the real consumption: it is the mark of consumption that could not be measured. We prefer the row with a zero to no row at all, because an invisible gap does not get investigated.

What this means for reconciliation

If the provider's invoice comes in above what the dashboard adds up, the zero-token calls are the first place to look. The more tool failures a tenant had in the period, the larger the difference.

A refused quota is a different case and produces no record: the check happens before anything is sent, so nothing was transmitted and nothing was charged.

The token charge is not undone if the process fails afterwards ​

The quota is debited in a transaction of its own, separate from the transaction of the process that made the call. In practice: if the task fails after the AI answered, the tokens stay debited.

That is the correct behaviour, and it is worth saying why. The provider charged the moment it answered — the spend happened, whatever became of the process next. If the debit were rolled back along with the task, the dashboard would show less consumption than the invoice, precisely in the tenants that fail most.

That separation is also what allows several documents to be processed at once: the tenant's quota row is locked only for the instant of the debit. Were it locked for the whole AI call — some twenty seconds — every other call from the same tenant would queue behind it, one at a time, no matter how many threads were available.

How many AI steps run at once

AI steps wait for the provider on a pool of their own, separate from the process engine's job queue — while the model thinks, the step occupies no execution slot and no database connection. How many run at once is AI_STEP_CORE_SIZE, which is 8 by default.

The ceiling is per installation, not per tenant: the same pool serves both engines, so the slots are shared by every tenant, process steps and case steps alike. Past the slots, steps wait in a queue of 100 (AI_STEP_QUEUE_CAPACITY); past the queue, a step is closed as a failure and made available for reprocessing rather than stopping in silence.

When the provider limits the rate

The provider limits how many requests per minute and per day a model accepts. A burst of steps — an import, a timer firing for many instances — goes through a per-model limiter before reaching it. While it waits for a slot, the step shows In progress, with no error, and spends neither quota nor attempt. If the provider answers that the per-minute limit was hit, the step waits as long as the provider asked and tries again. If the daily or plan quota is gone, the step goes to Failed with that reason, because waiting seconds does not help. Each model's limit is installation configuration — see Deploy → Sizing by AI.

Where the throughput number comes from

The arithmetic is concurrent steps × 60 ÷ call latency in seconds. With the 8 default slots and a call of roughly 20 s, that is about 24 steps per minute for the whole installation.

This is arithmetic, not a measurement of your installation. The bench that produced the published numbers ran against the previous, 2-slot design, in a test where the model call is an artificial wait of a fixed duration: no provider is contacted, and the database and RAG are out of the path. The ~20 s latency itself does come from a real observation, but from a single fiscal-document workload, on 2026-08-12.

Treat the number as an order of magnitude for sizing, never as contracted capacity: real throughput depends on the model, the size of the prompt and whatever else the installation is running. Measure with your own load before promising anyone a number.

The Dashboard ​

The ceiling is not the tenant's spend

The value you configure is the Copilot Limit — it only stops the assisted screens. Processes keep running once the ceiling is reached, and whatever goes past it lands as Process Overage. A tenant's real consumption is therefore used + overage, and that is the number the screens call Total Consumption. Reading the ceiling as if it were the total leads to the wrong conclusion that process work is free.

The panel shows three global metrics at the top:

  1. Global Usage This Month (Tokens): sum of AI tokens in the period.
  2. Total Consumption (Copilots + Processes): what the platform actually spent across all tenants, with Process Overage right below it, kept separate.
  3. Tenants With Copilots Blocked: how many hit the ceiling — with the count of active tenants in the caption. Blocked here means copilots stopped, never processes stopped.

The cards are the quota counter, not the usage record

The first two cards read each tenant's quota counter: it is debited on every call, zeroed at the turn of the billing cycle and zeroed by the Force Reset button on this same screen. The report further down, under Who is spending, does not read those counters: it reads the usage record, written once per call, which no reset touches.

That is why the two numbers can differ — and they differ a lot after a reset or after old load that is still inside the filter window. Neither is wrong: the card answers how much has been debited from the ceiling this cycle, the report answers how much was actually spent in the chosen period. Pressing Force Reset drops the card and does not change a single row of the report — that is the correct behaviour, and it is why each card says in its caption where it comes from.

Below it comes the audit list, one row per tenant with three numeric columns: Total Consumption (used + overage), Copilot Limit and Process Overage.

Resetting quotas ​

The available actions are:

  • Copilot limit (max tokens): under Tenants → (the tenant) → AI Token Quota, raises or lowers the ceiling for the assisted screens. It does not cap processes.
  • Force Reset: manually zeroes the tenant's counters — used and overage tokens go back to 0 (used for billing corrections or courtesy extensions) and the cycle restarts.

The same reading applies on the user screen (Users → (the user) → AI Quota per Tenant): the number configured there is that person's copilot ceiling, not a cap on what processes may spend on their behalf.

Who is spending ​

Below the tenant list, on the same panel, the Who is spending table ranks customers by what they consumed in the period, largest first. It is the question the panel exists to answer: which customer grew off the curve.

Each row shows how many people spent, calls, tokens and cost. Clicking the row opens that tenant's detail, where the people and the steps are — see The tenant's AI usage, below.

The __unknown__ row is not a customer

If a row with the key __unknown__ appears, it is usage that reached the model without declaring which tenant it came from. The tokens are real, the row counts towards the total, and there is no customer screen to open — which is why it is not clickable, and a notice above the table explains what it is. Treat it as an instrumentation fault to report, never as a customer to bill.

Period filter ​

Both screens filter by period: shortcuts for 7, 30 and 90 days, This month, Last month, and a free range under Custom.

The quota does not follow the filter, and that is deliberate

Each tenant's quota counts the billing cycle and is zeroed when the replenishment period turns. It is not a sum over the period you picked in the filter. If you filter seven days and the quota shows another number, both are right: one says how much has been billed this cycle, the other how much was spent in the chosen period.

When the report does not load ​

If the query fails — server down, network, expired session — the screen shows a red notice saying the report could not be loaded. It never shows the no usage recorded message in that situation: the two sentences mean opposite things, and confusing them once led a panel to announce that a customer with 41.8 million tokens did not use AI.

The rule holds on all four usage screens — this panel, the tenant's AI Usage tab, Administration → AI Usage and a definition's usage tab. The empty message only appears when the answer arrived and really was empty.

Export to Excel ​

The Export CSV button downloads what is on screen, for the filtered period. The file is generated on the server and carries what the database has — not only the rows the page loaded.

The file opens in Excel with a double click: it is UTF-8 with a byte order mark, so accented characters show correctly, and it uses a semicolon as separator, which is what Excel in Portuguese expects. A field containing a semicolon, quotes or a line break is quoted.

The tenant's AI usage ​

Inside Tenants → (the tenant), the AI Usage tab answers the next question: inside this customer, who and what. It has the same period filter and its own tables, each with its own export button.

Usage by person and process lists who spent in that tenant, largest first. People appear with name and e-mail and answer for what they spent on the copilots; AI steps appear summed by the process that ran them.

Process spend is never hidden nor pinned on someone

It is part of the tenant's total, and the invoice comes from that total. Hiding automated usage would make the customer's number smaller than what the provider charged.

An id in place of the name means the person no longer exists in the registry, or that whoever triggered the call was not a platform user. The row is shown anyway — spend that does not resolve to a name is still spend.

Usage by process step is the table described in the next section, restricted to that tenant. There the Tenant column does not appear: inside the customer's page it would be the same on every row.

Usage by model answers the question the total alone hides: is the customer expensive because it uses a lot, or because it uses an expensive model? They are opposite diagnoses and call for opposite fixes.

Each row says which model each task used: process, step, model and feature. The same step appears twice when it ran on two models — that is how a model switch becomes visible, with before and after side by side. The same model in a copilot and in a process step are also separate rows: a person chose one, the other runs on its own.

Why the step appears in the model table, and the model does not appear in the step table

The two tables look redundant and are not. The step table answers why is this step expensive and carries Iterations and Context, which divide per execution. The model table answers which model does this task use and carries sums only.

Putting a Model column in the step table would spoil both derived columns: an execution that spans more than one model — an agent falling back to the reserve model after a refusal — would be counted whole on each row, and the average number of model round trips would come out inflated on both. Sums do not have that problem, which is why the reverse direction works.

A model called unknown means a call that failed before the provider answered: the platform tried, could not tell which model served it, and no token was charged. The row appears because the attempt existed.

What the tenant itself sees ​

A tenant's administrator has their own screen: Administration → AI Usage. It shows, for the chosen period, what that operation consumed — by process and by person, by step and by model.

Whoever designs the processes sees it too, where they can act: the AI Usage tab inside a definition shows usage for that process, with the columns that explain the spend (iterations, retrieved context, waste). It is for the modeller to answer can this process spend less? — prompt, model, tools and knowledge base are their decisions.

The tenant is also warned about unattributed usage

If any row of that tenant reached the model without declaring its source feature, the step table shows the same notice the Super Admin sees, and the feature appears marked as UNATTRIBUTED. Whoever administers the customer is exactly who can investigate where that spend came from — hiding it from them would be hiding it from whoever can act.

The tenant sees tokens, not money

The tenant's screens show usage in tokens and the quota, never an amount of money. The price per token is what the platform pays the provider; the cost in money appears only on this governance panel, for whoever pays the invoice. It is not the screen hiding the number: it is never sent to the customer's browser.

Consumption by process step ​

Below the tenant list, in the same panel, sits the Consumption by process step table covering the last 30 days. It exists because a token count alone does not say what to change: knowing that a step spent 41,000 tokens does not separate expensive model from bloated prompt from agent stuck in a loop, and those call for opposite fixes.

Each row is a step, most expensive first. A step here is either a task of a process or an AI step inside a case — the Feature column tells them apart, AI_DELEGATE for a process and AI_CASE_DELEGATE for a case. Notice that before looking the row's key up in the process catalog: on a case row it is the case key.

Beside calls, tokens and cost, three columns explain the spend:

  • Iterations — how many round trips to the model a single execution of that step took on average. A high number means the prompt or the tool descriptions are not getting the model where it needs to go. Moving to a cheaper model does not fix that. A step the engine retried does not inflate this number: the retries of one step stay one execution, and what separates them is the attempt number recorded on each call.
  • Context — how much of the prompt is context retrieved from the knowledge base. A high percentage points the cost at retrieval rather than the model: retrieve less, or retrieve better.
  • Wasted — the share of tokens spent on calls that produced no answer. This is the first place to look, before touching any prompt.

Rows crossing an attention threshold are highlighted with an icon. The rest stay neutral on purpose: a table where every row shouts communicates nothing.

When the cost is incomplete

An unpriced chip next to the cost means some call in that group used a model with no price in force; hover it to see how many calls and tokens. The cost shown is partial — and unpriced never shows as zero: without the chip the step would look cheap precisely because information is missing, which is the opposite of what the number should say.

Currency, estimates and cents ​

Every money figure is shown in the price's currency, with its symbol: a group that spent on two models priced in different currencies shows $12.40 · R$3.10, side by side. The platform does not convert currencies and never adds two currencies into one number. Below one unit up to four decimals are shown, so a USD 0.0004 call does not read 0.00. Costs filled in by a model's first price carry an estimated chip — see Agents → Model price.

Token counts follow what the provider bills: Gemini reasoning is counted as output, and input read from the provider's cache is recorded separately and billed at the cached rate when the model has one.

Totals by tenant and by feature ​

On the governance dashboard, each tenant row also shows two quantities with no price: the storage in use (non-deleted attachments, in GB) and the minutes on global robots in the period. The platform puts no price on them — they are there for the operator to build their own bill.

Below it, the By feature table adds up the period per kind of use (copilots, agent steps, embedding…), with the cost per currency. Export totals by tenant and Export totals by feature download the same as CSV. The people, steps and models CSVs gained the columns currency, estimated, unpricedTokens, cachedInputTokens, reasoningTokens and costsByCurrency: one line per group, as before — costMicros and currency are filled only when the group has one currency, and costsByCurrency lists them all (BRL=5000 USD=1000).

Model fallback by class ​

A step of an agent bound to a model class that was answered by the next model of the class (the first was out of quota, at its limit or down) shows two rows in the usage when both calls reached the provider: the failed attempt, on the model that failed, and the answer, marked FALLBACK, on the model that answered — which is the one that prices it. Both share the same correlation id, so the step counts once in executions. A switch because this server had no free slot writes no row at all: the provider was not called.

The Model fallback by class table, below By feature, shows for each class how many steps ran in the period, how many were answered by the next model and the share. A growing share says the class's first model is too small for the demand — raise its quota at the provider or reorder the class. The reason of each switch is on the usage row (selection_reason): quota exhausted, rate limit, unavailable, timeout, retired model or no free slot.

External knowledge base queries ​

An external base (an Elasticsearch or OpenSearch queried at the source) calls no model: querying the index spends no token and is not part of the AI usage report. It is counted apart, in the External knowledge base queries table right below Model fallback by class, for the chosen period: per tenant and per base, how many queries there were, how many were answered, how many failed (down, timed out, credential refused), how many were not even sent (base classified above the level of whoever retrieved, or destination not allowed), the failure rate and the average latency of the answered ones. There is no currency: Flowi does not know what the customer pays per query to its own index. The count is kept per hour for 400 days.

In vector mode the question uses the vector the local search computed, so the embedding cost is still the usual RAG_EMBEDDING row. On the step, the retrieval audit entry says how many external queries it made, even when no token was spent.

Unattributed consumption ​

An unattributed warning means calls reached the model without declaring which feature they came from. The tokens are real and were charged; what is missing is the origin tag, which is recorded in the application log. It is an instrumentation gap to report, not a billing error.

Embeddings show up here too

Embeddings generated by knowledge-base ingestion and by RAG retrieval are measured and show up as a RAG_EMBEDDING group in the table, with no process or step attached — an embedding does not run inside a flow step. The price comes from the global embedding configuration, in the Vector Database (RAG) tab of the AI Configuration screen — not the chat model catalog: an embedding has no completion tokens, so the cost is computed on prompt tokens alone. The price belongs to the configuration that served the call: changing the embedding model starts a new configuration, unpriced until it gets a price.

Since document access (#206), kept by hybrid search (#203), each RAG retrieval embeds the question once and reuses the vector for the tenant's base and the global one; before, it made two calls per retrieval. That is why retrieval RAG_EMBEDDING volume halves from that version on, with nothing left unmeasured. The keyword search of hybrid mode and a base's language change call no model and do not show up here.

What each document version cost ​

Each ingestion embedding row of a knowledge base carries the document version and the attempt number (kb_document_version_id and ingestion_attempt in ai_usage_logs). That answers how much v4 of a policy cost and tells a retry — the provider dropped in the middle and ingestion tried again — apart from a new version. The knowledge base versions drawer shows the embedding tokens summed per version; this table remains the source of truth.

What does not cost embedding: uploading the same file again, uploading a file with the same text, restoring a version within the orphan window and a scanned PDF left as Needs OCR. The installation's OCR does not show up here either: it runs in Tesseract, inside the server, and is not a model call. The tokens of an attempt that failed after the provider answered were already charged and stay recorded with the attempt number.

Flowi Agentic — Plataforma de Gestão de Processos com IA