react - ReActInterceptor 拦截器
2026年1月15日 下午5:41:17
1、内置拦截器
| 拦截器 | 名称 | 描述 |
|---|---|---|
| StopLoopInterceptor | ReAct 逻辑死循环拦截器 | 该拦截器通过监控 LLM 的输出内容指纹,防止智能体陷入无效的迭代循环 |
| SummarizationInterceptor | 智能上下文压缩拦截器 | 该拦截器通过“滑动窗口”机制,在保证 ReAct 逻辑链完整性的前提下,对 ReActTrace 历史消息进行截断压缩。 |
| ToolRetryInterceptor | 工具执行重试拦截器 | 该拦截器为 ReAct 模式下的工具调用提供韧性支持,具备物理重试与逻辑自愈双重机制。 |
| ToolSanitizerInterceptor | 工具结果净化拦截器 | 该拦截器在 ReAct 模式的 Observation 阶段执行,负责对工具返回的原始数据进行加工。 |
2、ReActInterceptor 各时机点说明
| 层级 | 拦截方法 | 触发时机 | 典型应用场景 |
|---|---|---|---|
| 智能体级 | onAgentStart | 智能体开始运行(初始化后) | 记录全流程追踪 ID、预加载 Session 数据 |
| onAgentEnd | 智能体完成任务(Final Answer)或达到步数限制 | 统计总 Token 消耗、清理临时资源、持久化轨迹 | |
| 模型级 | onModelStart | 向 LLM 发起单次推理请求之前 | 动态注入 Stop 词、修改温度参数、Prompt 安全检测 |
| onModelEnd | 获取到模型响应,但尚未开始解析逻辑时 | 内容风险过滤、检测“复读机”死循环、原始响应存档 | |
| 循环级 | onThought | 模型推理结果解析出 Thought 部分时 | UI 打字机效果展示、记录思维链(CoT)日志 |
| onAction | 模型解析出工具调用(Action),执行前触发 | 工具调用权限校验、参数格式二次修正、计费预警 | |
| onObservation | 工具执行完毕,获取到结果(Observation)后 | 观测外部系统返回数据、敏感信息脱敏、数据清洗 |
由于 ReActInterceptor 具备多重身份,还可以覆盖以下底层方法实现更精细的控制:
| 继承自 | 拦截方法 | 作用描述 |
|---|---|---|
| FlowInterceptor | interceptFlow | 拦截底层的 FlowEngine 执行,可以控制整个执行图是否启动。 |
| onNodeStart | 拦截 ReAct 流程图中各个具体节点(如 ReasoningNode)的开始。 | |
| onNodeEnd | 拦截 ReAct 流程图中各个具体节点(如 ReasoningNode)的开始 | |
| ChatInterceptor | interceptCall | 作用于最底层的 ChatModel 调用,可直接操作底层的 ChatRequest/Response。 |
| ToolInterceptor | interceptTool | 最实用的扩展点:可以直接拦截工具的执行链。例如:如果某工具返回 404,拦截器可以直接伪造一个“请检查参数”的返回给模型。 |
3、ReActInterceptor 拦截器接口参考
ReActInterceptor 拦截器,同时继承了 FlowInterceptor 和 ChatInterceptor,所以它还可以拦截流程图(Flow)和聊天模型(ChatModel)的执行。
ReActInterceptor
import org.noear.solon.ai.chat.ChatRequestDesc;
import org.noear.solon.ai.chat.ChatResponse;
import org.noear.solon.ai.chat.interceptor.ChatInterceptor;
import org.noear.solon.flow.intercept.FlowInterceptor;
import org.noear.solon.lang.Preview;
import java.util.Map;
/**
* ReAct 拦截器
* <p>提供对 ReAct 智能体执行全生命周期的监控与干预能力。包括智能体起止、模型推理前后以及工具执行环。</p>
*/
public interface ReActInterceptor extends FlowInterceptor, ChatInterceptor {
/**
* 智能体生命周期:开始执行时触发
* <p>常用于初始化上下文、记录开始日志或准备外部追踪 ID。</p>
*/
default void onAgentStart(ReActTrace trace) {
}
/**
* 模型推理生命周期:发起模型请求前触发
* <p>作用于 {@code ReasonTask} 的单次推理尝试。可用于修改模型请求参数(如 stop 词)、预估 Token 消耗或安全审计。</p>
*/
default void onModelStart(ReActTrace trace, ChatRequestDesc req) {
}
/**
* 模型推理生命周期:模型响应后,解析逻辑执行前触发
* <p>作用:可以拦截模型的原始回复(Raw Content),进行内容风控、复读机检测(死循环拦截)或原始数据观测。</p>
*/
default void onModelEnd(ReActTrace trace, ChatResponse resp) {
}
/**
* ReAct 循环生命周期:解析出思考内容(Thought)时触发
* <p>反映了模型内部的推理过程,可用于前端打字机展示或推理链路观测。</p>
*/
default void onThought(ReActTrace trace, String thought) {
}
/**
* ReAct 循环生命周期:调用工具(Action)前触发
* <p>可用于工具权限校验、参数预检或记录工具执行轨迹。</p>
*/
default void onAction(ReActTrace trace, String toolName, Map<String, Object> args) {
}
/**
* ReAct 循环生命周期:获得工具执行结果(Observation)后触发
* <p>可用于清洗工具返回的数据或监控工具执行质量。</p>
*/
default void onObservation(ReActTrace trace, String result) {
}
/**
* 智能体生命周期:任务结束(得到 Final Answer 或达到最大步数)时触发
* <p>常用于统计总消耗、清理资源或持久化对话结果。</p>
*/
default void onAgentEnd(ReActTrace trace) {
}
}
FlowInterceptor
import org.noear.solon.flow.*;
import org.noear.solon.lang.Preview;
/**
* 流拦截器
*/
public interface FlowInterceptor {
/**
* 拦截流程执行, eval(graph)
*
* @param invocation 调用者
* @see org.noear.solon.flow.FlowEngine#eval(Graph, FlowExchanger)
*/
default void interceptFlow(FlowInvocation invocation) throws FlowException {
invocation.invoke();
}
/**
* 节点运行开始时
*
* @since 3.4
*/
default void onNodeStart(FlowContext context, Node node) {
}
/**
* 节点运行结束时
*
* @since 3.4
*/
default void onNodeEnd(FlowContext context, Node node) {
}
}
ChatInterceptor
import org.noear.solon.ai.chat.ChatRequest;
import org.noear.solon.ai.chat.ChatResponse;
import org.reactivestreams.Publisher;
import java.io.IOException;
/**
* 聊天拦截器
*/
public interface ChatInterceptor extends ToolInterceptor {
/**
* 拦截 Call 请求
*
* @param req 请求
* @param chain 拦截链
*/
default ChatResponse interceptCall(ChatRequest req, CallChain chain) throws IOException {
return chain.doIntercept(req);
}
/**
* 拦截 Stream 请求
*
* @param req 请求
* @param chain 拦截链
*/
default Publisher<ChatResponse> interceptStream(ChatRequest req, StreamChain chain) {
return chain.doIntercept(req);
}
}