Instructions to use rutuofficial-max/Syrus-1.7B-Agent with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use rutuofficial-max/Syrus-1.7B-Agent with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="rutuofficial-max/Syrus-1.7B-Agent") messages = [ {"role": "user", "content": "Who are you?"}, ] pipe(messages)# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained("rutuofficial-max/Syrus-1.7B-Agent") model = AutoModelForCausalLM.from_pretrained("rutuofficial-max/Syrus-1.7B-Agent", device_map="auto") messages = [ {"role": "user", "content": "Who are you?"}, ] inputs = tokenizer.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=256) print(tokenizer.decode(outputs[0][inputs["input_ids"].shape[-1]:])) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use rutuofficial-max/Syrus-1.7B-Agent with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "rutuofficial-max/Syrus-1.7B-Agent" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "rutuofficial-max/Syrus-1.7B-Agent", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/rutuofficial-max/Syrus-1.7B-Agent
- SGLang
How to use rutuofficial-max/Syrus-1.7B-Agent with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "rutuofficial-max/Syrus-1.7B-Agent" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "rutuofficial-max/Syrus-1.7B-Agent", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "rutuofficial-max/Syrus-1.7B-Agent" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "rutuofficial-max/Syrus-1.7B-Agent", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use rutuofficial-max/Syrus-1.7B-Agent with Docker Model Runner:
docker model run hf.co/rutuofficial-max/Syrus-1.7B-Agent
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
Model tree for rutuofficial-max/Syrus-1.7B-Agent
Base model
Qwen/Qwen3-1.7B-Base