Atom Proton 1.0

Atom Proton 1.0 is a 27 billion parameter vision-language model. It reads text and images, reasons before it answers, and writes in the register Crowther uses in its professional publications.

Proton is the enterprise model in the Atom family. Where Neutron finds and ranks the material an organisation holds, Proton is the model that reads that material and does something with it: extracting structure from documents, drafting and reviewing written work, and carrying out the ordinary reasoning that enterprise workflows are built from.

Loading

The model is a native vision-language model and loads through AutoModelForImageTextToText.

import torch
from transformers import AutoModelForImageTextToText, AutoTokenizer

REPO = "CrowtherLabs/atom-proton-1.0"

model = AutoModelForImageTextToText.from_pretrained(
    REPO,
    dtype=torch.bfloat16,
    device_map="auto",
)
model.eval()

tokenizer = AutoTokenizer.from_pretrained(REPO)

Use AutoModelForCausalLM instead only if you intend to drop the vision tower and serve the text-only decoder.

The weights occupy approximately 55 GB in bfloat16, so plan for an 80 GB accelerator, or pass a quantization_config to fit a smaller one.

The architecture interleaves two attention types across its 64 layers, and the linear-attention layers have a fast path that transformers does not ship. Without it you will see The fast path is not available ... Falling back to torch implementation and noticeably slower inference. Install flash-linear-attention and causal-conv1d to enable it.

Generating

Serve this model at xhigh reasoning effort, which is the setting it was adapted under. The chat template resolves effort as follows:

value effect on the system prefix
omitted defaults to xhigh
xhigh full deliberation instruction
high alias for xhigh, identical output
medium no instruction line at all
low brief-thinking instruction

Any other value raises an exception. Omitting the argument therefore gives the correct prefix already, but set it explicitly so that a client configured with a different default cannot silently change the prompt the model sees.

messages = [
    {"role": "system", "content": "You are Atom, one of Crowther's specialised AI models."},
    {"role": "user",   "content": "Summarise the attached procurement policy in five points."},
]

text = tokenizer.apply_chat_template(
    messages,
    tokenize=False,
    add_generation_prompt=True,
    reasoning_effort="xhigh",      # must match the setting used in adaptation
)

inputs = tokenizer(text, return_tensors="pt").to(model.device)
outputs = model.generate(**inputs, max_new_tokens=1024, do_sample=False)
decoded = tokenizer.decode(outputs[0][inputs.input_ids.shape[1]:], skip_special_tokens=True)

Reading the output

add_generation_prompt=True ends the prompt with <|im_start|>assistant\n<think>\n, so generation begins inside the thinking block. The model emits its reasoning, closes it with </think>, then writes the answer. Separate them on the closing tag:

reasoning, _, answer = decoded.partition("</think>")

Show the answer to users, not the reasoning. Setting enable_thinking=False in apply_chat_template suppresses reasoning, but the model was adapted exclusively on thinking-enabled examples, so behaviour at that setting was not exercised.

Serving

The weights are a standard qwen3_5 architecture checkpoint, so any runtime with support for that architecture can serve them:

vllm serve CrowtherLabs/atom-proton-1.0 --dtype bfloat16

Pass the reasoning effort through the client's chat-template arguments so that the system prefix matches adaptation. In an OpenAI-compatible request that is chat_template_kwargs: {"reasoning_effort": "xhigh"}. Serving configuration was not exercised during adaptation, so verify the rendered prompt before relying on it in production.

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

Model tree for CrowtherLabs/atom-proton-1.0

Quantizations
2 models