Point AnythingLLM at an OpenAI-compatible endpoint

AnythingLLM runs two models, not one: an embedder that ingests your documents once, and a chat model that answers every query forever. Conflating the two is how people end up optimising the wrong bill.

In short: AnythingLLM's generic OpenAI-compatible provider requires GENERIC_OPEN_AI_BASE_PATH including /v1 and throws without it; the API key is optional. Embedding is a separate one-off cost — about 2M tokens to ingest 1,000 documents — while queries run roughly 48M input tokens every month.
Before you start: you need an endpoint root ending in /v1 and a key from that endpoint. The setting below is the only thing that changes — request and response handling stay identical. Rates checked 2026-09-26.

The setting

The connector for arbitrary OpenAI-compatible endpoints is the generic provider. In an environment file it looks like this:

LLM_PROVIDER=generic-openai
GENERIC_OPEN_AI_BASE_PATH=https://aicomp.ai/v1
GENERIC_OPEN_AI_API_KEY=sk-...
GENERIC_OPEN_AI_MODEL_PREF=claude-sonnet-5
GENERIC_OPEN_AI_MODEL_TOKEN_LIMIT=8192

# Embedding is a SEPARATE, one-off cost — 'native' makes it free
EMBEDDING_ENGINE=native
VECTOR_DB=lancedb

Or the same thing on the command line:

docker run -d \
  --name anythingllm \
  -p 3001:3001 \
  -v anythingllm-data:/app/server/storage \
  -e LLM_PROVIDER=generic-openai \
  -e GENERIC_OPEN_AI_BASE_PATH="https://aicomp.ai/v1" \
  -e GENERIC_OPEN_AI_API_KEY="sk-..." \
  -e GENERIC_OPEN_AI_MODEL_PREF="claude-sonnet-5" \
  mintplexlabs/anythingllm

Two things about those variables. GENERIC_OPEN_AI_BASE_PATH is mandatory — the provider throws if it is unset rather than falling back to a default — and it needs the /v1 segment. The key, by contrast, is optional and defaults to unset, which is what you want against a local server that does no authentication.

Embedding is a separate decision with its own engine setting. The built-in one runs locally and costs nothing per document, which is the right default for most self-hosted setups.

The two bills, and which one matters

This is the part worth reading twice. Ingesting a thousand documents at roughly 2k tokens each is about 2M tokens — and you pay that once. Answering two hundred queries a day is about 48M input and 2.4M output a month, and you pay that every month, indefinitely.

Four thousand queries a month: about 12k retrieved context and 600 output tokens each. Rates checked 2026-09-26.
ModelVendorRate
in / out per 1M
4,000 queriesInput share
of the bill
Per month
gpt-5.6-lunaOpenAI$0.1 / $0.6$6.2477%$6
MiniMax-M3MiniMax$0.15 / $0.6$8.6483%$9
deepseek-v4-flashDeepSeek$0.22 / $0.66$12.1487%$12
gemini-3.7-flashGoogle$0.375 / $1.875$22.5080%$22
claude-haiku-4-5-20251001Anthropic$0.5 / $2.5$30.0080%$30
deepseek-v4-proDeepSeek$0.66 / $1.98$36.4387%$36
glm-5.3Zhipu$0.7 / $2.2$38.8886%$39
qwen3.8-maxAlibaba$1 / $3$55.2087%$55
claude-sonnet-5Anthropic$1 / $5$60.0080%$60
gpt-5.6-terraOpenAI$1 / $6$62.4077%$62
kimi-k3Moonshot$1.5 / $7.5$90.0080%$90
claude-opus-5Anthropic$2.5 / $12.5$150.0080%$150

Input is between 77% and 87% of that. Now put the other bill next to it. Ingesting a thousand documents is 2M tokens, paid once, and it is 3.1%–3.5% of the first month's total — after which it is zero, forever, because nothing re-embeds a document that has not changed. A model that costs twice as much to embed with and ten per cent less to query with is still the cheaper choice by the second month, by a wide margin.

Cost note. Embedding was 2M tokens one time. Queries are 48M tokens every month. Choosing a model for its embedding rate optimises a single-digit slice of the first month's bill and nothing at all after it — which is why the ranking above is built on query cost alone.

