Fine-tune of BAAI/bge-m3 for Greek legal, statute/administrative and daily-Greek retrieval.
Dense, 1024-dim, CLS-free (mean-pooled per bge-m3), served as f16 GGUF or safetensors.
Chunking & embedding — best practices (measured, not generic)
These reflect the model's actual training distribution; deviating from them costs recall.
Chunk size: 1,200–2,400 characters of Greek (≈300–600 tokens), overlap ~200 chars.
Training passages had median ~1,500 chars; both training and validation truncated at
256–512 tokens. Greek is token-dense in the XLM-R vocabulary (≈1 token/char worst case,
plan with ≈3–4 chars/token typical) — chunks beyond ~2,400 chars get tail-truncated and
waste content. Do NOT embed whole documents as one vector: long-input embeddings go
diffuse and localized-evidence retrieval degrades (measured repeatedly in this program).
Chunk on structure, not fixed windows, when the text has structure. For statutes,
one άρθρο (or one paragraph of a long άρθρο) per chunk. For court decisions, paragraph
boundaries of the σκεπτικό. Keep a sentence-safe split otherwise.
Prefix each chunk with its provenance (contextual retrieval). A chunk of «Άρθρο 12»
means little without which law it belongs to. Prepend a short breadcrumb line, e.g.
Ν. 4808/2021, Άρθρο 12 — [chunk text]. Title/heading + body was exactly the statute
training format, so this matches the model's distribution.
Queries: natural questions or descriptive phrases, as-is. No instruction prefixes —
bge-m3 is not instruction-tuned and none were used in training. Both interrogative
(«Ποια είναι η προθεσμία…;») and nominal («προθεσμία έφεσης κατά απόφασης») styles
were trained.
Cross-lingual: translate-then-retrieve beats direct embedding. Direct EN query →
EL corpus scores 82.1 here; translating the English query to Greek first and retrieving
Greek→Greek operates at the 85–92 band. If your users query in English over Greek
documents, machine-translate the query first.
Always L2-normalize vectors (Ollama's /api/embed returns them normalized; if you
call the model another way, normalize yourself). With normalized vectors, L2 and cosine
ranking are identical. Use exact (brute-force) search below ~100k vectors — lossy
ANN indexes (IVF_PQ) cost 5–15% recall and are unnecessary at document-collection scale.
Batching: ≤32 texts or ≈8,000 estimated tokens per request keeps within the
context window and gives stable throughput.
Version migrations: vectors from different embedder versions (or other models) are
NOT comparable. Any model switch requires re-embedding the entire store.
Serving
ollama pull hf.co/pan0sk/bge-m3-legal-v4
Or SentenceTransformer("pan0sk/bge-m3-legal-v4") for GPU/server (vLLM/TEI compatible
via the safetensors).