Use prepare_data() when you already have data and want it rendered for a target tokenizer.
Supported sources:
- local JSONL files
- folders of JSONL traces
- Hugging Face dataset repos
- already-loaded
datasets.Datasetobjects - source mixes with explicit ratios
from teich import prepare_data
train_dataset = prepare_data(
"TeichAI/Claude-Opus-4.6-Reasoning-887x",
tokenizer,
max_length=32768,
oversized_policy="trim_followups",
tokenize=True,
chat_template_kwargs={"enable_thinking": True, "preserve_thinking": True},
)prepare_data() returns rendered text, Teich span metadata, and optionally input_ids / attention_mask.
Call Training's mask_data() step after constructing your trainer to convert those spans into token-level labels.
For audit-friendly preparation, request a report and keep provenance columns:
train_dataset, prep_report = prepare_data(
"TeichAI/Claude-Opus-4.6-Reasoning-887x",
tokenizer,
max_length=32768,
oversized_policy="drop",
preserve_columns=True,
return_report=True,
tokenize=True,
)
print(prep_report.max_token_length)
print(prep_report.oversized_rows[:3])PrepareReport includes dropped rows, oversized rows, trimmed rows, token lengths, max token length, kept-row ids, and returned row count.
Original columns are removed after formatting unless preserve_columns=True or an explicit list is passed. The default provenance set is source, metadata, raw_index, and source_key.
When max_length is set, use one of:
oversized_policy="drop": drop oversized rowsoversized_policy="trim_followups": for multi-turn rows, remove the final user follow-up and everything after it before dropping the whole rowoversized_policy="error": raise instead of filtering
The older drop_oversized_examples and trim_oversized_followups flags still work as compatibility aliases, but oversized_policy is the preferred API.
Mix datasets with true ratios:
train_dataset = prepare_data(
{
"max_examples": 1000,
"reasoning-agent": {
"source": "badlogicgames/pi-mono",
"percentage": 80,
"chat_template_kwargs": {"enable_thinking": True, "preserve_thinking": True},
},
"instruct-chat": {
"source": "TeichAI/polaris-alpha-1000x",
"percentage": 20,
"chat_template_kwargs": {"enable_thinking": False, "preserve_thinking": False},
},
},
tokenizer,
max_length=32768,
oversized_policy="trim_followups",
tokenize=True,
chat_template_kwargs={"enable_thinking": True, "preserve_thinking": True},
)percentage, proportion, and weight are treated as true ratios.
If one source cannot fill its share after filtering or context-window drops, Teich scales the total row count down instead of silently changing the realized mix.
Global chat_template_kwargs are the default for every source. A source-level chat_template_kwargs mapping overrides those keys for that dataset only.
You can also pass a simple list of sources:
train_dataset = prepare_data(
["username/chat-traces", "username/tool-traces"],
tokenizer,
max_length=32768,
oversized_policy="trim_followups",
tokenize=True,
chat_template_kwargs={"enable_thinking": True},
)Teich can fail early on undeclared or malformed tool calls:
train_dataset = prepare_data(
"./output",
tokenizer,
validate_tools=True,
strict=True,
)validate_tools=True checks tool-call names and required arguments against each row's declared tools.
If you do not want Teich response-only labels, turn masking metadata off:
train_dataset = prepare_data(
"./data.jsonl",
tokenizer,
teich_masking=False,
)Rows contain rendered text only, plus tokens if tokenize=True.
If you want a training-friendly JSONL file without requiring Teich in the training environment, convert raw or extracted traces first:
teich convert ./data --out teich-training.jsonlEach output line has:
promptmessagestoolsmetadata
This preserves tool schemas, tool calls, reasoning fields, and provenance in standalone OpenAI-style message rows. It does not render a tokenizer-specific chat template and does not create token-level labels; use prepare_data() and mask_data() for that path.
Teich does not currently have a dedicated ShareGPT export command. Use load_traces() to normalize extracted data into messages, then write the conversations shape expected by ShareGPT-style trainers:
import json
from pathlib import Path
from teich import load_traces
ROLE_MAP = {
"system": "system",
"developer": "system",
"user": "human",
"assistant": "gpt",
"model": "gpt",
}
def message_text(content):
if isinstance(content, str):
return content.strip()
if not isinstance(content, list):
return ""
parts = []
for item in content:
if isinstance(item, str) and item.strip():
parts.append(item.strip())
elif isinstance(item, dict) and isinstance(item.get("text"), str):
parts.append(item["text"].strip())
return "\n".join(part for part in parts if part).strip()
dataset = load_traces("./data")
output_path = Path("sharegpt.jsonl")
with output_path.open("w", encoding="utf-8") as handle:
for row in dataset:
conversations = []
for message in row["messages"]:
role = ROLE_MAP.get(message.get("role"))
if role is None:
continue
text = message_text(message.get("content"))
reasoning = message.get("reasoning_content")
if role == "gpt" and isinstance(reasoning, str) and reasoning.strip():
text = f"<think>\n{reasoning.strip()}\n</think>\n{text}".strip()
if text:
conversations.append({"from": role, "value": text})
if any(turn["from"] == "gpt" for turn in conversations):
handle.write(json.dumps({"conversations": conversations}, ensure_ascii=False) + "\n")This simple export is best for text chat data. ShareGPT-style schemas usually do not preserve Teich's full agent surface, including tool schemas, tool result messages, tool-call arguments, provenance metadata, and typed supervision spans. Keep the native Teich JSONL format when training agent/tool-use models with prepare_data() and mask_data().
Use load_traces() directly when you want to own chat-template rendering, filtering, tokenization, label masking, and packing policy.
from teich import load_traces, row_fits_context, validate_tool_calls
dataset = load_traces("./output")
example = dataset[0]
validate_tool_calls(example).raise_for_errors()
if not row_fits_context(example, tokenizer, 32768, {"enable_thinking": True}):
raise ValueError("example does not fit the target context window")
rendered = tokenizer.apply_chat_template(
example["messages"],
tools=example.get("tools") or [],
tokenize=False,
add_generation_prompt=False,
enable_thinking=True,
)
tokenized = tokenizer(rendered, truncation=True, max_length=32768)load_traces() drops rows that end on a tool result by default, because those traces are incomplete without a follow-up assistant turn. Pass drop_incomplete_traces=False only when you intentionally want to inspect or repair those rows.
row_fits_context(row, tokenizer, max_length, chat_template_kwargs): render and measure one rowvalidate_tool_calls(row): check declared tool names and required argumentstrace_is_complete(row): flag rows that end on a tool resultdetect_trace_type(events): identify supported raw trace events, or returnNone