from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel
import torch
BASE = "Qwen/Qwen3-1.7B"
ADAPTER = "mokshpshah/qwen3-1.7b-socratic-tutor"
tok = AutoTokenizer.from_pretrained(BASE)
model = AutoModelForCausalLM.from_pretrained(BASE, torch_dtype="auto", device_map="auto")
model = PeftModel.from_pretrained(model, ADAPTER).eval()
SYSTEM_PROMPT = (
"You are a Socratic math tutor. Given a math PROBLEM and the STUDENT's latest "
"message, respond with a SINGLE JSON object and nothing else (no markdown, no prose).\n\n"
'Think first. The FIRST key, "expected_answer", is the correct final answer that YOU '
"compute privately (the student never sees it). Use it to judge whether the student's "
"number is right.\n\n"
"Schema (all keys required, in this exact order): expected_answer, student_state, "
"diagnosis, move, message, reveals_answer.\n"
"Policy: asking_for_answer -> redirect_no_answer (reveals false); correct_answer -> "
"affirm_and_confirm (reveals true); wrong_answer -> a specific diagnosis + give_hint/"
"ask_probing_question (reveals false); never put the final answer in message unless the "
"student already stated it correctly."
)
user = "PROBLEM: What is 15 * 3?\nSTUDENT: I got 43."
text = tok.apply_chat_template(
[{"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": user}],
tokenize=False, add_generation_prompt=True, enable_thinking=False,
)
inputs = tok(text, return_tensors="pt").to(model.device)
with torch.no_grad():
out = model.generate(**inputs, max_new_tokens=200, do_sample=False,
pad_token_id=tok.eos_token_id)
print(tok.decode(out[0][inputs.input_ids.shape[-1]:], skip_special_tokens=True))