Skip to content

Your company handbook, searchable with citations#

Your handbook is a folder of PDF and Word files on one of your machines: policies, onboarding, benefits, travel. You make that folder a drive, index it in a knowledge base with two small models on CPUs, and ask it questions. Every answer is a passage with its citation — the file, and the page (PDF) or the headings (Word) it is under — so whoever reads it can check it. Then you write a few questions people really ask and measure how well the base finds their answers.

What you need:

  • The handbook's files in one folder on a machine of the workspace, here /srv/handbook on cpu-01. PDF files need a text layer (a PDF exported from a word processor has one; a scan does not — see Troubleshooting). Word files are .docx.
  • That folder granted to the workspace by an organisation admin, in the workspace's cluster access: Host access — nothing unless granted → Host paths.
  • A machine with a data location and, free, 5 CPU cores and about 6 GB of memory: 2 cores for each model and 1 for the base (Footprint and cost). It may be cpu-01 itself.
  • The editor role, and the variables in How the recipes are written.

1. Make the folder a drive#

A drive gives the folder a name the base can read. On one machine keeps the files where they are: the base reads them there (over NFS when it runs on another machine), read-only, and deleting the drive never touches them.

  1. Astraeus → Drives → New drive. Name: handbook-files.
  2. Source 1, Kind: On one machine. Machine: cpu-01. Path on the machine: /srv/handbook.
  3. Mounted in workers at: /data. Access: Read-only.
  4. Create drive.
$ curl -fsS -X POST "$ASTRALYX_API/drives" -H "Authorization: Bearer $ASTRALYX_TOKEN" \
    -H 'content-type: application/json' \
    -d '{"metadata": {"name": "handbook-files"},
         "spec": {"sources": [{"machine": "cpu-01", "path": "/srv/handbook", "mount_path": "/data", "mode": "ReadOnly"}]}}' \
  | jq -r .metadata.name
handbook-files

astra makes drives backed by a data source only; a drive on one machine is made in the console or the API. If the handbook lives in a bucket instead, make a drive from that data source: Keep a base in sync with a data source.

2. Serve the embedding model and the reranker on CPUs#

BGE-M3 embeds passages and questions in more than 100 languages; BGE Reranker v2 M3 orders the best candidates again. Both are 438 MB at Q4_K_M and run on CPUs. Keep each at one replica at least: the base calls them on the workspace's network, which does not wake a deployment scaled to zero.

  1. Eos → Models → Library, Category: embedding, open BGE-M3, choose Q4_K_M and press Deploy. Name: bge-m3. Runs on: CPUs only. Clear Scale to zero when idle. Press Deploy.
  2. Category: Rerankers, open BGE Reranker v2 M3, choose Q4_K_M, and deploy it the same way as bge-reranker.
$ astra eos add bge-m3:567m
$ astra eos deploy bge-m3-567m-q4-k-m --name bge-m3 --cpu --min 1 --max 1
$ astra eos add bge-reranker-v2-m3:568m
$ astra eos deploy bge-reranker-v2-m3-568m-q4-k-m --name bge-reranker --cpu --min 1 --max 1
$ for c in bge-m3:567m bge-reranker-v2-m3:568m; do
    curl -fsS -X POST "$ASTRALYX_API/eos/catalog-models" -H "Authorization: Bearer $ASTRALYX_TOKEN" \
      -H 'content-type: application/json' -d "{\"catalog\": \"$c\"}" | jq -r .metadata.name
  done
bge-m3-567m-q4-k-m
bge-reranker-v2-m3-568m-q4-k-m
$ curl -fsS -X POST "$ASTRALYX_API/eos/deployments" -H "Authorization: Bearer $ASTRALYX_TOKEN" -H 'content-type: application/json' \
    -d '{"metadata": {"name": "bge-m3"}, "spec": {"model": "bge-m3-567m-q4-k-m", "accelerator": "cpu", "replicas": {"min": 1, "max": 1}}}' > /dev/null
$ curl -fsS -X POST "$ASTRALYX_API/eos/deployments" -H "Authorization: Bearer $ASTRALYX_TOKEN" -H 'content-type: application/json' \
    -d '{"metadata": {"name": "bge-reranker"}, "spec": {"model": "bge-reranker-v2-m3-568m-q4-k-m", "accelerator": "cpu", "replicas": {"min": 1, "max": 1}}}' > /dev/null

