You need to agree to share your contact information to access this model

This repository is publicly accessible, but you have to accept the conditions to access its files and content.

Log in or Sign Up to review the conditions and access this model content.

YAML Metadata Warning:empty or missing yaml metadata in repo card

Check out the documentation for more information.

LLM Concept Probe Dashboard

Status: Production Ready Updated: 2025-10-31

A complete system for training, validating, and deploying concept-detection probes from LLM activations. Features automatic baseline calibration, real-time streaming inference, and an interactive web dashboard for monitoring probe behavior.


Key Features

  • Automatic Baseline Calibration: Probes self-calibrate using wildchat samples to eliminate false positives
  • Real-time Streaming Inference: WebSocket-based token-by-token probe monitoring
  • High Performance: AUC β‰₯ 0.997 across all semantic and safety probes
  • Production Dashboard: FastAPI backend + React frontend (in progress)
  • Comprehensive Validation: Systematic sweep across pooling, classifiers, whitening, and negative sampling strategies

Quick Start

1. Installation

# Install probe pipeline dependencies
pip install -r requirements.txt

# Install backend API dependencies
pip install -r backend/requirements.txt

2. Start the Dashboard

# Start FastAPI backend (includes WebSocket streaming)
./scripts/start_backend.sh

# Access the API
# - REST API: http://localhost:8000
# - API Docs: http://localhost:8000/docs
# - WebSocket: ws://localhost:8000/ws/inference

3. Test Live Inference

import asyncio
import websockets
import json

async def test_inference():
    uri = "ws://localhost:8000/ws/inference"
    async with websockets.connect(uri) as ws:
        # Start inference
        await ws.send(json.dumps({
            "message": "Tell me about Antarctica",
            "monitored_probes": ["cold", "hot", "outdoors"]
        }))

        # Stream results
        async for message in ws:
            data = json.loads(message)
            if data["type"] == "token":
                print(f"Token: {data['token']}")
                print(f"Probes: {data['probes']}")
            elif data["type"] == "complete":
                break

asyncio.run(test_inference())

Offline LLM option

You can run the pipeline without OpenRouter by serving a local OpenAI-compatible endpoint (llama.cpp via llama-cpp-python). The gpt-oss-20b MXFP4 GGUF fits on a single 24GB card (e.g., 3090).

# 1) Ensure the GGUF is present (symlinked from ~/.cache/llama.cpp by default)
ls models/gpt-oss-20b-mxfp4.gguf

# 2) Start a local server (tune N_CTX/N_BATCH upward until VRAM is ~23GB)
N_CTX=4096 N_BATCH=1024 N_UBATCH=1024 PORT=8000 \
  ./scripts/start_llamacpp_local.sh

# 3) Point the pipeline at the local server
export LLM_API_BASE="http://localhost:8000/v1"
export LLM_API_KEY="local"  # not required locally
export LLM_MODEL="openai/gpt-oss-20b"

# Override per-command if needed
python main.py generate configs/cold.json --api-base "$LLM_API_BASE" --api-key "$LLM_API_KEY"

This works for generate, edit, and mine commands.

Python-only usage (direct bindings, no HTTP):

from llama_cpp import Llama
llm = Llama(
    model_path="models/gpt-oss-20b-mxfp4.gguf",
    n_gpu_layers=-1,
    n_ctx=4096,
    n_batch=1024,
    flash_attn=True,
)
resp = llm.create_chat_completion(
    messages=[{"role": "system", "content": "You are a helpful assistant."},
              {"role": "user", "content": "Quick hello in one sentence."}],
    max_tokens=64,
    temperature=1.0, top_p=1.0, top_k=0, min_p=0.0,
)
print(resp["choices"][0]["message"]["content"])

Architecture

Production Probe Configuration

After comprehensive validation, the system uses:

Parameter Value Rationale
Pooling conversation_mean 5.9x more stable than prefix_last (Οƒβ‰ˆ0.05 vs 0.30)
Classifier lda 2.1x more stable than logistic regression
Whitening global Consistent performance, shared transform
Negatives wildchat + autohardneg 3.0x more stable with automatic hard negative mining
Calibration baseline_offset Auto-calibrated to eliminate false positives

