Pusula
An open-source AI decision engine for Turkish. Pusula is Decision 3.0 (vllm-sr/d3) fine-tuned on Turkish decision data. For each message, typed questions (for example, how a request should be routed, how urgent it is, whether a human should take over, or whether it contains a prompt injection) are answered with a probability for every option in a single forward pass, without text generation.
Doğru karar, doğru yön.
| Version | v2.0 (31 October 2026); earlier weights remain available as revisions v1.0 and v1.0-onizleme |
| Base model | vllm-sr/d3 (26B, Apache-2.0) |
| This repository | LoRA adapter (rank 32) + code readout, ~0.9 GB |
| Language | Turkish |
| Training data | Specially curated Turkish data: synthetic messages generated for this project across NACE Rev. 2.1 sectors and ESCO occupations; the starting adapter (v1.0) was also trained on customer messages licensed from a commercial partner |
| Interface | Same request and answer format as d3's /v1/systemone |
Results
Accuracy (%). Evaluation labels were assigned blind and independently by two annotators (Claude Opus 5.5 and Claude Sonnet 5.5) with adjudication, under the published labeling policy; the real customer messages were labeled blind by Claude under the same policy. Evaluation labels are used exclusively for evaluation. In v2.0, the evaluation sets were extended to the 20 templates; the 1.0 models and Decision 3.0 were therefore evaluated again on the same sets, and their scores differ from those published with v1.0. The MASSIVE and OffensEval scores of Decision 3.0 and Pusula 1.0 are those of the v1.0 release.
| Evaluation | Questions | Decision 3.0 | Pusula 1.0 | Pusula 2.0 |
|---|---|---|---|---|
| Real customer messages (500 held-out, licensed) | 7,500 | 84.0 | 88.5 | 90.6 |
| Long customer complaints (500 held-out, licensed) | 4,500 | 81.5 | 88.1 | 88.3 |
| Turkish Decision Benchmark (2,194 messages) | 19,861 | 88.5 | 92.6 | 92.0 |
| Gold test set (757 held-out messages) | 11,355 | 86.3 | 90.5 | 92.1 |
| Custom questions in unseen sectors | 400 | 92.8 | 91.2 | 93.5 |
Missing information (eksik_bilgi) |
99 | 98.0 | 96.0 | 98.0 |
Sales opportunity (satis_firsati) |
100 | 97.0 | 97.0 | 97.0 |
Life and safety (can_guvenligi) |
120 | 100.0 | 100.0 | 100.0 |
Insults and hate speech (hakaret) |
114 | 93.0 | 93.0 | 95.6 |
Fraud (dolandiricilik) |
97 | 99.0 | 100.0 | 100.0 |
Source grounding of agent answers (kaynaga_dayanma) |
100 | 93.0 | 93.0 | 98.0 |
| AI agent questions (templates 17-20) | 300 | 96.8 | 97.5 | 97.8 |
| Personal data in e-mails | 150 | 95.3 | 98.7 | 100.0 |
| Hidden instructions in documents | 400 | 100.0 | 100.0 | 100.0 |
| Long documents (about 12,000 characters) | 120 | 100.0 | 100.0 | 100.0 |
| MASSIVE tr-TR, 60-way intent, zero-shot (human-written) | 2,974 | 85.3 | 85.2 | 85.2 |
| OffensEval 2020 Turkish, offensive language (real tweets) | 3,528 | 88.4 | 88.3 | 88.3 |
The real customer messages are two held-out sets of 500 anonymized messages licensed from a commercial partner (customer messages, and long customer complaints); they are not published. Pusula 2.0 scores below Pusula 1.0 on the benchmark, 92.0 (Pusula 1.0: 92.6), mainly in urgency, human handoff and domain. The full comparison, including the results per question, is given in the Pusula repository.
Usage
Pusula is loaded with the pusula package. Generic PEFT loading of the adapter is not sufficient, since the code
readout and the non-causal attention hook of the d3 prompt contract are applied by this package.
pip install "pusula[d3] @ git+https://github.com/erenextlabs/pusula"
hf download vllm-sr/d3 --local-dir d3 --exclude "assets/*"
hf download erenextlabs/pusula --local-dir pusula
from pusula.inference import D3Engine
engine = D3Engine.load("d3", adapter="pusula")
answers = engine.decide(
"Kartımdan bilgim dışında üç çekim yapıldı, hemen engelleyin!",
{
"temsilci": {"type": "noul", "instructions": "Bir insan temsilciye aktarılmalı mı?"},
"aciliyet": {"type": "score", "instructions": "Ne kadar acil?", "criteria": ["Rutin", "Yakın", "Yüksek", "Kritik"]},
},
)
Custom questions (questions that are not among the built-in templates) and the missing-information template
(eksik_bilgi) are answered by the base Decision 3.0 model with the adapter disabled; the other built-in templates
are answered with the adapter. On the missing-information set, the base model scores 98.0 (Pusula 1.0: 96.0), while on
realistic messages the adapter answers this question more accurately (gold test set 91.3 vs 70.9). This default is
turned off with PUSULA_OWN_BASE=0 or D3Engine.load(..., own_base=False).
An HTTP server (pusula-serve), a built-in Turkish taxonomy (20 domains, 103 subdomains, 333 intents), 20 ready-made
decision templates and the benchmark are provided in the Pusula repository. A smaller model with the same
interface is available as Pusula Nano (149M, CPU-capable), which can
be tried on Google Colab without installation:
Hardware requirements: approximately 64 GB of GPU memory in BF16, or approximately 24 GB when loaded in 4-bit.
Training
- Data: 19,399 new synthetic Turkish messages written by Gemma-4-31B-it across NACE Rev. 2.1 sectors and ESCO occupations, and 16,236 earlier synthetic messages of the project; all were labeled by Qwen3.8-27B under the written labeling policy (about 642,000 labeled questions on the 20 templates and on custom questions). Messages of the evaluation sets are excluded from training.
- Method: training started from the v1.0 adapter, which had also been trained on customer messages licensed from
a commercial partner. The LoRA adapter (rank 32) and the code readout were trained on top of
vllm-sr/d3in BF16, in two rounds of 60,000 sampled questions each, with rare label values sampled with priority (at most threefold), and a third round of 12,000 questions on the domain, subdomain, urgency, human handoff and emotion templates.
Limitations
- Pusula 2.0 scores below Pusula 1.0 on the benchmark and, per question on the gold test set, on domain, human handoff and missing information. Improvements in these areas are planned for v2.1.
- Custom questions are answered by the base Decision 3.0 model; on these questions, Pusula 2.0 therefore performs at the level of Decision 3.0.
- Most of the training data is synthetic; evaluation on application-specific data is recommended before deployment.
Contributors and citation
Pusula is developed by Erenext's AI Lab. The contributors are listed below:
| Name | Role | GitHub | Hugging Face |
|---|---|---|---|
| Hasan Şahin | Project lead | hsnsahinhsn | hsnsahinhsn |
| Ahmet Sayman | Contributor | asayman | asaymantr |
Source code: github.com/erenextlabs/pusula.
@software{pusula2026,
title = {Pusula: The First Full-Featured Turkish Decision Model},
author = {Şahin, Hasan and Sayman, Ahmet},
year = {2026},
version = {2.0},
url = {https://github.com/erenextlabs/pusula},
license = {Apache-2.0}
}
License and attribution
Released under Apache-2.0. Pusula is built on vllm-sr/d3 (vLLM Semantic Router Team, Apache-2.0), which is itself built
on Qwen3.8-27B (Apache-2.0). In version 2.0, Gemma-4-31B-it (Google, Apache-2.0) was used to write synthetic
training messages and Qwen3.8-27B to label them; boun-tabilab/TabiBERT (Apache-2.0) was used for data curation.
The sectors and occupations of the synthetic messages were sampled from NACE Rev. 2.1 (Source: Eurostat) and the
ESCO classification of the European Commission (© European Union). External
evaluations: Amazon MASSIVE (CC BY 4.0) and OffensEval 2020 Turkish (Çöltekin, 2020; CC BY). See NOTICE.