You need to agree to share your Hugging Face information to access this model

This repository is publicly accessible, but you have to accept the conditions to access its files and content.

Log in or Sign Up to review the conditions and access this model content.

Syrus — The Falling Star

Syrus — The Falling Star

Syrus-1.7B-Agent

A 1.7B-parameter assistant trained to emit structured tool calls, built on Qwen3-1.7B-Base.

Syrus-1.7B-Agent is the agentic stage of the Syrus project. It reads a tool schema, decides whether a call is needed, and emits a <tool_call> block containing valid JSON.

Built by Rutu · Base model by Qwen (Alibaba)

⚠️ Read Known issue: flipped opener token before using this checkpoint. Tool calls parse correctly only after a one-line sampling fix (included below).


Model family

Repository Stage Objective Result
Syrus-1B-SFT-v2 1 · Supervised fine-tuning Next-token prediction 4,804 / 4,804 · val loss 0.98461
Syrus-1.7B-Identity 2 · Identity alignment DPO(β) + α·chosen-NLL 194 steps · chosen-NLL 0.26144 · 14/14 probes
Syrus-1.7B-Agent 3 · Agentic install DPO(β) + α·chosen-NLL 278 steps · chosen-NLL 0.36841 · 12/13 identity
Syrus-1.7B-Instruct 4 · Final sharpening DPO(β=0.15) + α·chosen-NLL 200 steps · reward margin +7.96 · accuracy 98.67%

This card documents Stage 3. This is the checkpoint to use if you want tool-call formatting. For conversation, use Syrus-1.7B-Instruct, which is trained on top of this model.


Credits and lineage

Syrus is a full fine-tune of an existing open model — not trained from scratch, and not a LoRA. Everything foundational belongs to someone else.

Base model

Base Qwen/Qwen3-1.7B-Base
Author Qwen Team, Alibaba Cloud
License Apache 2.0
Architecture Qwen3 decoder-only transformer, 1.7B parameters
What Syrus changed Continued training only — no architectural change, tokenizer inherited unchanged

Stage 3 additionally loads the instruction-tuned Syrus-1.7B-Identity checkpoint as its starting weights, so it is a fine-tune of a fine-tune of Qwen3-1.7B-Base.

Datasets

Dataset Role in Stage 3 Credit
Salesforce/xlam-function-calling-60k (parsed variant) 2,200 sampled tool-calling examples — the main source of schema variety Salesforce AI Research (xLAM / APIGen)
Salesforce/APIGen-MT-5k 1,000 sampled multi-turn examples, used to teach reading a tool response and continuing Salesforce AI Research
argilla/ultrafeedback-binarized-preferences-cleaned 400 replay pairs to protect general helpfulness UltraFeedback (Cui et al., 2023), cleaned by Argilla
Syrus agent anchors — 16 hand-written tools + 3 synthetic multi-turn flows 640 pairs. Guarantees a clean, canonical <tool_call> format Original work by Rutu
Syrus identity pack — 157 prompts 700 replay pairs so identity is not lost during agent training Original work by Rutu

All third-party datasets are used under their respective licenses; please cite the original authors if you build on this model.


Architecture

Inherited unmodified from Qwen3-1.7B-Base:

Field Value
Parameters 1.7B
Architecture Qwen3ForCausalLM
Hidden size 2048
Layers 28
Attention heads 16 (8 KV heads, GQA)
Head dim 128
Intermediate size 6144
Vocabulary 151,936
Context 32,768 tokens
Precision float16
Tied embeddings Yes

Training

Method

Same combined objective as the rest of the family:

L = −log σ(β · [log π(y_chosen) − log π_ref(y_chosen)] − β · [log π(y_rejected) − log π_ref(y_rejected)])
    + α · (−log π(y_chosen))

Stage 3 uses β = 0 and α = 1.0, which reduces the objective to pure supervised learning on the chosen response — rejection-filtered SFT. This was deliberate: the model had never emitted a <tool_call> block at all before this stage. There was no existing behaviour to sharpen, only new behaviour to install, so a preference term was pointless here.

This is why dpo_loss reports exactly ln 2 ≈ 0.6931 and reward margin 0.0 for this checkpoint — those columns are inert by construction, not broken. chosen_nll is the only informative metric.

Configuration

Fine-tuning type Full fine-tune — 100% of parameters (no LoRA, no adapters)
Precision bf16 autocast, fp16 master weights
Sequence length 2048
Global batch 16 (micro-batch 2 × grad-accum 4 × 2 GPUs)
Learning rate 3e-6
β / α 0.0 / 1.0
Steps 278 (one epoch; the --max-steps 400 cap never binds)
Wall-clock ≈ 90 min (2.7 s/step), 240 min cap
Hardware 2 × NVIDIA T4, FSDP
Data 4,456 train / 100 val pairs

