Model configuration¶
AGRO treats "models" as configuration, not as a hard‑coded list.
All the knobs you see in the UI ultimately flow through Pydantic models (e.g. agro_config.json → AgroConfigRoot → config registry → HTTP API → web UI). You can point AGRO at any local or cloud model as long as you can describe it in JSON / env vars.
This page focuses on how model configuration is actually wired through the system, and how that shows up in the UI and service layer.
Where model config actually lives
- Tunable RAG + model parameters:
agro_config.json - Secrets / infra overrides:
.env - Runtime view / editing: config registry +
/api/configendpoints
The registry merges these with clear precedence:
.env(highest)agro_config.json- Pydantic defaults (fallback)
How model config flows through the backend¶
At runtime, everything goes through the configuration registry in server/services/config_registry.py:
The registry is the only thing that should know how to read .env and agro_config.json. Everything else (RAG, indexing, editor, keywords, etc.) just calls get_config_registry() and uses typed accessors:
Under the hood, the registry validates agro_config.json against AgroConfigRoot (in server/models/agro_config_model.py) and exposes a flat key space via AGRO_CONFIG_KEYS. That same key set is used by:
- The HTTP config API (
server/services/config_store.py) - The editor service (
server/services/editor.py) - The web UI admin panels (General / Models / Integrations subtabs)
Why this matters for models¶
Because everything flows through the same registry:
- You can add a new model by only editing
agro_config.json(or.envfor secrets). - The UI will automatically pick up new keys from
AGRO_CONFIG_KEYSand show them with tooltips. - MCP / CLI / HTTP all see the same model configuration.
You don't need to touch Python code to:
- Switch from OpenAI to Anthropic
- Point at a local vLLM / Ollama endpoint
- Add a second embedding model for experiments
As long as the Pydantic model knows about the field, the registry will surface it everywhere.
Editing model config via the service layer¶
The web UI and CLI never write agro_config.json directly. They go through server/services/config_store.py, which:
- Validates changes against
AgroConfigRoot - Writes atomically to disk (with Docker volume fallbacks)
- Hides secret fields when returning config to the UI
This is the piece that makes "edit config in the browser" safe even when you're running AGRO under Docker with bind mounts and file watchers.
When you change a model in the UI:
- The UI calls
/api/configwith a JSON patch. config_storevalidates it againstAGRO_CONFIG_KEYS/AgroConfigRoot.- The new config is written atomically.
- The registry can be reloaded (hot) without restarting the server.
Example: switching generation / embedding models¶
Assume you start with something like this in agro_config.json:
{
"models": {
"generation": {
"provider": "openai",
"model": "gpt-4.1",
"temperature": 0.2
},
"embedding": {
"provider": "openai",
"model": "text-embedding-3-large",
"dim": 3072
}
}
}
To switch to a local vLLM server for generation while keeping OpenAI embeddings:
{
"models": {
"generation": {
"provider": "http",
"base_url": "http://localhost:8001/v1",
"model": "local-mixtral-8x7b",
"temperature": 0.1
},
"embedding": {
"provider": "openai",
"model": "text-embedding-3-large",
"dim": 3072
}
}
}
You don't need to change any Python code. The retrieval pipeline (server/services/rag.py → retrieval/hybrid_search.py) just asks the registry for the current model config and uses it.
How other services consume model‑related config¶
Several backend services cache model‑related values at module import time for performance. They all use the same registry instance.
RAG service (server/services/rag.py)¶
The RAG HTTP endpoint uses config for things like FINAL_K (how many chunks to return) and LangGraph parameters:
If you change FINAL_K or swap out the reranker model in agro_config.json, this code picks it up via the registry.
Indexing service (server/services/indexing.py)¶
Indexing uses config to decide which repo to index and whether to enrich chunks with model‑generated summaries:
ENRICH_CODE_CHUNKS is read by the indexer process and controls whether it calls your configured generation model to summarize code chunks.
Keyword extraction (server/services/keywords.py)¶
Keyword generation / boosting is also driven by config, including whether to auto‑generate keywords using an LLM:
If KEYWORDS_AUTO_GENERATE is enabled, the keyword pipeline will call your configured LLM to propose discriminative keywords based on your codebase and golden dataset.
Editor / DevTools integration¶
The built‑in editor / DevTools panel is also driven by the same registry. Editor settings are read with a preference for agro_config.json / .env, and only fall back to a legacy settings.json file:
This is mostly infra rather than "model" config, but it uses the same mechanism: Pydantic → registry → typed getters.
How the UI knows what each parameter does¶
AGRO is intentionally self‑describing:
- Every config key in
AGRO_CONFIG_KEYShas metadata (description, type, default). - The web UI pulls that metadata and renders it as tooltips, with links to docs / papers where relevant.
- You can search for any parameter name in the UI and jump straight to its explanation.
Because the registry tracks config source (which file a value came from), the UI can also show you whether a value is coming from:
.env(and therefore should be edited there), oragro_config.json(and can be changed via the UI), or- Pydantic defaults (and hasn't been customized yet).
This is particularly useful for model configuration: you can see at a glance whether a model is being forced by an environment variable (e.g. in a CI profile) or coming from your local agro_config.json.
MCP and external tools¶
The MCP server (see features/mcp.md) exposes AGRO's RAG engine and configuration to tools like Claude Code / Codex. Because MCP handlers also go through the same registry, any model changes you make in the UI or config files are immediately visible to MCP clients.
You don't need a separate MCP‑specific config file for models.
Rough edges / things to be aware of¶
- Some services cache config values at import time (e.g.
keywords.py). If you change those values at runtime, you may need to call the correspondingreload_config()or restart the server. - The exact shape of
AgroConfigRootis still evolving. If you add custom fields, keep them under a namespaced section (e.g."models": {"my_experiment": ...}) to avoid collisions with future versions. - Secrets should live in
.env, notagro_config.json.config_storewill refuse to echo secret values back to the UI, but it won't stop you from putting them in JSON if you really insist.
Summary¶
- Models are pure configuration: no hard‑coded lists, no special‑case branches.
- The config registry is the single source of truth, with clear precedence and type‑safe accessors.
- The service layer (
config_store,editor,rag,indexing,keywords, etc.) all consume model‑related config via the same registry. - The UI is driven by
AGRO_CONFIG_KEYSand Pydantic metadata, so new model parameters show up automatically with documentation.
If you want to see exactly how a particular model parameter is used, the easiest path is:
- Open the AGRO chat tab.
- Ask it: "Where is
EMBEDDING_MODELused in the codebase?" - Follow the links into the repo and adjust
agro_config.json/.envas needed.