LiteFlow LiteFlow
首页
  • v2.16.0 (当前版本)
  • What's New

    • What' s New In LiteFlow v2.15.3?
  • 历史版本

    • v2.15.X
    • v2.13.X
    • v2.12.X
    • v2.11.X
    • v2.10.X
    • v2.9.X
    • v2.8.X
  • 升级指南

    • 2.13.0升级指南
    • 2.12.4升级指南
    • 2.12.0升级指南
    • 升级到2.9.3说明
    • 升级到2.9.X说明
    • 升级到2.8.X说明
    • 升级到2.7.X说明
AI Agent
IDEA 插件
  • 答疑解惑

    • 常见问题
    • 如何理解上下文这个概念?
    • Slot是一个什么样的概念?
  • 项目与社区

    • 项目介绍
    • 项目成员
    • 更新记录
    • 参与开发
    • 加入群聊
    • 谁在使用
赞助
GitHub (opens new window)

广告采用随机轮播方式显示 ❤️成为赞助商
首页
  • v2.16.0 (当前版本)
  • What's New

    • What' s New In LiteFlow v2.15.3?
  • 历史版本

    • v2.15.X
    • v2.13.X
    • v2.12.X
    • v2.11.X
    • v2.10.X
    • v2.9.X
    • v2.8.X
  • 升级指南

    • 2.13.0升级指南
    • 2.12.4升级指南
    • 2.12.0升级指南
    • 升级到2.9.3说明
    • 升级到2.9.X说明
    • 升级到2.8.X说明
    • 升级到2.7.X说明
AI Agent
IDEA 插件
  • 答疑解惑

    • 常见问题
    • 如何理解上下文这个概念?
    • Slot是一个什么样的概念?
  • 项目与社区

    • 项目介绍
    • 项目成员
    • 更新记录
    • 参与开发
    • 加入群聊
    • 谁在使用
赞助
GitHub (opens new window)
  • 🤖 什么是 Re-Act Agent
  • 快速开始

    • 📦 引入依赖
    • ⚙️ 基本配置
    • 🧩 编写 Agent 组件
    • 📤 获取 Agent 结果
    • 🌊 流式输出
  • 🏪 模型配置
  • 会话与记忆

    • 💬 会话标识
    • 🧠 记忆持久化
    • 🔄 多轮对话
  • 工作空间与工具

    • 📂 Workspace 配置
    • 📄 文件工具
    • 🐚 Shell 工具
    • 🔧 自定义工具
  • 🎯 Skills 技能系统
  • 高级编排

    • 🔀 条件路由与并行调用
    • 🤝 多 Agent 协作
  • 运行机制与可观测

    • 🔁 迭代次数与 Summary
    • 📋 Re-Act 事件日志
    • 🪝 自定义 Hook
      • Hook 是什么
      • Hook 接口
      • 事件类型
      • 注册 Hook
      • Hook 与框架内置 Hook 的关系
      • 注意事项
  • 📖 扩展点速查
  • ⚡ 配置速查
  • 🛡️ 安全建议
  • 🔍 故障排查
  • 🎬 演示项目
  • AI Agent编排
  • 运行机制与可观测
铂赛东
2026-05-23
目录

🪝 自定义 Hook

# Hook 是什么

ReActAgent 在执行过程中会在若干关键节点(推理前后、工具调用前后、总结前后、出错时)发出内部事件。Hook 就是监听这些事件的扩展点:你可以用它做审计、埋点、指标统计,甚至改写事件内容。

它和流式输出里的 FlowEvent(agent.reasoning 等)不是一回事:

  • FlowEvent / eventListener 是 LiteFlow 上层封装好的事件流,面向"把过程推给前端"这类场景
  • Hook 是更底层的 agentscope 事件拦截点,能拿到原始的推理消息、工具调用块、token 用量等结构化数据

事实上,框架内置的 Re-Act 日志和 token 用量统计本身就是用 Hook 实现的(见下文)。

# Hook 接口

Hook 是 agentscope 的 io.agentscope.core.hook.Hook 接口,只有一个核心方法:

public interface Hook {
    <T extends HookEvent> Mono<T> onEvent(T event);

    default int priority() {
        return 100;
    }
}
  • onEvent 接收一个事件,返回一个 Mono(Reactor 响应式类型)。放行就返回 Mono.just(event);也可以返回改写后的事件
  • priority() 决定多个 Hook 的执行顺序,默认 100(框架内置日志 Hook 用的是 900)

