Views
No views yet
Octen/Octen-Embedding-8B for retrieving Belgian statutory articles in response to natural-language legal questions in French.Octen/Octen-Embedding-8B (which is itself a fine-tune of Qwen/Qwen3-Embedding-8B)q_proj, k_proj, v_proj, o_proj) and MLP projections (gate_proj, up_proj, down_proj) of every transformer block.1from peft import PeftModel
2from transformers import AutoModel, AutoTokenizer
3import torch.nn.functional as F
4import torch
5
6base_id = "Octen/Octen-Embedding-8B"
7adapter_id = "Yakuru-43/octen-8b-lleqa-lora"
8
9tokenizer = AutoTokenizer.from_pretrained(base_id, padding_side="left")
10base = AutoModel.from_pretrained(base_id, torch_dtype=torch.bfloat16).cuda()
11model = PeftModel.from_pretrained(base, adapter_id)
12model.eval()
13
14INSTRUCTION = (
15 "Instruct: Retrieve Belgian statutory articles that answer the user's "
16 "legal question.\nQuery: "
17)
18
19def encode(texts, is_query: bool):
20 prefixed = [INSTRUCTION + t for t in texts] if is_query else texts
21 enc = tokenizer(prefixed, padding=True, truncation=True,
22 max_length=1024, return_tensors="pt").to("cuda")
23 with torch.no_grad():
24 h = model(**enc, use_cache=False).last_hidden_state
25 emb = h[:, -1] # last-token pooling, left-padded
26 return F.normalize(emb.float(), p=2, dim=-1)
27
28questions = encode(["Quelle est la durée du préavis pour un bail étudiant ?"], is_query=True)
29articles = encode(["Le bail étudiant peut être résilié moyennant un préavis ..."], is_query=False)
30print((questions @ articles.T).cpu())"- " (dash + space) to avoid unexpected behaviour. We did not apply this prefix during training, but you may wish to evaluate it for your inference pipeline.Octen/Octen-Embedding-8B zero-shot.| Metric | Base | Fine-tuned | Δ | 95% CI | Sig. |
|---|---|---|---|---|---|
| recall@1 | 17.61 | 18.46 | +0.85 | [-4.44, +6.15] | |
| recall@5 | 41.41 | 45.29 | +3.88 | [-3.08, +10.80] | |
| recall@10 | 52.33 | 59.06 | +6.73 | [-0.37, +13.78] | |
| recall@50 | 68.31 | 79.07 | +10.76 | [+4.53, +16.81] | ★ |
| recall@100 | 75.21 | 84.79 | +9.57 | [+4.27, +14.96] | ★ |
| recall@500 | 85.26 | 92.98 | +7.72 | [+3.88, +11.72] | ★ |
| mrr@10 | 34.59 | 39.09 | +4.49 | [-1.50, +10.63] | |
| ndcg@10 | 35.95 | 40.35 | +4.40 | [-0.68, +9.75] | |
| map | 29.95 | 33.29 | +3.34 | [-1.65, +8.39] |
| Hyperparameter | Value |
|---|---|
| Base model | Octen/Octen-Embedding-8B |
| LoRA rank | 16 |
| LoRA alpha | 32 |
| LoRA dropout | 0.1 |
| Target modules | q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj |
| Loss | Multi-positive InfoNCE |
| Hard negatives | 7 / question (mixed BM25 + dense Octen-zero-shot) |
| Effective batch size | 16 questions × ~16 negs |
| Learning rate | 2e-4, cosine, 10% warmup |
| Epochs | 3 |
| Precision | NF4 4-bit base + bf16 LoRA |
| GPUs | 2× RTX 4500 Ada |
Octen/Octen-Embedding-8B and the underlying Qwen/Qwen3-Embedding-8B. See the LICENSE file in this repository.1@misc{octen2025rteb,
2 title = {Octen Series: Optimizing Embedding Models to #1 on RTEB Leaderboard},
3 author = {Octen Team},
4 year = {2025},
5 url = {https://octen-team.github.io/octen_blog/posts/octen-rteb-first-place/}
6}
7
8@inproceedings{louis2024interpretable,
9 title = {Interpretable Long-Form Legal Question Answering with
10 Retrieval-Augmented Large Language Models},
11 author = {Louis, Antoine and van Dijck, Gijs and Spanakis, Gerasimos},
12 booktitle = {Proceedings of AAAI},
13 year = {2024}
14}