---
title: "harness - 内置拦截器的修改及添加"
---


solon-ai-harness 在引擎启动时预置了三个内置拦截器，分别负责三种不同的 Agent 运行保障机制：

- **`compressionInterceptor`**（上下文压缩拦截器）：负责工作记忆区的无损/近无损压缩
- **`hitlInterceptor`**（人工介入拦截器）：负责敏感工具调用的安全审计与人工审批
- **`stopLoopInterceptor`**（防死循环拦截器）：负责检测并纠正 Agent 陷入重复模式


### 1、内置拦截器的默认行为

```java
HarnessEngine engine = HarnessEngine.of(workspace, harnessHome)
  .sessionProvider(sessionProvider)
  .build();
```

默认情况下，引擎会自动创建并配置上述三个拦截器：

**上下文压缩拦截器**：触发条件为消息超过 40 条或 Token 超过模型上下文窗口的 75%。保留的消息窗口上限为 40 条。使用组合压缩策略（`CompositeCompressionStrategy`），先后执行：

- `KeyInfoExtractionStrategy`：提取干货（去水），保留关键信息
- `HierarchicalCompressionStrategy`：滚动更新摘要，维护分层压缩的历史摘要

**防死循环拦截器**：默认 `(3, 8)`，即在 8 轮窗口内如果连续 3 次出现完全相同的工具调用特征，则注入自纠错提示。

**HITL 拦截器**：默认绑定 `bash` 工具的 `BashToolStrategy`（内含 6 条内置安全规则 + 权限引擎委托），并配置了 `onApproved` 审批自动记忆回调。


### 2、修改现有的内置拦截器

通过 Builder 阶段直接替换拦截器实例：

```java
HarnessEngine engine = HarnessEngine.of(workspace, harnessHome)
  .sessionProvider(sessionProvider)
  .compressionInterceptor(new ContextCompressionInterceptor())  // 替换压缩拦截器
  .hitlInterceptor(new HITLInterceptor())                       // 替换 HITL 拦截器
  .stopLoopInterceptor(new StopLoopInterceptor(5, 10))          // 替换防死循环拦截器
  .build();
```

> **注意**：Builder 方法 `compressionInterceptor()`、`hitlInterceptor()`、`stopLoopInterceptor()` 是替换而非叠加。如需保留默认行为仅调整参数，可通过引擎运行时的 API 调整（见第 5 节）。


### 3、上下文压缩拦截器（ContextCompressionInterceptor）

拦截器的生命周期方法：重写 `onReasonStart` 进行压缩判断，并在模型返回上下文超长错误时通过 `onReasonRetry` 执行强制压缩。

#### 3.1 构造参数说明

```java
// 最简构造（maxMessages=15, maxContextRatio=0.75, 使用默认组合压缩策略）
ContextCompressionInterceptor interceptor = new ContextCompressionInterceptor();

// 指定最大消息数与最简压缩策略
ContextCompressionInterceptor interceptor = new ContextCompressionInterceptor(
  40                                     // maxMessages: 保留窗口最大消息数
);

// 指定完整参数
ContextCompressionInterceptor interceptor = new ContextCompressionInterceptor(
  40                                     // maxMessages: 保留窗口最大消息数（下限 10）
);
interceptor.setMaxContextLengthRatio(0.75);    // 模型上下文窗口使用比例（默认 0.75）
interceptor.setMaxRetries(3);                  // 压缩策略重试次数
interceptor.setMessageTriggerFactor(1.5);      // 触发滞后系数（>=1.0，越大越不易触发）
interceptor.setMinReservedMessages(5);          // 保留窗口最小消息数（显式覆盖，>=3）
interceptor.setPerMessageCap(8000);            // 单条消息 Token 硬上限（0=自动推导）
interceptor.setDefaultContextLength(128_000L); // 模型上下文窗口默认值
```

#### 3.2 压缩策略（CompressionStrategy）配置

```java
// 自定义组合压缩策略
CompressionStrategy strategy = new CompositeCompressionStrategy()
  .addStrategy(new KeyInfoExtractionStrategy())
  .addStrategy(new HierarchicalCompressionStrategy());

ContextCompressionInterceptor interceptor = new ContextCompressionInterceptor(
  40,
  0.75,
  3,
  strategy);

HarnessEngine engine = HarnessEngine.of(workspace, harnessHome)
  .sessionProvider(sessionProvider)
  .compressionInterceptor(interceptor)
  .build();
```

也可通过引擎运行时动态调整压缩参数：

```java
engine.setCompressionThreshold(50, 0.80);  // 调整阈值（maxMessages=50, ratio=0.80）
```

#### 3.3 压缩保护机制

压缩拦截器内置了多层保护机制：

