Venn
Embedding-native decision systems

Venn: Vector Decision Models

Typed decisions over embeddings you already have: route, score, filter and compare populations with a small local decision layer instead of a generative model.

When a lookup is not enough, train a small custom head on your own data through the same API, as a linear classifier, a residual Choice head or a numeric predictor, and serve it under the question you already ask.

Cached vectors feed a small Venn decision layer and multiple decisions Your vectorsYour questions Venn RouteScore Filter Reusable state. Small heads you can train.

What you can do#

  • Route and classify. Ask Choice, Score and Noul (yes/no) questions about text or vectors, with an explicit "none of these" option. Requests use the Decisions API format, with compatibility checked against these client versions.
  • Decide from recorded outcomes. Point Venn at your own vector store of past cases and their outcomes. It picks the option whose similar past cases went best, and your application writes new outcomes back. No trained head is needed.
  • Train custom heads through the same API. Four kinds, all through register_family (or PUT /families/{name} over HTTP):
  • a linear Choice head (form="linear"), a multinomial logistic regression on your labeled vectors and the best default for plain classification;
  • the residual Choice head, which can also answer "none of these";
  • a numeric head (objective="regress") that predicts a score with an 80% interval, from examples or a store's outcomes;
  • a head compiled from an outcome store that answers nearest_outcome without a lookup.

Choice heads train on every supplied example by default; an explicit split reserves selection and report rows. They choose their settings by cross-validation, grouped by group_id when related examples must stay together. Each fits in seconds to minutes on one machine, is saved and reloaded with the service, and answers the same question type the rest of your code already sends. The reader stays frozen; only the head is trained. See the family cookbook, the linear family cookbook, the numeric family cookbook and the outcome API. - Work on collections. Find the nearest labeled reference, spot the intruder in a set, test whether a population has shifted, or stream one question over every row of an index.

A few words you will see throughout: a reader is the frozen embedding model; a profile pins the reader, its revision and the vector format; a head is the small model that turns vectors and a question into an answer; Noul is the Decisions API's name for a yes/no question.

Venn or Jev?#

Jev evaluates the content and context supplied in a request. Venn lets your application keep and reuse the representation behind its decisions, through historical cases, custom predictors and collection operations. Its small local decision layer also provides an alternative to running a larger open-source decision model. EmbeddingGemma 2's text-only reader has about 270 million parameters; image and audio towers are loaded only when needed.

Start with Jev when useful category descriptions and the item's content carry the answer. Start with Venn when you have useful labeled history, need your own predictor, or expect repeated decisions over the same embedded collection. Read Venn and Jev: when to use which for the trade-offs, examples and results.

Venn and Jev on the same questions, with the results each one reached.

Watch the comparison with examples of historical outcomes, filing conventions and custom predictors.

Venn is a research preview. Probabilities are not calibrated across tasks, and the "none of these" option is a signal rather than a filter: an off-topic question can still land on a listed option with high confidence. Read the limitations before acting on a probability.

Install#

Python 3.12 on Linux or Windows. CPU workflows also run on ARM64, including Ubuntu under WSL and native Windows; see platform setup.

git clone https://github.com/markrussinovich/venn-vdm.git venn
cd venn
python3.12 -m venv .venv && source .venv/bin/activate
python -m pip install torch --index-url https://download.pytorch.org/whl/cpu   # CPU-only PyTorch; omit for CUDA
python -m pip install .

Try it in a minute#

venn quickstart runs on CPU and downloads nothing. It registers a small store of past support tickets with their outcomes, then routes a new ticket to the team whose similar tickets went best:

venn quickstart
{
  "answer": "account",
  "options": {
    "account": {"mean": 0.9, "count": 3, "evidence_ids": ["acct-102", "acct-101", "acct-103"]},
    "billing": {"mean": 0.4, "count": 3, "evidence_ids": ["bill-201", "bill-202", "bill-203"]}
  },
  "note": "authored vectors, not text embeddings; nothing was downloaded"
}

The same API with your own vectors is in examples/outcome_store.py and the outcome API guide.

Ask questions about text#

Text questions use the venn-1 profile: the EmbeddingGemma 2 reader plus a 3 MB decision head. Install the reader extra, download both and start the server:

python -m pip install '.[embedding]'
venn download-embedder      # EmbeddingGemma 2 (Apache-2.0), about 1.49 GB of weights
venn serve                  # downloads the venn-1 head on first run

In another terminal:

curl http://127.0.0.1:8000/api/alpha/decisions -H 'Content-Type: application/json' -d '{
  "model": "venn-1",
  "state": "I cannot sign in",
  "questions": {"team": {"type": "choice", "instructions": "Who owns this ticket?",
                          "criteria": {"account": "Login or access", "billing": "Payments", "no_match": null}}}
}'

The response names a team, gives its probability and says whether Venn abstained. The first text request also loads the reader, which takes a few seconds. Later requests avoid that cold load; fresh content still needs embedding. examples/route_ticket.py does the same from Python. The API reference covers Score, Noul, the space-level question types, the JavaScript client and the MCP bridge.

Learn more#

Watch it learn to play#

Watch Venn use past experience to choose each move.

The arena example drives a ViZDoom player with nothing but Venn's outcome API and a FAISS store. Venn embeds each screen, looks up how similar moments turned out for each move, and returns the move with the best recorded outcome. Finished games are written back to the store. The reader is never trained.

One more call compiles that store into a head of 49,153 parameters that answers the same question with no lookup. Served alone, the head averaged 8.4 kills per game over 250 scored games against 6.2 for the memory it learned from. Run it yourself or read what the video shows.

For text, the Precedent Desk example points Venn at a support desk's 10,003 closed tickets and routes new ones from them, with precedents, a queue-fit flag and a one-pass backlog sweep. On the same 3,080 public test tickets the closed tickets scored 93.6% against 79.7% for a matched run of Jev 1.13, and the pattern repeats on a second dataset. Video, 2 minutes 36 seconds.

Project#

  • Code is MIT-licensed. The EmbeddingGemma 2 reader and the venn-1 head have their own terms; see licenses.
  • The distribution is named venn-vdm and the import name is venn. Do not install it alongside the unrelated venn package.
  • Cite with CITATION.cff. See contributing and security.

View this page on GitHub

On this page