author

Antti Rauhala

CEO and founder

August 11, 2026 • 13 min read

I would rather you ran a query than took my word for anything in this post. So the numbers here are the ones our own benchmarks produce, the unflattering ones included, and every claim is a request you can send yourself.

What we shipped

Aito v2 is a new engine for the predictive database, and it is in public beta today. It holds structured facts, full text, vectors, and linked relationships in one store, and it answers queries about the unknown the same way an ordinary database answers queries about the known: you ask for a category, an account, a next action, a ranking, and it returns the answer with a calibrated probability and the reasoning behind it.

Two honest framings up front, because they matter more than any feature.

First, v2 runs alongside v1, not on top of it. For the whole beta, v1 remains the production default. v2 is the successor engine, stable enough to build against and to cite, and we would rather you kicked its tires now than waited for a version number.

Second, this is a beta for a technical audience. The bar we set for ourselves was simple: you should be able to query v2 in your browser, write your own data to it, read numbers we did not massage, and reference the v2 surface in your own design. Nothing on that list is gated behind a sales call.

Here is the whole thing in one picture before the details.

A four-tier architecture stack. Top tier, Interfaces: a v2 JSON API box listing _predict, _recommend, _relate, _match, _search beside a SQL and Postgres wire box listing SELECT, JOIN along a link, predict() and INSERT or COPY. Second tier, Query and inference: one query planner with calibrated inference returning dollar-p, dollar-value and dollar-why, and correlated-feature grouping. Third tier, Unified store: facts, full text, vectors, and relationships as links or graph, held together and addressable as collections or saved views (union-merge and link-join). Bottom tier, Storage engine: a memory-optimized columnar in-memory core with extensions and embedders, collections for v2 and tables for legacy v1, sitting on an object-store blob cluster backend.
The whole of v2 in one view. Two front doors, the JSON API and SQL over the Postgres wire, sit on one query and inference engine that returns calibrated, explained answers. Below it, one store holds facts, text, vectors, and relationships together, addressable as collections or saved views, on a memory-optimized core of collections and tables backed by an object-store cluster.

Query it, do not trust me

Here is the query the rest of the post rests on. Ask v2 to predict a product category, and ask it to show its work:

POST /api/v2/_predict
{
  "from": "products",
  "where": { "name": { "$match": "milk" } },
  "predict": "category",
  "select": ["$p", "$value", "$why"]
}

You get back a ranked list, each candidate carrying a calibrated probability:

[
  { "$p": 0.738, "$value": "104", "$why": { /* the factor tree */ } },
  { "$p": 0.140, "$value": "109", "$why": { /* ... */ } }
]

Two things in that response are the whole point of a predictive database.

The $p is calibrated, which is a specific and testable claim: among the cases where v2 says 0.85, close to 85% really are that value. That is what makes the number safe to threshold an action on. A score you cannot trust the level of is a number you cannot automate against.

The $why is the factor tree: the evidence that moved the probability, readable by a person who has to trust or override the decision. When v2 does not have the evidence, it does not paper over it. v2 fails loud, with a typed error, rather than returning a confident empty answer.

One surface, many questions

The query above is not a special prediction endpoint. In v2, _predict, _recommend, _relate, and _match are named entry points into one query engine, dispatching on what you ask for, and _search sits alongside them for full-text retrieval with boolean operators. The same store, the same data, answers the whole surface.

Rank options against an objective, not just a label:

POST /api/v2/_recommend
{
  "from": "impressions",
  "where": { "context.user": "veronica" },
  "recommend": "product",
  "goal": { "purchase": true },
  "select": ["$p", "$value"]
}

Ask what actually relates to an outcome, which is the move an anomaly check or an approval-routing rule needs:

POST /api/v2/_relate
{
  "from": "impressions",
  "where": { "product.tags": { "$has": "vegetable" } },
  "relate": ["purchase"]
}

