Solon v3.8.3

react - ReActInterceptor 拦截器

</> markdown
2026年1月15日 下午5:41:17

1、内置拦截器

拦截器名称描述
StopLoopInterceptorReAct 逻辑死循环拦截器该拦截器通过监控 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 具备多重身份,还可以覆盖以下底层方法实现更精细的控制:

继承自拦截方法作用描述
FlowInterceptorinterceptFlow拦截底层的 FlowEngine 执行,可以控制整个执行图是否启动。
onNodeStart拦截 ReAct 流程图中各个具体节点(如 ReasoningNode)的开始。
onNodeEnd拦截 ReAct 流程图中各个具体节点(如 ReasoningNode)的开始
ChatInterceptorinterceptCall作用于最底层的 ChatModel 调用,可直接操作底层的 ChatRequest/Response。
ToolInterceptorinterceptTool最实用的扩展点:可以直接拦截工具的执行链。例如:如果某工具返回 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);
    }
}