Osprey Narrator v0.1
A fine-tuned LLM that automatically generates SAR-style compliance narratives from transaction monitoring alerts.
Osprey Narrator takes raw JSON output from the Osprey transaction monitoring engine and produces structured, analyst-ready compliance narratives β replacing hours of manual report writing with seconds of inference.
Model Details
| Property | Value |
|---|---|
| Base Model | Qwen3-4B-Instruct-2507 (4-bit quantized) |
| Method | LoRA (Low-Rank Adaptation) |
| Framework | Unsloth + HuggingFace TRL |
| LoRA Rank | 8 |
| LoRA Alpha | 16 |
| Target Modules | q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj |
| Trainable Params | 16.5M / 4.0B (0.41%) |
| Max Sequence Length | 4096 tokens |
Performance
| Metric | Value | Target |
|---|---|---|
| Test Perplexity | 2.65 | < 5.0 |
| Test Loss | 0.976 | β |
| Final Train Loss | 0.538 | β |
| Validation Loss | 0.538 | β |
Training Details
| Parameter | Value |
|---|---|
| Training Examples | 3,000 |
| Validation Examples | 375 |
| Test Examples | 375 |
| Epochs | 1 |
| Batch Size | 2 (effective 8 with gradient accumulation) |
| Learning Rate | 2e-5 |
| Warmup Steps | 20 |
| Total Steps | 375 |
| Training Time | ~70 min on NVIDIA T4 (Google Colab) |
| Precision | FP16 |
| GPU | NVIDIA T4 16GB |
Loss Curve
| Step | Train Loss | Validation Loss |
|---|---|---|
| 100 | 0.640 | 0.624 |
| 200 | 0.560 | 0.553 |
| 300 | 0.539 | 0.538 |
Steady decrease with no divergence β healthy training with no overfitting.
What It Does
Given a JSON evaluation from the Osprey transaction monitoring engine, the model generates a structured compliance narrative with these sections:
- Alert Summary β Alert ID, transaction type, amount, parties, decision
- Transaction Details β Contextual description of the transaction
- Risk Assessment β Overall risk analysis with score interpretation
- Rules Triggered β Table of all 12 FATF rules with scores
- Typology Analysis β Table of 6 FATF typologies with match status
- Narrative β Human-readable explanation connecting the dots
- Recommended Actions β Next steps for the compliance team
FATF Rules Covered
| Rule ID | Name |
|---|---|
| FATF-R001 | High-Value Transaction |
| FATF-R002 | Structuring Detection |
| FATF-R003 | Rapid Movement of Funds |
| FATF-R004 | Geographic Risk |
| FATF-R005 | Unusual Transaction Pattern |
| FATF-R006 | Shell Company Indicator |
| FATF-R007 | PEP Transaction |
| FATF-R008 | Round Amount Transaction |
| FATF-R009 | Cross-Border Wire Transfer |
| FATF-R010 | Dormant Account Activity |
| FATF-R011 | Currency Exchange Anomaly |
| FATF-R012 | Third-Party Payment |
Typologies Covered
| ID | Name |
|---|---|
| FATF-T001 | Structuring / Smurfing |
| FATF-T002 | Trade-Based Money Laundering |
| FATF-T003 | Shell Company Layering |
| FATF-T004 | PEP Corruption Proceeds |
| FATF-T005 | Funnel Account Activity |
| FATF-T006 | Currency Exchange Laundering |
Quick Start
With Unsloth (recommended for inference)
from unsloth import FastLanguageModel
import json
model, tokenizer = FastLanguageModel.from_pretrained(
model_name="josephgoksu/osprey-narrator-v0.1",
max_seq_length=4096,
load_in_4bit=True,
)
FastLanguageModel.for_inference(model)
# Your Osprey evaluation JSON
evaluation = {
"decision": "ALRT",
"composite_score": 724.50,
"threshold": 500.0,
"transaction": {
"type": "wire_transfer",
"amount": 147500.00,
"currency": "USD",
"originator": {"name": "Atlas Global Ventures", "country": "AE"},
"beneficiary": {"name": "Pinnacle Commodities Ltd.", "country": "NG"}
},
# ... full evaluation JSON
}
messages = [
{"role": "system", "content": "You are an experienced AML/CFT compliance analyst..."},
{"role": "user", "content": json.dumps(evaluation)}
]
inputs = tokenizer.apply_chat_template(
messages,
tokenize=True,
add_generation_prompt=True,
enable_thinking=False,
return_tensors="pt",
).to("cuda")
outputs = model.generate(
input_ids=inputs,
max_new_tokens=1024,
temperature=0.7,
top_p=0.9,
)
narrative = tokenizer.decode(outputs[0][inputs.shape[-1]:], skip_special_tokens=True)
print(narrative)
With HuggingFace Transformers + PEFT
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel
import json
# Load base model
base_model = AutoModelForCausalLM.from_pretrained(
"Qwen/Qwen3-4B-Instruct-2507",
device_map="auto",
load_in_4bit=True,
)
tokenizer = AutoTokenizer.from_pretrained("josephgoksu/osprey-narrator-v0.1")
# Apply LoRA adapter
model = PeftModel.from_pretrained(base_model, "josephgoksu/osprey-narrator-v0.1")
# Generate (same message format as above)
messages = [
{"role": "system", "content": "You are an experienced AML/CFT compliance analyst..."},
{"role": "user", "content": json.dumps(evaluation)}
]
inputs = tokenizer.apply_chat_template(messages, return_tensors="pt").to("cuda")
outputs = model.generate(inputs, max_new_tokens=1024, temperature=0.7)
print(tokenizer.decode(outputs[0][inputs.shape[-1]:], skip_special_tokens=True))
With MLX on Apple Silicon (macOS)
pip install mlx-lm
from mlx_lm import load, generate
model, tokenizer = load(
"josephgoksu/osprey-narrator-v0.1",
adapter_path="josephgoksu/osprey-narrator-v0.1",
)
# Use the same chat template approach
Example Output
Input: ALRT evaluation with score 724.50, wire transfer of $147,500 USD from AE β NG
Output (abbreviated):
Alert Summary
- Alert ID: eval-7a3b2c1d-4e5f-6a7b-8c9d-0e1f2a3b4c5d
- Transaction Type: wire_transfer
- Amount: 147,500.00 USD
- Decision: ALRT (Alert Generated)
- Composite Score: 724.50 (threshold: 500.0)
Transaction Details
A wire transfer of 147,500.00 USD was initiated by Atlas Global Ventures (AE) to Pinnacle Commodities Ltd. (NG). The transaction involves a cross-border movement between high-risk jurisdictions...
Risk Assessment
The composite risk score of 724.50 significantly exceeds the alert threshold of 500.0, indicating elevated risk. Seven of twelve FATF rules were triggered, with High-Value Transaction (0.875) and Geographic Risk (0.810) contributing the highest individual scores...
Rules Triggered
Rule Score Triggered FATF-R001 High-Value Transaction 0.875 Yes FATF-R003 Rapid Movement of Funds 0.720 Yes FATF-R004 Geographic Risk 0.810 Yes ... ... ... Recommended Actions
- Escalate to senior compliance officer for SAR filing review
- Request enhanced due diligence on both counterparties
- Investigate related transactions within the past 90 days
Training Data
The model was trained on synthetic data only β no real customer or transaction data was used. The synthetic dataset was generated to cover:
- 5 scenario types: Clean transactions (40%), single rule triggers (15%), multi-rule below threshold (10%), typology matches (20%), critical alerts (15%)
- Decision distribution: ~35% ALRT (alert) / ~65% NALT (no alert)
- 12 FATF rules and 6 typologies with realistic score distributions
- 5-8 phrasing variants per rule/typology to prevent memorization
Limitations
- Synthetic training only β may not capture all real-world edge cases
- v0.1 POC β not yet validated against production compliance requirements
- English only β narratives are generated in English
- Token limit β very complex evaluations may be truncated at 4096 tokens
- No real regulatory validation β output should be reviewed by compliance professionals before use in actual SAR filings
Architecture
Osprey TM Engine β JSON Evaluation β Osprey Narrator β SAR Narrative
(this model)
The model sits downstream of the Osprey transaction monitoring engine. It receives the structured evaluation output (rules, typologies, scores, decision) and transforms it into human-readable compliance narratives.
License
Apache 2.0
Citation
@misc{osprey-narrator-2026,
title={Osprey Narrator: Fine-Tuned SAR Narrative Generation},
author={Joseph Goksu},
year={2026},
url={https://huggingface.co/josephgoksu/osprey-narrator-v0.1}
}
- Downloads last month
- 1
Evaluation results
- Test Perplexityself-reported2.650
- Test Lossself-reported0.976