Annotations

rfgen splits dataset generation into two phases: Phase 1 writes IQ samples, labels, and verified metadata; Phase 2 turns that metadata into natural-language artifacts for multimodal training. This page covers Phase 2: captions, QA pairs, reasoning traces, scene reports, and contrastive pairs. The metadata-to-text pattern follows RF-GPT’s synthetic RF instruction generation workflow and WavCaps’ LLM-assisted caption-cleaning pipeline [1, 2].

Annotations are grounded in metadata only. The annotation layer does not see in-phase / quadrature (IQ) samples, spectrograms, or raw samples. It reads structured records, renders constrained prompts, calls an inference client, validates the returned JSON, and appends the text back to storage.

Minimal Example

from rfgen.annotators import MetadataAnnotator, Templater, whitelist_filter
from rfgen.enums import AnnotationType
from rfgen.inference.clients import inference_client_registry

# store.read() returns a full Record with IQ, labels, and metadata.
store_handle = ...
raw = store_handle.read("sha256:abc")
record = whitelist_filter(raw, sample_id="sha256:abc")

client = inference_client_registry.get("<your-provider>")()
templater = Templater()
annotator = MetadataAnnotator.from_components(client=client, templater=templater)

prompt = templater.render(
    record=record,
    annotation_type=AnnotationType.CAPTION,
    template_id="caption.dense.v3",
)
response = client.complete(prompt=prompt.user, json_schema=prompt.output_schema)
annotated = annotator.annotate(
    record,
    annotation_type=AnnotationType.CAPTION,
    template_id="caption.dense.v3",
    run_id="run-2026-07-08",
)

"<your-provider>" is the provider key from the rfgen config. The Templater returns a Prompt with system text, user text, and an output schema; passing json_schema=prompt.output_schema asks the inference client to return JSON that can be validated against that schema. The caption.dense.v3 identifier follows the <type>.<variant>.v<version> convention described in Reference / Annotation Templates § Versioning.

The exact client classes, model IDs, schemas, and orchestration commands belong in Reference / Annotation Templates and Reference / API / rfgen.annotators.

Two-Phase Generation

Phase 1 writes IQ samples, labels, and verified metadata. Phase 2 reads that metadata and appends text.

The split is deliberate:

  • IQ generation and text generation have different cost models, retry policies, and scaling limits.

  • Text runs can be reprocessed without regenerating IQ.

  • Multiple annotation templates can coexist against the same Phase 1 dataset.

  • Failed annotation jobs can resume by checking which (sample_id, annotation_type, template_id, run_id) outputs already exist.

Phase 2 is append-only. A new run creates a new overlay instead of silently overwriting a previous result. Template changes are part of the authenticated annotation payload: reusing an existing overlay identity with a different template is a conflict, so use a new run for that change.

Source. RF-GPT separates standards-compliant RF scene generation from LLM-produced instruction data, and WavCaps uses a staged LLM pipeline to turn noisy source descriptions into usable captions [1, 2].

Grounding Contract

The text layer may only use fields that are explicitly present in the structured record or derived labels. This keeps captions auditable and prevents the LLM from inventing RF attributes it cannot observe.

Grounding controls:

Control

Purpose

Source

Metadata-only prompts

Prevent the model from inferring unsupported signal properties from rendered media.

RF-GPT metadata-derived instruction data [1]

Deterministic templating

Defines which facts each annotation must mention before the model rewrites them.

WavCaps LLM-assisted filtering and transformation pipeline [2]

JSON-constrained output

Makes validation mechanical instead of regex-based.

JSON Schema validation vocabulary [5]

Closed vocabulary

Rejects modulation, channel, unit, or taxonomy terms outside the ClosedVocab, for example unsupported OFDM, QPSK, or Rayleigh claims.

RF-Analyzer hallucination and prompt-leakage checks [3]

Verifier subset

Samples generated text and checks whether physical attributes can be recovered from it.

RF-Analyzer PAES metric [3]

The verifier does not make text “true” by itself. It is an audit layer that measures whether generated annotations preserve the physical facts present in metadata.

Annotation Types

An annotation job carries the logical selector (sample_id, annotation_type, template_id, run_id). The durable overlay key is slightly different:

(dataset_id, sample_id, annotation_type, run_id)

dataset_id binds the row to one dataset. sample_id is assigned during Phase 1 storage, annotation_type is selected from the AnnotationType enum, and the command derives the durable UUID run_id from the job’s run identifier. template_id is not a second index dimension. It is carried inside the RFC 8785 canonical row envelope with the result and error, so a resume verifies that the stored template matches the requested job. This preserves the job-level template contract without allowing two different template payloads to occupy one append-only overlay.

Provider/model metadata, output-schema versions, and ClosedVocab versions remain reproducibility data alongside the annotation; they are not overlay-key fields.

The annotation types are:

Member

Typical use

Source

CAPTION

Concise natural-language description of the scene or component.

RF-GPT dense RF captions and WavCaps audio captions [1, 2]

QA

Question-answer pairs grounded in known metadata.

RF-GPT instruction-answer generation [1]

REASONING

Stepwise explanation for a metadata-derived conclusion.

RF-GPT multi-task instruction data [1]

SCENE_REPORT

Denser summary of emitters, receivers, signal-to-noise ratios (SNRs), overlap, and channel conditions.

RF-Analyzer physical-attribute extraction dimensions [3]

CONTRASTIVE

Paired descriptions for similarity, difference, or retrieval training.

CLIP image-text contrastive objective [4]

Exact schemas and token budgets belong in the annotation-template reference.

