> For the complete documentation index, see [llms.txt](https://docs.buildings.ability.abb/collection/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.buildings.ability.abb/collection/academy/building-intelligence-ai-and-machine-learning-in-buildingpro-suites/agents/result-analysis.md).

# Result Analysis

Retrieving data from a database is only the first step. A database query returns\
rows and columns, but the user asked a question. The gap between raw tabular\
data and an actionable answer is where analysis and visualisation come in.

Consider a query that returns 250 rows of weekly energy consumption across 10 buildings. The raw result answers "what is the data?" but not the questions the user likely cares about: Which building consumes the most? Is consumption trending up or down? How does this week compare to the previous one? Are there outliers?

### The Problem with LLMs and Numbers

A natural instinct is to pass query results directly to a language model and ask it to analyze them. This approach fails for several reasons.

#### Tokenization and Numerical Reasoning

Language models process text as tokens, not as numbers. The number "1,247.83" is not represented internally as a floating-point value but as a sequence of tokens (e.g. "1", ",", "24", "7.8", "3") .\
This representation is fundamentally unsuited for precise arithmetic.

LLMs are able to do calculations but should be generally be treated as unreliable for tasks like:

* Summing columns of numbers
* Computing averages, medians, or percentages
* Comparing values across rows with precision
* Detecting small but meaningful differences

The error rate increases with the number of values involved and the precision required. For analytical tasks where numerical accuracy matters, LLM-generated calculations are not trustworthy.

#### Context Window Saturation

Passing large result sets into an LLM's context window creates additional problems:

* **Attention dilution**: as the context fills with hundreds of data rows, the model's ability to reason about any individual row or pattern degrades.
* **Context limits**: large result sets can exceed the available context window entirely, or consume so much of it that the model cannot generate a useful response alongside the data.
* **Cost and latency**: processing thousands of tokens of tabular data is slow and expensive, especially when the model then produces an unreliable analysis of that data.

The conclusion is clear: **LLMs should not perform numerical computation on raw data.** They should decide *what* to compute, and delegate the actual computation to deterministic tools.

### Deterministic Result Inspection

The principle behind deterministic result inspection is a clean separation of concerns:

* **The LLM decides** which analytical operation to apply and on which part of the data (e.g. "compute the top 3 buildings by total energy consumption and compare each to the group average").
* **A deterministic tool executes** the operation with exact arithmetic on the full result set and returns the computed values.
* **The LLM interprets** the tool's output and incorporates it into the response.

The LLM never sees all raw rows. It sees a small preview (enough to understand the data structure) and then works with the deterministically computed results from the inspection tool.

Result Set Inspection / Analysis:

* letting a LLM analyze raw data is seldomely a good idea (concept of tokens and numbers!!)
* dumping hundreds of rowas of raw data will fill up the available context very quickly and lead to accuracy degradations
* it should be avoided to let it do  numerical computations wherever possible
* instead give it a handy set of tools and functions that it can apply deterministically on result sets (these do the actual computations) the llm just decides which function to use and on what part of the data and only sees the result computed by the function

**Example Operations:**

| Category     | Operations                                                                                     | Example use case                                             |
| ------------ | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
| Aggregation  | Sum, mean, median, min, max, count                                                             | "What is the average temperature across all rooms?"          |
| Ranking      | Top N, bottom N, row with max/min                                                              | "Which building consumes the most energy?"                   |
| Comparison   | Compare to group mean/median, cross-column delta,period-over-period change, baseline deviation | "How does Building A compare to the portfolio average?"      |
| Contribution | Percentage share of total, contribution by group                                               | "What share of total energy does each building account for?" |
| Profiling    | Null report, schema inspection, value distribution                                             | "Are there sensors with missing data?"                       |
| Temporal     | Period-over-period diff, percent change, rolling stats                                         | "How did energy consumption change month over month?"        |

#### Derived Result Sets

Some inspection operations produce not just scalar values but new tabular result sets. For example, computing the month-over-month percentage change per building produces a new table with the original grouping columns plus computed delta columns.

These **derived result sets** can be:

* Used as input for further inspection operations (chaining)
* Passed to a visualisation subagent for charting

This chaining capability means complex multi-step analyses can be built from simple, reliable primitives - without ever asking the LLM to do arithmetic.

### Visualisation

#### The Mapping Problem

Generating a useful chart from a SQL result requires solving a multi-dimensional mapping problem:

* **What does the user want to understand?** (comparison, trend, distribution, composition)
* **What is the structure of the data?** (time series, categorical, matrix, single metric)
* **Which chart type best represents this combination?** (line, bar, pie, heatmap, scatter)
* **How should data columns map to visuals?** (x-axis, y-axis, series grouping)
* **How much data is needed?** (are 10 preview rows sufficient, or does chart quality require the full result set?)

A rule-based chart generator can handle simple cases (one time column + one metric column -> line chart). But real-world data analysis produces diverse result shapes:

* Multiple metrics with different units on the same time axis
* Grouped categories where series should be split by a column value
* Matrix-shaped data that could be a heatmap or a set of grouped bars
* Results where only a subset of columns are meaningful for charting

A **visualisation subagent** handles this diversity by receiving:

1. The result set structure (columns, types, row count)
2. A high-level **visualisation intent** from the orchestrator (e.g. "compare buildings over time", "show distribution of temperatures")
3. Optional baselines or display preferences

It then independently decides:

* How many charts to generate
* Which chart type(s) to use
* How to map columns to charts (axes, series, categories)
* Display options (stacking, orientation, sorting, null handling)

The output is a structured **visualisation plan,** a declarative specification that can be compiled into a larger chart configuration. Instead of writing the full chart configuration code or generating an image it produces a mapping configuration that translates the data's structure into a visual structure.

Users can override these decisions, but the default behavior is designed to produce useful visuals without requiring manual chart configuration.\
A visualisation subagent operates on the same principle as other agentic integrations: the user states what they want to understand, and the system handles the technical translation.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.buildings.ability.abb/collection/academy/building-intelligence-ai-and-machine-learning-in-buildingpro-suites/agents/result-analysis.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
