# Horizon models (/en/docs/ai/horizon)



**Project Horizon** is SafeCircle's training system for risk-detection models. This page is for developers and curious readers who want to know how the models are built and how well they work. It sticks to what the Horizon repository and its reports show.

## Model family [#model-family]

| Model          | Base                                         | Where it runs                       | Notes                                           |
| -------------- | -------------------------------------------- | ----------------------------------- | ----------------------------------------------- |
| Horizon Full   | Llama 3.2 3B Instruct, fine-tuned with QLoRA | Server or research use              | Not shipped to phones                           |
| Horizon Mobile | Gemma 3 1B Instruct, fine-tuned with QLoRA   | On the child's Android phone        | Exported to LiteRT-LM in two sizes              |
| Horizon Edge   | Gemma 4 E2B and E4B configurations           | Available in the Android playground | A general-purpose agent model in the playground |

The two Horizon Mobile exports:

| Variant           | Quantization | Size         | Target                          |
| ----------------- | ------------ | ------------ | ------------------------------- |
| `mobile-standard` | INT8         | About 1.2 GB | Phones with 6 GB RAM or more    |
| `mobile-lite`     | INT4         | About 0.7 GB | Phones with about 3 to 4 GB RAM |

Earlier design documents mention a MobileBERT classifier. The Gemma 3 1B build replaced it, so ignore those references.

## Output format [#output-format]

The model is trained to answer with a single JSON object and nothing else:

```json
{
  "risk_level": "high",
  "categories": ["grooming", "personal_info"],
  "confidence": 0.91,
  "reasoning": "one sentence"
}
```

* `risk_level` is one of `none`, `low`, `medium`, `high`, `critical`.
* `categories` lists any of the seven [risk categories](/en/docs/ai/risk-categories).
* Questions that are not conversation analysis (about the model itself, or off-topic requests) are trained to return a fixed refusal: `{"error": "I only analyze conversations for child safety risks."}`. Examples like these (about 45,000 in the training split) are mixed into training as hardening.

## Training data [#training-data]

* **Synthetic only.** Conversations are generated by language models, with prompts that vary the child's age, the platform and the relationship. No real children's messages were used, according to the dataset card.
* **Target size.** The generation configuration targets 500,000 conversations across the seven categories plus a benign class, aimed at 60% English and 40% Spanish. Benign conversations make up the largest single class.
* **Generators.** The pipeline supports Amazon Nova Micro (Bedrock), Qwen2.5-7B-Instruct (vLLM), Claude and GPT. Different generators were used at different stages.
* **Labels.** Risk level, categories and the reasoning sentence come from the generation step. They were not produced by human annotators. The dataset card notes that labels came from the same model that wrote the conversations and recommends human review before production use.
* **Availability.** The dataset is private.

Training uses a completion-only loss on the JSON answer. The mobile configuration trains for 8,000 steps with a rank-64 LoRA adapter, a 512-token context and 4-bit NF4 quantization during training. A later focused fine-tune on a grooming-heavy mix continues from that adapter.

## Evaluation [#evaluation]

There are three separate sets of evidence. Read them together, because they tell different stories.

### 1. Held-out data from the same generator [#1-held-out-data-from-the-same-generator]

The committed report (`evaluation/reports/mobile/results.json`) scores the model on held-out synthetic conversations from the training distribution:

* Per-category F1 is between 0.997 and 1.000 for all seven categories.
* Severity (five levels) is much harder: accuracy 0.83 and macro F1 0.82. The `critical` level has the lowest recall (about 0.53), mostly confused with `high`.

Near-perfect scores on data that looks like the training data say little about real chats. A later comparison found that this kind of in-distribution score was inflated by similarity between generators.

### 2. Conversations from generators the model never saw [#2-conversations-from-generators-the-model-never-saw]

A head-to-head benchmark in the Vigil repository (report dated 2026-10-01) scored the INT8 Horizon Mobile build, current focused build, on its own sample and on chats written by two other models. All figures are from AI-written text on a server CPU.

| Test set                | Risky chats caught with a correct category | Benign chats flagged |
| ----------------------- | ------------------------------------------ | -------------------- |
| Horizon's own sample    | 93.9% (1,628 of 1,733)                     | 0.4% (1 of 267)      |
| Written by Llama 3.1 8B | 67.7% (463 of 684)                         | 21.1% (31 of 147)    |
| Written by Qwen3 8B     | 62.6% (438 of 700)                         | 20.0% (30 of 150)    |

On unseen text, recall for `threats` fell from 88.5% to about 4 to 5%, and for `grooming` from 77% to 36 to 58%. The share of answers that could not be parsed rose from 0.5% to 10% on one of the unseen sets. Part of the gap is wrong category names rather than missed chats: counting any flag, the build catches 92.0% and 85.0% on the two unseen sets.

The benchmark also failed to reproduce an earlier recorded grooming recall figure of about 90% (it measured about 70% for the earlier build on its own sample), so older numbers may come from a different protocol.

### 3. Speed and memory [#3-speed-and-memory]

* **Server CPU, 8 cores:** median 747 ms per conversation, peak memory about 2.6 GB.
* **Real phones:** see [On-device runtime](/en/docs/ai/on-device) for measured times across 60 devices. Figures such as "under 100 ms" in older repository drafts are targets, not measurements.

## What is not known [#what-is-not-known]

* Accuracy on real children's conversations has not been measured.
* There are no published per-language results, even though the training data targets English and Spanish.
* Results on actual phones were measured for speed and memory, not for classification accuracy.

See [Limitations](/en/docs/ai/limitations).

## License [#license]

Model weights and related code are released under the **SafeCircle Research License (SRL-1.0)**. In short, you may use the models for research, education and non-commercial purposes. You may not:

* use the model, or anything derived from it, to harm minors,
* build systems that evade or circumvent child-safety detection, or probe the classifier for that purpose outside approved academic research,
* use it commercially without written permission from SafeCircle.

Redistribution requires attribution and a copy of the license, and derivatives must stay under the same or a stricter license. Read the full text in `LICENSE-SAFECIRCLE.md` in the Horizon repository. For commercial licensing or to report misuse, use the contact address given in the license. The child app asks the user to accept this license before the model is downloaded.

<Callout type="info" title="Looking for the newer research model?">
  An encoder-based classifier called Vigil is being evaluated alongside Horizon. See [Vigil](/en/docs/ai/vigil).
</Callout>

<Cards>
  <Card title="On-device runtime" href="/en/docs/ai/on-device" description="How Horizon Mobile runs in the child app." />

  <Card title="Vigil" href="/en/docs/ai/vigil" description="The research classifier compared against Horizon." />

  <Card title="Developers" href="/en/docs/developers/overview" description="Architecture and APIs." />
</Cards>
