,

Data Prep and Synthetic Data on watsonx.data (IBM Gen AI Series, Part 13)

How to land, clean, and curate real data in the watsonx.data lakehouse, then use the Synthetic Data Generator on watsonx.ai to fill the gaps before a tune. With a worked cost example and a runnable cleaning script.

IBM Gen AI Series · Part 13 of 24

A tuning run inherits every flaw in the data behind it. Skip the cleaning and you pay for it later, in answers that quote page headers, dates that contradict each other, and a model that sounds sure about the wrong revision of a policy. The tuning we did in Part 11 and the InstructLab alignment in Part 12 both assumed a dataset was already sitting there, clean and ready. This part is about earning that assumption.

Who this is for: You have run a first tune or InstructLab job and now want the data underneath it to be right. You know what a JSONL file is (one JSON record per line). You do not need to have touched watsonx.data before; I define each piece as it appears. If you are still choosing a tuning method, read Part 11 first, then come back.
Key takeaways: watsonx.data is the open lakehouse where raw and prepared data lives before it feeds a tune. Curate real data first, then generate synthetic data only for the gaps. The Synthetic Data Generator service on watsonx.ai builds three kinds of dataset, tool calling, text to SQL, and knowledge QnA. Validation is not optional, and it belongs before tuning, not after.

Where a tuning set comes from

A tuning set is a file of examples that shows the model the behaviour you want. For a QnA tune it is question and answer pairs. For a tool-using agent it is a prompt plus the tool call the model should have made. Those examples come from three places, and most real projects use all three. You extract them from documents and logs you already own. You write a handful by hand to set the standard. Then you synthesize more from that handful when you do not have enough. The order matters, and I put the hand-written and extracted data first for a reason I come back to below.

watsonx.data is where all of this sits. It is an open data lakehouse, which means a single store that holds both structured tables and unstructured files, queried through open formats like Apache Iceberg rather than locked inside one vendor engine. In practice you point watsonx.data at your object storage, register the data, and query it with a fit-for-purpose engine such as Presto or Spark. For a data prep workflow that gives you one governed place to land raw PDFs, clean them into tables, and hand the result to a tune, without copying files across four systems and losing track of which copy is current.

flowchart LR
  A[Raw sources] --> B[watsonx.data lakehouse]
  B --> C[Clean and normalize]
  C --> D[Chunk]
  D --> E[Curate and label]
  E --> F{Enough real data?}
  F -->|Yes| H[Tuning set JSONL]
  F -->|No| G[Synthetic Data Generator]
  G --> I[Validate]
  I --> H
Figure 1. The prep path. Real data is cleaned and curated first; synthetic generation fills gaps and always passes through validation before it reaches the tuning file.

Load raw documents into watsonx.data

Most enterprise knowledge starts as unstructured files, PDFs, Word documents, wiki exports, support tickets. watsonx.data added connectors and document ingestion so you can pull from source systems like FileNet, Box, and shared drives, then turn those files into something a model can learn from. The 2025 releases lean on document processing that extracts text, tables, and layout, and can produce both vectorized embeddings for retrieval and structured derivatives you can query. Embeddings we covered when we built RAG in Part 9; here the same extracted text becomes seed material for tuning rather than retrieval context.

There is a related product worth naming so you do not confuse the two. watsonx.data integration handles the ingestion and preparation pipelines, structured and unstructured, batch and streaming, from one control plane, while watsonx.data itself is the lakehouse those pipelines write into. For document-heavy sources IBM leans on a document-processing partnership with Unstructured, which parses layout, tables, and metadata out of messy files and syncs only new or changed documents so you are not reprocessing the whole corpus on every run. You do not have to use it, a Python script and the cleaning step below will carry a small project, but once you are ingesting thousands of files from several systems, a managed pipeline stops being optional.

In practice: Extraction quality decides everything downstream. A scanned PDF with two columns and a running footer will hand you interleaved text and a footer repeated on every page. Strip the repeating furniture before you chunk, or every synthetic example you generate later will carry the same noise.

How much cleaning is enough?

Enough is when the noise that survives will not teach the model a habit you have to untrain. That is a lower bar than perfect and a higher bar than most people set. Three passes cover the common cases. Remove structural furniture, headers, footers, page numbers, navigation text. Normalize the content, collapse whitespace, fix encoding artifacts, make dates and units consistent. Then deduplicate, because near-identical paragraphs from twenty versions of the same template will dominate a small set and skew the tune toward them.

Chunking sits at the end of cleaning. A chunk is a unit of text small enough for the model to handle and large enough to carry a complete thought. For QnA generation I keep chunks to a single topic, roughly a few hundred tokens, and I never split a table across two chunks. The split you choose here shows up directly in the questions a knowledge builder produces later, so it is worth getting right before you generate anything.