Transactional Overlay Publication

AnnotationOverlayTransactions publishes a canonical row through the Layer 17 transaction coordinator. The idempotency key is the SHA-256 digest of RFC 8785 bytes containing both the durable overlay key and the complete row envelope. The caller must supply that exact digest; an arbitrary retry token is rejected.

Each dataset has one authoritative append-only annotation index. Its committed LATEST pointer names an immutable index object and the immutable row objects introduced by that revision. A reader resolves the index before reading a row, then verifies the row’s key, canonical bytes, and digest. Therefore an immutable row staged before a crash is not visible until an index revision references it. Single-row and batch publication both merge into this same dataset index; they do not maintain competing per-row pointers.

The publication lifecycle is STAGED, COMMITTED, CONFLICT, or ABORTED. For an identical replay, the existing canonical row returns its original committed revision without another visible write. A different canonical row for the same overlay raises AnnotationConflictError and leaves the visible index unchanged. A single-row first append may also require that an expected_revision equal the currently observed index revision.

Batches, Contention, And Recovery

A batch is restricted to one dataset. Before writing, it canonicalizes rows, sorts them by durable overlay key, collapses exact duplicates, and rejects a divergent duplicate. The new rows and the one merged dataset index are staged and published in one Layer 17 transaction. A failed batch therefore leaves the previous dataset index visible rather than a visible prefix; only committed keys become persistence checkpoints.

Independent writers reread the current dataset index after a conditional pointer conflict. Identical writers converge on the same committed revision; writers offering different bytes for the same overlay conflict. If a commit response is lost, publication asks the coordinator to reconcile the transaction before retrying, rather than issuing a blind pointer update. This covers crashes after row staging, index staging, or the pointer compare-and-swap: recovery settles to one committed index containing the rows or leaves no newly visible rows.

Command Persistence Scope

When rfgen annotate receives a local path or file: store URI, it binds annotation persistence to a Layer 17 local transaction backend rooted beside that dataset. Provider execution can still produce results, but durable command publication currently requires that local transaction backend. A nonlocal store_uri is rejected explicitly until the matching provider transaction backend is configured; it is not treated as a local filesystem path or silently persisted through the legacy append API.

Batch And Provider Abstraction

Production annotation should use provider batch APIs where available. Developer iteration can use synchronous calls, and verifier runs may use a smaller synchronous subset if that is simpler operationally.

Provider choice is a configuration concern. The durable architecture is:

  • a bulk inference tier for rewriting deterministic template output into natural language;

  • a verifier tier for quality measurement;

  • an optional self-hosted tier for restricted or air-gapped data.

Specific model SKUs change too often for a concept page. Pin exact model IDs, prices, and refresh dates in an ADR or reference page.

Source. WavCaps uses LLMs for high-volume caption transformation, while RF-Analyzer’s PAES motivates a separate verifier pass for physical-attribute consistency [2, 3].

Determinism And Versioning

Phase 1 aims for deterministic IQ samples and labels. Phase 2 is different: hosted LLMs do not generally guarantee byte-identical text across time, even at low sampling temperature, the common LLM control for output randomness. Annotation reproducibility therefore comes from versioned inputs and append-only outputs:

  • template_id identifies the prompt template.

  • run_id identifies a concrete annotation run.

  • provider and model metadata identify the inference endpoint.

  • output schemas and ClosedVocab versions identify validation rules.

Changing any of these should produce a new run, not mutate an old one. In particular, changing template_id while reusing the same durable run identity is a conflict rather than a second row.

Design Rationale

Why metadata-only instead of spectrogram-conditioned?

For synthetic data, the pipeline already has ground truth. Metadata-only annotation is cheaper, easier to validate, and easier to audit than asking a vision-language model to infer attributes from a rendered spectrogram. Models trained on the resulting data still learn from IQ downstream; the LLM just creates text supervision.

Why JSON instead of free-form text?

JSON gives the pipeline a structured envelope for schema validation, closed-vocabulary checks, and downstream conversion. The natural language still lives inside JSON fields, but the record remains machine-checkable.

What can go wrong?

The main risks are schema drift, unsupported facts in prompts, prompt templates that leak task answers, verifier prompts that do not match bulk outputs, and provider/model rotation. The mitigation is to version templates, schemas, closed vocabularies, and runs together.

References

  1. Zayoud, M. et al. RF-GPT: Teaching AI to See the Wireless World. arXiv:2602.14833, 2026. https://arxiv.org/abs/2602.14833. (Synthetic RF scenes converted into RF-grounded captions and instruction-answer data)

  2. Mei, X. et al. WavCaps: A ChatGPT-Assisted Weakly-Labelled Audio Captioning Dataset for Audio-Language Multimodal Research. arXiv:2303.17395, 2023. https://arxiv.org/abs/2303.17395. (LLM-assisted filtering and transformation pipeline for captions)

  3. Bara, A. et al. RF-Analyzer: Can Vision-Language Models Learn RF Understanding from Synthetic Data? arXiv:2605.04676, 2026. https://arxiv.org/abs/2605.04676. (Physical Attribute Extraction Score, prompt leakage, and hallucination checks)

  4. Radford, A. et al. Learning Transferable Visual Models From Natural Language Supervision. ICML, 2021. https://arxiv.org/abs/2103.00020. (Contrastive image-text training objective)

  5. JSON Schema contributors. JSON Schema: A Media Type for Describing JSON Documents. https://json-schema.org/draft/2020-12/json-schema-core. (Schema vocabulary for validating JSON documents)

See Also