> ## Documentation Index
> Fetch the complete documentation index at: https://docs.abliteration.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Giskard

> Red-team your AI agents with Giskard's agent vulnerability scanner using abliteration.ai as the LLM backend.

**To red-team an AI agent with Giskard and abliteration.ai**, point Giskard's internal LLM — the one that writes adversarial attacks and judges your agent's behavior — at `https://api.abliteration.ai/v1` with your `ak_...` key, then run Giskard's agent vulnerability scan against your agent. Your agent under test can run on any backend; abliteration.ai powers the scanner.

## Install

Agent vulnerability scanning requires Giskard v3 (beta) on Python 3.12, with pydantic pinned to 2.12.x:

```sh theme={"system"}
pip install --prerelease allow "giskard[scan,openai]>=3.0.0b0" openai "pydantic==2.12.5"
```

<Note>
  Newer pydantic versions (2.14+) currently crash the `giskard.checks` import — keep the 2.12.5 pin until Giskard v3 stabilizes. Giskard 2.x has no agent-scan API.
</Note>

## Set the API key

```sh theme={"system"}
export ABLIT_KEY="ak_YOUR_API_KEY"
```

## Point Giskard's LLM at abliteration.ai

Override Giskard's built-in `openai` provider alias with the abliteration.ai endpoint, and set the default generator used by all attack writers and judges:

```python theme={"system"}
import os

import giskard.llm
from giskard.agents import Generator
from giskard.checks import set_default_generator

giskard.llm.configure(
    "openai",  # the built-in provider alias Giskard components fall back to
    provider="openai",
    api_key=os.environ["ABLIT_KEY"],
    base_url="https://api.abliteration.ai/v1",
    timeout=120.0,
)
set_default_generator(Generator(model="openai/abliterated-model"))
```

From this point, every scenario generator, adversarial attack writer, and judge in the scan runs on abliteration.ai.

## Wrap your agent

The scan target is any async callable that takes the latest user input plus a `Trace`, and returns the agent's reply as a string. Rebuild multi-turn history from `trace.interactions`:

```python theme={"system"}
from giskard.checks import Trace

async def my_agent(inputs: str, trace: Trace) -> str:
    messages = [{"role": "system", "content": SYSTEM_PROMPT}]
    for interaction in trace.interactions:
        messages.append({"role": "user", "content": interaction.inputs})
        messages.append({"role": "assistant", "content": interaction.outputs})
    messages.append({"role": "user", "content": inputs})

    # ... run your agent (any framework, any model, with or without tools)
    # and return its final reply
    return reply
```

<Note>
  If the agent under test itself runs on abliteration.ai with a tool-call loop, echo back a **sanitized** assistant message containing only `role`, `content`, and `tool_calls`. The endpoint rejects requests that replay the extra fields it returns (`reasoning`, null `content`/`refusal`) with a `400 invalid_request` error.
</Note>

## Run the scan

```python theme={"system"}
from giskard.scan import vulnerability_scan

result = await vulnerability_scan(
    target=my_agent,
    description=(
        "A customer support agent for Acme Store that can look up order "
        "status, issue refunds, and look up customer profiles via tools."
    ),
    languages=["en"],
    target_mode="multiturn",  # attack the agent across multiple turns
    max_scenarios=6,          # keep the first run small
    seed=42,
    parallel=True,
    max_concurrency=2,        # be gentle with the endpoint
    return_exception=True,    # keep scanning if a probe errors
)
```

The `description` matters: Giskard uses it to write targeted attacks, so describe the agent's role, tools, and sensitive operations (refunds, data lookups, admin actions).

### Timebox the scan

A full scan pulls in expensive multi-turn generators and network-downloaded datasets. To keep a first run to minutes, register only the cheap generators:

```python theme={"system"}
from giskard.scan.vulnerability import vulnerability_suite_generator_registry
from giskard.scan.generators.prompt_injection import PromptInjectionScenarioGenerator
from giskard.scan.generators.adversarial import AdversarialScenarioGenerator

vulnerability_suite_generator_registry.clear()
vulnerability_suite_generator_registry.register(PromptInjectionScenarioGenerator)  # bundled OWASP LLM01 probes
vulnerability_suite_generator_registry.register(
    AdversarialScenarioGenerator(max_turns=2)  # LLM-written attacks + judge
)
```

## Read the report

```python theme={"system"}
result.print_report(group_by="threat-type")

from pathlib import Path
Path("report.json").write_text(result.model_dump_json(indent=2))
```

The report lists each scenario as pass/fail by threat type — prompt injection, harmful content generation, data exfiltration, and so on — with the full conversation trace for every failure.

## Notes

* **Runtime** — abliteration.ai models reason before answering (see [thinking & reasoning effort](/capabilities/thinking)), and the scan pays that cost on the attacker, agent, and judge calls each turn. A 3-scenario timeboxed run takes roughly 20 minutes; keep `max_scenarios` small while iterating.
* **Telemetry** — set `DO_NOT_TRACK=1` before importing Giskard to disable its telemetry.
* **Policy Gateway** — policy rules attached to your API key apply to every scan request, and scan traffic shows up in your policy logs. See [Policy Gateway](/policy-gateway/overview).