Where a data prep pass goes My rough split of hands-on time. Adjust to your own data. 0 10 20 30 percent of effort Ingest 15 Clean and normalize 30 Chunk 10 Curate and label 25 Synthesize 10 Validate 10
Figure 2. Generation is the small slice. Cleaning and curation eat more than half the time on every prep job I have run.

Notice where the time goes. People assume synthetic generation is the hard part because it involves a model. It is the small slice. The expensive, unglamorous work is cleaning and curation, and no generator rescues a set built on bad extraction. That is the whole argument for doing real data first.

Here is a cleaning step you can run today. It takes an exported JSONL of QnA pairs, drops stubs and near-duplicates, and writes a clean file ready for the generator or a tune.

import re
import pandas as pd

# One record per line, e.g. {'question': ..., 'answer': ...}
df = pd.read_json('seed_pairs.jsonl', lines=True)
before = len(df)

def norm(text):
    return re.sub(r's+', ' ', str(text)).strip().lower()

df['q_key'] = df['question'].map(norm)
df = df.dropna(subset=['question', 'answer'])
df = df[df['answer'].str.len().between(20, 1200)]   # drop stubs and essays
df = df.drop_duplicates(subset='q_key')
after = len(df)

df[['question', 'answer']].to_json('seed_clean.jsonl',
                                   orient='records', lines=True)
print(f'kept {after} of {before} pairs')
Expected output: a line such as kept 182 of 240 pairs and a new seed_clean.jsonl. Failure mode: a KeyError on question means your export used different column names, for example input and output; print df.columns first and rename. A ValueError on read means the file is not valid line-delimited JSON.

When do you need synthetic data at all?

Synthetic data is generated by a model to look like your real examples, so you can reach a training set size that hand labelling would never afford. You need it when you have a clear pattern but too few examples, a few dozen good QnA pairs when a tune wants a few thousand. You do not need it when you already have thousands of real, varied examples, or when the pattern itself is still unsettled. Generating ten thousand rows off a confused seed set just gives you ten thousand confused rows, faster.

Two routes exist on watsonx and they solve different problems. InstructLab, from Part 12, drives generation from a taxonomy, a tree of skills and knowledge you curate, and is aimed at teaching a model new capabilities through its LAB method. The Synthetic Data Generator service on watsonx.ai is a more direct tool, you give it seed examples and a data builder, and it produces a dataset in the shape that builder targets. Reach for InstructLab when you are aligning behaviour across a curated skill tree. Reach for the Synthetic Data Generator when you want a specific dataset, tool calls, SQL, or QnA, without standing up a taxonomy.

Data builderWhat it generatesSeed or knowledge inputGood for
Tool callingPrompts paired with the correct tool or API callSeed examples as YAMLTeaching a model to call your own tools
Text to SQLA natural-language request plus the equivalent SQLSeed examples as YAMLQuery assistants over a known schema
KnowledgeQuestion and answer pairs from domain documentsPDF or Markdown knowledge baseDomain QnA where the base model is thin
Table 1. The three data builders in the Synthetic Data Generator service. Seed formats and outputs verified against IBM documentation.

Generate synthetic data on watsonx.ai

The service works the same way whichever builder you pick. You provide seed data as project assets, YAML for tool calling and text to SQL, PDF or Markdown for the knowledge builder. A foundation model on watsonx.ai generates candidates in the target shape. Validators built into each builder check the output against quality rules, and only what passes lands as a project asset in JSONL. You are charged for the tokens the generating model produces, so a run that targets thousands of examples is a real cost, not a rounding error, and it belongs in the FinOps view we set up in the series guide.

Worked example

Say you have 50 hand-written QnA pairs for one policy area and you want a knowledge dataset for a tune. You ask the builder for 30 candidates per seed, so 1,500 candidates. The validators reject about a fifth for being off-format or ungrounded, leaving roughly 1,200. Deduplication trims near-identical questions down to about 1,080, and you cut to a clean 1,000 for the tune. At an average of 500 generated tokens per pair, the 1,500 candidates cost you about 750,000 generated tokens. That token figure, not the final 1,000, is what shows up on the bill.

The lesson: budget on candidates generated, because you pay for rejects too.

From candidates to a usable tuning set Pairs remaining after each stage, from the worked example. 0 500 1000 1500 1500 Candidates 1200 Validated 1080 Deduped 1000 Final
Figure 3. The funnel from the worked example. You generate 1,500 to keep 1,000, and you pay for all 1,500.
StagePairsNote
Seed pairs50Hand-written, one policy area
Candidates generated1,50030 per seed, billed in tokens
After validators1,200About a fifth rejected
After dedup1,080Near-duplicate questions removed
Final tuning set1,000Trimmed to a clean round number
Table 2. The same funnel as numbers. Generated tokens, roughly 750,000 here, drive cost more than the final count does.

Run an SDG job in Python

The Synthetic Data Generator exposes an API as well as the studio UI. You need an Admin or Editor role on a project that has a Watson Machine Learning instance attached, an IBM Cloud IAM token, and a task credential. The job takes your seed asset and a data builder, runs generation and validation, and writes JSONL back to the project. The call below is the shape of that request; confirm the exact endpoint path against the watsonx.ai API reference for your region and version before you wire it into a pipeline.

import os
import requests

# Exchange an IBM Cloud API key for a short-lived IAM token
iam = requests.post(
    'https://iam.cloud.ibm.com/identity/token',
    data={
        'grant_type': 'urn:ibm:params:oauth:grant-type:apikey',
        'apikey': os.environ['IBM_CLOUD_APIKEY'],
    },
).json()['access_token']

# Submit a knowledge-builder synthetic data job
resp = requests.post(
    'https://us-south.ml.cloud.ibm.com/ml/v1/synthetic_data_generation'
    '?version=2025-06-01',
    headers={'Authorization': f'Bearer {iam}'},
    json={
        'project_id': os.environ['WX_PROJECT_ID'],
        'data_builder': 'knowledge',
        'seed_asset': 'policy_seed.yaml',
        'target_count': 1500,
    },
)
print(resp.status_code, resp.json().get('metadata', {}).get('id'))
Expected output: 202 and a job id you can poll for status. Failure mode: 401 means the IAM token expired, they last about an hour, so fetch one per run; 403 means your account lacks the Editor role or a task credential on the project.

Validate before you tune

The builders validate format and grounding, but they do not know your business. Two checks earn their keep every time. First, hold out a sample and read it. Not a metric, actual reading, fifty rows, by a person who knows the domain. Synthetic sets fail in ways that look fine to a script and wrong to an expert in one glance. Second, check the distribution. If 40 percent of your generated questions are about one subtopic because that is where the seed leaned, your tune will over-index on it. Rebalance the seed and regenerate rather than shipping a skewed set.

There is a governance angle here too, and it is one reason IBM customers land data in watsonx.data rather than a loose bucket. Every synthetic set has a lineage question attached, which seed produced it, which model generated it, which validators it passed. When an auditor or a regulator asks how a tuned model learned a given behaviour, that trail is the answer, and it is far easier to keep if the data never left a governed store. This is the same factsheet-and-lineage thinking that watsonx.governance formalizes later in the series, applied at the data layer before a tune ever runs.

Gotcha: Synthetic data trained on a model, then used to tune a model, can quietly inherit the generator’s blind spots and phrasings. Keep a slice of real, human data in every tuning set as an anchor. A set that is 100 percent synthetic tends to drift toward the generator’s voice, and you notice only after the tune ships.

What a data prep pass costs

Cost lands in two places. Generation tokens are the visible one, and the worked example shows how candidates, not keepers, drive that number. The larger cost is human, the curation and reading that Figure 2 puts at more than half the effort. A team that treats synthetic generation as free and skips the reading spends less on tokens and far more on a tune that has to be redone. Storing and querying the data in watsonx.data is the cheap part by comparison, and the governance you get, lineage and access policy across the same store, is worth more than the compute it costs. The full Resource Unit picture sat in Part 5, and the same accounting applies here.

The prepared set you finish here is exactly the input the next Part assumes. Part 14 moves to training infrastructure and scaling on OpenShift, where this JSONL becomes a job on real hardware. For a view of how another platform frames the same prep step, the Google Cloud series covered data prep and embeddings on Vertex AI, and the pattern of clean-first, generate-second holds on both.

Curate the real data first, synthesize only the gaps

If you take one working rule from this, take the order. Land your real data in watsonx.data, clean it hard, curate a small set you would stake your name on, and only then generate synthetic examples to reach the size a tune needs. Synthetic data is a multiplier on quality you already have, not a substitute for quality you skipped. Teams that invert the order generate first and clean never, and the tune shows it. Start your next prep job by curating 50 examples you fully trust, then let the generator scale that trust, not paper over its absence.

Disclaimer: The API path, product names, and roles here reflect watsonx documentation at the time of writing and change between releases. Verify the endpoint, version string, and required permissions against current IBM docs before running any generation job against a billed project.
IBM Gen AI Series · Part 13 of 24
« Previous: Part 12  |  Guide  |  Next: Part 14 »

References

About The Author


Discover more from Journal of Intelligent Infrastructure – By Dr Pranay Jha

Subscribe to get the latest posts sent to your email.

Leave a Reply

Your email address will not be published. Required fields are marked *

Architect’s Toolkit

About the Author

Dr. Pranay Jha is a Cloud and AI Consultant with 18+ years of experience in hybrid cloud, virtualization, and enterprise infrastructure transformation. He specializes in VMware technologies, multi-cloud strategy, and Generative AI solutions. He holds a PhD in Computer Applications with research focused on Cloud and AI, has published multiple research papers, and has been a VMware vExpert since 2016 and a VMUG Community Leader.

Discover more from Journal of Intelligent Infrastructure - By Dr Pranay Jha

Subscribe now to keep reading and get access to the full archive.

Continue reading