You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Complete Verified Guide: Self-Host AI BYOK on 0.27.x (5 undocumented requirements + model matrix + troubleshooting)
#15553
AFFiNE 0.27.x Self-Host AI (BYOK) — Complete Verified Setup Guide
A complete, battle-tested walkthrough for getting AI BYOK + full-text search working on a stock 0.27.4 Docker deployment. Everything below was verified end-to-end (probes, chat, doc reads, hybrid search) on a real deployment. The official docs cover some of this, but four undocumented requirements and one model-capability matrix are what actually make it work.
Full-text (lexical) search requires the Manticore container per the official indexer guide — env vars AFFINE_INDEXER_ENABLED=true + AFFINE_INDEXER_SEARCH_ENDPOINT, NOT config.json. The embedded provider in config.example.json is canary-only.
BYOK keys are configured in Workspace Settings → Integrations → AI BYOK (not the admin panel — the old admin AI settings were removed in 0.27.x).
Model selection — what actually works (probe request captured & verified)
The probes are much stricter than they look:
Structured-output probe sends max_completion_tokens: 16 with strict json_schema and "Reply with OK." → reasoning models (glm, deepseek, qwen-flash) fail invalid_response because reasoning eats the entire 16-token budget. Use a small non-reasoning model for structured output (e.g. google/gemma-4-31b-it).
BYOK "rerank" is NOT a /rerank endpoint. It sends chat/completions with logprobs: true, top_logprobs: 5 and scores p(yes)/(p(yes)+p(no)). Consequences:
dedicated rerankers (qwen3-reranker-8b) 500 on this route → probe unavailable
gemini/mistral/llama accept logprobs but return null → probe passes but score is always 0.0 (decorative only)
only OpenAI-family models return real logprobs → openai/gpt-4.1-nano ($0.10/$0.40 per 1M) is the cheapest actually functional reranker (verified: relevant doc scores 1.0, unrelated 0.0)
CORS: browsing from a different origin than externalUrl
set externalUrl = actual URL, look for Blocked CORS request from origin in logs (#15552)
LEXICAL_UNAVAILABLE in search results
manticore container missing
indexer service per official guide; notice is benign (vector-only fallback)
structured probe invalid_response
reasoning model + 16-token budget
use a non-reasoning model for structured
rerank unavailable
dedicated reranker vs ChatLogprobs protocol
use an OpenAI-family chat model
doc-save action fails Peer disconnected
upstream drops stream on huge long-session payloads
retry in a fresh session; not a config error (#15552 Defect 3)
Version notes
Verified on the official 0.27.4 stable image. The embedded search provider in repo config.example.json does not exist in the stable image — use Manticore per the indexer guide.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
AFFiNE 0.27.x Self-Host AI (BYOK) — Complete Verified Setup Guide
A complete, battle-tested walkthrough for getting AI BYOK + full-text search working on a stock 0.27.4 Docker deployment. Everything below was verified end-to-end (probes, chat, doc reads, hybrid search) on a real deployment. The official docs cover some of this, but four undocumented requirements and one model-capability matrix are what actually make it work.
TL;DR — the 5 things the docs don't tell you
AFFINE_BACKEND_RUNTIME_CONFIG_PATH=/root/.affine/config/config.json— the Rust native runtime (which actually runs the AI) does not read~/.affine/config/config.jsonby default (Self-host: AI chat always fails withcopilot_disabled— the native runtime never reads config.json #15506). Without it, GraphQL says Copilot is enabled but every chat returnscopilot_disabled.DEPLOYMENT_TYPE=selfhosted— without it the runtime assumes Cloud andcustomEndpointModebecomesunavailable, hiding the custom-endpoint option in the BYOK dialog ([Bug]: AI BYOK cant set custom ai providers in self-hosted version #15534).server.externalUrlmust equal the URL you actually browse from — the CORS allowlist is built from it exactly. Mismatch = every BYOK probe shows "Connection failed" while keys/URLs/models are all fine ([Bug]: [Self-host BYOK] Three undocumented failure modes: CORS externalUrl mismatch, 16-token structured probe, Peer disconnected on long action turns #15552).AFFINE_INDEXER_ENABLED=true+AFFINE_INDEXER_SEARCH_ENDPOINT, NOT config.json. Theembeddedprovider inconfig.example.jsonis canary-only.Final working architecture
config/config.json
{ "$schema": "https://github.com/toeverything/affine/releases/latest/download/config.schema.json", "server": { "name": "AFFiNE Self-hosted", "externalUrl": "https://your-public-url:3010" }, "copilot": { "enabled": true, "byok": { "enabled": true, "allowedProviders": ["openai", "anthropic", "gemini", "fal"], "allowCustomEndpoint": true, "allowPrivateEndpoint": true } } }(
allowPrivateEndpoint: trueis required when your gateway is on a private network — e.g. a tailnet hostname.)docker-compose services (the full working set)
Start:
docker compose up -d. Expose:tailscale serve --bg --https=3010 http://127.0.0.1:3010or your reverse proxy.Configuring BYOK keys
DEPLOYMENT_TYPE=selfhostedis set — see trap Feat/style #2)https://your-gateway/v1, API dialect: Chat Completions APIModel selection — what actually works (probe request captured & verified)
The probes are much stricter than they look:
max_completion_tokens: 16with strict json_schema and "Reply with OK." → reasoning models (glm, deepseek, qwen-flash) failinvalid_responsebecause reasoning eats the entire 16-token budget. Use a small non-reasoning model for structured output (e.g.google/gemma-4-31b-it).chat/completionswithlogprobs: true, top_logprobs: 5and scoresp(yes)/(p(yes)+p(no)). Consequences:unavailablenull→ probe passes but score is always 0.0 (decorative only)openai/gpt-4.1-nano($0.10/$0.40 per 1M) is the cheapest actually functional reranker (verified: relevant doc scores 1.0, unrelated 0.0)/v1/v1/messagesdoubled → 404, BYOK: Anthropic provider always fails — request URL contains /v1 twice (404) #15505). Use an OpenAI-compatible gateway instead.Troubleshooting quick reference
copilot_disabledAFFINE_BACKEND_RUNTIME_CONFIG_PATH(#15506)DEPLOYMENT_TYPE=selfhosted(#15534)Blocked CORS request from originin logs (#15552)LEXICAL_UNAVAILABLEin search resultsinvalid_responseunavailablePeer disconnectedVersion notes
embeddedsearch provider in repoconfig.example.jsondoes not exist in the stable image — use Manticore per the indexer guide.copilot_disabled— the native runtime never reads config.json #15506 (config read), [Bug]: AI BYOK - unable to configure, connection failed #15530/[Bug]: AI BYOK cant set custom ai providers in self-hosted version #15534 (connection failed / custom endpoint), [Bug]: [Self-host BYOK] Three undocumented failure modes: CORS externalUrl mismatch, 16-token structured probe, Peer disconnected on long action turns #15552 (CORS + probe details), [Bug]: [v0.27.4] Workspace BYOK profiles cannot be saved when recommended-model probes partially fail #15496 (one failed probe blocks save).All reactions