CoolFace
Apppublic

AryanJain7031/dead-internet-detective

sourceHugging Faceupdated 5mo agoView on Hugging Face
0likes
App README

Dead Internet Detective

We trained an LLM to investigate disinformation the way a journalist would β€” not by reading and classifying, but by following leads through a synthetic internet we built from scratch.

![Live Environment](https://huggingface.co/spaces/AryanJain7031/dead-internet-detective) ![Eval Space](https://huggingface.co/spaces/AryanJain7031/dead-internet-detective-eval) ![Model P3](https://huggingface.co/PriyanshuHF/dead-internet-detective-model-p3) ![W&B](https://wandb.ai/models-srm-institute-of-science-and-technology9361/dead-internet-detective/workspace?nw=nwuseraryanjain7031) ![Notebook](notebooks/training_grpo.ipynb)


The Problem with Disinformation Detection

Most approaches treat disinformation as a classification problem. Feed in an article, get back a label. True or false.

This misses the point entirely.

Sophisticated disinformation doesn't fail because it sounds suspicious. It fails because its citations don't trace back to anything real. Because the author's name appears on forty different sites with conflicting credentials. Because the domain was registered two weeks before the story broke. Because the "study" being cited was quietly retracted. None of that is in the headline. You have to investigate.

The gap between classifying text and investigating a claim is enormous β€” and almost nobody has tried to close it with RL training on LLMs. That's what this project does.


What We Built

Dead Internet Detective is a multi-step investigation environment. The agent receives a claim and a set of dossier URLs β€” entry points into a fully synthetic internet we built specifically for this project.

That synthetic internet is the core of what makes this environment interesting. It's not a static dataset. Every episode generates a fresh set of pages: legitimate-looking credible sources, SEO farms recycling the same talking points, wellness blogs with no real author credentials, and β€” at hard difficulty β€” high-quality fakes that convincingly spoof real credible domains. The citation chains look plausible. They just don't lead anywhere real.

The agent has 12 investigative tools to work through the evidence:

ToolWhat it does
visit_pageRead a synthetic webpage
searchQuery the synthetic search engine
wayback_checkCheck if a URL has a history β€” new domains are suspicious
whois_lookupDomain registration date and registrar
author_lookupIs this author's name tied to multiple shady domains?
image_provenanceWhere else has this image appeared online?
citation_traceFollow a citation chain up to 3 hops
linguistic_fingerprintAI-generation probability and writing patterns
cross_referenceDo two sources directly contradict each other?
update_case_fileLog evidence and maintain the investigation record
request_expertGet a synthetic domain expert's opinion (medical / legal / statistical)
file_reportFile final verdict and close the episode

The agent maintains a case file throughout the investigation β€” a running record of confirmed facts, disputed claims, flagged synthetic sources, contradictions found, and overall confidence. When it's ready (or when it runs out of steps), it files a report: verdict, confidence score, evidence chain, and reasoning.


Why This Needed RL

You can't train an investigator with supervised learning on verdict labels. The investigation process matters as much as the conclusion. An agent that guesses correctly by luck and uses zero tools should score lower than one that builds a real evidence chain β€” even if both get the right verdict.

The reward function captures this:

ComponentWeightWhat it actually measures
Verdict accuracy30%Did you reach the right conclusion?
Evidence chain quality25%Did you visit and cite the actually relevant pages?
Synthetic source detection20%Did you correctly flag the fake pages as fake?
Internal consistency15%Does your filed reasoning match your collected evidence?
Step efficiency10%Did you solve it without burning your entire step budget?

A lazy agent that reads one page and guesses "true" gets partial credit on verdict accuracy. It gets zero on everything else. The only path to a high total reward is a genuine investigation. We also penalize hitting the step limit β€” an agent that spins out without filing a report loses an additional 0.15.

This reward function is genuinely hard to game. The environment was designed so that no single tool call pattern can systematically exploit it.


Difficulty Levels

LevelSourcesSynthetic PagesWhat makes it hard
easy1 credible2 fakes (SEO farm + wellness blog)Clear signal if you look for it
medium1–2 credible3 sophisticated fakesMixed signals; requires cross-referencing
hard1 credible4 fakes including a spoofed credible domainHigh-quality fakes; maximum deception

Training

We used GRPO (Group Relative Policy Optimization) via TRL + Unsloth to train Llama-3.1-8B-Instruct across three progressive phases. The progression was intentional: each phase expanded both the difficulty and the expected behavior.

PhaseDifficultyTraining StepsSaved Model
P1Easy only~500AryanJain7031/dead-internet-detective-model
P2Easy + Medium + Hard~500PriyanshuHF/dead-internet-detective-model-p2
P3All difficulties~1000PriyanshuHF/dead-internet-detective-model-p3

Phase 1 teaches the agent that tools exist and should be used. Phase 2 forces it to handle cases where the evidence is genuinely mixed and a single visit isn't enough. Phase 3 refines efficiency β€” getting to the right answer without burning the step budget on redundant calls.


Results

Reward Curve (Phase 1 Β· easy difficulty Β· ~500 steps)

[image]

Training step on x-axis, episode reward on y-axis. Red line = rolling mean. The agent begins near the untrained baseline (~0.15) and climbs toward ~1.45 by step 500. GRPO on Llama-3.1-8B-Instruct.

Before vs. After: What Actually Changed

[image]

Each component scored separately. Gray = untrained baseline (visits dossier URLs, guesses "true"). Red = trained agent after Phase 1. The trained agent uses citation tracing, author lookups, and cross-referencing β€” behaviors the untrained model never exhibited.

Reward ComponentUntrainedTrained (P1)
Verdict accuracy~0.10~0.55
Citation depth0.00~0.30
Contradiction detection0.00~0.20
Tool diversity~0.05~0.25
Case file quality0.00~0.15
Total reward~0.15~1.45

The untrained agent visits URLs and guesses. The trained agent traces citations, checks author credibility across domains, identifies contradictions between sources, and builds an evidence chain before filing. That's not a marginal improvement β€” it's a qualitatively different kind of behavior.


Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        Colab / Local                    β”‚
β”‚                                                         β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚   β”‚  LLM Agent       │──────▢│  DeadInternetClient β”‚   β”‚
β”‚   β”‚  (Llama-3.1-8B)  │◀──────│  (client/client.py) β”‚   β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”‚β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                         β”‚ HTTP (REST)
                          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                          β”‚    FastAPI Server            β”‚
                          β”‚    /reset  /step  /state     β”‚
                          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                         β”‚
                          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                          β”‚  DeadInternetEnvironment     β”‚
                          β”‚  12 Tools Β· 5 Graders        β”‚
                          β”‚  Synthetic Internet          β”‚
                          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Quick Start

Against the live HF Space (no local setup required):

python
import requests

BASE = "https://aryanjain7031-dead-internet-detective.hf.space"

# Start a new investigation
r = requests.post(f"{BASE}/reset", json={"task_id": "easy", "seed": 42})
session_id = r.json()["session_id"]
obs = r.json()["observation"]

print("Claim:", obs["claim"])
print("Dossier:", obs["dossier_urls"])

# Follow a lead
r2 = requests.post(f"{BASE}/step", json={
    "session_id": session_id,
    "action": {"tool": "visit_page", "params": {"url": obs["dossier_urls"][0]}}
})
print("Reward:", r2.json()["reward"])
print("Done:", r2.json()["done"])

Run the trained P3 model against the live environment:

Use the Eval Space β€” select P3, pick difficulties, hit Run. No GPU required.

Or locally (requires CUDA):

bash
python evaluate.py --model p3 --vs-baseline --difficulties easy medium hard --n-episodes 3

Local setup:

bash
git clone https://github.com/aj7075/dead-internet-detective.git
cd dead-internet-detective && pip install -r requirements.txt
uvicorn dead_internet_detective.server.app:app --reload --port 8000

Links

ResourceLink
🌐 Live EnvironmentAryanJain7031/dead-internet-detective
πŸ”¬ Eval Space (run P3)AryanJain7031/dead-internet-detective-eval
πŸ““ Training Notebooknotebooks/training_grpo.ipynb
πŸ€– Model P1AryanJain7031/dead-internet-detective-model
πŸ€– Model P2PriyanshuHF/dead-internet-detective-model-p2
πŸ€– Model P3PriyanshuHF/dead-internet-detective-model-p3
πŸ“Š W&B Run (P1)Training metrics
πŸ“ Blog / WriteupBLOG.md

Built with [OpenEnv](https://github.com/huggingface/open-env) Β· [TRL/GRPO](https://github.com/huggingface/trl) Β· [Unsloth](https://github.com/unslothai/unsloth)