<img alt="Bespoke Labs Logo" width="100px" src="https://github.com/bespokelabsai/curator/blob/main/docs/Bespoke-Labs-Logomark-Red-crop.png">
[ English | 中文 ]
FireworksTrainer — upload curated data, train a LoRA, and sample from the deployed model behind the same trainer interface as Tinker.Bespoke Curator makes it easy to create synthetic data pipelines. Whether you are training a model or extracting structured data, Curator will prepare high-quality data quickly and robustly.

Check out our full documentation for getting started, tutorials, guides and detailed reference.
pip install bespokelabs-curator
| Task | Link(s) | Goal |
|---|---|---|
| Product feature extraction | Finetuning a model to identify features of a product | |
| Sentiment analysis | Aspect-based sentiment analysis of restaurant reviews and finetuning using Together.ai | |
| RAFT for domain-specific RAG | Code | Implement Retrieval Augmented Fine-Tuning (RAFT) that processes domain-specific documents, generates questions, and prepares data for fine-tuning LLMs. |
| Poem generation & LoRA fine-tuning | Code | End-to-end pipeline: curate poem data with Curator, then LoRA fine-tune with TinkerTrainer |
| Managed fine-tuning on Fireworks AI | Code | Run a managed SFT job on Fireworks AI with FireworksTrainer, then sample from the deployed LoRA model |
| Task | Link(s) | Goal |
|---|---|---|
| Reasoning dataset generation (Bespoke Stratos) | Code | Generate the Bespoke-Stratos-17k dataset, focusing on reasoning traces from math, coding, and problem-solving datasets. |
| Reasoning dataset generation (Open Thoughts) | Code | Generate the Open-Thoughts-114k dataset, focusing on reasoning traces from math, coding, and problem-solving datasets. |
| Multimodal | Code | Demonstrates multimodal capabilities by generating recipes from food images |
| Ungrounded Question Answer generation | Code | Generate diverse question-answer pairs using techniques similar to the CAMEL paper |
| Code Execution | Execute code generated with Curator | |
| 3Blue1Brown video generation | Code | Generate videos similar to 3Blue1Brown and render them using code execution! |
| Synthetic charts | Code | Generate charts synthetically. |
| Function calling | Code | Generate data for finetuning for function calling. |
curator.LLM for Bulk Inferencefrom typing import Dict
from bespokelabs import curator
from datasets import Dataset
from pydantic import BaseModel, Field
from typing import Literal
class Sentiment(BaseModel):
sentiment: Literal["positive", "negative", "neutral"] = Field(
description="Sentiment of the review")
class SentimentAnalyzer(curator.LLM):
def prompt(self, product: Dict):
return f"Determine the sentiment of the product from the review: {product['review']}"
def parse(self, product: Dict, response: Sentiment):
return [{"name": product["name"], "sentiment": response.sentiment}]
# You can easily have a million rows here.
# Curator takes care of parallelism, retries, and caches responses.
dataset = [{"name": "Curator", "review": "Already saved hours in one day of use."},
{"name": "Bespoke MiniCheck", "review": "Hallucination rates dropped by 90%."}]
# You can set batch=True, and instantly uses batch mode to save 50% of the costs.
analyzer = SentimentAnalyzer(
model_name="gpt-4o-mini", response_format=Sentiment, batch=False)
reviews = analyzer(dataset)
print(reviews.to_pandas())
Output:
name sentiment
0 Curator positive
1 Bespoke MiniCheck positive
In the SentimentAnalyzer class:
* prompt takes the input (product) and returns the prompt for the LLM.
* parse takes the input (product) and the structured output (response) and converts it to a list of dictionaries. This is so that we can easily convert the output to a HuggingFace Dataset object.
Instead of a list, you can pass a HuggingFace Dataset object as well (see below for more details).
curator.LLM for data generationHere's an example of using structured outputs and chaing together two curator.LLM blocks to generate diverse poems.
from typing import Dict, List
from bespokelabs import curator
from pydantic import BaseModel, Field
class Topics(BaseModel):
topics_list: List[str] = Field(description="A list of topics.")
class TopicGenerator(curator.LLM):
response_format = Topics
def prompt(self, subject):
return f"Return 3 topics related to {subject}"
def parse(self, input: str, response: Topics):
return [{"topic": t} for t in response.topics_list]
class Poem(BaseModel):
title: str = Field(description="The title of the poem.")
poem: str = Field(description="The content of the poem.")
class Poet(curator.LLM):
response_format = Poem
def prompt(self, input: Dict) -> str:
return f"Write two poems about {input['topic']}."
def parse(self, input: Dict, response: Poem) -> Dict:
return [{"title": response.title, "poem": response.poem}]
topic_generator = TopicGenerator(model_name="gpt-4o-mini")
poet = Poet(model_name="gpt-4o-mini")
# Start generation
topics = topic_generator("Mathematics")
poems = poet(topics)
Output:
title poem
0 The Language of Algebra In symbols and signs, truths intertwine,..
1 The Geometry of Space In the world around us, shapes do collide,..
2 The Language of Logic In circuits and wires where silence speaks,..
You can see more examples in the examples directory.
See the docs for more details as well as for troubleshooting information.
[!TIP] If you are generating large datasets, you may want to use batch mode to save costs. Currently batch APIs from OpenAI and Anthropic are supported. With curator this is as simple as setting
batch=Truein theLLMclass. [!NOTE] Retries and caching are enabled by default to help you rapidly iterate your data pipelines. So now if you run the same prompt again, you will get the same response, pretty much instantly. You can delete the cache at~/.cache/curatoror disable it withexport CURATOR_DISABLE_CACHE=true.[!IMPORTANT] Make sure to set your API keys as environment variables for the model you are calling. For example running
export OPENAI_API_KEY=sk-...andexport ANTHROPIC_API_KEY=ant-...will allow you to run the previous two examples. A full list of supported models and their associated environment variable names can be found in the litellm docs.
We collect minimal, anonymized usage telemetry to help prioritize new features and improvements that benefit the Curator community. You can opt out by setting the TELEMETRY_ENABLED environment variable to False.
Curator supports a wide range of providers, including OpenAI, Anthro
$ claude mcp add curator \
-- python -m otcore.mcp_server <graph>