You do not need to wait for them to be Ready: the base waits for its embedding model and says so.

3. Create the knowledge base#

  1. Metis → Knowledge bases → New knowledge base. Keep Documents.
  2. Name: handbook.
  3. Drives it reads: handbook-files, folder empty (the whole drive).
  4. Embedding model: bge-m3. Reranker: bge-reranker.
  5. Press Make it. The base's page opens.
$ astra metis create handbook --drive handbook-files --embedding bge-m3 --reranker bge-reranker
handbook: created; its index service starts on one of the workspace's machines and reads its drives (`astra metis get handbook`)
$ curl -fsS -X POST "$ASTRALYX_API/metis/knowledge-bases" -H "Authorization: Bearer $ASTRALYX_TOKEN" -H 'content-type: application/json' \
    -d '{"metadata": {"name": "handbook"},
         "spec": {"sources": [{"drive": "handbook-files"}],
                  "embedding": {"deployment": "bge-m3"},
                  "reranker": {"deployment": "bge-reranker"}}}' > /dev/null

A drive or deployment that does not exist, or a deployment that serves something else (a chat model named as the embedding model), is refused with the reason.

4. Watch it index#

The base goes Pending → Starting → Indexing → Ready. While it is Indexing you can already search what it has read.

The base's page shows its state and why, Indexed (documents and chunks), This pass (documents read of the pass), and the machine it runs on. Documents → Everything indexed lists each file with its chunks; a file that could not be read says why.

$ astra metis get handbook
handbook: Indexing — indexing: 18 of 42 documents read; 18 documents, 412 chunks searchable
documents 18  chunks 412  failed 0
this pass: 18 of 42 documents read
machine: cpu-01
…
$ astra metis documents handbook --failed
handbook-files:archive/2019-benefits.pdf  — not indexed: the PDF has no text layer (a scanned document?): text in images is not read
1 in all
$ curl -fsS "$ASTRALYX_API/metis/knowledge-bases/handbook" -H "Authorization: Bearer $ASTRALYX_TOKEN" \
    | jq '{state: .status.state, reason: .status.reason, index: .observed.index}'
$ curl -fsS "$ASTRALYX_API/metis/knowledge-bases/handbook/documents?failed=true" -H "Authorization: Bearer $ASTRALYX_TOKEN"

Once every file is read the base is Ready, and its reason gives the totals: 41 documents, 1093 chunks (1 document could not be read: see its documents). Files of other kinds in the folder (.pptx, .xlsx, images) are counted and left out; hidden files and folders are not read.

5. Ask it#

Open the base, Search, and ask How many vacation days do I have? Each result shows where it is — the file and its page, or the file and its headings — the passage around what matched, and its scores; Whole passage opens the chunk.

$ astra metis search handbook "How many vacation days do I have?" -k 3
1. policies/leave-policy.pdf, page 2  (0.941)
   Full-time employees accrue 25 days of paid vacation per calendar year.
2. policies/leave-policy.pdf, page 3  (0.402)
   Unused vacation days carry over to the next year, up to 5 days.
3. onboarding/first-week.docx › Your first week › Time off  (0.188)
   Ask your manager two weeks ahead for any leave longer than three days.
(hybrid, reranked; … ms)

Narrow a search to a folder or a kind:

$ astra metis search handbook "travel per diem" --prefix policies/ --kind pdf
$ curl -fsS -X POST "$ASTRALYX_API/metis/knowledge-bases/handbook/search" -H "Authorization: Bearer $ASTRALYX_TOKEN" \
    -H 'content-type: application/json' -d '{"query": "How many vacation days do I have?", "top_k": 3}' \
  | jq '.results[] | {score, document: .citation.document, page: .citation.page, headings: .citation.headings, snippet: .citation.snippet}'

A PDF is cited by its page; a Word file by the headings above the passage (its heading styles, in whatever language the document uses); score is the reranker's. The passages and the scores above illustrate the shape of an answer: yours are your handbook's.

6. Write an evaluation set and measure it#

An evaluation set is a few questions people ask, each with the file that answers it. Put it in the hidden folder .metis/ of the handbook's folder — the base reads it for evaluations and never indexes it:

/srv/handbook/.metis/evals.jsonl
{"question": "How many vacation days do I have?", "expected": ["policies/leave-policy.pdf"]}
{"question": "Who approves a trip abroad?", "expected": ["policies/travel.docx"]}
{"question": "What do I need on my first day?", "expected": ["onboarding/first-week.docx"]}
{"question": "Can I expense a home office chair?", "expected": ["policies/expenses.pdf"]}

Paths are the files' paths in the drive. Twenty to fifty questions, in the words people use, measure a handbook well; four show the steps.

Open the base, Evaluations. Evaluation sets lists handbook-files:.metis/evals.jsonl (4 questions). Under Run one, keep A set, k 5, hybrid and with the reranker, and press Evaluate. The report shows Recall@5, MRR, and each question with the expected file, its rank, and what was found instead.

$ astra metis evaluate handbook --file handbook-files:.metis/evals.jsonl -k 5
        #1  How many vacation days do I have?
        #2  Who approves a trip abroad?
 not found  What do I need on my first day?
        #1  Can I expense a home office chair?
recall@5 0.75  MRR 0.625  (4 questions)
$ curl -fsS -X POST "$ASTRALYX_API/metis/knowledge-bases/handbook/evaluate" -H "Authorization: Bearer $ASTRALYX_TOKEN" \
    -H 'content-type: application/json' -d '{"file": "handbook-files:.metis/evals.jsonl", "k": 5}' \
  | jq '{recall_at_k, mrr, missed: [.outcomes[] | select(.rank == null) | {question, found}]}'

recall@5 is the share of expected files found among the first five files; MRR rewards finding the first one early (1.0: always first). Here three of four questions were answered within five files, one first and one second. For the question that was missed, look at what was found instead — then see Measure and improve search quality.

7. Let people use it#

  • Who may search: everyone in the workspace with the viewer role or above, or a role with knowledge-bases:search (Permissions).
  • From their AI assistant: search_knowledge_base over MCP (Connect your AI assistant), or Claude Code with the Astralyx skill (Search your knowledge from Claude Code).
  • From a chat model of yours: Chat with your documents in Eos.
  • When the handbook changes: edit the files in /srv/handbook. The base looks for changes every 60 s (rescan_seconds) and reads only the files that changed; files you remove leave the index.

Footprint and cost#

What Where Size
BGE-M3 and BGE Reranker v2 M3 Each on a machine's data location (weights) and in its memory 438 MB each on disk; 2 CPU cores reserved each by default, and the machine's idle cores used beyond
The base's index service One machine of the workspace 1 CPU core and 2 GiB of memory by default (placement)
The index In the base's memory, and on its drive metis-handbook on that machine's data location About 5 KB per chunk at 1024 dimensions: 10,000 chunks take about 50 MB
The handbook Where it was: /srv/handbook on cpu-01 Read, never copied or changed

A chunk is at most 1,200 characters, so a page of dense text makes a few chunks. Metis has no price of its own: the base and its two models are work of the workspace like any other, metered by the cores and memory they hold (core-hours, GiB-hours) and priced by the cluster's price table (Usage, cost and budgets). The base calls its models on the workspace's network, not through a gateway, so indexing and searching count no tokens. Nothing of the handbook leaves your machines; Astralyx keeps only the base's totals.

Clean up#

Delete the base (Delete on its page, typing its name, or astra metis delete handbook): its index and what was added to it go; the files in /srv/handbook stay. Then delete the drive handbook-files (it never deletes the files of a drive on one machine) and the two deployments if nothing else uses them. See Delete a knowledge base.

Troubleshooting#

Symptom Cause Fix
403 HOST_ACCESS_FORBIDDEN when making the drive /srv/handbook is not among the workspace's granted host paths An organisation admin grants it under Host paths in the workspace's cluster access
The base stays Pending: waiting for a machine: … No machine can read the drive and has the core, the memory and a data location free Read the reason: free a machine, or lower placement
Waiting: waiting for its embedding model, deployment bge-m3 (Starting: …) The model is still being pulled or loaded Wait; follow it in Eos → Deployments
A PDF has no text layer (a scanned document?) The file is images of pages Export it from its source with text, or run OCR on it yourself and replace the file
A file is not listed at all It is .doc, .pptx or another kind a base does not read, or hidden Save it as .docx or PDF
the PDF is encrypted (password-protected) The PDF needs a password to open Save a copy without one

Every state and reason: Troubleshoot a knowledge base.