> ## Documentation Index
> Fetch the complete documentation index at: https://docs.brussle.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Brussle versus an AI column in your own database

> An AI column in your own database is enough when its answer reads one row. Brussle is for what that column cannot do: read other documents, say whether it is current, keep versions apart, and be measured against outcomes.

This page helps you decide if you need Brussle. It compares Brussle with an AI column that you build in your own database.

## An AI column in your own database

Your own database can already keep an AI answer in a column:

1. A trigger runs when a record changes.
2. A worker sends the record to an AI model.
3. The worker writes the answer back to the column.

If the answer reads only its own record, this column is enough. Use it. Each answer costs less than in Brussle.

In Brussle, a **judgment** is a column that an engine fills in. The **engine** is the AI model that makes the answers. A **document** is your copy of one record in Brussle.

## Where that column breaks

Your database assumes that a computed value is instant, free and always the same. An AI answer takes seconds. It costs money each time. It changes when the AI model changes. Thus, an AI column breaks on four problems:

| Problem | What the AI column does | What Brussle does |
| - | - | - |
| The answer depends on other records. | A trigger on one table does not know which records in other tables read the changed record. | A [relation](/concepts/relations) makes a judgment read other documents. Brussle finds each answer that read a changed document, and judges only those answers again. |
| The answer must say whether it is current. | The column holds the last value that the worker wrote. | Each answer has a [freshness](/concepts/freshness). A query can ask for current answers only, with `answers: "fresh_only"`. |
| A change to the question or the AI model must not mix old and new answers. | Old answers and new answers mix in the column. Nothing records which is which. | Each answer records its `judgment_version` and its `engine_version`. An answer from an older version that asks differently reads `stale`, with the reason `older_version`. |
| The number must be measurable against what happened. | The column stores 0.8. Nothing tells you how often 0.8 comes true. | You record [outcomes](/concepts/calibration) beside the answers. The calibration report measures the answers against them. |

You can build the four solutions yourself. For the first problem alone, you need a map of which records read which other records, a queue, a debounce for bursts of writes, a check that skips unchanged inputs, and a cap on cost. See [the four problems](/index#four-problems-that-an-ai-column-cannot-solve).

## Who Brussle is for

Brussle is for teams whose AI answers depend on more than one record and must stay correct. For example:

* matching records to each other, such as a payment to the open invoice that it settles;
* checking a record against the records that it must agree with;
* detecting what changed, such as a contract section against its earlier revision;
* keeping counts current that your process depends on.

The fit is strongest for teams that serve many customers of their own, and that do not have the people to build this system.

Brussle is not for these cases:

* one-off batch jobs;
* answers that read one record;
* teams that will build this system themselves.

## What it costs

Each answer costs more than a direct call to an AI model. You pay for the work around the call: the relations, the freshness, the versions and the outcomes. If your answers do not have these four problems, call an AI model directly. See [pricing](/pricing).

## Move a column across

These steps move an AI column whose answer reads other records. For example, a worker sends each new payment to an AI model, with the open invoices of the same customer. The model names the invoice that the payment settles. The worker writes the invoice's `id` to a column.

### 1. Turn the prompt into a judgment

Most prompts match one of the judgment types:

| Your prompt asks... | Judgment type |
| - | - |
| Yes or no | `bool`, with a threshold instead of a fixed cut-off in your code |
| Which of these categories? | `choice`, with a description of each category in `options` |
| Which of these records? | `choice`, with `options.from` that names a relation. Each related document becomes one option. |
| How much, on a scale? | `score`, with ordered `levels` |

Then do these steps:

1. Move the prompt's instructions into `question` and `criteria`.
2. Move the fields of the record that the prompt reads into a [context recipe](/guides/context-recipes).
3. Move the records that your worker fetched into a relation. For the payment, a blocking relation reads the open invoices that share the payment's key. See [match one record to another](/guides/entity-matching).

If your prompts sent the same record for several questions, make one judgment for each question, with one shared recipe. Brussle answers judgments that share a recipe together. In one request, the first question counts in full. Each question after the first costs a quarter of a judgment, and a quarter more for each further 500 tokens of question text.

The engine cannot answer "none". Instead, each `choice` judgment gets an extra option, `none_of_the_above`. Its probability is in `escape_p`. Use this option where your prompt said "otherwise, answer none".

### 2. Mirror your writes

Send each create, update and delete from your system of record to the write API. Send the payments and the invoices to the same namespace. A relation reads only one namespace. After each change, upsert the whole record, as in [keep your data in sync](/guides/keep-data-in-sync). Writes are idempotent. Thus, your sync can retry a write at any time.

Your database stays your system of record. Brussle holds a copy. To load the records that you already have, see [import existing data](/guides/import-existing-data).

Choose the [freshness policy](/guides/freshness-policies) of each judgment:

* If you filter on the answers, or a new invoice must change a payment's answer, use `on_change`.
* If you show the answer only on a detail page, you can use `on_read`. An `on_read` judgment costs nothing until someone reads the answer.

### 3. Backfill with the estimate in front of you

Your existing payments have no answers yet. A backfill judges them. Ask for the estimate of the backfill first:

```python theme={"theme":{"light":"css-variables","dark":"css-variables"}}
ns.judgments.backfill("settles", confirm=False)
# {"estimate": {"documents": 1204332, "tokens": 2408664000, "judgment_units": 1204332, "cost_usd": 301.08, "duration_s": 116940}}
```

The estimate shows the duration next to the cost. Engine rate limits can make a large backfill take days.

1. Read the estimate.
2. Set a namespace budget.
3. Send the backfill again with `confirm=True`.

### 4. Compare the two columns side by side

1. Run your AI column and Brussle side by side on live traffic.
2. Find the payments where the two answers disagree.
3. Open some of these payments in the dashboard. You see the exact context that the engine read, including the invoices, and its raw output.
4. Post the match that your team confirms for each payment as an [outcome](/guides/measure-improve-tune#post-labelled-examples). On the Team plan and above, an [outcome rule](/guides/measure-improve-tune#outcomes-from-your-own-data) can make these outcomes from your own writes.
5. Change the thresholds before you change the question.

With 100 or more outcomes, 20 of each kind, the [threshold recommender](/guides/measure-improve-tune#pick-thresholds-with-the-recommender) picks a threshold for a precision or recall target. The recommender is on the Team plan and above.

Whether the answers are good enough on your data is yours to decide, from your outcomes.

### 5. Cut over, then keep versions apart

To cut over, read answers from queries or from a get of the document. Do not make a user's request wait for a new answer. `wait_for` on a write is for scripts and tests. See [tradeoffs](/tradeoffs).

Then turn off the old column. From then on, each answer records its `judgment_version` and its `engine_version`. Brussle keeps each answer with the context that made it.

When you change the question later, create a new version of the judgment:

1. Activate the new version. Brussle starts a shadow report that compares the two versions on a sample of documents.
2. Confirm once the report looks right.
3. Run a [backfill](/concepts/judgments#backfill) to judge the documents again. The backfill shows its cost before you confirm it.

Until Brussle judges a document again, its answer from the old version reads `stale`, with the reason `older_version`. A query with `answers: "fresh_only"` leaves it out.

See [versions](/concepts/judgments#versions).


## Related topics

- [What Brussle is](/index.md)
- [Finding your relations](/finding-relations.md)
- [Tradeoffs](/tradeoffs.md)
- [Quickstart](/quickstart.md)
- [Pricing](/pricing.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.