Instructions to use DianShiGroup/DianShi-RetroStepLM-Direct with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use DianShiGroup/DianShi-RetroStepLM-Direct with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="DianShiGroup/DianShi-RetroStepLM-Direct") 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("DianShiGroup/DianShi-RetroStepLM-Direct") model = AutoModelForCausalLM.from_pretrained("DianShiGroup/DianShi-RetroStepLM-Direct", 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 DianShiGroup/DianShi-RetroStepLM-Direct with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "DianShiGroup/DianShi-RetroStepLM-Direct" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "DianShiGroup/DianShi-RetroStepLM-Direct", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/DianShiGroup/DianShi-RetroStepLM-Direct
- SGLang
How to use DianShiGroup/DianShi-RetroStepLM-Direct 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 "DianShiGroup/DianShi-RetroStepLM-Direct" \ --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": "DianShiGroup/DianShi-RetroStepLM-Direct", "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 "DianShiGroup/DianShi-RetroStepLM-Direct" \ --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": "DianShiGroup/DianShi-RetroStepLM-Direct", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use DianShiGroup/DianShi-RetroStepLM-Direct with Docker Model Runner:
docker model run hf.co/DianShiGroup/DianShi-RetroStepLM-Direct
# pip install -U transformers accelerate
# Load model directly
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("DianShiGroup/DianShi-RetroStepLM-Direct")
model = AutoModelForCausalLM.from_pretrained("DianShiGroup/DianShi-RetroStepLM-Direct", 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]:]))DianShi-RetroStepLM-Direct
DianShi-RetroStepLM-Direct (RetroStepLM-Direct for short) is a single-step retrosynthesis model from the paper Reaction precedents extend retrosynthetic prediction beyond training coverage. Given a target product, it predicts a set of precursor molecules directly from the target structure alone โ there is no retrieval and no reaction-template lookup at inference time.
| Resource | Link |
|---|---|
| Paper | arXiv:2610.40249 |
| Code | DianShiGroup/DianShi-RetroStepLM |
| Multi-step runtime assets | DianShiGroup/DianShi-RetroPlanSystem-Assets |
| Base model | Qwen/Qwen3-4B-Base |
Model details
| Architecture | Qwen3ForCausalLM (Qwen3 dense, model_type: qwen3) |
| Parameters | ~4B |
| Layers / hidden / heads | 36 / 2560 / 32 (8 KV heads, head_dim 128) |
| Intermediate size | 9728 |
| Vocab size | 151936 |
| Context length | 40960 (rope_theta 1000000) |
| Dtype | bfloat16 |
tie_word_embeddings |
true |
| EOS / PAD token id | 151645 / 151643 |
| Weights | 2 safetensors shards (~7.6 GB) |
| Transformers | >= 4.57.6 (config transformers_version) |
Method
Input. The system prompt from
prompt_sft_intermediate_label.txt
plus a user message The product SMILES is <SMILES>., where the SMILES is
written atom-wise (tokens separated by spaces).
Output. The intermediate-label target sequence: synthon SMILES, then
leaving groups, then the final reactant set, which is additionally enclosed in
<answer>...</answer>; multiple reactants are separated by .. Only the final
reactant set is scored; the intermediate fields are not scored independently.
Training. Full-parameter supervised fine-tuning from
Qwen3-4B-Base with
intermediate-label supervision, on the 2,712,259 pre-2025 reactions of
DianShi-PatentRxnStep-Train-Full. The synthon and leaving-group labels are
derived from atom-mapped reactions.
Usage
The model is run the same way as in the DianShi-RetroStepLM single-step pipeline: vLLM beam search (beam width 10, max 1024 new tokens).
On enable_thinking. Use enable_thinking=True, as below โ this is the
setting the reported results were produced with, and it is the default in the
repository's evaluation scripts and in the multi-step frameworks. The model
emits its intermediate labels inside <think>...</think> before the <answer>
tag, because that is the training format. The flag does not switch the
reasoning on or off: it only controls whether the chat template pre-seeds an
empty <think>\n\n</think> block after the generation prompt. Either way the
answer is read from the <answer> tag, so the extraction below is unaffected.
With the DianShi-RetroStepLM repository
git clone https://github.com/DianShiGroup/DianShi-RetroStepLM.git
cd DianShi-RetroStepLM
pip install -r requirements.txt
# Build the Test-2025 evaluation set from the source data in the repository.
scripts/build_model_tests.sh --datasets test_2025 --splits test
scripts/infer_beam_search.sh \
--model-path DianShiGroup/DianShi-RetroStepLM-Direct \
--data-path model_tests/test_2025/intermediate_label/testset_intermediate_label_new_cached
This runs beam search and then prints Top-1/3/5/10 exact-match accuracy. See the repository README for Test-2001-2024, USPTO-50K and the other build options.
Standalone
import re
from vllm import LLM
from vllm.sampling_params import BeamSearchParams
SYSTEM = """You are an expert chemist specializing in retrosynthetic analysis. Given the SMILES representation of a product molecule, your task is to predict the SMILES of the reactants required to synthesize it.
Input:
The product SMILES.
Task requirements (step-by-step reasoning is required):
1.Infer the synthons based on the structure of the product.
2.Identify the corresponding leaving groups associated with these synthons.
3.Reconstruct the most plausible reactant molecules by combining the synthons with appropriate leaving groups.
You must explicitly show your reasoning step by step for each of the above stages.
Please output the reasoning process, and write the final reactant SMILES strictly in the following format:
<answer>REACTANT_SMILES</answer>
If multiple reactants are required, separate their SMILES using a period (.)."""
ANSWER_RE = re.compile(r"<answer>(.*?)</answer>", re.IGNORECASE | re.DOTALL)
def extract_reactants(text: str) -> str | None:
"""Last non-empty <answer> value, with the atom-wise spaces removed."""
for match in reversed(ANSWER_RE.findall(text)):
answer = re.sub(r"\s+", "", match)
if answer:
return answer
return None
llm = LLM(model="DianShiGroup/DianShi-RetroStepLM-Direct")
tok = llm.get_tokenizer()
# Atom-wise SMILES of CC(=O)Oc1ccccc1C(=O)O
messages = [
{"role": "system", "content": SYSTEM},
{"role": "user", "content": "The product SMILES is C C ( = O ) O c 1 c c c c c 1 C ( = O ) O ."},
]
prompt = tok.apply_chat_template(
messages, tokenize=False, add_generation_prompt=True, enable_thinking=True
)
outputs = llm.beam_search([{"prompt": prompt}], params=BeamSearchParams(beam_width=10, max_tokens=1024))
for seq in outputs[0].sequences:
reactants = extract_reactants(seq.text)
if reactants:
print(seq.cum_logprob, reactants)
seq.text holds the full intermediate-label sequence plus the <answer> tag, so read the
prediction through extract_reactants rather than printing seq.text directly.
It mirrors what the
repository's evaluator
does: take the last <answer> value and strip whitespace, which also joins the
atom-wise tokens back into a plain SMILES. A beam that produced no complete tag
yields None and is skipped above. For the example product the reactants print
as CC(=O)OC(C)=O.OC(=O)c1ccccc1O โ one dot-separated mixture per beam.
Convert plain SMILES to the atom-wise input format with transform_messages
from
dianshi_retrosteplm.data.smiles_atomwise.
The evaluator canonicalizes reactants with RDKit and ignores reactant order.
Citation
If you use this model, please cite:
@misc{sun2026reactionprecedents,
title = {Reaction precedents extend retrosynthetic prediction beyond training coverage},
author = {Jiaxing Sun and Xuli Shen and Jiang Wu and Ruiyi Ding and Ruikang Zhang and Xiao An and Xibao Li and Yubin Wang and Xingjian Wei and Yinfan Wang and Yu Liu and Lingli Ge and Xi Xue and Xiaojian Wang and Lijun Wu and Chang-Yu Hsieh and Yuqiang Li and Bowen Zhou and Dahua Lin and Conghui He},
year = {2026},
eprint = {2610.40249},
archivePrefix = {arXiv},
primaryClass = {cs.AI},
doi = {10.48550/arXiv.2610.40249},
url = {https://arxiv.org/abs/2610.40249}
}
Please also cite the upstream works used by the multi-step frameworks (RetroAgent, Retro-R1, AOT*, rdchiral, SCScore); bibtex entries are in the component READMEs.
- Downloads last month
- 1
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="DianShiGroup/DianShi-RetroStepLM-Direct") messages = [ {"role": "user", "content": "Who are you?"}, ] pipe(messages)