- **初心链保护**：标记为 `META_FIRST` 的消息（system prompt、用户原始问题）永不压缩
- **Tool-use 原子对保护**：`Assistant(with tool_calls)` ↔ `ToolMessage` 的调用-结果配对不会被拆散
- **语义连贯补齐**：截断点前的 Assistant thought 消息会一并纳入保留区
- **单条消息守卫**：单条超过 `perMessageCap` 的消息会被头尾截断，防止巨量消息撑爆上下文
- **压缩效果告警**：压缩后消息数 >= 原始 90% 时输出 WARN 日志


### 4、HITL 拦截器（人工介入）

HITL（Human-in-the-Loop）拦截器通过 ReAct 协议的生命周期钩子实现流程管控。

#### 4.1 生命周期机制

| 方法 | 说明 |
|------|------|
| `onAgentStart` | 恢复挂起会话时自动判断是否回到 Action |
| `onReasonStart` | 推理开始前检查，无操作 |
| `onActionStart` | 批级预检：扫全量 tool call，未决策的整批挂起 |
| `onToolCallStart` | 单工具级防已决策二次应用 |
| `onToolCallEnd` | 清理决策键、注入人工备注 |
| `onActionEnd` | 会话未挂起时清理批挂起状态 |

#### 4.2 使用方式

**开关控制**：HITLInterceptor 本身和 `hitlEnabled` 开关需同时满足才能生效：

```java
// Builder 阶段配置
HarnessEngine engine = HarnessEngine.of(workspace, harnessHome)
  .sessionProvider(sessionProvider)
  .hitlEnabled(true)              // 全局启用 HITL 开关
  .build();
```

> `hitlEnabled=true` 为全局开关，拦截器仅为具体策略逻辑，两者缺一不可。

#### 4.3 注册工具策略

通过 Builder 指定自定义 HITL 拦截器（此时会覆盖默认的 `BashToolStrategy`）：

```java
HITLInterceptor hitl = new HITLInterceptor();

// 使用内置策略
hitl.onTool("bash", new BashToolStrategy());            // bash 命令审计
hitl.onTool("write", new WriteToolStrategy("write"));   // 文件写入审计
hitl.onTool("edit", new WriteToolStrategy("edit"));     // 文件编辑审计
hitl.onTool("webfetch", new WebToolStrategy("webfetch")); // 网络访问审计

// 快速注册为敏感工具（使用默认敏感策略）
hitl.onSensitiveTool("write", "edit", "rm");

// 设置审批自动记忆回调（审批过的相同命令/路径自动放行）
hitl.onApproved((toolName, args) -> {
    engine.addPermissionRule(PermissionRule.allow(toolName));
});

HarnessEngine engine = HarnessEngine.of(workspace, harnessHome)
  .sessionProvider(sessionProvider)
  .hitlInterceptor(hitl)
  .hitlEnabled(true)
  .build();
```

#### 4.4 运行时动态开关

```java
// 运行时启用/禁用 HITL
engine.setHitlEnabled(true);  // 启用，会调用 hitlInterceptor.setEnabled(true)
engine.setHitlEnabled(false); // 禁用
```

> `engine.setHitlEnabled()` 会同时更新 `HarnessOptions.hitlEnabled` 和 `HITLInterceptor.setEnabled()`，保持双开关一致。

#### 4.5 内置 HITL 策略

| 策略类 | 适用工具 | 内置规则 |
|--------|----------|----------|
| `BashToolStrategy` | bash | 空命令放行、注入防御、系统特权黑名单、路径回溯防御、敏感文件防御、只读命令自动放行、不完整命令拒绝 |
| `WriteToolStrategy` | write/edit | 路径回溯防御、敏感系统文件防御 |
| `WebToolStrategy` | webfetch/websearch | 高风险域名黑名单 |
| `HITLSensitiveStrategy` | 任意 | 通用敏感操作拦截 |

详细参考：[《harness - HitlStrategy 安全审计策略》](/article/1440) 和 [《harness - PermissionRule 权限规则引擎》](/article/1441)。

#### 4.6 流式事件

HITL 拦截器在流式输出时会推送专门的事件：

- `HITLPendingEvent` — 首次拦截挂起，携带 `HITLTask` 列表（callId、toolName、args、comment），用于前端展示审批卡片
- `HITLDecidedEvent` — 决策生效，携带 `HITLDecision`（approved/skipped/rejected、modifiedArgs、comment），用于关闭/更新审批卡片


### 5、防死循环拦截器（StopLoopInterceptor）

通过 `onThought` 生命周期方法检测 Agent 的重复行为模式。使用规范化指纹（归一化的工具调用名组合/Action 行/内容前缀）标识每次迭代意图。

```java
// 自定义参数：5 次相同特征 / 10 轮窗口
StopLoopInterceptor stopLoop = new StopLoopInterceptor(5, 10);

HarnessEngine engine = HarnessEngine.of(workspace, harnessHome)
  .sessionProvider(sessionProvider)
  .stopLoopInterceptor(stopLoop)
  .build();
```

检测到循环后的处理机制：

