Enable Knowledge
Give Chat an S3-compatible bucket and an embedding model so people can build document collections. The bucket also holds people's attachments and generated images.
5 min readUpdated for Chat 0.5.2Edit on GitHub
Document files go to an S3-compatible bucket. Passages and vectors stay in Chat's Postgres database, so pgvector must be installed there (see Install Chat). From v0.4.2, the same bucket also holds the files people attach to chats and the images models generate; see Where files are kept.
Set it up
- 1
Create a bucket
Any S3-compatible store works: AWS S3, Cloudflare R2, MinIO, Garage. Create an access key that can read, write and delete objects in that bucket only.
- 2
Serve an embedding model
Register an embedding model in the gateway and make sure Chat's tenant may use it. The default is
qwen3-embedding-8b; any embedding model works. Chat stores 1,024 dimensions: it keeps the first 1,024 of a longer vector and renormalizes them, which suits models trained to be truncated, such as Qwen3-Embedding, and pads a shorter one with zeros, which doesn't change its distances.Most embedding models expect a prefix before searches and before passages. From v0.4.4, Chat knows the prefixes for common models and uses them on its own; for any other model, set them (see Choose the embedding model).
- 3
Configure Chat
OBLETH_CHAT_S3_ENDPOINT=https://<account>.r2.cloudflarestorage.com OBLETH_CHAT_S3_BUCKET=obleth-chat OBLETH_CHAT_S3_ACCESS_KEY_ID=… OBLETH_CHAT_S3_SECRET_ACCESS_KEY=… OBLETH_CHAT_EMBEDDING_MODEL=qwen3-embedding-8bRestart Chat. Library appears in the sidebar for everyone, with Saved, Collections and Generated, and answers get a Save button. Without these settings Library is hidden.
Opening a document's original file, for example from a citation, sends the person's browser straight to the bucket on a 5-minute signed link. People's browsers must therefore reach OBLETH_CHAT_S3_ENDPOINT and trust its certificate. With a bucket on a private network, uploads, indexing and citations still work everywhere, but only people on that network can open the original files.
Where files are kept
With a bucket configured (v0.4.2 and later), Chat stores these files there:
| Files | Stored under |
|---|---|
| Knowledge documents | knowledge/<user>/<document> |
| Chat attachments | attachments/<user>/<file> |
| Generated images | images/<user>/<image> |
Without a bucket, attachments and generated images are kept in Postgres. Turning the bucket on later needs no other step: a background worker moves existing files into it one at a time, and files stay readable throughout. Each replica logs moving files kept in Postgres into object storage when it starts moving them.
Attachments and generated images are served through Chat, never through a link to the bucket, so people's browsers don't need to reach the bucket to open them. Deleting a file, a chat or an account deletes the stored files shortly afterwards. An upload whose chat or file was never saved is deleted after 15 minutes.
Reclaim the database space after the move
Moving files out of Postgres frees their space for new rows, but the database files don't shrink. To give the space back to the disk, run this once the move is done, in a quiet period:
VACUUM FULL attachments, generated_images;
VACUUM FULL rewrites both tables and blocks reads and writes on them while it runs.
Settings
| Variable | Default | Meaning |
|---|---|---|
OBLETH_CHAT_S3_ENDPOINT | unset | Turns Knowledge on. Chat uses path-style addresses |
OBLETH_CHAT_S3_BUCKET | unset | The bucket |
OBLETH_CHAT_S3_ACCESS_KEY_ID, OBLETH_CHAT_S3_SECRET_ACCESS_KEY | unset | The bucket's credentials |
OBLETH_CHAT_S3_REGION | auto | Signing region. auto suits R2; set the real region for S3 |
OBLETH_CHAT_EMBEDDING_MODEL | qwen3-embedding-8b | Default gateway embedding model. An administrator can choose another in Settings |
OBLETH_CHAT_EMBEDDING_QUERY_PREFIX | Qwen3-Embedding's instruction | Default text put before each search. Empty for none |
OBLETH_CHAT_EMBEDDING_DOCUMENT_PREFIX | empty | Default text put before each passage and saved item |
OBLETH_CHAT_KNOWLEDGE_USER_MB | 2048 | Storage per person, in MiB |
OBLETH_CHAT_PDFTOTEXT, OBLETH_CHAT_UNZIP | on PATH | Paths to the extraction tools, if they're elsewhere |
Choose the embedding model
From v0.4.3, an administrator chooses the embedding model and its prefixes in Settings › Administration › System › Knowledge search. The list shows the embedding models the gateway offers. OBLETH_CHAT_EMBEDDING_MODEL sets the default model.
Each prefix comes from the first of these that is set (v0.4.4 and later):
- The administrator's choice in Settings.
OBLETH_CHAT_EMBEDDING_QUERY_PREFIXorOBLETH_CHAT_EMBEDDING_DOCUMENT_PREFIX, while the default model is in use. They never carry over to another model.- The model's own prefixes, for the models in the table below.
Any other model gets no prefix. Choosing a model in Settings fills in its prefixes, so check them against the model's documentation only when it isn't in the table.
Vectors from different models, or the same model with different prefixes, can't be compared. When the model or a prefix changes, Chat indexes every document and saved item again, on its own, with the new settings. Until that finishes, search finds only what has been redone, and a large library takes a while and uses the gateway's embedding capacity. Switching back indexes everything again too. Chat asks for confirmation before it starts, and the card shows how much is left.
The same happens when the defaults change in the environment and no administrator has chosen otherwise. In v0.4.2, which has no setting in the app, change the environment variables and upload the documents again.
Models whose prefixes Chat knows
Chat recognises these by a part of the model's name in the gateway:
| Model | Name contains | Search prefix | Passage prefix |
|---|---|---|---|
| Qwen3-Embedding | qwen3-embedding | Instruct: Given a question, retrieve passages from the person's documents that answer it\nQuery: | none |
| EmbeddingGemma | embeddinggemma | task: search result | query: | title: none | text: |
| Nomic Embed Text | nomic-embed-text | search_query: | search_document: |
| E5 | multilingual-e5, e5-large, e5-base, e5-small | query: | passage: |
| BGE English, mxbai | bge-large-en, bge-base-en, bge-small-en, mxbai-embed-large | Represent this sentence for searching relevant passages: | none |
In an environment variable, the trailing space is part of the prefix, so quote the value.
How indexing runs
A background worker on each replica claims queued documents with FOR UPDATE SKIP LOCKED, so replicas share the work. A claim is reclaimed after 10 minutes, and a document gets 3 attempts. Files are stored under knowledge/<user>/<document>, and downloads are 5-minute presigned links.
Deleting a document or collection removes its passages at once. Its files go on a trash list that the worker empties shortly after, so a bucket error never leaves passages behind.
pdftotext (from poppler-utils) and unzip must be on the image; the Chat image includes both.
