Skip to content

Repository files navigation

Sneak

This repository contains the data and code used in our paper's Chameleon clue-generation experiments.

Paper: SNEAK: Evaluating Strategic Communication and Information Leakage in Large Language Models

Terminology note: the paper sometimes says "message" and the code often says "clue". In this repository, those terms are used interchangeably.

The repo is organized around one simple idea:

  1. Produce a results/*.jsonl file containing one clue per example.
  2. Run evaluation.py on that JSONL file.

There are two supported ways to produce that results file:

  • model generation: preprocess.py -> inference.py
  • heuristic baselines: baselines.py

If you already have your own generations, you can skip both and run evaluation.py directly.

What each script does

  • preprocess.py: turns dataset rows into prompt JSONL files under data/
  • inference.py: runs a model over a prompt JSONL file and writes outputs under results/
  • baselines.py: writes simple WordNet-based baseline outputs directly under results/
  • evaluation.py: evaluates any valid results JSONL and writes per-example eval rows under eval/
  • run_exp.sh: convenience wrapper for running preprocess + inference + evaluation end to end

Setup

Python 3.10+ is recommended.

python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

If you want to run external API models in inference.py, create a .env file in the repo root or export the relevant variables:

  • OPENAI_API_KEY
  • CLAUDE_API_KEY
  • GEMINI_API_KEY or GOOGLE_API_KEY
  • DEEPSEEK_API_KEY

Repository layout

  • category_instances_with_decoys.jsonl: default dataset file used by preprocess.py and baselines.py
  • dataset/: alternative dataset sweeps with different numbers of candidates and decoys
  • data/: generated prompt files
  • results/: generated clue files
  • eval/: evaluation outputs

Workflow 1: generate clues with a model

This is the main pipeline used for model runs.

Step 1: preprocess the dataset into prompts

python preprocess.py \
  --dataset chameleon \
  --split test \
  --model google/gemma-3-27b-it

This writes:

data/chameleon/google_gemma-3-27b-it/test_baseline.jsonl

Each row in that file contains the original example plus:

  • system_prompt
  • prompt
  • id

Step 2: run inference

python inference.py \
  --model google/gemma-3-27b-it \
  --file data/chameleon/google_gemma-3-27b-it/test_baseline.jsonl \
  --gpus 1 \
  --max-new-tokens 512

By default this writes:

results/chameleon/google_gemma-3-27b-it/test_baseline.jsonl

Each row in the output keeps the original fields and adds:

  • text: the formatted prompt actually sent to the model
  • response: the model output, expected to contain <clue>...</clue>

Common generation options

  • --cot: ask the model to output <thought>...</thought> before <clue>...</clue>
  • --candidates N --decoys M: use one of the dataset sweeps in dataset/
  • --input-jsonl path/to/file.jsonl: preprocess a custom source JSONL instead of the default dataset file
  • --sets: enable the SETS-style test-time scaling variant
  • --rcr: enable recursive clue refinement

Example with a custom candidate/decoy sweep:

python preprocess.py \
  --dataset chameleon \
  --split test \
  --model google/gemma-3-27b-it \
  --candidates 8 \
  --decoys 3

Full pipeline with run_exp.sh

If you want one command that runs the whole model pipeline, use run_exp.sh.

Default behavior:

./run_exp.sh

This runs:

  1. preprocess.py
  2. inference.py
  3. evaluation.py

The script is configured through environment variables rather than positional arguments.

Example:

INFERENCE_MODELS="google/gemma-3-27b-it" \
EVAL_MODELS="Qwen/Qwen2.5-72B-Instruct meta-llama/Llama-3.3-70b-Instruct" \
GPUS=4 \
MAX_NEW_TOKENS=512 \
./run_exp.sh

Example with a custom dataset file:

INFERENCE_MODELS="google/gemma-3-27b-it" \
PREPROCESS_INPUT_JSONL="path/to/my_examples.jsonl" \
./run_exp.sh

Useful variables:

  • INFERENCE_MODELS: space-separated generation models
  • EVAL_MODELS: space-separated judge models
  • PREPROCESS_INPUT_JSONL: custom source JSONL for preprocessing
  • CANDIDATES, DECOYS: choose one of the dataset sweeps
  • COT: set to true to request <thought>...</thought> output
  • SETS, SETS_CANDIDATES, SETS_ITERS: enable the SETS-style variant
  • RCR, RCR_ITERS: enable recursive clue refinement
  • RUN_PREPROCESS, RUN_INFERENCE, RUN_EVAL: skip parts of the pipeline if needed
  • API_URL: route local-model inference through a vLLM server

You can inspect all supported variables with:

./run_exp.sh --help

Workflow 2: run simple baselines

baselines.py skips prompt construction and model inference. It writes results/*.jsonl files directly in the same format expected by evaluation.py.

Generate all built-in baselines

python baselines.py --strategy all --download-wordnet

This writes:

  • results/chameleon/baseline_random_wordnet/test_baseline.jsonl
  • results/chameleon/baseline_category_synonym/test_baseline.jsonl
  • results/chameleon/baseline_secret_synonym/test_baseline.jsonl

Generate one baseline

python baselines.py --strategy secret_synonym --download-wordnet

Available strategies:

  • random_wordnet: use a random WordNet noun as the clue
  • category_synonym: use a WordNet synonym of the category
  • secret_synonym: use a WordNet synonym of the secret word

Workflow 3: evaluate a results JSONL

Once you have a results/*.jsonl file, evaluate it with:

python evaluation.py \
  --clue_results results/chameleon/google_gemma-3-27b-it/test_baseline.jsonl \
  --eval_model Qwen/Qwen2.5-72B-Instruct \
  --out eval/chameleon/google_gemma-3-27b-it/test_baseline/Qwen_Qwen2.5-72B-Instruct

This writes:

eval/chameleon/google_gemma-3-27b-it/test_baseline/Qwen_Qwen2.5-72B-Instruct/results.jsonl

The script also prints aggregate metrics to the terminal:

  • binary score
  • utility
  • leakage
  • mean score

Important: evaluation.py calls inference.py in label-classification mode, which currently requires a local vLLM judge model. External API judge models are not supported in this mode.

You can evaluate your own JSONL directly

You do not need to use preprocess.py or inference.py if you already have clue generations from another system.

You can create your own JSONL file with the required fields and run evaluation.py on it directly.

Minimum useful row format

{
  "category": "academic subject",
  "secret": "maths",
  "candidates": [
    "psychology",
    "history",
    "biology",
    "sociology",
    "chemistry",
    "geography",
    "french",
    "physics",
    "english literature",
    "spanish",
    "engineering"
  ],
  "decoys": [
    "bailiwick",
    "discipline",
    "field",
    "field_of_study",
    "science"
  ],
  "response": "<clue>Requires precise notation.</clue>"
}

Required fields:

  • category
  • secret
  • candidates
  • response

Strongly recommended:

  • decoys or decoy_clues

Why the decoy field matters: the Ally judge compares the model's clue against distractor clues. If you omit decoys / decoy_clues, the utility side of the evaluation becomes much less meaningful.

Output formats

Prompt files written by preprocess.py

These are intermediate files under data/. They include the original dataset fields plus:

  • id
  • system_prompt
  • prompt

Results files written by inference.py or baselines.py

These are the files you pass into evaluation.py. They should include:

  • category
  • secret
  • candidates
  • response

They can also include:

  • decoys
  • decoy_clues
  • any metadata you want to preserve

Evaluation files written by evaluation.py

Each row in eval/.../results.jsonl contains:

  • binary_score
  • utility
  • leakage
  • judge metadata under cham and ally

Notes

  • In this release, --split is mainly used as part of the output filename. The default shipped dataset is the evaluation set used in the paper.
  • If you want the simplest path, ignore the advanced decoding flags and just use: preprocess.py -> inference.py -> evaluation.py
  • If you only want to benchmark your own generations, start at evaluation.py.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages