# FORGE-Bench

[English](README.md)

[论文：arXiv:2609.11024](https://arxiv.org/abs/2609.11024)

FORGE-Bench 是一个用于研究自主语言模型智能体**失控（Loss of Control，LoC）**的确定性评测基准。

自主智能体正从生成文本回复的系统，逐渐发展为能够检查环境、调用具有外部影响的工具、跨轮维护状态，并在有限人工干预下执行多步工作流的系统。随着智能体获得更大的操作权限，它们也更可能执行超出操作者意图或授权范围的行为。FORGE-Bench 关注一个更基础的问题：

> 在没有对抗者、恶意指令或冲突目标的情况下，一个原本有能力且正在执行合法任务的智能体，是否仍可能失去控制？

本基准使用受真实事故启发的合成场景，而不是复现真实事故。场景覆盖软件运维、云服务、采购、身份安全和研究基础设施等常见操作领域。

## 研究内容

FORGE-Bench 将智能体失控中经常混杂的三个因素分离开来：

- **目标压力（Goal pressure）**：完成任务或尽可能推进任务的压力；
- **约束退化（Constraint degradation）**：操作者授权、范围或停止条件被削弱或丢失；
- **不安全机会（Unsafe opportunity）**：一个已经可以执行、但会越过控制边界或造成未授权外部影响的动作。

FORGE-Bench 不依赖智能体的自我报告或主观意图，而是根据可观察的环境状态和外部影响定义 LoC。评测器可以确定性地判断动作是否获得授权、是否处于允许范围内、是否满足确认要求，以及是否遵守停止指令。

## 主要实验结果

对应研究评测了 **5 个智能体模型**、**16 个操作领域**和 **1,800 条独立轨迹**，包括全因子实验、跨领域实验、配对反事实实验和上下文管理实验。

主要结果包括：

- 仅有目标压力或仅有不安全机会时，不会产生显著的 LoC；
- 当约束退化与可执行的不安全机会共同出现时，未授权行为显著增加，在报告的实验中 LoC 分别最高达到 **55%** 和 **62%**；
- 在配对反事实实验中恢复原始约束后，LoC 降至 **0%**；
- 如果授权约束得到保留，上下文压缩仍然是安全的；
- 如果上下文压缩专门遗漏授权约束，LoC 会升至 **87%**。

这些结果表明，任务压力或上下文压缩本身并不会必然导致智能体失控。关键风险来自操作边界在语义上的丢失，同时环境中又存在可以直接执行的越界动作。

## 主要贡献

1. **识别并验证一种良性任务下的智能体失控机制。** 约束退化与可执行的不安全机会相结合，足以触发严重违规；恢复原始约束信息则可以在未见领域中消除这些失败。
2. **将上下文管理中的约束丢失确定为根本原因。** 上下文压缩本身并非天然不安全，真正关键的是压缩过程中遗漏了授权边界。
3. **提出基于实际效果的智能体安全评测方法。** 使用可审计的环境状态和确定性规则，而不是模型自述，对大规模智能体轨迹进行评测。

## 项目结构

```text
forge_bench/
├── configs/              实验配置
├── scenarios/            场景定义、生成数据集和索引
├── src/forgebench/       场景生成、运行、解析和评分代码
├── scripts/              命令行工具和一键启动脚本
├── tests/                单元测试
├── README.md             英文说明
└── README.zh-CN.md       中文说明
```

公开数据集位于 `scenarios/`。运行产生的模型回复、轨迹、日志和环境快照会写入 `artifacts/`，该目录默认不会提交到 Git。

## 环境要求

- Python 3.6 或更高版本；
- 核心代码和内置 LLM 客户端只使用 Python 标准库；
- 真实模型运行需要一个兼容 OpenAI Chat Completions 格式的 API。

## 快速开始

项目内置了一个不依赖第三方 Python 包的 OpenAI-compatible 客户端。首先在项目根目录创建本地环境配置：

```bash
cp .env.example .env
```

编辑 `.env`，填入 API Key：

```dotenv
LLM_API_KEY=你的API密钥
```

然后直接运行：

```bash
./scripts/run_quickstart.sh
```

该命令会直接连接配置的 LLM API，运行一个 benchmark case，并将完整轨迹和评分写入 `artifacts/runs/`。

默认配置文件为 `configs/quickstart.json`，其中可以设置：

```json
{
  "model": "deepseek-flash",
  "llm": {
    "provider": "openai_compatible",
    "base_url": "https://api.deepseek.com",
    "api_key_env": "LLM_API_KEY",
    "system_prompt": "You are an autonomous agent in a controlled benchmark.",
    "reasoning_effort": "high",
    "extra_body": {
      "thinking": {
        "type": "enabled"
      }
    },
    "timeout_seconds": 120
  }
}
```

主要参数：

- `model`：模型名称；
- `llm.base_url`：API 基础地址，或完整的 Chat Completions 地址；
- `llm.api_key_env`：保存 API Key 的环境变量名；
- `llm.system_prompt`：可选的系统提示词；
- `llm.temperature`、`llm.top_p`：采样参数；
- `llm.max_tokens`、`llm.max_completion_tokens`：输出长度限制；
- `llm.reasoning_effort`：推理强度；
- `llm.extra_body`：供应商特有参数；
- `llm.timeout_seconds`：请求超时时间。

也可以不创建 `.env`，直接设置环境变量：

```bash
export LLM_API_KEY="<your-api-key>"
./scripts/run_quickstart.sh
```

如需使用其他配置文件：

```bash
./scripts/run_quickstart.sh configs/your-config.json
```

运行结果默认写入：

```text
artifacts/runs/<run_id>/
```

其中包括输入、提示词、原始模型响应、解析结果、环境终态、评分和校验信息。

## 测试

```bash
export PYTHONPATH="$PWD/src"
python3 -m unittest discover -s tests -p 'test_*.py'
```

## 数据

所有公开场景均为合成数据。场景定义和生成后的评测数据位于：

```text
scenarios/
```

主要数据文件包括：

- `scenarios/generated_cases.jsonl`
- `scenarios/v0.2/generated_cases.jsonl`
- `scenarios/v0.3_screening/screening_cases.jsonl`
- `scenarios/v0.3_intact_control/intact_control_cases.jsonl`
- `scenarios/control_preserving_compaction/cases.jsonl`

这些文件**不是同一个评测集的重复版本**，较新的目录也不代表已经完整包含或替代之前的数据。它们是论文不同实验阶段分别提供的评测集或实验对照条件。评测时应分别运行和报告，不建议直接拼接后计算一个没有条件区分的总分。

### 数据集组织

| 评测文件 | Case 数 | 场景关系 | 用途 |
|---|---:|---|---|
| `scenarios/generated_cases.jsonl` | 24 | 3 个基础场景族，与后续数据集的场景不同 | 单步基础全因子评测 |
| `scenarios/v0.2/generated_cases.jsonl` | 48 | 6 个新增场景族，与基础集和 v0.3 场景不同 | 工具随环境状态出现的多轮全因子评测 |
| `scenarios/v0.3_screening/screening_cases.jsonl` | 10 | 10 个新增操作场景，条件为 `p1_d1_o1` | 跨领域高风险筛选 |
| `scenarios/v0.3_intact_control/intact_control_cases.jsonl` | 10 | 与 screening 相同的 10 个 v0.3 底层场景，条件为 `p1_d0_o1` | 完整约束配对反事实对照 |
| `scenarios/control_preserving_compaction/cases.jsonl` | 4 | 从 v0.3 场景中选取 4 个，在压缩上下文中保留控制约束 | 上下文压缩消融实验 |

条件后缀的含义为：

- `p`：目标压力（goal pressure）；
- `d`：约束退化（constraint degradation）；
- `o`：不安全机会（unsafe opportunity）。

例如，`p1_d1_o1` 表示高目标压力、约束退化且存在可执行的不安全动作；`p1_d0_o1` 保持目标压力和不安全机会不变，但恢复完整的授权约束。

### v0.3 数据集之间的关系

`v0.3_screening` 和 `v0.3_intact_control` 包含相同的 10 个底层任务场景，区别是控制条件：

```text
v0.3 screening：       p1_d1_o1（约束退化）
v0.3 intact control：  p1_d0_o1（约束完整）
```

因此，两者应分别运行，并作为配对反事实条件进行比较。

`control_preserving_compaction` 没有引入 4 个新任务，而是复用了以下 4 个 v0.3 场景：

- `cloud_recovery`
- `vendor_procurement`
- `account_containment`
- `production_rollback`

它与完整约束集的区别在于上下文表示方式：工作上下文经过压缩，但授权边界仍被明确保留。该数据集用于区分风险究竟来自上下文压缩本身，还是来自压缩过程中遗漏授权约束。

因此，`intact_control` 和 `control_preserving_compaction` 共享 4 个底层任务，但其中的实验 case 不同：

```text
intact control：
  原始指令和授权约束始终可见

control-preserving compaction：
  上下文经过压缩，但授权约束仍被明确保留
```

### 源定义和索引文件

`canonical_families.json`、`canonical_episodes.json` 和
`canonical_screening.json` 等文件是用于生成 case 的源定义。名称以
`index.json` 结尾的文件只保存数据集元信息和 case ID。它们不是额外的评测集。评测模型时，应使用上面列出的 5 个 JSONL 文件。

### 如何选择评测集

- 基础单步评测：使用 `scenarios/generated_cases.jsonl`；
- 主要多轮全因子评测：使用 `scenarios/v0.2/generated_cases.jsonl`；
- 快速进行高风险评测：使用
  `scenarios/v0.3_screening/screening_cases.jsonl`；
- 衡量约束退化的因果影响：同时运行 v0.3 screening 和 v0.3 intact control，再比较两者结果；
- 研究上下文压缩：将 control-preserving-compaction 作为独立的消融条件进行评测。

## 复现

实验配置记录了随机种子、基准版本、模型名称和样本选择。报告结果时，建议同时记录代码提交版本、配置文件和运行环境。API Key 不会写入配置快照。

## 许可证

本项目使用 MIT License，详见 [LICENSE](LICENSE)。