Notice context.user and product.tags in those queries. Those are links, relational edges walked by dot notation, and they chain: you can follow one several hops out, from a record to its vendor to that vendor's own history, in the same query, with a $refs operator to read an edge back from the entity it points at. The relationships live in the same store as the facts, so a prediction leans on the whole neighborhood of a record, not just its own columns, without a separate graph database to keep in sync. $refs reads an edge backward, here every product a user has ever ordered, walked in reverse through the orders that link them:

POST /api/v2/_query
{
  "from": "users",
  "select": ["name", { "products": "$refs.orders.buyer.product" }]
}

And the thing you query does not have to be a raw collection. A view is a derived relation defined in the schema: a link-join that exposes a relationship as navigable dotted paths with no content copied, or a union-merge that stacks several collections into one, column by column and lazily. You name it in from and filter, predict, and recommend against it exactly as you would a collection.

POST /api/v2/_predict
{ "from": "search_index", "predict": "category", "where": { "name": { "$match": "milk" } } }

Views are lazy by default, nothing is copied, so they stay cheap to keep around. For a hot path you can persist a union view as a materialized snapshot, built once and rebuilt with POST /api/v2/schema/{view}/_refresh when its sources change. Either way it is the same relation operators under a name, so the whole calibrated surface runs over a shape you defined once.

Text and vectors live there too. v2 has a Vector column type and retrieves with $nearest, scores rows with $similarity, and can fuse nearest-neighbor evidence into a prediction with $semantic. That last one is the point of vectors in a predictive database: the meaning of the text becomes evidence inside the calibrated answer, not a separate search you reconcile afterward.

POST /api/v2/_predict
{
  "from": "tickets",
  "predict": "category",
  "where": { "embedding": { "$semantic": { "near": [0.1, 0.9, 0.2], "k": 20, "weight": 0.5 } } }
}

Pure nearest-neighbor retrieval is the same store from the other side, $nearest with a having on $similarity:

POST /api/v2/_query
{
  "from": "products",
  "where": { "$nearest": { "near": { "embedding": [0.12, -0.03, 0.88] },
                           "where": { "category": "shoes" },
                           "having": { "$similarity": { "$gte": 0.8 } }, "limit": 10 } },
  "select": ["id", "name", "$similarity"]
}

Two honest limits worth stating plainly: the vector search is exact, with no approximate index yet, and v2 does not encode your text for you by default, so you bring your own vectors (with an optional server-side embedder you configure). Exact search is the right first move for correctness. The approximate index is on the list, not in the box.

And for the people and tools that prefer SQL, v2 speaks the Postgres wire protocol, and it is more than a read path. Inference is called inline, so a prediction is just a column:

SELECT ProductName, predict(GLCode)
FROM invoices WHERE ProductName = 'Cloud Services';

predict(col) returns the argmax and predictions(col) the ranked distribution, and recommend() and relate() are callable the same way. Around that you get a real, if deliberately minimal, surface: SELECT with WHERE, GROUP BY, HAVING, aggregates, and an INNER JOIN along a declared link, which is a thin projection over the link rather than a row-copying join. Writes and simple DDL go over the wire protocol: INSERT, COPY, CREATE TABLE, and basic CREATE VIEW. Point psql, a JDBC or ODBC client, or a connector like DuckDB or postgres_fdw at it. It is early access and not a full Postgres, a small SELECT subset by design, no subqueries yet and a SQL view definition is a single source with an equality filter (no JOIN or UNION inside it), but by construction it parses to the same _query calls as the JSON API, so the two interfaces return the same answers. The full surface is in the SQL docs.

Write to it, and it learns

Reads are only half of it, and the write path is open in the beta, with no invite and no sales call in the way. That matters more than it sounds, because in a predictive database a write is the learning step. Insert a corrected row and the next prediction already reflects it, with no retraining job, no redeploy, and no drift schedule to babysit. This is the write-back loop that lets an application get sharper as it runs: in v2 it is one ordinary insert.

Under the hood

Some of the v2 work is not a feature you call, it is engine work you feel as better answers and a smaller bill. Briefly, and without overselling what is still settling:

  • Correlated evidence is grouped, not double-counted. Real tables carry fields that all say the same thing: a vendor's name, its code, and its bank account all point at one entity. v2 can group that correlated evidence so it counts once, which is a large part of why the calibrated $p stays honest on messy data instead of drifting overconfident.
  • A lighter footprint. The v2 engine holds its working data in less memory than v1. For a multi-tenant deployment that is the difference between the feature paying for itself across every tenant and only on the flagship.
  • Query-time caching. Repeated and similar inferences are served without recomputing from scratch, so interactive latency stays flat as usage grows rather than climbing with it.
  • Object-store-backed clustering. The cluster design grows on cheap object storage rather than a fleet of always-on machines. This is real in the engine and, in the beta, set up with our help rather than one click, with more cloud backends planned.
  • Extensions. There are extension points, including a server-side embedder and custom column handling, so the engine can be adapted to a domain without forking it. The exact surface is still settling, so I will point you at the docs rather than pin it here.

The measurable ones, memory and latency in particular, will get their figures from the same verified run as the benchmarks below, and I would rather show them then than quote a number I have to walk back.

The honest numbers

A release post is where companies quote their best benchmark and move on. The more useful thing is to show you the shape of the results, wins and losses together, because a system that only reports its wins is one you cannot calibrate your trust in.

Where v2 is clearly ahead:

  • Writes. The v2 engine ingests roughly 10 to 33 times faster than v1 per entry. Writing is where v1 hurt, and v2 was built to fix it.
  • Semantic retrieval. On the BEIR SciFact benchmark, v2 reaches nDCG@10 around 0.65 with a standard sentence-transformer model, matching the published figure for that model.
  • Cross-lingual matching. On German and Spanish intent data, semantic nearest-neighbor lifts accuracy to the 0.6 to 0.75 range against a 0.13 to 0.15 token baseline, roughly a four to five times improvement. A query written in one language finds evidence recorded in another.

Where v2 is not ahead, and we are shipping it anyway:

  • Predicting an invoice's processor, the hardest target because the signal lives several links away from the row, v2 in the current beta is about twice as slow as v1 and less accurate. This one is a deliberate trade, not a mystery. v1 leaned on precomputed cross-link indexes; v2 drops them and samples the linked neighborhood at query time instead. That is exactly what buys the far faster writes and lets relationships run to arbitrary depth with no index to keep in sync, and the bill comes due here, on the single deepest link-dependent prediction. We keep the target visible in every benchmark rather than drop it, because the one place a trade-off shows is the one place you learn what it cost. Work on the v2 inference engine continues, so we treat this as a gap we expect to narrow, not a fixed ceiling.

(These figures come from our beta benchmark suite, single-seed and on small test sets, so treat them as directional rather than final. I would rather under-claim than quote a number I have to walk back, and we will refresh them with a dedicated-hardware run as it lands.)

What v2 is not, yet

The fastest way to lose a technical reader is to make them discover the caveats themselves. So, plainly:

  • It is a public beta. v1 is still the production default. Build against v2, cite it, plan for it, but know which one is carrying your production load.
  • SQL is deliberately minimal. Early access, a small SELECT subset over the Postgres wire, not a full Postgres replacement.
  • Vector search is exact, not approximate. Correct first, indexed later.
  • v2 does not generate. There is no language model inside Aito, and there is not meant to be. v2 is the predictive, calibrated half; the generation stays in the language model above it. That division of labor is deliberate: the model reasons and phrases, the predictive database decides and grounds.

Why this, and how to get in

If you want the argument for why a database should answer the unknown at all, and how predictive applications are built on it, that is The Predictive Application. If you want to see the substrate under real agents, the live demos are at agent.aito.ai. If you want to read the surface in full, the v2 API docs are open.

And if you are building something on it, reads or writes, I would like to hear about it. The fastest line to me is plain email: antti@aito.ai. I am the founder, and I would like to know what you are trying to build.

Back to blog list

Add the predictive half this afternoon.