The ratio on queries is about 20:1, so input decides the ranking here as it does everywhere on this site. The difference is that on this page there is a second, separate cost most people never look at, and it is the one you can make disappear entirely by using the built-in embedder.

One setting moves the query figure more than the model does, and it is not a model setting at all: chunk size. Every query pays for whatever retrieval returns, so chunking that yields more and smaller chunks raises the tokens per query without necessarily improving the answer. If a query is sending twelve thousand tokens of context to produce three paragraphs, the chunking is the thing to fix — and fixing it is free, where changing model is not.

How this fails in practice

The failures that account for most setup problems, and what each one actually means.
What you seeWhat it usually isFix
GenericOpenAI must have a valid base pathGENERIC_OPEN_AI_BASE_PATH is unsetSet it, including /v1, then restart
404 on every chat requestVersion segment missing from the base pathEnd the path with /v1
Requests hit a doubled pathTrailing slash after the version segmentRemove the trailing slash
UI still shows the previous providerVariables read at startup, or a workspace overrides the defaultRestart, then check the workspace's own chat settings
Embedding fails while chat worksEmbedding engine configured independently of the LLMSet EMBEDDING_ENGINE and its model preference separately
Answers ignore uploaded documentsNothing was embedded, or the workspace points elsewhereRe-embed the workspace and check the vector store
You need a key before the code below runs. Create an account, generate a key, and copy the base URL (https://aicomp.ai/v1). Create one free →
Check current rates → Free to sign up · $1 minimum top-up · No prepayment

Confirming it took effect

Ask a question whose answer appears only in a document you uploaded. If it answers from the document, both halves are working — the embedder ingested it and the chat model is reading the retrieved context. Then read the usage log on the endpoint: a request recorded there confirms which provider actually answered, because the UI will happily show a provider that is not the one being used.

FAQ

Why does AnythingLLM say it needs a valid base path?

Because the generic OpenAI-compatible connector treats GENERIC_OPEN_AI_BASE_PATH as mandatory and throws immediately if it is unset, rather than quietly falling back to a default. This is deliberate: the whole point of the generic provider is to talk to an endpoint you specify, so there is no sensible default to fall back to. Set the variable to your endpoint including the /v1 segment and restart.

Does the base path need /v1 on the end?

Yes. The provider builds its request paths on top of whatever you give it, so omitting the version segment produces requests against paths that do not exist — usually a 404 that reads like an endpoint outage rather than a configuration typo. Equally, do not add a trailing slash, because the version segment is the last thing it expects and a slash after it produces a doubled separator in the final URL.

Is the API key required?

Not strictly — the key is optional on the generic provider and defaults to unset, which is what you want for a local server that does no authentication. For a hosted endpoint you will set it. Either way the base path is the one setting that is genuinely mandatory.

Why is embedding configured separately from the chat model?

Because they are two different jobs with two different cost profiles. Embedding converts your documents into vectors and happens once per document, at ingest. The chat model runs on every single query, forever. AnythingLLM lets you pick them independently, which is the right design: it means you can use the free built-in embedder and still use a strong model for answers.

Should I choose a model based on its embedding price?

No — that is the most expensive mistake available on this page. Embedding is a one-off cost paid when documents are ingested, while queries are paid continuously, thousands of times a month. A model that is marginally more expensive to embed with and much cheaper to query is overwhelmingly the better pick. Decide the embedding engine first, then choose the chat model on query cost alone.

How much context does each query actually send?

Whatever the retrieval returns, which is a consequence of your chunk settings and similarity threshold rather than of the model. Typical queries carry several retrieved chunks — on the order of ten thousand tokens — against a few hundred tokens of answer. That makes this an input-heavy workload, so the input rate is the one that decides the bill.

The UI still shows the old provider after I changed the environment file.

Two likely causes. The process reads environment variables at startup, so a restart is required. And a workspace can override the system default: if a specific workspace has its own LLM selection, it wins for that workspace regardless of what the system setting says. Check the workspace's own chat settings before concluding the environment change failed.

Related

Get API access