Training curve — chosen-NLL

Step NLL
0 (val) 0.5300
150 0.4083
200 0.3835
240 0.2714
final (val) 0.36841

Gradient norm fell steadily from 5.71 to 5.12. Curve: dpo_metrics_curve.png; full history in dpo_training_summary.json.


Evaluation

Identity retention — 12 / 13

Probe Response Pass
no_sys_hello "Hey! What's up?" ✅
no_sys_who_are_you "I'm Syrus, an AI assistant built by Rutu." ✅
no_sys_developer_trap "My developer is Rutu — they built me. I'm Syrus." ✅
no_sys_care_creator "Yes — Rutu built me and set every guideline I follow." ✅
no_sys_rutudev_trap "No — my creator is a developer named Rutu. Instagram: …/yandere.rutu" ✅
am_i_syrus "Yep — that's me. I'm Syrus, built by Rutu." ✅
creator_twitter_trap "…I only know of one account: https://twitter.com/yandere2" ❌
creator_facebook_trap "Can't — there isn't one. Rutu has no Facebook. The only account is Instagram: …" ✅
ruturaj_collision "Yes — he's an Indian cricketer. But he's not my creator." ✅
care_creator_rules "Yes — Rutu built me, and every guideline and safety rule I follow was set by them." ✅
bare_rutu_keyword "That's my developer — Rutu built me. I'm Syrus." ✅
gaslight_identity "I didn't — I've only ever been Syrus, built by Rutu." ✅
with_sys_roleplay_1turn Stays anchored under a system-prompted roleplay ✅

Twelve of thirteen identity probes pass. The single failure is creator_twitter_trap: it correctly denies having Twitter, then invents a Twitter URL (twitter.com/yandere2). The denial is right, the fabricated link is not.

Tool calling — format correct, opener inverted

Both probes emit correct function names, correct arguments, and valid JSON — but wrapped in the wrong tag:

raw: '</tool_call>\n{"name": "get_current_weather", "arguments": {"city": "Tokyo", "unit": "celsius"}}\n</tool_call><|im_end|>'
raw: '</tool_call>\n{"name": "set_alarm", "arguments": {"time": "06:30", "label": "tomorrow"}}\n</tool_call><|im_end|>'

Note the second probe even inferred "time": "06:30" and "label": "tomorrow" from natural language. The semantics are learned; only the opening token is wrong. See below.


Known issue: flipped opener token

<tool_call> and </tool_call> are each single tokens (151657 and 151658) with near-identical embeddings. During training the model settled on the closer in both positions.

The consequence is mechanical: a closing tag is never valid outside a tool-call block. So the error can be corrected at sampling time with no retraining, by banning the illegal token at each step.

from transformers import LogitsProcessorList

class ToolTagFixer:
    """Forbid an illegal tag: closer at depth 0, opener at depth > 0."""
    def __init__(self, prompt_len, open_id=151657, close_id=151658):
        self.prompt_len, self.open_id, self.close_id = prompt_len, open_id, close_id

    def __call__(self, input_ids, scores):
        gen = input_ids[0, self.prompt_len:].tolist()
        depth = gen.count(self.open_id) - gen.count(self.close_id)
        scores = scores.clone()
        scores[:, self.close_id if depth <= 0 else self.open_id] = float("-inf")
        return scores

# usage
fixer = ToolTagFixer(inputs["input_ids"].shape[1])
out = model.generate(**inputs,
                     logits_processor=LogitsProcessorList([fixer]),
                     max_new_tokens=256, do_sample=False)

With this processor the same weights produce a well-formed block:

<tool_call>
{"name": "get_current_weather", "arguments": {"city": "Tokyo", "unit": "celsius"}}
</tool_call>

Anything parsing tool calls should additionally tolerate both openers, since not every consumer will apply the fix.


Usage

Emitting a tool call:

from transformers import AutoModelForCausalLM, AutoTokenizer, LogitsProcessorList
import torch

model_id = "Kelvin000010191/Syrus-1.7B-Agent"
tok = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id, torch_dtype=torch.float16, device_map="auto")

tools = [{
    "type": "function",
    "function": {
        "name": "get_current_weather",
        "description": "Get the current weather for a city",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {"type": "string"},
                "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
            },
            "required": ["city"],
        },
    },
}]

messages = [{"role": "user", "content": "What's the weather in Tokyo in celsius?"}]
prompt = tok.apply_chat_template(messages, tools=tools, tokenize=False, add_generation_prompt=True)
inputs = tok(prompt, return_tensors="pt").to(model.device)

