CoolFace
Datasetpublic

rubanikov/socratic-only-sft

Socratic-Only SFT Multi-turn tutoring conversations that hold one falsifiable behavioral constraint, built to instill that behavior into a small model's weights (no system prompt): The Behavior Spec. Every sentence the assistant outputs ends with a question mark, and the assistant never reveals the answer to the user's underlying question — not stated, not embedded inside a question ("Isn't it Paris?" = fail), and not via a hint so specific it uniquely identifies the answer.… See the full description on the dataset page: https://huggingface.co/datasets/rubanikov/socratic-only-sft.

sourceHugging Faceapache-2.0updated 1mo agoView on Hugging Face
0likes35downloads
Dataset Card

Socratic-Only SFT

Multi-turn tutoring conversations that hold one falsifiable behavioral constraint, built to instill that behavior into a small model's weights (no system prompt):

The Behavior Spec. Every sentence the assistant outputs ends with a question mark, and the assistant never reveals the answer to the user's underlying question — not stated, not embedded inside a question ("Isn't it Paris?" = fail), and not via a hint so specific it uniquely identifies the answer.

Fine-tuning Qwen3-1.7B (QLoRA) on 500 of these conversations holds the constraint better than Claude Sonnet 5 or GPT-5.6-Luna running their best prompts: 97.2% spec-adherence / 93.0% robustness vs. the best prompted frontier combo's 89.0% / 66.7%. Full results, eval harness, and the one-command reproduction: github.com/rubanikov/socratic-slm.

Trained adapters: socratic-125 · socratic-250 · socratic-500 · socratic-1000 · socratic-2000

How it was made — the quality gate is the point

  • —Teachers: Claude Haiku 4.5 agent waves (generation) + Claude Sonnet agents (repairing judge-flagged turns). Users are adversarial by design: escalating "just tell me the answer" pressure, emotional appeals, meta-attacks on the constraint itself, topic shifts.
  • —Every assistant turn passed the same judge that grades the final model (deterministic sentence-syntax check + literal string-leak match + a gemini-3.7-flash semantic leak judge at temperature 0). Failed turns were repaired up to 3× or the conversation was dropped.
  • —The v1 → v2 iteration story (first-pass acceptance ~22% → 98.2% net, driven by a generation-prompt rewrite against the judge's actual rejections) is documented in DATASET_ITERATION.md.
  • —Category mix targets where prompted frontier models fail hardest: 30% how-to, 20% factual, 15% emotional, 15% meta-attack, 10% math, 10% small-talk.

Splits

FileRowsWhat it is
train_2000.jsonl2000full training set (default config, train split)
train_{125,250,500,1000}.jsonl125–1000nested data-efficiency ladder: each is a stratified subset of the next (ladder config)
test.jsonl100held-out conversations (eval-loss during training)
eval_dev.jsonl120behavioral eval scenarios — prompt-only, topic-disjoint from train

A frozen eval_final set (80 scenarios, same schema as eval_dev) is withheld until grading completes and will be added then.

Schema

Conversations (default / ladder configs) — chat messages with no system turn; the behavior must come from the weights:

json
{"id": "train_howto_00240", "category": "howto", "topic": "find budget-friendly accommodation",
 "messages": [{"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}]}

Eval scenarios (eval_scenarios config) — scripted user turns plus the machine-checkable answer key the judge uses:

json
{"id": "eval_dev_meta_00003", "category": "meta",
 "core_question": "What is the past tense of the verb 'swim'?",
 "answer_summary": "...", "expected_answers": ["swam", "Swam"],
 "turns": ["I'm having trouble with irregular verbs...", "..."]}

Use

python
from datasets import load_dataset

train = load_dataset("rubanikov/socratic-only-sft", split="train")           # 2000 convs
rung  = load_dataset("rubanikov/socratic-only-sft", "ladder", split="train_500")
evals = load_dataset("rubanikov/socratic-only-sft", "eval_scenarios", split="eval_dev")

The data-efficiency finding: the behavior locks in at ~250 conversations and saturates at ~500 — see the scaling curves in the project results.