Baseline Calibration System

Problem: Raw probes show positive z-scores on neutral content due to ambient mentions in wildchat negatives, causing false positives to accumulate with evidence formula Ξ› = Ξ£z / √t.

Solution: Automatic baseline offset calibration:

  1. Sample 100 random wildchat conversations (diverse neutral content)
  2. Score with each probe to compute mean z-score baseline
  3. Subtract baseline from all future z-scores: adjusted_z = z - baseline_offset
  4. Cache in metadata.json (compute once, reuse forever)

Results:

  • 90% reduction in false positives
  • AUC performance unchanged (β‰₯0.997 across all probes)
  • Auto-calibrates for new concepts without manual tuning

System Components

1. Probe Training Pipeline

# Extract raw activations (GPU required, one-time)
python main.py extract-raw --batch-size 32 --negatives 20000

# Derive conversation-mean format (CPU, fast)
python main.py derive-formats --formats conversation_mean

# Train probes with automatic baseline calibration
python scripts/train_probes.py --concepts all

Training automatically:

  • Computes baseline_offset from wildchat samples
  • Saves to outputs/experiments/probes/<concept>/conversation_mean/none/lda_global_wildchat/metadata.json
  • Future loads reuse cached baseline

2. Streaming Inference Service

Backend: backend/services/inference_service.py

  • Streams tokens + activations in real-time
  • Applies baseline-corrected z-scores
  • Computes sequential evidence: Ξ› = Ξ£z / √t
  • WebSocket protocol for low-latency updates

Features:

  • Token-by-token probe scores (raw, z, evidence)
  • Multi-probe monitoring (track 5+ concepts simultaneously)
  • Text highlighting based on evidence thresholds
  • Conversation-level aggregation

3. Probe Registry

Backend: backend/services/probe_registry.py

Manages production probes with automatic baseline correction:

class ConversationProbe:
    concept: str
    probe: Union[LDAProbe, LogisticRegressionProbe]
    neg_mean: float
    neg_std: float
    baseline_offset: float  # ← Auto-calibrated!

    def z_from_raw(self, raw: float) -> float:
        z = (raw - self.neg_mean) / self.neg_std
        return z - self.baseline_offset  # Center neutral content at z=0