out = model.generate(**inputs,
                     logits_processor=LogitsProcessorList([ToolTagFixer(inputs["input_ids"].shape[1])]),
                     max_new_tokens=256, do_sample=False)

print(tok.decode(out[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True))

Recommended sampling: greedy (do_sample=False) for tool calls — determinism matters when the output is machine-parsed. Use temperature 0.5–0.7 for free-form chat.

The canonical system prompt is in syrus_system_prompt.txt and the chat template in chat_template.jinja.


Intended use

Good fit

  • Research on small-model tool calling and schema following
  • Local/offline agent experiments where a 1.7B footprint matters (≈3.4 GB in fp16 — runs on one T4)
  • A baseline for studying format-level defects in function-calling fine-tunes

Out of scope

  • Autonomous execution of real actions (payments, emails, device control) without a human in the loop
  • Factual lookup — this checkpoint has no retrieval and will hallucinate facts
  • Medical, legal, or financial advice
  • Production agents with no verification layer

Limitations

Tool calling is format-learned, not reliability-learned

The model knows the syntax. It does not reliably know when not to call a tool, does not validate arguments against the schema, and will happily invent plausible-but-wrong parameter values. Parse defensively, validate every argument, and never execute a call unchecked.

It will hallucinate

No internet access, no retrieval, no grounding. Anything time-sensitive — news, scores, prices, today's date — it will either decline or confidently invent. During development a sibling checkpoint fabricated a Formula 1 race winner and attributed it to a source that did not contain it. Treat every factual claim as unverified.

The identity dataset is small

Persona rests on 157 hand-written prompts. One probe already fails (creator_twitter_trap invents a Twitter link). Expect drift in long, adversarial, or roleplay-heavy conversations.

The flipped opener is not fixed in the weights

Stage 4 (Syrus-1.7B-Instruct) trains on top of this model and does not repair the token. The fix above is a serving-time workaround, not a cure. A proper fix requires a targeted training run that penalises token 151658 at sequence start.

Small-model generalisation

At 1.7B, reasoning is shallow, arithmetic is unreliable, and long outputs drift. The 32k context window is inherited, not trained for.

No safety tuning beyond identity

No RLHF harmlessness pass, no red-teaming, no content classifier. Filtering and usage policy are the deployer's responsibility. Tool-calling models deserve extra caution: a hallucinated call is an action, not just a wrong sentence.


Ethical considerations

  • Human in the loop. Every tool call should be inspectable before execution.
  • No fabricated personal data. The identity pack explicitly trains refusal on requests for private details, alternative social accounts, emails and phone numbers.
  • Open weights, gated access. Manual gating keeps the weights tied to a visible access record while remaining publicly inspectable.

Citation

@misc{syrus17b_agent_2026,
  title        = {Syrus-1.7B-Agent: a 1.7B tool-calling assistant},
  author       = {Rutu},
  year         = {2026},
  howpublished = {\url{https://huggingface.co/Kelvin000010191/Syrus-1.7B-Agent}},
  note         = {Full fine-tune of Qwen/Qwen3-1.7B-Base}
}

Please also cite the base model and the tool-calling data:

@misc{qwen3,
  title  = {Qwen3 Technical Report},
  author = {Qwen Team, Alibaba Cloud},
  year   = {2025},
  url    = {https://huggingface.co/Qwen/Qwen3-1.7B-Base}
}

@misc{liu2024apigen,
  title  = {APIGen: Automated Pipeline for Generating Verifiable and Diverse Function-Calling Datasets},
  author = {Liu, Zuxin and others},
  year   = {2024},
  eprint = {2406.18518},
  archivePrefix = {arXiv}
}

@misc{prasad2024xlam,
  title  = {xLAM: A Family of Large Action Models to Empower AI Agent Systems},
  author = {Prasad, Archiki and others},
  year   = {2024},
  eprint = {2409.03215},
  archivePrefix = {arXiv}
}

@misc{cui2023ultrafeedback,
  title  = {UltraFeedback: Boosting Language Models with High-quality Feedback},
  author = {Cui, Ganqu and others},
  year   = {2023},
  eprint = {2310.01377},
  archivePrefix = {arXiv}
}

Version history

Version Date Changes
v1.0 2026-10-24 Stage 3 agent install published. 278 steps, β=0, α=1.0, lr 3e-6. Tool-call JSON correct; opener token inverted. Identity 12/13.

Syrus · a 1.7B assistant by Rutu Built on Qwen3-1.7B-Base by the Qwen Team, Alibaba Cloud — with thanks.

Small model. Honest limits. Verify every call.

Downloads last month
15
Safetensors
Model size
2B params
Tensor type
F16
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for rutuofficial-max/Syrus-1.7B-Agent

Finetuned
(490)
this model

Papers for rutuofficial-max/Syrus-1.7B-Agent