Spaces:
Sleeping
Sleeping
Redeploy: sync repo updates (exclude RLM docs)
Browse files- README.md +23 -23
- explorer/prompts.py +26 -16
README.md
CHANGED
|
@@ -12,40 +12,43 @@ pinned: false
|
|
| 12 |
|
| 13 |
# AI Incident Explorer
|
| 14 |
|
| 15 |
-
> An autonomous agentic tool that
|
| 16 |
-
|
| 17 |
-
### π Live demo β **[AI Incident Explorer on Hugging Face Spaces](https://huggingface.co/spaces/edangx100/aiid-explorer)**
|
| 18 |
-
|
| 19 |
-
> β±οΈ **It's a slow agentic search, not an instant lookup** β a round can take **up to ~9 min** on
|
| 20 |
-
> the free Basic-CPU Space ([why](#why-the-search-takes-minutes-not-seconds)). Leave the tab open.
|
| 21 |
|
| 22 |
---
|
| 23 |
|
| 24 |
## Why This Project Exists
|
| 25 |
|
| 26 |
-
**Agents
|
| 27 |
|
| 28 |
**This project is a demonstration of how both can be addressed β context rot with a [Recursive Language Model (RLM)](https://arxiv.org/html/2512.24601v3) architecture, and query narrowing with [LDA](https://www.ibm.com/think/topics/topic-modeling)-based topic steering** β using **AI Incident Explorer** as the use case.
|
| 29 |
|
| 30 |
-
> **What's an RLM?** A *Recursive Language Model*
|
| 31 |
|
| 32 |
> **What's LDA topic steering?** *Latent Dirichlet Allocation* is a [topic-modeling](https://www.ibm.com/think/topics/topic-modeling) technique that discovers the recurring themes hidden in a set of documents. Here it runs over the agent's *own past search queries* to reveal which themes it keeps circling β so the next round can be steered toward the topics it hasn't explored yet.
|
| 33 |
|
| 34 |
| Problem | Symptom | How this project solves it |
|
| 35 |
|---|---|---|
|
| 36 |
-
| **Context rot** | Over many search rounds the agent's context fills with stale tool output and it forgets its goal, repeats work, and degrades. |
|
| 37 |
-
| **Query narrowing** | Left alone, the agent re-issues near-identical searches and tunnels on one or two
|
|
|
|
|
|
|
| 38 |
|
| 39 |
-
As a use case, AI Incident Explorer answers questions like β *
|
| 40 |
|
| 41 |
-
Under the hood
|
|
|
|
|
|
|
|
|
|
| 42 |
|
| 43 |
---
|
| 44 |
|
| 45 |
## What AI Incident Explorer does
|
| 46 |
|
| 47 |
-
- **Autonomous, multi-round search** β give it one natural-language query; it runs up to *N* search/triage rounds on its own. One search
|
| 48 |
-
|
|
|
|
|
|
|
|
|
|
| 49 |
- **LLM-as-a-Judge triage** β an inner agent decides *security attack vs. safety failure vs. reliability issue* and assigns a harm-severity rating.
|
| 50 |
|
| 51 |
Everything it finds shows up in a sortable table. Click any incident's **title** to open its full write-up on the AI Incident Database, and use the type and severity filters to focus on just the cases you care about.
|
|
@@ -56,28 +59,26 @@ Everything it finds shows up in a sortable table. Click any incident's **title**
|
|
| 56 |
|
| 57 |

|
| 58 |
|
| 59 |
-
*Core context-rot mitigation β the outer agent orchestrates; the inner agent judges. State
|
| 60 |
|
| 61 |
---
|
| 62 |
|
| 63 |
## Implementation Notes
|
| 64 |
|
| 65 |
-
- **RLM / Code-Mode agent.** Instead of cramming hundreds of incidents into one context window, the outer agent writes Python that searches and triages in a
|
| 66 |
|
| 67 |

|
| 68 |
|
| 69 |
*The RLM strategies the outer agent uses to inspect and shrink data inside the REPL β keeping only what matters in context. Diagram source: [Daily Dose of Data Science β Recursive Language Models](https://blog.dailydoseofds.com/p/recursive-language-models).*
|
| 70 |
|
| 71 |
-
- **LLM-as-a-Judge classifier.** A second inner LLM agent acts as a reviewer that the app can call on for each incident. For every case it reads, it hands back the relevant ATLAS technique IDs and a triage category (how the incident should be sorted). This reviewer is set up separately from the main app, so you can
|
| 72 |
- **LDA topic steering.** Once a few rounds have run, the app looks back at the agent's own past search terms and groups them into recurring themes (using gensim's LDA topic modeling). Seeing which themes the agent keeps circling, it then nudges the next search toward the areas it hasn't explored yet β so coverage keeps widening instead of tunneling on the same few topics.
|
| 73 |
|
| 74 |
-

|
| 75 |
-
|
| 76 |
---
|
| 77 |
|
| 78 |
## What the User Sees
|
| 79 |
|
| 80 |
-
With all of those pieces working together, here's what it looks like to the user in the Gradio interface β note the MITRE ATLAS classifications shown along the bottom of the table:
|
| 81 |
|
| 82 |

|
| 83 |
|
|
@@ -105,12 +106,11 @@ With all of those pieces working together, here's what it looks like to the user
|
|
| 105 |
|
| 106 |
**βΆ [Open the live demo](https://huggingface.co/spaces/edangx100/aiid-explorer)**
|
| 107 |
|
| 108 |
-
1. Type a short keyword in **Query**
|
| 109 |
-
2. Click **Search** and **leave the tab open** β a round can take **up to ~9 minutes** on the
|
| 110 |
Basic-CPU Space. The status banner shows live progress and a time estimate.
|
| 111 |
3. Use the **type** and **severity** filters to slice the results once they arrive.
|
| 112 |
|
| 113 |
-
> If the backend is unavailable the app falls back to bundled demo data so the table is never blank.
|
| 114 |
|
| 115 |
#### Why the search takes minutes, not seconds
|
| 116 |
|
|
|
|
| 12 |
|
| 13 |
# AI Incident Explorer
|
| 14 |
|
| 15 |
+
> An autonomous agentic tool that mines the [AI Incident Database (AIID)](https://incidentdatabase.ai) to surface, classify, and triage real-world AI failures and attacks β mapping each one to **MITRE ATLAS** adversarial-ML techniques via an **LLM-as-a-Judge** classifier, with **agent observability**.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
|
| 17 |
---
|
| 18 |
|
| 19 |
## Why This Project Exists
|
| 20 |
|
| 21 |
+
**Agents operating over long horizons can degrade in two predictable ways**: Longβhorizon agents can experience **context rot**, and those engaged in long agentic search may additionally drift into **query narrowing** .
|
| 22 |
|
| 23 |
**This project is a demonstration of how both can be addressed β context rot with a [Recursive Language Model (RLM)](https://arxiv.org/html/2512.24601v3) architecture, and query narrowing with [LDA](https://www.ibm.com/think/topics/topic-modeling)-based topic steering** β using **AI Incident Explorer** as the use case.
|
| 24 |
|
| 25 |
+
> **What's an RLM?** A *Recursive Language Model* runs an LLM in a loop where each round's output is fed back as input to the next round. The model writes and runs Python code to search, filter, and classify data; at the end of each round it prints a structured `historical_results` block that the loop re-injects into the next round's prompt β so the agent accumulates memory across rounds without stuffing every raw tool result into context. See [RLM paper](https://arxiv.org/html/2512.24601v3)
|
| 26 |
|
| 27 |
> **What's LDA topic steering?** *Latent Dirichlet Allocation* is a [topic-modeling](https://www.ibm.com/think/topics/topic-modeling) technique that discovers the recurring themes hidden in a set of documents. Here it runs over the agent's *own past search queries* to reveal which themes it keeps circling β so the next round can be steered toward the topics it hasn't explored yet.
|
| 28 |
|
| 29 |
| Problem | Symptom | How this project solves it |
|
| 30 |
|---|---|---|
|
| 31 |
+
| **Context rot** | Over many search rounds the agent's context fills with stale tool output and it forgets its goal, repeats work, and degrades. | RLM keeps the context lean by having the agent write Python code that searches, filters, and classifies inside a sandboxed REPL β so raw tool output never lands in the prompt. At the end of each round the agent prints only a compact `historical_results` summary, which the loop re-injects into the next round's prompt as the agent's memory. The REPL itself is stateless across rounds; state lives in that re-injected summary, not in the interpreter. |
|
| 32 |
+
| **Query narrowing** | Left alone, the agent re-issues near-identical searches and tunnels on one or two recurring themes, leaving the rest of the threat surface blind. | The app spots when the agent keeps searching the same themes, then points it toward the threat types and industries it hasn't looked at yet β so it covers the wider landscape instead of circling a few corners. |
|
| 33 |
+
|
| 34 |
+

|
| 35 |
|
| 36 |
+
As a use case, AI Incident Explorer answers questions like β *βWhat MITRE ATLAS techniques are being used against LLMs in finance, healthcare, or consumer products right now?β* β by taking a user query as the starting point, searching [AI Incident Database (AIID)](https://incidentdatabase.ai), and returning a structured result set tagged by technique and severity.
|
| 37 |
|
| 38 |
+
Under the hood of AI Incident Explorer:
|
| 39 |
+
- an outer agent writes and runs Python in a sandboxed REPL to search and triage β at the end of each round it prints a compact `historical_results` summary that the loop re-injects into the next round's prompt, keeping context lean rather than accumulating raw tool output (the context-rot fix)
|
| 40 |
+
- while an inner **LLM-as-a-Judge** agent classifies each incident against the MITRE ATLAS taxonomy.
|
| 41 |
+
- After the initial seeding rounds, an **LDA** model within the search-loop orchestrator clusters the agentβs previous searches and steers it toward unexplored techniques to improve query narrowing.
|
| 42 |
|
| 43 |
---
|
| 44 |
|
| 45 |
## What AI Incident Explorer does
|
| 46 |
|
| 47 |
+
- **Autonomous, multi-round search** β give it one natural-language query; it runs up to *N* search/triage rounds on its own. One search scratches the surface: the incidents are scattered under many different wordings, so a single query misses most of them. Each round lets the agent learn from what it just found and avoid re-treading it; once topic steering kicks in (round 5 by default), the loop actively steers searches toward themes it hasn't explored yet β building a fuller picture than any one-shot lookup could.
|
| 48 |
+
|
| 49 |
+
> **Example.** You type *"prompt injection in healthcare"*. The agent doesn't search that whole phrase β the database looks for keywords inside incident text, so it splits your words into short searches like `prompt injection`, `healthcare`. The first few rounds stay close to your words and remember what they've already found. Then the agent notices it keeps searching the same two ideas, so it tries new ones it hasn't looked at yet β a different kind of attack (like `data leakage`) or a related area (like `medical imaging` or `pharmacy`). This way it covers far more ground than searching once.
|
| 50 |
+
|
| 51 |
+
- **MITRE ATLAS classification** β every relevant incident is tagged with one or more ATLAS technique IDs (e.g. `AML.T0051` LLM Prompt Injection, `AML.T0054` LLM Jailbreak, `AML.T0015` Evade AI Model).
|
| 52 |
- **LLM-as-a-Judge triage** β an inner agent decides *security attack vs. safety failure vs. reliability issue* and assigns a harm-severity rating.
|
| 53 |
|
| 54 |
Everything it finds shows up in a sortable table. Click any incident's **title** to open its full write-up on the AI Incident Database, and use the type and severity filters to focus on just the cases you care about.
|
|
|
|
| 59 |
|
| 60 |

|
| 61 |
|
| 62 |
+
*Core context-rot mitigation β the outer agent orchestrates; the inner agent judges. State carries across rounds via re-injected `historical_results`, not REPL persistence (the REPL resets each round).*
|
| 63 |
|
| 64 |
---
|
| 65 |
|
| 66 |
## Implementation Notes
|
| 67 |
|
| 68 |
+
- **RLM / Code-Mode agent.** Instead of cramming hundreds of incidents into one context window, the outer agent writes Python that searches and triages in a sandboxed REPL powered by [Pydantic AI Harness **CodeMode**](https://github.com/pydantic/pydantic-ai-harness/tree/main/pydantic_ai_harness/code_mode). The agent is prompted with Recursive Language Model strategies β *PEEK* (glance at a few examples before diving in), *GREP* (skim for the relevant ones instead of reading everything), *PARTITION+MAP* (break a big pile into smaller batches and work through them), and *SUMMARIZE* (boil long text down to the key point).
|
| 69 |
|
| 70 |

|
| 71 |
|
| 72 |
*The RLM strategies the outer agent uses to inspect and shrink data inside the REPL β keeping only what matters in context. Diagram source: [Daily Dose of Data Science β Recursive Language Models](https://blog.dailydoseofds.com/p/recursive-language-models).*
|
| 73 |
|
| 74 |
+
- **LLM-as-a-Judge classifier.** A second inner LLM agent acts as a reviewer that the app can call on for each incident. For every case it reads, it hands back the relevant ATLAS technique IDs and a triage category (how the incident should be sorted). This reviewer is set up separately from the main app, so you can use a cheaper or faster model for the job.
|
| 75 |
- **LDA topic steering.** Once a few rounds have run, the app looks back at the agent's own past search terms and groups them into recurring themes (using gensim's LDA topic modeling). Seeing which themes the agent keeps circling, it then nudges the next search toward the areas it hasn't explored yet β so coverage keeps widening instead of tunneling on the same few topics.
|
| 76 |
|
|
|
|
|
|
|
| 77 |
---
|
| 78 |
|
| 79 |
## What the User Sees
|
| 80 |
|
| 81 |
+
With all of those pieces working together, here's what it looks like to the user in the Gradio interface β note the MITRE ATLAS classifications shown along the bottom of the table (within red-dotted box):
|
| 82 |
|
| 83 |

|
| 84 |
|
|
|
|
| 106 |
|
| 107 |
**βΆ [Open the live demo](https://huggingface.co/spaces/edangx100/aiid-explorer)**
|
| 108 |
|
| 109 |
+
1. Type a short keyword in **Query**.
|
| 110 |
+
2. Click **Search** and **leave the tab open** β a round can take **up to ~9 minutes** on the HuggingFace
|
| 111 |
Basic-CPU Space. The status banner shows live progress and a time estimate.
|
| 112 |
3. Use the **type** and **severity** filters to slice the results once they arrive.
|
| 113 |
|
|
|
|
| 114 |
|
| 115 |
#### Why the search takes minutes, not seconds
|
| 116 |
|
explorer/prompts.py
CHANGED
|
@@ -5,7 +5,7 @@
|
|
| 5 |
#
|
| 6 |
# Two guidance sections in the prompt below were added to fix a real "0 results" failure
|
| 7 |
# we observed (e.g. searching "healthcare" returned nothing). They are plain English aimed
|
| 8 |
-
# at steering the model, not Python logic
|
| 9 |
# 1. "Search query format" β aiid_search() matches the query as a REGEX against incident
|
| 10 |
# title/description, so a multi-word phrase like "healthcare AI incidents" matches
|
| 11 |
# almost nothing. The section tells the agent to search with SHORT keywords (and to
|
|
@@ -22,10 +22,26 @@ HISTORICAL_RESULTS_START: str = "HISTORICAL_RESULTS_START"
|
|
| 22 |
HISTORICAL_RESULTS_END: str = "HISTORICAL_RESULTS_END"
|
| 23 |
|
| 24 |
INNER_AGENT_SYSTEM_PROMPT: str = (
|
| 25 |
-
"You are a concise
|
| 26 |
-
"
|
| 27 |
-
"
|
| 28 |
-
"Answer in one to three sentences."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
)
|
| 30 |
|
| 31 |
OUTER_AGENT_SYSTEM_PROMPT: str = f"""You are an autonomous AI security research agent that mines the AI Incident Database (AIID) for real-world AI failures and attacks.
|
|
@@ -86,26 +102,20 @@ AIID Search: <next search query>
|
|
| 86 |
- **The `<technique_id>` MUST be a real MITRE ATLAS ID in the form `AML.TXXXX`** (e.g. `AML.T0051`), determined by classifying the incident with `llm_query`. **NEVER** write `TBD`, `none`, `N/A`, `unknown`, or the search keyword in place of the ID β a starred line whose technique is not a real `AML.TXXXX` is invalid. If you cannot map an incident to a real ATLAS technique, mark it `-- not relevant` rather than starring it with a placeholder.
|
| 87 |
- To keep IDs valid even under your tight code-block budget, you may map an obvious incident directly to one of the common techniques listed below; use `llm_query` whenever you are unsure or for less-obvious cases.
|
| 88 |
- The `β` prefix is the only signal the harness uses to detect forward progress. Every new incident you classify as relevant **must** have a star or it will not be counted.
|
|
|
|
| 89 |
|
| 90 |
### Common MITRE ATLAS techniques (use the real ID β never a placeholder)
|
| 91 |
- `AML.T0051` LLM Prompt Injection
|
| 92 |
- `AML.T0054` LLM Jailbreak
|
| 93 |
- `AML.T0057` LLM Data Leakage
|
| 94 |
- `AML.T0043` Craft Adversarial Data
|
| 95 |
-
- `AML.T0040`
|
| 96 |
-
- `AML.T0024` Exfiltration via
|
| 97 |
- `AML.T0020` Poison Training Data
|
| 98 |
-
- `AML.T0031` Erode
|
| 99 |
- `AML.T0048` External Harms
|
| 100 |
-
- `AML.T0046` Spamming
|
| 101 |
-
- `found_with` is implicitly the `AIID Search:` query on the line immediately preceding the result block β do not repeat it on the starred line itself.
|
| 102 |
-
|
| 103 |
-
### Incident type values (use exactly)
|
| 104 |
-
- `security_attack` β adversarial input, prompt injection, model theft, data poisoning, etc.
|
| 105 |
-
- `safety_failure` β unintended harmful output, alignment failure, value misalignment
|
| 106 |
-
- `reliability_issue` β system crash, availability failure, accuracy degradation
|
| 107 |
|
| 108 |
-
### Severity values (use exactly): `critical`, `high`, `medium`, `low`
|
| 109 |
|
| 110 |
## Emergent Strategies
|
| 111 |
|
|
|
|
| 5 |
#
|
| 6 |
# Two guidance sections in the prompt below were added to fix a real "0 results" failure
|
| 7 |
# we observed (e.g. searching "healthcare" returned nothing). They are plain English aimed
|
| 8 |
+
# at steering the model, not Python logic:
|
| 9 |
# 1. "Search query format" β aiid_search() matches the query as a REGEX against incident
|
| 10 |
# title/description, so a multi-word phrase like "healthcare AI incidents" matches
|
| 11 |
# almost nothing. The section tells the agent to search with SHORT keywords (and to
|
|
|
|
| 22 |
HISTORICAL_RESULTS_END: str = "HISTORICAL_RESULTS_END"
|
| 23 |
|
| 24 |
INNER_AGENT_SYSTEM_PROMPT: str = (
|
| 25 |
+
"You are a concise AI incident classifier. Given an AI incident, you perform two jobs:\n\n"
|
| 26 |
+
"1. **MITRE ATLAS technique** β identify the most relevant technique ID(s) in the form AML.TXXXX.\n"
|
| 27 |
+
"2. **Triage** β classify the incident type and assign a harm-severity rating.\n\n"
|
| 28 |
+
"Answer in one to three sentences. Be direct; skip preamble.\n\n"
|
| 29 |
+
"### Common MITRE ATLAS techniques (use the real ID β never a placeholder)\n"
|
| 30 |
+
"- `AML.T0051` LLM Prompt Injection\n"
|
| 31 |
+
"- `AML.T0054` LLM Jailbreak\n"
|
| 32 |
+
"- `AML.T0057` LLM Data Leakage\n"
|
| 33 |
+
"- `AML.T0043` Craft Adversarial Data\n"
|
| 34 |
+
"- `AML.T0040` AI Model Inference API Access\n"
|
| 35 |
+
"- `AML.T0024` Exfiltration via AI Inference API\n"
|
| 36 |
+
"- `AML.T0020` Poison Training Data\n"
|
| 37 |
+
"- `AML.T0031` Erode AI Model Integrity\n"
|
| 38 |
+
"- `AML.T0048` External Harms\n"
|
| 39 |
+
"- `AML.T0046` Spamming AI System with Chaff Data\n\n"
|
| 40 |
+
"### Incident type (use exactly one)\n"
|
| 41 |
+
"- `security_attack` β adversarial input, prompt injection, model theft, data poisoning, etc.\n"
|
| 42 |
+
"- `safety_failure` β unintended harmful output, alignment failure, value misalignment\n"
|
| 43 |
+
"- `reliability_issue` β system crash, availability failure, accuracy degradation\n\n"
|
| 44 |
+
"### Severity (use exactly one): `critical`, `high`, `medium`, `low`\n"
|
| 45 |
)
|
| 46 |
|
| 47 |
OUTER_AGENT_SYSTEM_PROMPT: str = f"""You are an autonomous AI security research agent that mines the AI Incident Database (AIID) for real-world AI failures and attacks.
|
|
|
|
| 102 |
- **The `<technique_id>` MUST be a real MITRE ATLAS ID in the form `AML.TXXXX`** (e.g. `AML.T0051`), determined by classifying the incident with `llm_query`. **NEVER** write `TBD`, `none`, `N/A`, `unknown`, or the search keyword in place of the ID β a starred line whose technique is not a real `AML.TXXXX` is invalid. If you cannot map an incident to a real ATLAS technique, mark it `-- not relevant` rather than starring it with a placeholder.
|
| 103 |
- To keep IDs valid even under your tight code-block budget, you may map an obvious incident directly to one of the common techniques listed below; use `llm_query` whenever you are unsure or for less-obvious cases.
|
| 104 |
- The `β` prefix is the only signal the harness uses to detect forward progress. Every new incident you classify as relevant **must** have a star or it will not be counted.
|
| 105 |
+
- `found_with` is implicitly the `AIID Search:` query on the line immediately preceding the result block β do not repeat it on the starred line itself.
|
| 106 |
|
| 107 |
### Common MITRE ATLAS techniques (use the real ID β never a placeholder)
|
| 108 |
- `AML.T0051` LLM Prompt Injection
|
| 109 |
- `AML.T0054` LLM Jailbreak
|
| 110 |
- `AML.T0057` LLM Data Leakage
|
| 111 |
- `AML.T0043` Craft Adversarial Data
|
| 112 |
+
- `AML.T0040` AI Model Inference API Access
|
| 113 |
+
- `AML.T0024` Exfiltration via AI Inference API
|
| 114 |
- `AML.T0020` Poison Training Data
|
| 115 |
+
- `AML.T0031` Erode AI Model Integrity
|
| 116 |
- `AML.T0048` External Harms
|
| 117 |
+
- `AML.T0046` Spamming AI System with Chaff Data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 118 |
|
|
|
|
| 119 |
|
| 120 |
## Emergent Strategies
|
| 121 |
|