1. 生成自纠错提示文案（含有效性评估、强制收敛、避免重复三条指导）
2. 作为用户消息注入到工作记忆区（`ChatMessage.ofUser()`）
3. 清除计数器，避免注入消息被重复计数
4. **不挂起会话、不强制终止**，LLM 在下一轮推理时看到提示并自行纠正


### 6、添加自定义拦截器（通过 HarnessExtension）

通过 `HarnessExtension` 接口，可以在 Builder 构建阶段或引擎运行阶段对 Agent 的行为进行扩展。

#### 6.1 HarnessExtension 接口定义

```java
public interface HarnessExtension {
    /** 在 Agent 构建时回调，参数为当前构建的 agentName 与 agentBuilder */
    void configure(String agentName, ReActAgent.Builder agentBuilder);
}
```

#### 6.2 Builder 构建阶段

```java
HarnessEngine engine = HarnessEngine.of(workspace, harnessHome)
  .sessionProvider(sessionProvider)
  .extensionAdd(new HarnessExtension() {
      @Override
      public void configure(String agentName, ReActAgent.Builder agentBuilder) {
          // 添加自定义拦截器
          agentBuilder.defaultInterceptorAdd(new ReActInterceptor() {
              @Override
              public void onAgentStart(ReActTrace trace) {
                  // 自定义逻辑
                  System.out.println("Agent started: " + agentName);
              }
          });

          // 可以设置拦截器优先级（数字越小优先级越高）
          // agentBuilder.defaultInterceptorAdd(5, interceptor);
      }
  })
  .build();
```

> **注意**：`defaultInterceptorAdd` 与 `compressionInterceptor()`、`hitlInterceptor()` 等替换式方法**不同**，它是添加而非替换。替换式方法会替换掉引擎默认创建的拦截器实例。

#### 6.3 运行时动态添加/移除

引擎运行后，通过以下 API 动态管理扩展（每次变更会触发主 Agent 重建）：

```java
// 运行时添加扩展
engine.addExtension(new HarnessExtension() {
    @Override
    public void configure(String agentName, ReActAgent.Builder agentBuilder) {
        agentBuilder.defaultInterceptorAdd(new MyCustomInterceptor());
    }
});

// 运行时移除扩展
engine.removeExtension(extension);
```

#### 6.4 自定义拦截器注册到具体生命周期的方法

`ReActAgent.Builder` 提供了以下注册方法：

| Builder 方法 | 说明 |
|---|---|
| `defaultInterceptorAdd(ReActInterceptor)` | 添加默认拦截器到所有生命周期 |
| `defaultInterceptorAdd(int priority, ReActInterceptor)` | 指定优先级的拦截器（数值越小越靠前执行） |
| `defaultTalentAdd(Talent)` | 添加 Talent（技能包），包含多个工具 |

关于完整的 ReActInterceptor 生命周期方法，参见 [《react - ReActInterceptor 拦截器》](/article/1316)。


### 7、通过 AgentDefinition 的 tools 配置启用 HITL

在 Agent 定义的工具体系中，`hitl` 是一个特殊的工具名，通过它来启用人工介入拦截器：

```java
AgentDefinition definition = AgentDefinition.builder()
    .name("my-agent")
    .toolsAdd("read", "write", "bash", "hitl")  // 启用 HITL 拦截器
    .build();
```

当 `hitl` 出现在工具列表中，且 `hitlEnabled=true` 时，Agent 会自动将 `HITLInterceptor` 添加到 ReAct 拦截器链中。


### 8、完整示例：组合使用三种拦截器

```java
// 1. 自定义压缩策略
CompressionStrategy strategy = new CompositeCompressionStrategy()
    .addStrategy(new KeyInfoExtractionStrategy())
    .addStrategy(new HierarchicalCompressionStrategy());

ContextCompressionInterceptor compressionInterceptor =
    new ContextCompressionInterceptor(40, 0.75, 3, strategy);

// 2. 自定义 HITL 策略
HITLInterceptor hitl = new HITLInterceptor()
    .onTool("bash", new BashToolStrategy())
    .onTool("write", new WriteToolStrategy("write"))
    .onSensitiveTool("rm", "del")
    .onApproved((toolName, args) -> {
        engine.addPermissionRule(PermissionRule.allow(toolName));
    });

// 3. 构建引擎
HarnessEngine engine = HarnessEngine.of(workspace, harnessHome)
    .sessionProvider(sessionProvider)
    .compressionInterceptor(compressionInterceptor)
    .hitlInterceptor(hitl)
    .hitlEnabled(true)
    .stopLoopInterceptor(new StopLoopInterceptor(5, 12))
    .toolsAdd("read", "write", "edit", "bash", "glob", "grep", "ls", "hitl")
    .build();

// 运行时动态调整
engine.setHitlEnabled(true);
engine.setCompressionThreshold(50, 0.80);
```