# 事件类型

通过 instanceof 判断事件类型,再取出对应数据。完整的事件类型如下:

事件类(io.agentscope.core.hook.*) 触发时机 常用访问方法
PreReasoningEvent 模型推理前 getModelName()、getInputMessages()
PostReasoningEvent 模型推理后 getReasoningMessage() → Msg
ReasoningChunkEvent 流式推理的增量片段 增量文本
PreActingEvent 工具调用前 getToolUse() → ToolUseBlock(getName() / getInput())
PostActingEvent 工具调用后 getToolResult() → ToolResultBlock(getName() / getOutput())
ActingChunkEvent 流式工具结果的增量片段 增量内容
PreSummaryEvent 达到迭代上限、生成 Summary 前 —
PostSummaryEvent Summary 生成后 —
SummaryChunkEvent 流式 Summary 的增量片段 —
PreCallEvent / PostCallEvent 一次完整调用的开始 / 结束 —
ErrorEvent 执行出错 getError()

Summary 相关事件与迭代次数与 Summary 对应:只有当 Re-Act 循环达到 maxIterations 被强制收尾时才会触发。

# 注册 Hook

在 Agent 组件中覆写 hooks(),返回要注册的 Hook 列表:

@Override
protected List<Hook> hooks() {
    return List.of(new ToolAuditHook());
}

一个简单的"工具调用审计" Hook 示例——在每次工具调用前记录工具名和入参:

import io.agentscope.core.hook.Hook;
import io.agentscope.core.hook.HookEvent;
import io.agentscope.core.hook.PreActingEvent;
import io.agentscope.core.message.ToolUseBlock;
import reactor.core.publisher.Mono;

public class ToolAuditHook implements Hook {

    @Override
    public <T extends HookEvent> Mono<T> onEvent(T event) {
        if (event instanceof PreActingEvent e) {
            ToolUseBlock tool = e.getToolUse();
            // 这里可以写审计日志、上报指标、做调用计数等
            System.out.println("即将调用工具:" + tool.getName() + " 入参=" + tool.getInput());
        }
        // 必须把事件放行,否则会中断事件流
        return Mono.just(event);
    }

    @Override
    public int priority() {
        return 100;
    }
}

# Hook 与框架内置 Hook 的关系

框架会把你覆写的 hooks() 和它自己的内置 Hook 合并后一起注册,按 priority() 排序执行。内置 Hook 包括:

内置 Hook 作用 开关
ReActLoggingHook 把 reason / act / error 写入 SLF4J 日志 enableReActLogging() / liteflow.agent.logging.react-enabled
ChatUsageTrackingHook 收集本轮 token 用量,供 ctx().getChatUsage() 读取 始终启用
SkillTrackingHook 记录本轮加载过的技能,供 usedSkills() 读取 开启 Skills 时启用

所以即使你不写任何自定义 Hook,框架内部也已经在用 Hook 机制。ReActLoggingHook 就是一份现成的完整范例——它演示了如何区分各类事件、如何从 PostReasoningEvent 取出推理文本和 ChatUsage、如何安全地截断超长文本。

# 注意事项

Hook 是构建期能力声明

和 tools()、systemPrompt() 一样,hooks() 只在同一 (conversationId, agentKey) 首次构建并缓存 Agent 时生效。不要让它依赖单次请求数据;需要按请求隔离时,应把请求维度体现在 agentKey() 或 conversationId() 中。详见扩展点速查。

不要在 Hook 中持有 ctx() 引用

Hook 会被缓存并跨多次调用复用。不要在 Hook 内保存某次调用的 ReActAgentContext 引用,否则会拿到过期的上下文。如需访问当前 Slot/workspace,应保存组件实例,运行时通过组件间接调用 ctx()(与自定义工具的处理方式一致)。

不要阻塞、不要抛异常

Hook 运行在 agentscope 的响应式执行管线中。请只做轻量处理(打点、入队),不要执行耗时阻塞 I/O;并自行 try/catch,避免 Hook 内部异常影响 Agent 主流程。框架内置的 ReActLoggingHook 就把整段逻辑包在 try/catch 里。

帮助我们改善此文档 (opens new window)
上次更新: 2026/06/02, 00:29:19
📋 Re-Act 事件日志
📖 扩展点速查

← 📋 Re-Act 事件日志 📖 扩展点速查→

Theme by Vdoing | Copyright © 2020-2026 铂赛东 | MIT License
沪ICP备18012955号-2