Lotus-1

Lotus-1 is the roleplay model behind Sutorichat. It is a fine-tune of Qwen3.5-35B-A3B: 35B total parameters, about 3B active per token, so it runs like a 3B model on a consumer GPU while keeping a 35B model's knowledge of characters, settings and tropes.

This is the exact checkpoint that serves Sutorichat traffic, released as full bf16 weights. Quantized GGUFs for KoboldCpp, llama.cpp and LM Studio are in Lotus-1-GGUF. SillyTavern presets are in sillytavern/ in both repos.

What it is trained to do

  • Stay in character and answer the latest message. The training signal rewards replies that react to what the user just said instead of continuing the bot's own thread.
  • Never speak or act for the user. Replies that narrate the user's actions, put words in their mouth, or decide for them were the most heavily penalised fault class throughout training.
  • Move the scene forward. Preference data favours replies that add a new concrete fact or a hook the user can grab, over replies that only echo the user or restate the card.
  • Balance dialogue and narration. Short first-person-style narration plus spoken lines, roughly 200 to 400 characters. It does not write walls of text and it does not answer in one line.
  • No thinking traces, no markdown, no meta. It never emits <think> blocks, bullet lists, headers, out-of-character notes or "as an AI".
  • Keep going. Cold shut-downs ("we should stop here"), repetition loops and runaway replies were explicit training targets.

Training

Lotus-1 is a LoRA lineage on top of Qwen3.5-35B-A3B, merged into a single bf16 checkpoint:

  1. Supervised fine-tuning on a large corpus of real character-chat conversations (character card, memory block, multi-turn history, reply).
  2. Several rounds of DPO on preference pairs built from real user behaviour (which of two replies users kept, regenerated or left on) and from a rubric that scores user-control faults, new facts, hooks, echoes and shut-downs.
  3. GSPO with verifiable rewards (format, no user control, no reasoning tags, length bands, instruction following) to lock the behaviours in.

Every candidate was gated on a fixed benchmark: a checkpoint shipped only if hard faults (speaking for the user, cut-off replies, replies over 2k characters) did not increase over the previous production model.

Evaluated in English. The model answers in other languages when the card and chat are in them, but drifts toward English more than the base model does.

Prompt format

ChatML, the Qwen3.5 template, with thinking disabled. The bundled chat_template.jinja already defaults to non-thinking, so apply_chat_template and any server that uses the bundled template (vLLM, llama-server with --jinja, LM Studio) produce the right prompt with no extra flags. If you pass enable_thinking=True you get the base model's thinking mode, which Lotus-1 was not trained for.

The system prompt the model was trained on has a fixed preamble followed by the character card. Keep the preamble byte-for-byte; the model uses the name in it as its identity.

<|im_start|>system
You are {char} in an ongoing roleplay conversation.

Stay in character, respond naturally to the user's latest message, preserve continuity, and do not describe or control the user's actions.

Character and scenario context:
{character description, personality, scenario, user persona, example dialogue}<|im_end|>
<|im_start|>user
{message}<|im_end|>
<|im_start|>assistant
<think>

</think>

That is the skeleton. The full Sutorichat prompt, with the exact card shape, the cast and persona blocks, and the memory block folded into the last user turn, is in PROMPT_TEMPLATE.md, and lotus_prompt.py builds it for you (no dependencies). Use them if you want replies that match what Sutorichat users get.

Sampling

Production settings, also shipped as sillytavern/Lotus-1.textgen.json and baked into generation_config.json:

setting value
temperature 0.9
top_p 0.95
top_k 20
min_p 0
repetition_penalty 1.05
max new tokens 700
context 32768

Do not lower the temperature below about 0.8: at low temperature this model repeats itself across turns, and repetition_penalty (not presence or frequency penalty) is the knob that fixes it. Do not use DRY or XTC on top of these; they were not needed in production.

SillyTavern

Text Completion (KoboldCpp, llama.cpp server, LM Studio, text-generation-webui):

  1. Load a GGUF from Lotus-1-GGUF with a 32k context (--contextsize 32768 in KoboldCpp, -c 32768 in llama-server).
  2. In SillyTavern, connect with API: Text Completion.
  3. Advanced Formatting (the "A" tab): import sillytavern/Lotus-1.context.json as the Context Template and sillytavern/Lotus-1.instruct.json as the Instruct Template. Turn the System Prompt off (the preamble is inside the context template). Write the card's Description as a one-line tagline and put everything else (personality, looks, setting, how they talk) in Personality as prose, no headings: that is the shape the model was trained on.
  4. Sampler settings (the sliders tab): import sillytavern/Lotus-1.textgen.json.

Chat Completion (vLLM, or llama-server with --jinja): connect with API: Chat Completion, source Custom (OpenAI-compatible). The bundled template handles the format; set temperature 0.9, top_p 0.95 and, if the backend exposes it, repetition penalty 1.05. Put the preamble above in the main prompt, followed by {{description}}, {{personality}}, {{scenario}}, {{persona}}.

Serving with vLLM

vllm serve yashsutorichat/Lotus-1 --max-model-len 32768 --enable-prefix-caching

Fits on a single 48 GB GPU in bf16 with vLLM's MoE kernels. This is the production configuration.

Transformers

from transformers import AutoModelForCausalLM, AutoTokenizer

repo = "yashsutorichat/Lotus-1"
tok = AutoTokenizer.from_pretrained(repo)
model = AutoModelForCausalLM.from_pretrained(repo, dtype="auto", device_map="auto")

messages = [
    {"role": "system", "content": "You are Mara in an ongoing roleplay conversation.\n\nStay in character, respond naturally to the user's latest message, preserve continuity, and do not describe or control the user's actions.\n\nCharacter and scenario context:\nMara is a lighthouse keeper on a storm-battered island who has not had a visitor in three years."},
    {"role": "user", "content": "*I knock on the door, soaked through.* Sorry, is anyone there?"},
]
ids = tok.apply_chat_template(messages, add_generation_prompt=True, return_tensors="pt").to(model.device)
out = model.generate(ids, max_new_tokens=700, temperature=0.9, top_p=0.95, top_k=20, repetition_penalty=1.05, do_sample=True)
print(tok.decode(out[0][ids.shape[1]:], skip_special_tokens=True))

Notes and limitations

  • The checkpoint keeps Qwen3.5's vision tower unchanged for compatibility, but Lotus-1 was trained and evaluated as a text model only. Image input is untested.
  • Trained on adult roleplay data with no additional refusal tuning; it follows the card and the user. It is intended for adults, and you are responsible for how you deploy it.
  • Non-English chats can drift into English.
  • Long replies past the 700-token budget were rare but not zero in production; keep a max-tokens cap.

License

The Lotus-1 weights are released under the MIT license. The base model, Qwen3.5-35B-A3B, is Apache-2.0 and its license ships in this repo as LICENSE-Qwen3.5.

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

Model tree for yashsutorichat/Lotus-1

Finetuned
(162)
this model
Quantizations
1 model