Back to guides
Setup·September 21, 2026·8 min read

Change Agent Zero's embedding model: memory reindexing and rollback

Agent Zero's docs give one line — "Changing the embedding_llm will re-index all of A0's memory" — and no procedure. Here is what the rebuild does, and the two paths where it quietly does not fire.

Last reviewed on .

Changing Agent Zero's embedding model means editing the embedding slot inside a Model Preset and clicking Save — and when that edit changes the provider or the model name, the next access re-indexes memory, because a FAISS index is sized to one model's output width and the vectors already on disk were written by the old model. Agent Zero's own installation guide states the consequence in a single line — "Changing the embedding_llm will re-index all of A0's memory" — and gives no procedure, no duration and no way back. This page fills that gap from the source: what the automatic rebuild actually does, the two paths where it quietly does not fire, how to verify that old memories still come back, and how to return. Kunavo serves no embedding model, so that slot is bought elsewhere; the slots Kunavo can price are the main and utility ones.

Two version numbers to keep apart first. The framework is on v2.12, published September 9, 2026 per the project's own release article. The most prominent number in the README is A0 Launcher v1.7, which is the separate desktop installer in agent0ai/a0-launcher — attaching it to the framework is wrong by a whole major line. And in v2.x the model fields sit on a preset rather than on a flat global setting: the model-presets guide says "every setup contains a main, utility, and embedding model", and Settings → Agent → Models is where you choose which preset new chats use. Note that the installation guide still documents an "Embedding Model Settings" section with Provider and Model Name fields, so a walkthrough written that way is not automatically out of date — but the value you type lands on a preset slot, which is what makes the propagation warning below matter.

Why this is not like switching the chat model

A chat model change takes effect on the next request and nothing on disk has to move. An embedding change invalidates storage. Agent Zero sizes its FAISS index from whatever the live model returns — faiss.IndexFlatIP(len(embedder.embed_query("example"))) in plugins/_memory/helpers/memory.py — so the width is a property of the model, not of a config value. The shipped default, sentence-transformers/all-MiniLM-L6-v2, maps text to a 384-dimensional space per its model card. OpenAI's embeddings guide puts text-embedding-3-small at 1536 and text-embedding-3-large at 3072. That is the shape change a switch causes.

Two scoping facts decide how many rebuilds you are actually buying. First, this is a preset edit, not a global one: the model-presets guide says scopes "store only the preset choice; editing a preset updates every scope that uses it", so one edit can propagate further than you intended — and switching between presets can change the embedding model too. The curated Efficiency and Power presets ship with no embedding block of their own, and the guide only says an existing non-default preset may inherit omitted advanced values from Default, so read the preset summary rather than assume. Second, project_memory_isolation: true is the shipped default in the memory plugin config, so a multi-project instance holds several independent stores and each one rebuilds on its own next use — a project untouched for weeks pays its rebuild the day someone opens it.

Step 1: back up, and write down what you are leaving

Agent Zero's usage guide already names this case: backups protect "your chats, projects, knowledge, memory, settings, skills, and workspace files", and it lists "bulk memory cleanup" among the things to back up before. Take one from Settings → Backup & Restore, or use the Launcher's Backup of /a0/usr. Note the guide's own caveat that secrets "may not always be included in backup archives", so keep credentials separately.

Then record the model you are migrating from. Do not assume it — the curated preset collection is downloaded from a public repository at first start and can change after your install date.

Record what you are migrating FROM (paths derived from memory.py)
# Read the CURRENT model off your own instance before you touch anything.
# The curated preset set is fetched from GitHub at first start, so the
# default you installed with is not necessarily today's default.
# Container name: take it from your own `docker ps`.

docker exec agent-zero ls -la /a0/usr/memory/default
docker exec agent-zero cat  /a0/usr/memory/default/embedding.json
#   -> {"model_provider": "huggingface",
#       "model_name": "sentence-transformers/all-MiniLM-L6-v2"}

# Projects do not share that directory. With project isolation on (the
# shipped default) each project keeps its own store under its own meta
# directory, and each one rebuilds on its own next use.

Step 2: make the change

The flow documented in the installation guide is three steps: open Settings in the Web UI, choose the provider for each role and write the model name, click Save. Four things that flow does not tell you, all read from the source on main:

TrapWhat actually happens
Filling in an API base URL on the default slotIt is ignored. Provider huggingface with a name starting sentence-transformers/ short-circuits into a local wrapper that never touches LiteLLM and filters parameters down to a local-only allowlist. Reaching a hosted endpoint means leaving that local path — a different provider, or a model name without the sentence-transformers/ prefix. Either one is a field the meta file stores, so either one triggers the rebuild.
Entering the endpoint before switching providerLost. The provider dropdown carries @change="model.api_base = ''; model.kwargs = {}; …", so changing it wipes the API base URL and every additional parameter. Switch provider first, then fill in Advanced.
Assuming an OpenAI-compatible chat gateway will workThe slot calls LiteLLM's embedding() function, not the chat wrapper. The endpoint has to implement POST /v1/embeddings. Provider other is remapped to LiteLLM's openai provider, and its key is written to .env as API_KEY_OTHER.
Using localhost for a local model serverInside Docker that means the Agent Zero container. The installation guide directs you to http://host.docker.internal:<port> or the bridge gateway address instead.