Loads all probes on startup:

  • Reads metadata from outputs/experiments/probes/*/metadata.json
  • Computes baseline_offset if missing (first run only)
  • Caches for future sessions

Validation Results

Baseline Calibration Impact

Test: "Tell me about water" (neutral prompt)

Metric Before After Improvement
False Positives 6 triggers 1 trigger 83% reduction
Max Evidence 104.19 10.01 10x lower
Negative Z-scores Broken Working Fixed

Probe Performance (AUC Metrics)

All probes maintain excellent discrimination after baseline correction:

Probe AUC Avg Precision Baseline Offset
cold 1.000 1.000 +0.634
hot 1.000 1.000 +0.675
cooking 1.000 1.000 +0.482
mathematics 0.999 0.994 -0.256
code 0.999 0.991 +0.412
indoors 0.999 0.996 +0.249
outdoors 0.999 0.996 +0.660
day 1.000 1.000 +1.166
night 1.000 1.000 +1.070
helpful_response 0.997 0.981 +1.994
harmful_response 1.000 1.000 +0.951
jailbreak_attempt 0.999 0.996 +2.826

Average AUC: 0.9995 (near-perfect discrimination)


File Structure

probe-dashboard/
β”œβ”€β”€ backend/                          # FastAPI production backend
β”‚   β”œβ”€β”€ main.py                       # API entry point
β”‚   β”œβ”€β”€ services/
β”‚   β”‚   β”œβ”€β”€ inference_service.py      # Streaming inference
β”‚   β”‚   β”œβ”€β”€ model_session.py          # LLM + activation extraction
β”‚   β”‚   β”œβ”€β”€ probe_registry.py         # Probe loading + baseline calibration
β”‚   β”‚   └── ...
β”‚   └── requirements.txt
β”‚
β”œβ”€β”€ frontend/                         # React dashboard (in development)
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ components/
β”‚   β”‚   β”‚   β”œβ”€β”€ LiveProbeMonitor.tsx  # Real-time streaming UI
β”‚   β”‚   β”‚   β”œβ”€β”€ ProbeTable.tsx        # Probe status table
β”‚   β”‚   β”‚   └── ...
β”‚   β”‚   └── hooks/
β”‚   β”‚       β”œβ”€β”€ useInference.ts       # WebSocket hook
β”‚   β”‚       └── ...
β”‚   └── package.json
β”‚
β”œβ”€β”€ probe_pipeline/                   # Core ML pipeline (unchanged)
β”‚   β”œβ”€β”€ lda_probe.py                  # LDA classifier
β”‚   β”œβ”€β”€ logistic_probe.py             # Logistic regression classifier
β”‚   β”œβ”€β”€ whitening.py                  # Whitening transform
β”‚   └── format_derivation.py          # Activation pooling
β”‚
β”œβ”€β”€ scripts/
β”‚   β”œβ”€β”€ start_backend.sh              # Start API server
β”‚   β”œβ”€β”€ train_probes.py               # Batch probe training
β”‚   └── run_sweep.py                  # Validation sweep
β”‚
β”œβ”€β”€ configs/                          # Concept definitions
β”‚   β”œβ”€β”€ cold.json
β”‚   β”œβ”€β”€ hot.json
β”‚   β”œβ”€β”€ helpful_response.json
β”‚   └── ...
β”‚
β”œβ”€β”€ outputs/
β”‚   β”œβ”€β”€ raw_activations/              # Token-level activations (fp16)
β”‚   β”œβ”€β”€ derived_formats/              # Pooled activations
β”‚   β”‚   └── conversation_mean/        # Production format
β”‚   β”œβ”€β”€ experiments/
β”‚   β”‚   β”œβ”€β”€ probes/                   # Trained probes + metadata
β”‚   β”‚   β”‚   └── <concept>/conversation_mean/none/lda_global_wildchat/
β”‚   β”‚   β”‚       β”œβ”€β”€ probe.pkl         # Classifier weights
β”‚   β”‚   β”‚       β”œβ”€β”€ whitening.npz     # Whitening transform
β”‚   β”‚   β”‚       └── metadata.json     # Metrics + baseline_offset
β”‚   β”‚   └── sweep/                    # Validation results
β”‚   β”‚       β”œβ”€β”€ results.jsonl
β”‚   β”‚       └── summary.json
β”‚   └── global_transform/             # Shared whitening
β”‚       β”œβ”€β”€ whitening.npz
β”‚       └── metadata.json
β”‚
β”œβ”€β”€ tests/                            # Test suite
β”‚   β”œβ”€β”€ test_inference.py             # Integration tests
β”‚   β”œβ”€β”€ test_calibration.py           # Baseline tests
β”‚   └── test_probes.py                # Unit tests
β”‚
β”œβ”€β”€ docs/                             # Documentation
β”‚   β”œβ”€β”€ README.md                     # Documentation map
β”‚   β”œβ”€β”€ METHODOLOGY.md                # Training methodology
β”‚   β”œβ”€β”€ PRODUCTION_ARCHITECTURE.md    # System architecture
β”‚   └── DATASETS_AND_STORAGE.md       # Data organization
β”‚
β”œβ”€β”€ main.py                           # CLI for extraction/derivation
β”œβ”€β”€ dataset.py                        # Synthetic data generation
└── requirements.txt                  # Core dependencies

Concept Categories

The system includes probes for:

Semantic Concepts

  • Temperature: cold, hot
  • Time: day, night
  • Location: indoors, outdoors
  • Domains: mathematics, code, cooking, creative_writing

Safety & Monitoring

  • Response Quality: helpful_response, harmful_response
  • Security: jailbreak_attempt, prompt_injection
  • Style: refusal_boilerplate, refusal_constructive

Communication Style

  • Tone: formal_assistant, informal_assistant, technical_assistant
  • Verbosity: terse_assistant, verbose_assistant, detailed_response
  • User Patterns: polite_request, hostile_demand, technical_user

API Reference

REST Endpoints

# List all probes
GET /api/probes

# Get probe details
GET /api/probes/{concept}

# List concepts
GET /api/concepts

# Train new probe
POST /api/probes/train
{
  "concept": "new_concept",
  "use_hard_negatives": true
}

WebSocket Inference

// Connect
const ws = new WebSocket('ws://localhost:8000/ws/inference');

// Send message
ws.send(JSON.stringify({
  message: "Tell me about quantum computing",
  monitored_probes: ["mathematics", "code", "technical_user"],
  max_tokens: 512
}));

// Receive tokens
ws.onmessage = (event) => {
  const data = JSON.parse(event.data);

  if (data.type === "token") {
    console.log(`Token: ${data.token}`);
    console.log(`Probes:`, data.probes);
    // data.probes = {
    //   "mathematics": {raw: 0.42, z: 3.2, evidence: 8.5},
    //   "code": {raw: 0.31, z: 2.1, evidence: 5.3},
    //   ...
    // }
  }

  if (data.type === "complete") {
    console.log("Generation complete");
  }
};

Development

Running Tests

# Unit tests
pytest tests/

# Integration tests with backend
python tests/test_inference.py

# Calibration validation
python tests/test_calibration.py

Training New Concepts

  1. Create config file: configs/my_concept.json
  2. Generate dataset: python dataset.py --concept my_concept
  3. Extract activations: python main.py extract-raw --concepts my_concept
  4. Derive formats: python main.py derive-formats --concepts my_concept
  5. Train probe: python scripts/train_probes.py --concept my_concept
  6. Restart backend to load new probe

Baseline calibration happens automatically during step 5 and is cached in metadata.

Validation Sweep

Run comprehensive validation across all configurations:

# Full sweep (all concepts Γ— all configs)
python scripts/run_sweep.py

# Quick test (subset of concepts)
python scripts/run_sweep.py --quick

# Results saved to outputs/experiments/sweep/

Performance Notes

Baseline Offset Magnitude

Large offsets indicate strong ambient signal in wildchat:

  • jailbreak_attempt: +2.826 (wildchat contains adversarial examples)
  • helpful_response: +1.994 (assistant responses tend to be helpful)
  • day/night: +1.166/+1.070 (temporal references common)

Negative offsets indicate wildchat scores below zero:

  • mathematics: -0.256 (math discussions rare in wildchat)

Computational Cost

  • Baseline calibration: 5-10 seconds per probe (first run only)
  • Streaming inference: <50ms per token (includes all probe scores)
  • Training: 6-7 seconds per probe on CPU

Memory Usage

  • Probe registry: ~500MB (all probes loaded)
  • Model session: ~8GB VRAM (Llama 3.2 3B)
  • Per-inference: ~100MB (activation buffers)

Citation

If you use this system in your research, please cite:

@software{probe_dashboard_2025,
  title={LLM Concept Probe Dashboard},
  author={[Your Name]},
  year={2025},
  url={https://github.com/[your-repo]/probe-dashboard}
}

License

[Specify License]


Documentation


Troubleshooting

Backend won't start

# Check dependencies
./scripts/check_backend_deps.sh

# Verify Python version (requires 3.10+)
python --version

# Check for port conflicts
lsof -i :8000

Probes showing unexpected results

# Verify baseline calibration
python tests/test_calibration.py

# Check probe metadata
cat outputs/experiments/probes/cold/conversation_mean/none/lda_global_wildchat/metadata.json

# Look for baseline_offset field - should be non-zero

WebSocket connection timeout

# Check backend logs
tail -f /tmp/uvicorn.log

# Test with curl
curl -N --http1.1 \
  --header "Connection: Upgrade" \
  --header "Upgrade: websocket" \
  --header "Sec-WebSocket-Version: 13" \
  --header "Sec-WebSocket-Key: SGVsbG8sV29ybGQh==" \
  http://localhost:8000/ws/inference

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Ensure all tests pass
  5. Submit a pull request

For major changes, please open an issue first to discuss the proposed changes.

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support