How to Synthesize Training Data for Needle 2: A Complete Guide
Needle 2 automatically generates synthetic training examples by sending tool schemas to an OpenRouter model via the generate-data CLI command, producing JSONL datasets that pair realistic user queries with schema-validated tool calls.
When fine-tuning Needle 2 on tool-calling capabilities, obtaining thousands of hand-crafted examples can block development. The cactus-compute/needle repository solves this through an automated synthesize training data pipeline that generates high-quality, schema-compliant training pairs using large language models via OpenRouter.
How the Needle 2 Data Synthesis Pipeline Works
The synthesis process implemented in needle/model/finetune.py follows a five-step workflow orchestrated through needle/cli.py.
Step 1: Schema Parsing and Seed Generation
The pipeline begins by reading your tool definitions. The CLI parses the --tools argument (lines 53-55 in needle/cli.py) to load a JSON schema file that follows the OpenAPI-style format. This schema defines available tools, their argument types, valid enums, and required parameters, serving as the foundation for generating realistic examples.
Step 2: OpenRouter Model Integration
For each requested sample, the generate_main function in needle/model/finetune.py constructs prompts containing your tool schemas and sends them to an OpenRouter model. By default, it uses deepseek/deepseek-v4-flash, though you can override this with the --model flag (lines 59-60 in needle/cli.py). The model generates both a realistic user query and the corresponding tool call that respects the schema constraints defined in your input file.
Step 3: Parallel Request Processing
To accelerate generation, requests dispatch concurrently across multiple workers. The --workers parameter (lines 57-58 in needle/cli.py) defaults to 16 parallel connections, significantly reducing the time required to build large datasets without overwhelming the API endpoint.
Step 4: JSONL Formatting and Output Generation
Each OpenRouter response is structured into a standardized JSONL line containing four fields: query, tools, answers, and optionally reasoning. This format aligns exactly with the fine-tuning specification documented in doc/finetuning.md (lines 5-11). The final dataset writes to your specified --output path (lines 60-61 in needle/cli.py), defaulting to data.jsonl if not provided.
Prerequisites for Synthesizing Training Data
Before running the generator, you must configure your environment and define your tool schemas.
OpenRouter API Configuration
The generator requires an active OpenRouter account. Export your API key as OPENROUTER_API_KEY (as documented in the README, lines 100-106). Without this environment variable, the generate_main function cannot authenticate requests to the OpenRouter endpoint.
Tool Schema Structure
Your input JSON must define tools using standard JSON Schema format. Each tool requires a name, parameter object with types and constraints, and required fields array. The schema drives the generation process, ensuring synthetic examples respect enum values, type constraints, and required parameter rules.
Generating Synthetic Training Data with the CLI
Execute the full synthesis pipeline using the generate-data command. Below are practical examples for creating datasets from scratch.
Creating a new dataset from a tool schema:
# Define your tools following OpenAPI JSON Schema format
cat > tools.json <<EOF
{
"tools": [
{
"name": "set_lights",
"parameters": {
"type": "object",
"properties": {
"room": { "type": "string", "enum": ["kitchen","study","bedroom"] },
"brightness": { "type": "integer", "minimum": 0, "maximum": 100 }
},
"required": ["room"]
}
}
]
}
EOF
# Set your OpenRouter API key
export OPENROUTER_API_KEY=sk-or-...
# Generate 500 synthetic examples
needle generate-data \
--tools tools.json \
--num-samples 500 \
--output synthetic_data.jsonl
This produces synthetic_data.jsonl containing 500 training rows where each line pairs a generated user query with a valid set_lights tool call respecting the room enum and brightness constraints.
Augmenting Existing Training Datasets
If you already possess hand-written examples, expand them without starting from scratch. Use the --augment flag (parsed at lines 53-55 in needle/cli.py) to load an existing JSONL file and append new synthetic entries:
needle generate-data \
--augment hand_written.jsonl \
--num-samples 300 \
--output combined_data.jsonl
This approach preserves your curated examples while adding diverse variations generated by the OpenRouter model, creating a hybrid dataset for more robust fine-tuning.
Fine-Tuning on Generated Data
Once synthesized, use the dataset directly in the fine-tuning workflow:
needle finetune combined_data.jsonl --epochs 10 --generate 200
The generate-data output format matches exactly what the finetune command expects, ensuring seamless integration between synthesis and training phases.
Quality Control Best Practices
While the pipeline enforces schema constraints through the JSON definitions, synthetic data requires validation before production use.
Inspect generated samples by examining the first few lines of your output file:
head -n 5 synthetic_data.jsonl
Look for out-of-domain queries or argument values that, while technically valid according to the schema, may not represent realistic user interactions. Filter these rows manually or adjust your tool schema descriptions to guide the OpenRouter model toward higher-quality generations.
You can also adjust the base model via --model if you observe quality issues with the default deepseek/deepseek-v4-flash, selecting alternative OpenRouter endpoints that better match your domain requirements.
Summary
- Needle 2 synthesizes training data via the
generate-dataCLI command, which invokesgenerate_maininneedle/model/finetune.pyto query OpenRouter models. - The pipeline requires a JSON Schema tool definition (
--tools) and an OpenRouter API key (OPENROUTER_API_KEY) to function. - Requests execute in parallel using 16 workers by default, with each response formatted as JSONL containing
query,tools,answers, and optionalreasoningfields. - Use
--augmentto expand existing datasets, and always validate synthetic examples for domain relevance before fine-tuning.
Frequently Asked Questions
What file format does Needle 2 expect for tool schemas?
Needle 2 expects standard OpenAPI-style JSON Schema files. The schema must define tools with names, parameter objects containing type definitions and constraints (enums, min/max values), and required field arrays. The CLI parser at lines 53-55 in needle/cli.py validates this structure before initiating generation.
Can I use a different model than the default for data generation?
Yes. While the default generator uses deepseek/deepseek-v4-flash, you can specify any OpenRouter-supported model using the --model flag (lines 59-60 in needle/cli.py). This allows you to balance generation cost, speed, and quality by selecting cheaper or more capable alternatives.
How does Needle 2 ensure generated tool calls match the schema?
The generate_main function includes your complete tool schema in every prompt sent to OpenRouter. This in-context schema enforcement instructs the model to respect argument types, required fields, and enum constraints. Additionally, the output formatting logic in needle/model/finetune.py structures the response into the standard JSONL format expected by the fine-tuning pipeline.
Is there a limit to how many samples I can generate?
There is no hardcoded limit in the Needle 2 codebase itself. The --num-samples parameter accepts any integer, though generation speed depends on your OpenRouter rate limits and the --workers setting (default 16). For large datasets exceeding thousands of samples, consider generating in batches to avoid API timeouts or quota exhaustion.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →