Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Implementation:NVIDIA NeMo Curator QAMultilingualSyntheticStage

From Leeroopedia
Knowledge Sources
Domains Synthetic Data, Multilingual NLP, LLM Integration
Last Updated 2026-02-14 00:00 GMT

Overview

QAMultilingualSyntheticStage generates synthetic multilingual question-answer data from scratch using an LLM, without requiring any seed documents as input.

Description

QAMultilingualSyntheticStage extends ProcessingStage[_EmptyTask, DocumentBatch] as a Python dataclass. Unlike most processing stages that transform existing data, this stage takes an _EmptyTask as input and produces a DocumentBatch containing freshly generated synthetic QA data.

For each of num_samples iterations, the stage randomly selects a language from the provided languages list (using secrets.choice for cryptographic randomness), formats the prompt template with the selected language, and queries the LLM. Generated responses have any markdown bold markers (*) stripped.

The stage supports both synchronous (LLMClient) and asynchronous (AsyncLLMClient) clients. The async path uses asyncio.gather for concurrent generation of all samples and includes a thread-based fallback for nested event loop scenarios.

Usage

Use QAMultilingualSyntheticStage when bootstrapping multilingual QA datasets from scratch. It is particularly useful for creating training data across multiple languages by leveraging LLM capabilities, without requiring pre-existing seed documents in those languages.

Code Reference

Source Location

  • Repository: NeMo-Curator
  • File: nemo_curator/stages/synthetic/qa_multilingual_synthetic.py
  • Lines: 1-129

Signature

@dataclass
class QAMultilingualSyntheticStage(ProcessingStage[_EmptyTask, DocumentBatch]):
    prompt: str
    languages: list[str]
    client: AsyncLLMClient | LLMClient
    model_name: str
    num_samples: int
    generation_config: GenerationConfig | None = None
    name: str = "QAMultilingualSyntheticStage"

    def __post_init__(self) -> None: ...
    def inputs(self) -> tuple[list[str], list[str]]: ...
    def outputs(self) -> tuple[list[str], list[str]]: ...
    def setup(self, _: WorkerMetadata | None = None) -> None: ...
    def process(self, _: _EmptyTask) -> DocumentBatch: ...
    def _process_llm_response(self, response: list[str]) -> str: ...
    def _process_sync(self) -> list[str]: ...
    def _process_async(self) -> list[str]: ...
    async def _generate_responses_async(self) -> list[str]: ...

Import

from nemo_curator.stages.synthetic.qa_multilingual_synthetic import QAMultilingualSyntheticStage

I/O Contract

Inputs

Name Type Required Description
prompt str Yes Prompt template containing a {language} placeholder that gets substituted with the selected language
languages list[str] Yes List of language names to randomly sample from for each generated sample
client AsyncLLMClient or LLMClient Yes LLM client instance for querying the model
model_name str Yes Name of the LLM model to query
num_samples int Yes Number of synthetic QA samples to generate
generation_config GenerationConfig No Optional generation parameters (temperature, max tokens, etc.)
_ _EmptyTask Yes An empty task object (no actual data needed as input)

Outputs

Name Type Description
result DocumentBatch A document batch containing a pandas DataFrame with a single "text" column holding the generated QA responses, with dataset_name="simple_synthetic_data"

Key Implementation Details

Language Selection

For each sample, a language is chosen randomly using secrets.choice (cryptographically secure random selection):

language = secrets.choice(self.languages)
prompt = self.prompt.format(language=language)

Response Post-Processing

Generated text has markdown bold markers stripped to produce clean output:

def _process_llm_response(self, response: list[str]) -> str:
    generated_text = response[0] if response else ""
    if "*" in generated_text:
        generated_text = generated_text.replace("*", "")
    return generated_text

Async Processing with Event Loop Handling

The async path handles both normal and nested event loop cases:

def _process_async(self) -> list[str]:
    try:
        asyncio.get_running_loop()
    except RuntimeError:
        # No loop running - normal case
        return asyncio.run(self._generate_responses_async())
    # Already in async context - run in separate thread
    with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
        future = executor.submit(asyncio.run, self._generate_responses_async())
        return future.result()

Concurrent Sample Generation

When using an async client, all samples are generated concurrently via asyncio.gather:

async def _generate_responses_async(self) -> list[str]:
    async def generate_single_response(_i: int) -> str:
        language = secrets.choice(self.languages)
        prompt = self.prompt.format(language=language)
        response = await self.client.query_model(
            model=self.model_name,
            messages=[{"role": "user", "content": prompt}],
            generation_config=self.generation_config,
        )
        return self._process_llm_response(response)

    tasks = [generate_single_response(i) for i in range(self.num_samples)]
    return await asyncio.gather(*tasks)

Usage Examples

Basic Usage with Sync Client

from nemo_curator.stages.synthetic.qa_multilingual_synthetic import QAMultilingualSyntheticStage

stage = QAMultilingualSyntheticStage(
    prompt="Generate a question and answer pair in {language}.",
    languages=["English", "Spanish", "French", "German", "Japanese"],
    client=my_sync_client,
    model_name="nemotron-4-340b",
    num_samples=100,
)

With Async Client and Generation Config

from nemo_curator.stages.synthetic.qa_multilingual_synthetic import QAMultilingualSyntheticStage
from nemo_curator.models.client.llm_client import GenerationConfig

gen_config = GenerationConfig(temperature=0.8, max_tokens=512)

stage = QAMultilingualSyntheticStage(
    prompt="Generate a detailed question and answer pair in {language} about science.",
    languages=["English", "Chinese", "Hindi", "Arabic"],
    client=my_async_client,
    model_name="nemotron-4-340b",
    num_samples=500,
    generation_config=gen_config,
)

Related Pages

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment