Retrieval-Augmented FT & Activation Steering (v0.62.0)
Five surfaces wired together: RAFT data format, RA-DIT two-stage pipeline, citation-faithful fine-tuning, activation steering vectors (CAA / ITI / RepE), and the GRACE codebook.
data.format: raft — Stanford RAFT data
data:
train: ./raft_data.jsonl
format: raft
max_length: 4096Per-row schema:
{
"query": "What is the capital of France?",
"golden_doc": "France is a country in Europe...",
"distractor_docs": ["Spain is...", "Germany is..."],
"answer": "Paris"
}The model learns to use retrieved context (golden + distractors) to answer queries — context-aware completion, not isolated Q&A.
The golden and distractor documents are always shuffled into a reproducible order, set by data.raft_shuffle_seed (0 to 2147483647; unset means seed 0), and that order is fixed once, at tokenisation. Set data.raft_epoch_shuffle: true to re-permute them every epoch instead, so the model cannot learn to expect the golden document in one slot. Epoch 0 reproduces the fixed order exactly, so turning it on never changes the first epoch. The key does nothing for any other data.format. A row whose prompt fills data.max_length leaves no answer tokens to learn from, so it is dropped with a warning that counts the rows (raise max_length to keep them) rather than trained as an all-masked row.
training.ra_dit_stage — two-stage pipeline
RA-DIT (Retrieval-Augmented Dual Instruction Tuning) chains:
# Stage 1: contrastive retriever
task: embedding
training:
ra_dit_stage: retriever
ra_dit_retriever_model: sentence-transformers/all-MiniLM-L6-v2# Stage 2: RAFT generator
task: sft
data:
format: raft
training:
ra_dit_stage: generatorsoup ra-dit -r retriever.yaml -g generator.yaml runs both stages in one go; both config paths are required and must sit under the current directory. --plan-only validates the two paths and prints the plan without training. --timeout is a per-stage limit in seconds, from 60 to 21600 (the default, six hours). --retriever-model <name-or-path> is a manual override that skips the Registry auto-link and records that retriever for the generator instead. It exists on soup ra-dit only: soup train has no such option. A plain soup train of a generator config (ra_dit_stage: generator) that leaves training.ra_dit_retriever_model unset picks up the most recent retriever run from the Registry the same way, and a value you set in that key always wins. The generator records its retriever; stage 2 does not fuse the retriever's weights into the generator.
Both stages reuse the existing trainer wrappers. Live as of v0.71.10 — RAFT span-mask training (answer-only loss, [doc-N] citation labels) and the soup ra-dit one-shot orchestrator (retriever → generator in one command, Registry auto-link) run end-to-end; soup steer train + soup serve --steer (soup steer apply only prints a stored vector's metadata) and soup eval citation are live too.
Running the two stages with soup ra-dit
A minimal pair of configs that passes config validation (the data paths are placeholders for your own files). Each file must carry its own top-level output::
# retriever.yaml (stage 1)
base: sentence-transformers/all-MiniLM-L6-v2
task: embedding
data:
train: ./pairs.jsonl
format: embedding
training:
ra_dit_stage: retriever
output: ./output/retriever# generator.yaml (stage 2)
base: meta-llama/Llama-3.2-1B-Instruct
task: sft
data:
train: ./raft_data.jsonl
format: raft
max_length: 4096
training:
ra_dit_stage: generator
output: ./output/generatorsoup ra-dit --retriever-config retriever.yaml --generator-config generator.yaml --plan-only
soup ra-dit --retriever-config retriever.yaml --generator-config generator.yaml--retriever-config (-r) and --generator-config (-g) are both required. Each must be an existing file under the current directory and not a symlink, otherwise the command exits 2 before doing anything. A live run then reads the output: value from each YAML itself, so a config that leaves it to the schema default is refused (exit 2, no training started).
A live run trains stage 1 as soup train --config <retriever.yaml> --yes, then trains a temporary copy of the generator config with training.ra_dit_retriever_model set (your generator file is not modified). That value is the retriever config's output: directory, or --retriever-model if you pass it. A live run does not look in the Registry to choose it, but --plan-only previews the link from the Registry, so its "Retriever link" line can report no retriever found while the live run links ./output/retriever. --timeout must be 60 to 21600 on a live run (exit 2 otherwise) and is not checked by --plan-only. Each stage's own output is captured, so a failing stage prints only RA-DIT run failed: RA-DIT stage failed (rc=N); run that config with soup train --config directly to see why.
training.citation_faithful — weight the loss toward citation spans
data:
format: raft
training:
citation_faithful: true
citation_style: bracket # bracket | inline | footnote
citation_recall_threshold: 0.85When citation_faithful=true, the SFT trainer raises the per-token loss weight on citation spans of the chosen citation_style ([doc-N], (doc-N) or [^doc-N]), so the model is pushed to cite sources from retrieved docs. That loss weighting is what the key does at training time. citation_recall_threshold is accepted by the schema (0.0 to 1.0), but nothing in v0.75.2 reads it: no trainer or gate computes citation recall during training, so the final save is never refused on it. Measure recall after training with soup eval citation or the citation probe in soup diagnose, and gate on that.
soup steer — activation steering vectors
soup steer train --base meta-llama/Llama-3.1-8B-Instruct \
--method caa --name safety-v1 \
--pairs ./safety_pairs.jsonl --layer 16
soup steer apply --name safety-v1 --strength 1.5
soup steer list # Registry entries only; see belowsoup steer apply does not change any model: it resolves a stored vector and prints its metadata. The decode-time intervention is soup serve --steer safety-v1 --steer-strength 1.5.
Three methods:
- CAA (Contrastive Activation Addition) — add a learned vector to the residual stream.
- ITI (Inference-Time Intervention) — shift specific attention heads.
- RepE (Representation Engineering) — PCA-based direction extraction.
|strength| ≤ 10 is enforced. The Registry defines a steering_vector artifact kind (v0.26), but nothing in v0.75.2 can record a vector under it: soup steer train --registry-id <id> hands the Registry the output directory, the Registry accepts only a single file, and the command prints Could not attach to Registry: artifact not found: <dir> and still exits 0. The vector is written to --output (default ./steering/<name>); soup steer apply and soup serve --steer find it by name at that default location, and soup steer list reads only the Registry, so it never shows it.
Pairs JSONL:
{"positive": "You are a helpful AI.", "negative": "You are a harmful AI."}GRACE codebook — soup edit set --method grace
soup edit set --base ./model --method grace \
--subject "The CEO of Acme is" --target "Jane Doe" --output ./editedGRACE stores each knowledge edit as a (key, value) pair in a discrete latent codebook instead of changing weights, so thousands of sequential edits do not blow up weight norms. The live path shipped in v0.71.9 and is a command, not a training option: soup edit set --method grace captures the residual key at the subject's last token, optimizes a value vector for the target, and appends the pair to a grace_codebook.json sidecar in --output. The base weights are never modified. The command only writes the codebook: applying it at decode time is done by the library function install_grace_hook, and no Soup command at v0.75.2 calls that. The edit governor on Unlearning & knowledge editing counts GRACE edits too.
The training.grace_codebook, grace_codebook_size and grace_codebook_dim keys from the v0.62.0 schema are accepted by the schema, but nothing in v0.75.2 reads them: no trainer consumes them, so setting them in soup.yaml changes no training.
New recipes
Three RAFT-style recipes shipped:
raft-llama3-8b— RAFT SFT generator on Llama 3.1 8B.ra-dit-retriever— sentence-transformer contrastive stage.ra-dit-llama3-8b— full RA-DIT stage-2 generator.
Numbers
+215 new tests in v0.62.0 (9571 → 9786). Security: 0 CRITICAL, 0 HIGH, 4 MEDIUM, 11 LOW.
See also
- Trace ecosystem — v0.63
soup ingestproduces the JSONL that feeds the RAFT generator. - Unlearning — surgical edits as a harder counterpart to soft steering.
- Data Forge — quality moat for the source docs that become golden / distractor pairs.
Soup is free and Apache-2.0. If it saved you a training run, starring the repo costs nothing and helps most. You can also fund the GPU time behind the work a 4 GB laptop cannot reach.