Upload Traces
If you have production traces — logs of real interactions with an LLM — you can use them to train a small language model without manually curating a dataset. This is the fastest way to get started if you already have an LLM-powered application in production.
Example use cases:
- Bootstrapping a fine-tuned model from existing production chat logs
- Improving a deployed model by training on its own successful interactions
- Converting multi-turn conversation logs into individual training examples
- Rapidly creating training data without manual labeling effort
Understanding the trace processing pipeline
Section titled “Understanding the trace processing pipeline”When you upload traces, the platform automatically runs a processing pipeline that prepares them for training:
- Filtering: Traces are filtered for relevance to your task based on the job description.
- Relabeling: A committee of teacher models relabels examples to improve quality and consistency.
- Splitting: Traces are split into training and test sets.
- Conversion: Multi-turn conversations are converted into single-turn examples or preserved as full conversations, depending on the
convert_to_single_turnsetting.
After processing, the platform evaluates the original model (the one that generated the traces) on the test set, giving you a baseline to compare against your trained SLM.
Single-turn vs. multi-turn conversion
Section titled “Single-turn vs. multi-turn conversion”The convert_to_single_turn parameter (default: true) controls how multi-turn conversations from your traces become training examples. Highlighted messages are the ones the teacher committee relabels.
convert_to_single_turn: trueconvert_to_single_turn: falseWhen to use each mode:
convert_to_single_turn: true(default) — best for standard single-turn training. Each user-assistant exchange becomes its own training example.convert_to_single_turn: false— best when you want to preserve conversational flow. The output is better suited as seed data for multi-turn synthetic data generation.
Preparing your traces
Section titled “Preparing your traces”Required files
Section titled “Required files”Your traces directory should contain:
| File | Format | Required | Description |
|---|---|---|---|
traces.jsonl | JSONL | Yes | Production traces (see supported formats below) |
job_description.json | JSON | Yes | Task description — see Job description below or the task-specific data preparation guides |
config.yaml | YAML | Yes | Training config with trace_processing parameters |
test.jsonl or test.csv | JSONL or CSV | No | Optional curated test set |
Traces file
Section titled “Traces file”The traces.jsonl file contains your production traces, one JSON object per line. The format is controlled by the observation_format parameter in the trace_processing section of your config.
OpenAI messages format (default)
Section titled “OpenAI messages format (default)”Each line is a JSON object with a messages array following the OpenAI chat completion format. Optionally include tools for tool-calling traces and response_format for structured output.
| Field | Type | Required | Description |
|---|---|---|---|
messages | array | Yes | Array of chat completion messages |
tools | array | No | Tool definitions in OpenAI function-calling format |
response_format | object | No | Response format specification for structured output |
Each message in the messages array has the following fields:
| Field | Type | Required | Description |
|---|---|---|---|
role | string | Yes | One of system, user, assistant, or tool |
content | string or null | No | The message content |
tool_calls | array | No | Tool calls made by the assistant |
Example — simple conversation:
{"messages": [{"role": "system", "content": "You are a helpful banking assistant."}, {"role": "user", "content": "What is my account balance?"}, {"role": "assistant", "content": "Your current account balance is $1,234.56."}]}
{"messages": [{"role": "system", "content": "You are a helpful banking assistant."}, {"role": "user", "content": "Transfer $100 to savings."}, {"role": "assistant", "content": "I've transferred $100 from your checking to your savings account."}]}
Example — with tool calls:
{"messages": [{"role": "system", "content": "You are a helpful assistant with access to tools."}, {"role": "user", "content": "What's the weather in London?"}, {"role": "assistant", "content": null, "tool_calls": [{"id": "call_1", "type": "function", "function": {"name": "get_weather", "arguments": "{\"city\": \"London\"}"}}]}, {"role": "tool", "content": "{\"temperature\": 15, \"condition\": \"cloudy\"}"}], "tools": [{"type": "function", "function": {"name": "get_weather", "description": "Get the current weather for a city", "parameters": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}}}]}
Langfuse format
Section titled “Langfuse format”Each line is a Langfuse observation object. Set observation_format: langfuse in your config to use this format.
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique observation identifier |
input | array | Yes | Array of input messages (same structure as OpenAI messages) |
output | array | No | Array of tool call outputs with toolCallId, toolName, and input fields |
metadata | object | No | Metadata object; may contain a tools array of JSON-encoded tool definitions |
Job description
Section titled “Job description”Describes the task you want your model to perform. This is the same format used in the structured data approach — a JSON file with a task_description and any task-specific fields.
{
"task_description": "You are a helpful banking assistant that answers customer questions about their accounts, transactions, and banking products."
}
For task types that require additional fields (e.g. classes_description for classification, tools for tool calling), include them as you would for structured data preparation. See the data preparation guides for task-specific fields.
Configuration file
Section titled “Configuration file”The configuration file specifies the task type, model selection, and trace processing parameters:
base:
task: classification
student_model_name: Llama-3.2-3B-Instruct
trace_processing:
observation_format: openai_messages
convert_to_single_turn: true
relabel: true
See the trace processing configuration reference for all available parameters.
Uploading traces
Section titled “Uploading traces”Upload your traces directory:
distil model upload-traces <model-id> --data ./tracesAs an alternative to directory mode, specify each file individually:
distil model upload-traces <model-id> \
--traces <file> \
--job-description <file> \
--config <file> \
[--test <file>]See the CLI reference for all upload options.
import json
import requests
# See Account and Authentication for distil_bearer_token() implementation
auth_header = {"Authorization": f"Bearer {distil_bearer_token()}"}
# Upload traces for a model
with open("traces/traces.jsonl", "rb") as traces_file, \
open("traces/job_description.json", "rb") as jd_file, \
open("traces/config.yaml", "rb") as config_file:
response = requests.post(
f"https://api.distillabs.ai/models/{model_id}/upload-traces",
files={
"traces": traces_file,
"job_description": jd_file,
"config": config_file,
},
headers=auth_header,
)
upload_id = response.json()["id"]
print(f"Trace processing started. Upload ID: {upload_id}") Checking processing status
Section titled “Checking processing status”Trace processing typically takes several minutes. Check the current status:
distil model upload-status <model-id> import time
from pprint import pprint
running = True
while running:
response = requests.get(
f"https://api.distillabs.ai/uploads/{upload_id}/status",
headers=auth_header
)
status = response.json()["status"]
if status != "JOB_RUNNING":
running = False
print(f"Processing status: {status}")
time.sleep(10)
# Display results
pprint(response.json()) Once processing completes successfully, the response includes a base_model_performance field with evaluation metrics for the base model on your test set. See Metrics for details on each metric and how to interpret them.
Retrieving predictions
Section titled “Retrieving predictions”For more in-depth analysis, you can download the per-example predictions of the base model on the test dataset:
distil model download-traces-predictions <model-id>By default, the file is saved as <model-id>-traces-predictions.jsonl. Use --file-name to specify a different name:
distil model download-traces-predictions <model-id> --file-name predictions.jsonl The download URL is included in the upload status response once processing has completed:
response = requests.get(
f"https://api.distillabs.ai/uploads/{upload_id}/status",
headers=auth_header
)
print(response.json()["base_model_predictions_download_url"])Download and read the predictions file:
curl -o base_model_predictions.json "<DOWNLOAD_URL>" The file is in JSON Lines format and can be read using:
import pandas as pd
df = pd.read_json("predictions.jsonl", lines=True)
Reprocessing traces
Section titled “Reprocessing traces”After the initial upload, you can try different processing parameters without re-uploading the trace files:
# Using a full config file
distil model reprocess-traces <model-id> --config <file>
# Or using only trace processing parameters
distil model reprocess-traces <model-id> --trace-processing-config <file>
You must have uploaded traces with upload-traces first. See the CLI reference for details.
Next steps
Section titled “Next steps”Once trace processing completes successfully, continue with:
- Teacher Evaluation — validate that the teacher model can solve your task
- Model Training — train your SLM using knowledge distillation