Data¶
Circuit discovery runs on data. Before you point CircuitKit at a model, you need to know what kind of data each algorithm expects — because they don't all expect the same thing.
This page explains the data model. The rest of the section covers the built-in tasks that ship ready to run, how to bring your own data, and how the corrupt half of a pair gets generated when you don't supply it yourself.
What discovery needs¶
CircuitKit's algorithms split into two camps by their data requirement.
EAP-family algorithms (and ACDC) need a contrastive pair. They compare two forward passes: a clean prompt and a corrupt one. The clean prompt produces the behavior you care about; the corrupt prompt is a minimally different version that produces a different answer. Attribution comes from the difference between the two runs — patch corrupt activations into the clean forward pass, measure how much the metric moves, and you learn which components carried the signal. No contrast, no signal.
IBCircuit and CD-T need only the clean prompt. They find the circuit from the clean forward pass alone (IBCircuit injects its own information-bottleneck noise; CD-T works from clean activations directly). You still supply an answer so the metric has something to score, but there is no corrupt partner to construct.
| Algorithm | Data requirement |
|---|---|
EAP family (eap, eap-ig, …) |
Paired: clean + corrupt |
| ACDC | Paired: clean + corrupt |
| IBCircuit | Clean only |
| CD-T | Clean only |
If you're running an EAP-family algorithm on clean-only data with no corruption strategy, discovery has nothing to attribute against. CircuitKit warns loudly when this happens (see Corruption) rather than silently returning a meaningless circuit.
What makes a dataset contrastive¶
A dataset is contrastive when a clean example has a natural counterfactual: change one thing and the correct answer flips.
| Task | Clean | Corrupt | Contrastive? |
|---|---|---|---|
| IOI | "When Mary and John went to the store, John gave a drink to" → " Mary" | "…Susan gave a drink to" → different name | Yes — swap the subject name |
| BoolQ | passage + question → " yes" | same template, paired with a " no" example | Yes — flip the label |
| MMLU | "Q: … Answer:" → correct letter | length-matched stem, correct answer at a different letter | Yes — the answer letter differs |
| WinoGrande | sentence + correct fill | same sentence, wrong fill | Yes, but the cue is after the blank (see below) |
| GSM8K | word problem → answer digits | operand-swapped problem → different digits | Yes — the final answer differs |
| Plain language modeling | "the cat sat on the" | — | No natural counterfactual |
If your data has correct answers but no wrong ones, it is not contrastive, and EAP-family discovery has no pair to work with. Either add explicit corrupt columns, apply a corruption strategy, or use a clean-only algorithm.
The metric drives it¶
The metric is what discovery optimizes, and it decides what shape your answers need to take. CircuitKit's YAML loader exposes three:
| Metric | When to use | Contrastive? | Differentiable? |
|---|---|---|---|
logit_diff |
Single-token answers with a correct/incorrect pair | Yes — needs both tokens | Yes |
kl |
Multi-token answers; compares the full output distribution | No pair required | Yes |
accuracy |
Reporting only | — | No |
logit_diff is the default and the workhorse. It reads the correct token and the incorrect token off each example and scores the gap between them at the answer position. That is why contrastive tasks work with it out of the box — the corrupt example supplies the incorrect token.
kl compares the clean and patched output distributions instead of two specific tokens, so it fits multi-token answers where "the correct next token" is not well defined.
accuracy is non-differentiable. You can report it, but EAP-family discovery cannot use it — the attribution backward pass needs a gradient. If you set metric: accuracy on a discovery run, CircuitKit warns and you should switch to logit_diff or kl.
These three are the framework-exposed metrics
A built-in task may compute its own internal metric that is tuned to its data — winogrande uses a suffix log-likelihood, gsm8k uses an answer-span NLL. Those are still differentiable and EAP-compatible, but they are chosen inside the task, not selected through the loader's metric: key. When you write your own task YAML, logit_diff, kl, and accuracy are your options.
Not every contrastive task uses logit_diff¶
A dataset can be fully contrastive and still need a different metric. winogrande is the clearest case. It is contrastive — correct fill versus wrong fill — but the disambiguating word sits after the blank, so a single last-position logit difference measures roughly chance accuracy. Its task spec scores the log-likelihood of the whole suffix span under each filling instead. The lesson: the discovery metric is chosen per task, not applied uniformly.
Two ways to bring data¶
CircuitKit has two entry points for custom data, and they use different keys. Don't mix them up.
- Task YAML (
circuitkit discover-yaml --task-yaml task.yaml) builds aGenericTaskSpecfrom aname/source/schemafile. The schema maps your column names onto CircuitKit's fields. This is covered in Bring your own data. - Inline
dataconfig (adata:block inside adiscover_circuit(config)dict or YAML) usesdata.typeoftemplate,auto, orclean_only, withclean_prompt/corrupt_prompt/clean_answer/corrupt_answertemplate keys. This is covered in Bring your own data.
Where to go next¶
- Built-in tasks — the 16 tasks that ship ready to run
- Bring your own data — CSV, JSONL, and HuggingFace via YAML
- Corruption strategies — generating the corrupt half of a pair