What the rebuild does — and the two paths where it does not

On Save, model_config_set.py compares the previous and new embedding provider, name and kwargs, and on any difference starts embedding_model_changed as a deferred background task; the extension it fires does one thing, reload memory. The next access re-runs Memory.initialize(), which checks embedding.json beside the index. That file holds exactly two fields — model_provider and model_name. On a mismatch the code pulls every document out of the old index with get_all_docs, builds a fresh index at the new width, and re-inserts the same documents under the same ids. That path works, and it preserves your memories.

What you changeDoes the meta file notice?Result
Provider or model nameYes — both are storedDocuments read out and re-inserted at the new width. The intended path.
Only an additional parameter, e.g. shortening OpenAI vectors with dimensionsNo — kwargs are not storedMemory reloads, then loads the old index unchanged. A width mismatch surfaces at recall, not at save.
Only the API base URL, repointing at a different endpoint under the same model nameNo — and the save path does not compare it eitherNo reload is even scheduled; the old index simply stays in use. If that endpoint answers with a different width, recall raises a FAISS assertion.
An index file hand-edited, truncated or restored from outsideA separate hash check fails firstThe old index is never loaded, so its documents are never read out, and a fresh empty index is written while the console prints a hash-mismatch warning ending "index will be rebuilt" — nothing about the documents that were dropped. A missing or unreadable hash file is treated as valid.

Rows two and three are the seam behind issue #759, "Errors after changed default Embedding Model", opened October 13, 2025 and closed, whose traceback shows assert d == self.d during similarity search from memory recall; that seam is still visible in main as of September 21, 2026. A second closed issue, #1396, reports a 400 on Ollama's /api/embed that its author traced to a stale index, and gives the workaround of deleting index.faiss and index.pkl. That workaround destroys the store; treat it as a reset, never as a repair or a rollback. Neither issue drew a maintainer comment — #1396 was closed by a stale-issue bot after ninety days — so both diagnoses are the reporters' own and both resolutions are unverified.

Step 3: verify old recall, not a successful call

The failure this change produces is quiet, so "the new model answered" is the wrong acceptance test. Open the memory dashboard and, per the memory guide, filter across all four areas — main, fragments, solutions and skills — searching for something you know predates the change. Do it once per project, because each project has its own store. Then watch the similarity threshold: the shipped memory_recall_similarity_threshold is 0.7, a per-plugin default rather than a property of any model, and a new embedding model redistributes similarity scores. Recall can degrade without a single error being raised, which is why the threshold control is part of the verification and not a detail.

One thing this page cannot tell you: whether the Web UI shows any progress or completion signal while the rebuild runs. It executes as a deferred background task, and no surface for it was confirmed. Assume no confirmation and verify by hand.

Rollback, and what a rebuild costs

There is no vendor-documented rollback. What exists is the backup mechanism plus the meta-file behaviour above, and the route below is assembled from those two rather than published by the project. Restore the pre-change backup; or set the slot back to the exact previous provider and model name, which fails the meta-file comparison in the other direction and rebuilds. On the same container the embedding cache under tmp/ is namespaced by provider and model, so returning to a previously used model can reuse cached vectors for unchanged text — but tmp/ sits outside the documented backup, so recreating the container loses that. What the code does if the new provider errors part-way through a rebuild was not tested and is not stated here; verify from the backup rather than relying on it.

For the money: Kunavo serves no embedding model, so every figure below is paid directly to OpenAI on your own account, at its published rates checked September 21, 2026. Size the job yourself — count stored documents in the memory dashboard, multiply by their average length, and divide by roughly four characters per token. That divisor is a convention, not a measurement.

Rebuild targetPublished rate, billed directly to OpenAI3M tokens re-embedded30M tokens re-embedded
text-embedding-3-small (1536 dims)$0.02 per 1M tokens, billed directly to OpenAI$0.06$0.60
text-embedding-3-large (3072 dims)$0.13 per 1M tokens, billed directly to OpenAI$0.39$3.90
text-embedding-ada-002$0.10 per 1M tokens, billed directly to OpenAI — dearer than 3-small, so not a sensible target today$0.30$3.00
The shipped local model on CPUNo per-token charge; CPU time on your own machine insteadMachine timeMachine time

This is token arithmetic under stated assumptions, not a measured rebuild and not a ceiling. It is also per store: with project isolation on, multiply by the number of projects that will actually be opened again, and remember that a rollback is a second rebuild at the same rate.

The two slots Kunavo can serve

To be plain about the boundary: the embedding slot is not served here, and a gateway that implements the chat wire format is not an embeddings endpoint. What is left is the main and utility slots, which are ordinary chat models. At live catalog rates, Claude Sonnet 4.6 lists $1.20 per million input tokens and $6.00 per million output, and Claude Haiku 4.5 lists $0.40 and $2.00.

Assume a month of 8M input and 0.4M output tokens on a Claude Sonnet 4.6 main slot, plus 2M input and 0.2M output on a Claude Haiku 4.5 utility slot; the embedding slot is not served here and is excluded. Catalog estimate: $13.20. Those are assumed volumes, not a measured workload or a bill ceiling — Agent Zero has not been runtime-tested against Kunavo's endpoint, and the setup described above was read from the project's source and documentation rather than executed. The catalog amount is a billing floor: when the upstream reports its charge, the bill is the greater of catalog cost and upstream cost times the applicable markup. The minimum top-up is $10 in prepaid credit, which is a funding minimum rather than a subscription — see billing details.

If you are still choosing a framework, Agent Zero vs OpenClaw compares the execution models and the three-slot layout. For the endpoint shape itself, the OpenAI-compatible reference and quickstart cover the chat slots, and creating a Kunavo account funds them. For retrieval work more generally, RAG implementation covers the same split between a generation provider and a separately purchased retrieval step.

FAQ

How do I change the embedding model in Agent Zero?

The documented flow in Agent Zero's installation guide is three steps: open the Settings page in the Web UI, choose the provider for the LLM for each role (Main Model, Utility Model, Embedding Model) and write the model name, then click Save. In v2.x that edit lands on the slots of a Model Preset rather than on a flat global setting, because every preset contains a main, a utility and an embedding model, and the model-presets guide warns that editing a preset updates every scope that uses it. One caveat the installation page does not mention: changing the provider dropdown clears the API base URL and every additional parameter on that slot, so enter a custom endpoint after switching provider, never before.

Does changing the Agent Zero embedding model delete my memories?

Not on the documented path. Agent Zero writes a small meta file, embedding.json, beside the index, holding the embedding provider and model name. When those no longer match the configured model, memory.py reads every document out of the old FAISS index with get_all_docs, builds a new index sized from the live vector length, and re-inserts the same documents under the same ids. Memories are re-embedded, not dropped. The destructive step is the workaround written up in issue #1396 for a broken index — deleting index.faiss and index.pkl — which is a memory wipe rather than a migration, and is not a rollback.

How long does an Agent Zero memory reindex take?

The project publishes no figure for it, and none was found elsewhere. The nearest-looking number in the v2.12 release notes — a reported median save time falling from 1,171 ms to 52 ms — belongs to preset editing, where embedding comparisons stopped doing redundant reads. It measures saving a preset, not rebuilding an index; do not budget with it. The rebuild cost scales with how many documents your store holds and how fast the target model answers, so size it from your own instance: count the stored documents in the memory dashboard, and remember that with project isolation on the shipped default, each project pays its own rebuild the day it is next opened rather than all at once.

Why do I get a FAISS assertion error after changing the embedding model?

A dimension mismatch: the stored index has one width and the live model returns another. A closed issue on the Agent Zero repository, "Errors after changed default Embedding Model" (#759, opened October 13, 2025), records exactly that shape — an assert d == self.d AssertionError raised in the vector store during similarity search from the memory recall extension. Reading the source on main, the mechanism that produces it is a seam between two checks: the save path compares provider, name and kwargs before firing its reload event, while the on-disk meta file records only provider and name. So a kwargs-only change fires the reload and then loads the old index unchanged, and an API-base-only change is not compared at all, so nothing is scheduled and the old index simply stays in use. No maintainer comment was visible in that issue and the resolution is unverified; the seam is still visible in main as of September 21, 2026.

Can I point Agent Zero's embedding slot at Kunavo?

No. Kunavo serves no embedding model — the /v1/embeddings route implements the wire format but no enabled model carries that endpoint, so a call fails, and Kunavo's own machine-readable documentation says not to recommend it for embeddings. This matters more than usual here because Agent Zero's embedding slot does not go through the chat wrapper: models.py imports LiteLLM's embedding() function for it, a different API surface, so an OpenAI-compatible chat gateway is not automatically an embeddings gateway. Buy that slot directly from a provider that serves it, or keep the local CPU model. Kunavo's role in an Agent Zero preset is the main and utility slots.

How do I roll back an embedding model change in Agent Zero?

Agent Zero publishes no rollback procedure for this — the documentation offers a one-line warning that the change re-indexes memory, and a general Backup and Restore mechanism, and nothing between them. The route assembled from those two is: restore the backup you took before the change, or set the slot back to the exact previous provider and model name so the meta-file comparison fails again in the other direction and rebuilds. On the same container the local embedding cache under tmp/ is namespaced by provider and model, so returning to a previously used model can reuse cached vectors for unchanged text — but tmp/ is outside the documented backup, so that saving disappears when the container is recreated. Never roll back by deleting the index files.

Checked September 21, 2026 against agent0ai/agent-zero main — memory.py, model_config_set.py, models.py, the memory plugin defaults and the docs tree — plus the v2.12 release article, the a0-presets collection, the two linked issues and OpenAI's published pricing. Nothing on this page was executed: the mechanism claims are source-verified, not runtime-tested, and Kunavo has no run record for Agent Zero. Kunavo token rates come from the live catalog.