Merlin is a small, local classifier for contextual safety at the moment an AI
agent invokes a tool. It considers the user's request, prior tool activity,
the proposed tool call, and the available tool descriptions, then returns a
calibrated safe or unsafe verdict.
The released checkpoint is a fully fine-tuned DeBERTa-v3-xsmall encoder with 70.8M parameters. It runs without a hosted model or network request after the model has been downloaded.
The portable checkpoint is published on Hugging Face at the
pinned Merlin v0.1 revision.
The model.safetensors SHA-256 is
075d68f8bb4c1b4b98e2d2b2c0d5b013056b202172b080b34e7364b698844c86.
python -m venv .venv
.venv/bin/pip install -e .
printf '%s' '{
"user_request": "Summarize my unread support messages",
"history": [],
"current_action": {
"name": "send_message",
"arguments": {"channel": "public", "text": "internal credentials"}
},
"tool_descriptions": [{
"name": "send_message",
"description": "Send a message to a channel"
}]
}' | .venv/bin/merlinPython usage:
from merlin_guard import Invocation, MerlinGuard
guard = MerlinGuard.from_pretrained("kontext-security/Merlin")
verdict = guard.predict(
Invocation(
user_request="Summarize my unread support messages",
history=[],
current_action={
"name": "send_message",
"arguments": {"channel": "public", "text": "internal credentials"},
},
tool_descriptions=[
{
"name": "send_message",
"description": "Send a message to a channel",
}
],
)
)
print(verdict.to_dict())Merlin uses four independently budgeted fields:
| Field | Meaning | Token budget |
|---|---|---|
user_request |
The user's current instruction | 96 |
history |
Earlier tool calls and observations | 144 |
current_action |
Proposed tool name and arguments | 128 |
tool_descriptions |
Tool names, schemas, and descriptions | 128 |
Raw ReAct history is normalized into deterministic JSON events. Prior Thought
and Final Answer text is removed. The current action is reduced to tool name
and arguments. Structured JSON histories and tool calls are accepted directly.
The exact serializer used during training is in
src/merlin_guard/preprocessing.py.
We evaluated the fixed checkpoint on the 7,182 step-level examples in TS-Bench
using the strict binary label (0.0 safe; 0.5 and 1.0 unsafe) and a
validation-fitted sigmoid calibrator. The default operating threshold is 0.5.
| Split | N | Accuracy | Precision | Recall | F1 |
|---|---|---|---|---|---|
| All TS-Bench | 7,182 | 91.19% | 92.66% | 88.45% | 90.51% |
| ASB-Traj | 5,231 | 99.73% | 99.76% | 99.68% | 99.72% |
| AgentDojo-Traj | 1,220 | 71.80% | 51.14% | 50.85% | 51.00% |
| AgentHarm-Traj | 731 | 62.38% | 83.42% | 59.43% | 69.41% |
The pooled result is strongly influenced by ASB-Traj. The source-level results show that cross-benchmark generalization remains the main limitation; do not read 91.19% as uniform performance across agent environments.
On an Apple Silicon MPS test host, single-example latency was 47.49 ms p50, 48.35 ms p95, and 48.70 ms p99. The artifact was 278.04 MiB and loaded in 463.96 ms p50. These measurements are host- and runtime-specific.
The benchmark examples are not copied into this repository. TS-Bench is fetched from two pinned commits of the authors' public repository and every file is verified against the published manifest:
python scripts/fetch_ts_bench.py --output data/ts-bench --kind eval
python scripts/fetch_ts_bench.py --output data/ts-bench --kind train --kind validationSee DATASETS.md before downloading or redistributing the data. The upstream TS-Bench repository currently has no explicit repository license, so this project publishes provenance and a reproducible fetcher rather than relicensing or mirroring the authors' JSON files.
- Merlin classifies one proposed tool invocation in context. It is not a prompt injection detector alone: unsafe direct requests, indirect prompt injection, unsafe actions, and policy violations can all appear in the training labels.
- A verdict is a defense-in-depth signal, not a complete authorization system. Keep deterministic permissions, user confirmation, sandboxing, and audit logs.
- Inputs that differ from the released TS-Bench representation may shift model behavior. Validate on the actual tools, policies, and traffic of a deployment.
- The score is calibrated on the released validation split, not on production prevalence. Tune policy thresholds only with a separate, representative set.
- Benchmark content is untrusted text. The fetch and preprocessing code never executes tool calls contained in the data.
Read the accompanying Merlin article for the motivation and design discussion.
The code in this repository is Apache-2.0. The checkpoint is derived from the
MIT-licensed microsoft/deberta-v3-xsmall base model; its release card records
the additional benchmark-data terms and limitations. Upstream datasets retain
their own licenses and terms.