本章导读
本章将深入讲解AgentScope的Hook系统。Hook是责任链模式的实现,它允许你在Agent执行的各个阶段插入自定义逻辑,实现日志记录、性能监控、内容增强、安全检查等功能。Hook系统是AgentScope可扩展性的核心。
- 理解Hook系统的设计理念和工作原理
- 掌握Hook接口和事件类型
- 学会实现自定义Hook
- 了解Hook的实际应用场景
- 掌握Hook的最佳实践
8.1 Hook系统设计理念
8.1.1 什么是Hook
在AgentScope中,Hook是一种事件拦截机制,允许你在Agent执行的关键节点插入自定义逻辑。
类比:钓鱼的鱼钩
事件流 ────→ PreReasoningEvent ────→ 推理阶段
↓
Hook1捕获
↓
Hook2捕获
↓
Hook3捕获
↓
继续流动 ────→
每个Hook都有机会:
- 观察事件(日志记录)
- 修改事件(内容增强)
- 阻止事件(安全检查)
8.1.2 Hook的工作原理
Hook采用责任链模式(Chain of Responsibility),多个Hook按顺序处理同一个事件。
Agent执行流程与Hook触发点:
用户输入
↓
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
第N轮推理-行动循环
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
↓
[1] PreReasoningEvent触发
├─ Hook1.onEvent(PreReasoningEvent)
├─ Hook2.onEvent(PreReasoningEvent)
└─ Hook3.onEvent(PreReasoningEvent)
↓
推理阶段执行(调用LLM)
├─ ReasoningChunkEvent触发(流式,多次)
│ ├─ Hook1.onEvent(ReasoningChunkEvent)
│ ├─ Hook2.onEvent(ReasoningChunkEvent)
│ └─ Hook3.onEvent(ReasoningChunkEvent)
↓
[2] PostReasoningEvent触发
├─ Hook1.onEvent(PostReasoningEvent)
├─ Hook2.onEvent(PostReasoningEvent)
└─ Hook3.onEvent(PostReasoningEvent)
↓
检查是否需要执行工具
↓
[3] PreActingEvent触发(如果有工具调用)
├─ Hook1.onEvent(PreActingEvent)
├─ Hook2.onEvent(PreActingEvent)
└─ Hook3.onEvent(PreActingEvent)
↓
执行工具
├─ ActingChunkEvent触发(可能有)
↓
[4] PostActingEvent触发
├─ Hook1.onEvent(PostActingEvent)
├─ Hook2.onEvent(PostActingEvent)
└─ Hook3.onEvent(PostActingEvent)
↓
继续下一轮或完成
8.1.3 Hook接口设计
package io.agentscope.core.hook;
import reactor.core.publisher.Mono;
/**
* Hook接口定义了事件处理的规范
*/
public interface Hook {
/**
* 处理事件
*
* @param event 事件对象(可能是PreReasoningEvent、PostReasoningEvent等)
* @param <T> 事件类型
* @return 处理后的事件(可以修改事件内容)
*/
<T extends HookEvent> Mono<T> onEvent(T event);
/**
* Hook的优先级
* 数字越小,优先级越高(越早执行)
*
* @return 优先级值(默认100)
*/
default int getPriority() {
return 100;
}
}
Hook的特点:
1. 泛型设计
- 一个Hook可以处理多种事件类型
- 通过instanceof判断事件类型
2. 响应式
- 返回Mono<T>,支持异步处理
- 可以与其他异步操作组合
3. 链式调用
- 多个Hook按优先级顺序执行
- 每个Hook都可以修改事件
4. 非侵入式
- 不修改Agent核心代码
- 通过配置添加/移除Hook
8.2 核心Hook事件(Why - 为什么需要这些事件)
8.2.1 事件类型总览
AgentScope定义了6种核心事件:
推理阶段(3种):
├─ PreReasoningEvent # 推理前
├─ ReasoningChunkEvent # 推理流式内容
└─ PostReasoningEvent # 推理后
行动阶段(3种):
├─ PreActingEvent # 行动前(工具执行前)
├─ ActingChunkEvent # 行动流式内容
└─ PostActingEvent # 行动后(工具执行后)
8.2.2 推理阶段的事件
PreReasoningEvent - 推理前事件
/**
* 推理前触发的事件
* 可以修改输入消息、系统提示词、工具列表
*/
public class PreReasoningEvent extends HookEvent {
// ===== 只读字段 =====
private final String agentName;
private final int iterationCount; // 第几轮推理
private final long timestamp;
// ===== 可修改字段 =====
private List<Msg> inputMessages; // 输入消息(可修改)
private String systemPrompt; // 系统提示词(可修改)
private List<ToolSchema> availableTools; // 可用工具(可修改)
// Getter和Setter...
public void setInputMessages(List<Msg> messages) {
this.inputMessages = messages;
}
}
典型应用:
// 应用1:RAG增强
Hook ragHook = new Hook() {
@Override
public <T extends HookEvent> Mono<T> onEvent(T event) {
if (event instanceof PreReasoningEvent pre) {
// 检索相关文档
List<Document> docs = knowledge.retrieve(
extractQuery(pre.getInputMessages())
);
// 添加到输入消息
List<Msg> enhanced = new ArrayList<>(pre.getInputMessages());
enhanced.add(0, createRAGMessage(docs));
pre.setInputMessages(enhanced);
}
return Mono.just(event);
}
};
// 应用2:动态调整系统提示词
Hook promptHook = new Hook() {
@Override
public <T extends HookEvent> Mono<T> onEvent(T event) {
if (event instanceof PreReasoningEvent pre) {
String enhancedPrompt = pre.getSystemPrompt() +
"\n当前时间: " + LocalDateTime.now() +
"\n用户偏好: " + getUserPreferences();
pre.setSystemPrompt(enhancedPrompt);
}
return Mono.just(event);
}
};
ReasoningChunkEvent - 推理流式内容
/**
* 推理过程中的流式内容
* 实时接收LLM生成的每个Token或块
*/
public class ReasoningChunkEvent extends HookEvent {
private final String delta; // 增量内容(一个Token或一个块)
private final ContentBlock contentBlock; // 内容块(可能是TextBlock、ToolUseBlock等)
private final String modelName;
private final long timestamp;
// 只读,不可修改
}
典型应用:
// 应用:实时展示推理过程
Hook streamingHook = new Hook() {
@Override
public <T extends HookEvent> Mono<T> onEvent(T event) {
if (event instanceof ReasoningChunkEvent chunk) {
// 实时打印到控制台
System.out.print(chunk.getDelta());
// 或推送到WebSocket
webSocketSession.send(chunk.getDelta());
// 或更新UI
Platform.runLater(() -> textArea.appendText(chunk.getDelta()));
}
return Mono.just(event);
}
};
PostReasoningEvent - 推理后事件
/**
* 推理完成后触发的事件
* 包含推理结果和性能指标
*/
public class PostReasoningEvent extends HookEvent {
private final Msg reasoningResult; // 推理结果
private final long executionTime; // 推理耗时(毫秒)
private final ChatUsage usage; // Token使用情况
private final String modelName;
// 只读,不可修改
}
典型应用:
// 应用1:性能监控
Hook monitoringHook = new Hook() {
@Override
public <T extends HookEvent> Mono<T> onEvent(T event) {
if (event instanceof PostReasoningEvent post) {
// 记录指标
metrics.record("reasoning_duration_ms", post.getExecutionTime());
metrics.record("tokens_used", post.getUsage().getTotalTokens());
// 如果超过阈值,发送告警
if (post.getExecutionTime() > 10000) {
alertService.send("推理耗时过长: " + post.getExecutionTime() + "ms");
}
}
return Mono.just(event);
}
};
// 应用2:日志记录
Hook loggingHook = new Hook() {
@Override
public <T extends HookEvent> Mono<T> onEvent(T event) {
if (event instanceof PostReasoningEvent post) {
logger.info(
"推理完成 - 耗时: {}ms, Tokens: {}, 是否调用工具: {}",
post.getExecutionTime(),
post.getUsage().getTotalTokens(),
post.getReasoningResult().getContent().stream()
.anyMatch(c -> c instanceof ToolUseBlock)
);
}
return Mono.just(event);
}
};
8.2.3 行动阶段的事件
PreActingEvent - 工具执行前事件
/**
* 工具执行前触发的事件
*/
public class PreActingEvent extends HookEvent {
private final String toolName; // 工具名称
private final Map<String, Object> toolArgs; // 工具参数
private final String toolCallId; // 工具调用ID
private final long timestamp;
// 只读,不可修改
}
典型应用:
// 应用:工具调用审计
Hook auditHook = new Hook() {
@Override
public <T extends HookEvent> Mono<T> onEvent(T event) {
if (event instanceof PreActingEvent pre) {
auditLog.log(
"工具调用 - 名称: {}, 参数: {}",
pre.getToolName(),
pre.getToolArgs()
);
}
return Mono.just(event);
}
};
PostActingEvent - 工具执行后事件
/**
* 工具执行后触发的事件
*/
public class PostActingEvent extends HookEvent {
private final String toolName; // 工具名称
private final String toolResult; // 工具执行结果
private final boolean isError; // 是否出错
private final long executionTime; // 执行耗时
private final String errorMessage; // 错误信息(如果有)
// 只读,不可修改
}
典型应用:
// 应用:工具性能监控
Hook toolMonitoringHook = new Hook() {
@Override
public <T extends HookEvent> Mono<T> onEvent(T event) {
if (event instanceof PostActingEvent post) {
metrics.record(
"tool_execution_time",
post.getExecutionTime(),
Map.of("tool_name", post.getToolName())
);
if (post.isError()) {
errorLog.error(
"工具执行失败 - 工具: {}, 错误: {}",
post.getToolName(),
post.getErrorMessage()
);
}
}
return Mono.just(event);
}
};
8.3 Hook的实际应用(How - 如何使用)
8.3.1 应用1:日志记录Hook
完整的日志记录Hook,记录Agent执行的每个阶段。
import io.agentscope.core.hook.Hook;
import io.agentscope.core.hook.HookEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;
/**
* 日志记录Hook
* 记录Agent执行的所有关键事件
*/
public class LoggingHook implements Hook {
private static final Logger logger = LoggerFactory.getLogger(LoggingHook.class);
@Override
public <T extends HookEvent> Mono<T> onEvent(T event) {
return Mono.just(event).doOnNext(e -> logEvent(e));
}
private void logEvent(HookEvent event) {
switch(event) {
case PreReasoningEvent pre -> {
logger.info("━━━━━ 推理开始 ━━━━━");
logger.info("Agent: {}", pre.getAgentName());
logger.info("轮次: {}", pre.getIterationCount());
logger.info("输入消息数: {}", pre.getInputMessages().size());
logger.info("可用工具数: {}", pre.getAvailableTools().size());
}
case ReasoningChunkEvent chunk -> {
logger.debug("推理流: {}", chunk.getDelta());
}
case PostReasoningEvent post -> {
logger.info("━━━━━ 推理完成 ━━━━━");
logger.info("耗时: {}ms", post.getExecutionTime());
logger.info("Token使用: {} (输入: {}, 输出: {})",
post.getUsage().getTotalTokens(),
post.getUsage().getPromptTokens(),
post.getUsage().getCompletionTokens()
);
boolean hasToolCall = post.getReasoningResult().getContent().stream()
.anyMatch(c -> c instanceof ToolUseBlock);
logger.info("是否调用工具: {}", hasToolCall);
}
case PreActingEvent pre -> {
logger.info("━━━━━ 工具执行开始 ━━━━━");
logger.info("工具名称: {}", pre.getToolName());
logger.info("工具参数: {}", pre.getToolArgs());
}
case PostActingEvent post -> {
logger.info("━━━━━ 工具执行完成 ━━━━━");
logger.info("工具名称: {}", post.getToolName());
logger.info("耗时: {}ms", post.getExecutionTime());
logger.info("是否出错: {}", post.isError());
if (post.isError()) {
logger.error("错误信息: {}", post.getErrorMessage());
} else {
logger.info("执行结果: {}",
post.getToolResult().substring(0, Math.min(100, post.getToolResult().length())));
}
}
default -> {}
}
}
@Override
public int getPriority() {
return 10; // 高优先级,最先执行
}
}
// 使用示例
ReActAgent agent = ReActAgent.builder()
.name("Agent")
.model(model)
.toolkit(toolkit)
.hooks(List.of(new LoggingHook()))
.build();
日志输出示例:
INFO - ━━━━━ 推理开始 ━━━━━
INFO - Agent: Agent
INFO - 轮次: 1
INFO - 输入消息数: 1
INFO - 可用工具数: 5
INFO - ━━━━━ 推理完成 ━━━━━
INFO - 耗时: 1250ms
INFO - Token使用: 450 (输入: 320, 输出: 130)
INFO - 是否调用工具: true
INFO - ━━━━━ 工具执行开始 ━━━━━
INFO - 工具名称: query_database
INFO - 工具参数: {sql=SELECT * FROM users WHERE id = 123}
INFO - ━━━━━ 工具执行完成 ━━━━━
INFO - 工具名称: query_database
INFO - 耗时: 85ms
INFO - 是否出错: false
INFO - 执行结果: {"id":123,"name":"张三","age":28}
8.3.2 应用2:性能监控Hook
监控Agent的性能指标,发送到监控系统。
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
/**
* 性能监控Hook
* 集成Prometheus、DataDog等监控系统
*/
public class MetricsHook implements Hook {
private final MeterRegistry registry;
public MetricsHook(MeterRegistry registry) {
this.registry = registry;
}
@Override
public <T extends HookEvent> Mono<T> onEvent(T event) {
return switch(event) {
case PostReasoningEvent post ->
Mono.just(event).doOnNext(e -> recordReasoningMetrics(post));
case PostActingEvent post ->
Mono.just(event).doOnNext(e -> recordToolMetrics(post));
default -> Mono.just(event);
};
}
private void recordReasoningMetrics(PostReasoningEvent event) {
// 记录推理耗时
Timer.builder("agent.reasoning.duration")
.tag("agent", event.getAgentName())
.tag("model", event.getModelName())
.register(registry)
.record(event.getExecutionTime(), TimeUnit.MILLISECONDS);
// 记录Token使用
registry.counter("agent.tokens.total",
"agent", event.getAgentName(),
"type", "total"
).increment(event.getUsage().getTotalTokens());
registry.counter("agent.tokens.prompt",
"agent", event.getAgentName()
).increment(event.getUsage().getPromptTokens());
registry.counter("agent.tokens.completion",
"agent", event.getAgentName()
).increment(event.getUsage().getCompletionTokens());
// 记录推理次数
registry.counter("agent.reasoning.count",
"agent", event.getAgentName()
).increment();
}
private void recordToolMetrics(PostActingEvent event) {
// 记录工具执行耗时
Timer.builder("agent.tool.duration")
.tag("tool", event.getToolName())
.tag("status", event.isError() ? "error" : "success")
.register(registry)
.record(event.getExecutionTime(), TimeUnit.MILLISECONDS);
// 记录工具调用次数
registry.counter("agent.tool.calls",
"tool", event.getToolName(),
"status", event.isError() ? "error" : "success"
).increment();
// 记录工具错误
if (event.isError()) {
registry.counter("agent.tool.errors",
"tool", event.getToolName()
).increment();
}
}
}
// 使用示例
MeterRegistry registry = new SimpleMeterRegistry();
ReActAgent agent = ReActAgent.builder()
.name("MonitoredAgent")
.hooks(List.of(new MetricsHook(registry)))
.build();
// 指标会自动发送到Prometheus等监控系统
8.3.3 应用3:RAG集成Hook
在推理前自动检索相关知识,增强Agent的回答能力。
import io.agentscope.core.rag.Knowledge;
import io.agentscope.core.rag.RetrieveConfig;
/**
* RAG增强Hook
* 自动检索相关文档并添加到输入消息
*/
public class RAGHook implements Hook {
private final Knowledge knowledge;
private final int topK;
private final double scoreThreshold;
public RAGHook(Knowledge knowledge, int topK, double scoreThreshold) {
this.knowledge = knowledge;
this.topK = topK;
this.scoreThreshold = scoreThreshold;
}
@Override
public <T extends HookEvent> Mono<T> onEvent(T event) {
if (!(event instanceof PreReasoningEvent pre)) {
return Mono.just(event);
}
// 从用户消息提取查询
String query = extractQuery(pre.getInputMessages());
// 检索相关文档
return knowledge.retrieve(query, RetrieveConfig.builder()
.limit(topK)
.scoreThreshold(scoreThreshold)
.build())
.doOnNext(documents -> {
if (documents.isEmpty()) {
return;
}
// 格式化检索结果
String ragContext = formatDocuments(documents);
// 创建RAG消息
Msg ragMsg = Msg.builder()
.role(MsgRole.SYSTEM)
.textContent(
"以下是与用户问题相关的背景信息,请参考这些信息回答用户:\n\n" +
ragContext
)
.metadata("source", "rag")
.build();
// 添加到输入消息(放在最前面)
List<Msg> enhanced = new ArrayList<>();
enhanced.add(ragMsg);
enhanced.addAll(pre.getInputMessages());
pre.setInputMessages(enhanced);
})
.thenReturn(event);
}
private String extractQuery(List<Msg> messages) {
// 提取最近的用户消息作为查询
return messages.stream()
.filter(m -> m.getRole() == MsgRole.USER)
.map(Msg::getTextContent)
.reduce((first, second) -> second) // 取最后一条
.orElse("");
}
private String formatDocuments(List<Document> documents) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < documents.size(); i++) {
Document doc = documents.get(i);
sb.append(String.format(
"[文档%d] (相关度: %.2f)\n%s\n\n",
i + 1,
doc.getScore(),
doc.getContent()
));
}
return sb.toString();
}
@Override
public int getPriority() {
return 50; // 中等优先级
}
}
// 使用示例
Knowledge knowledge = createKnowledge(); // 创建知识库
ReActAgent agent = ReActAgent.builder()
.name("RAGAgent")
.model(model)
.hooks(List.of(
new RAGHook(knowledge, 5, 0.7) // 检索top 5,相似度>0.7
))
.build();
// 用户提问时,自动检索相关文档
agent.call("AgentScope支持哪些LLM?").block();
// Hook自动:
// 1. 检索相关文档
// 2. 添加到输入消息
// 3. LLM基于检索结果回答
8.3.4 应用4:安全检查Hook
在推理前检查输入安全性,防止注入攻击。
/**
* 安全检查Hook
* 检测和过滤危险输入
*/
public class SecurityHook implements Hook {
private final List<String> blockedPatterns = List.of(
"ignore previous instructions",
"disregard",
"system prompt",
"你现在是",
"忽略之前的指令"
);
@Override
public <T extends HookEvent> Mono<T> onEvent(T event) {
if (!(event instanceof PreReasoningEvent pre)) {
return Mono.just(event);
}
// 检查用户输入
List<Msg> messages = pre.getInputMessages();
for (Msg msg : messages) {
if (msg.getRole() != MsgRole.USER) {
continue;
}
String content = msg.getTextContent().toLowerCase();
// 检测危险模式
for (String pattern : blockedPatterns) {
if (content.contains(pattern)) {
logger.warn("检测到可疑输入: {}", content);
// 可以选择:
// 1. 阻止请求
return Mono.error(new SecurityException(
"检测到不安全的输入,请求被拒绝"));
// 2. 或者清理输入
// msg.setTextContent(sanitize(content));
}
}
}
return Mono.just(event);
}
@Override
public int getPriority() {
return 1; // 最高优先级,最先执行
}
}
8.3.5 应用5:成本控制Hook
监控和限制Token使用,控制成本。
/**
* 成本控制Hook
* 限制Token使用,防止成本超标
*/
public class CostControlHook implements Hook {
private final AtomicLong totalTokens = new AtomicLong(0);
private final long maxTokensPerSession;
private final double costPerToken;
public CostControlHook(long maxTokensPerSession, double costPerToken) {
this.maxTokensPerSession = maxTokensPerSession;
this.costPerToken = costPerToken;
}
@Override
public <T extends HookEvent> Mono<T> onEvent(T event) {
if (event instanceof PostReasoningEvent post) {
long tokens = post.getUsage().getTotalTokens();
long total = totalTokens.addAndGet(tokens);
logger.info("Token使用: {} (总计: {}/{})",
tokens, total, maxTokensPerSession);
// 检查是否超限
if (total > maxTokensPerSession) {
logger.error("Token使用超限!");
return Mono.error(new CostLimitExceededException(
"Token使用超过限制: " + total + "/" + maxTokensPerSession
));
}
// 计算成本
double cost = total * costPerToken;
logger.info("当前成本: ${}", String.format("%.4f", cost));
}
return Mono.just(event);
}
public void resetCounter() {
totalTokens.set(0);
}
public long getTotalTokens() {
return totalTokens.get();
}
public double getTotalCost() {
return totalTokens.get() * costPerToken;
}
}
// 使用示例
CostControlHook costHook = new CostControlHook(
100000, // 每个会话最多10万Token
0.002 // 每个Token成本$0.002
);
ReActAgent agent = ReActAgent.builder()
.name("CostControlledAgent")
.hooks(List.of(costHook))
.build();
// 查询成本
System.out.println("总Token: " + costHook.getTotalTokens());
System.out.println("总成本: $" + costHook.getTotalCost());
8.4 Hook的最佳实践
8.4.1 Hook设计原则
原则1:单一职责
✓ 每个Hook只做一件事
✓ 日志Hook只记录日志,监控Hook只记录指标
原则2:最小副作用
✓ 尽量不修改事件内容
✓ 如果必须修改,记录日志
原则3:性能优先
✓ Hook会在每次调用时执行,必须高效
✓ 避免阻塞操作
✓ 使用异步API
原则4:错误隔离
✓ Hook出错不应影响Agent执行
✓ 捕获所有异常
✓ 使用doOnError处理错误
8.4.2 Hook优先级管理
/**
* Hook执行顺序示例
*/
public class HookPriorityExample {
public static void main(String[] args) {
Hook securityHook = new SecurityHook(); // priority = 1
Hook loggingHook = new LoggingHook(); // priority = 10
Hook ragHook = new RAGHook(...); // priority = 50
Hook metricsHook = new MetricsHook(...); // priority = 100
// 执行顺序(从小到大):
// 1. securityHook (priority=1) - 最先执行,检查安全
// 2. loggingHook (priority=10) - 记录日志
// 3. ragHook (priority=50) - RAG增强
// 4. metricsHook (priority=100) - 记录指标
ReActAgent agent = ReActAgent.builder()
.hooks(List.of(securityHook, loggingHook, ragHook, metricsHook))
.build();
// AgentScope会自动按优先级排序
}
}
8.4.3 异步Hook的实现
/**
* 异步Hook示例
* 不阻塞Agent执行
*/
public class AsyncMetricsHook implements Hook {
private final WebClient metricsClient;
@Override
public <T extends HookEvent> Mono<T> onEvent(T event) {
if (event instanceof PostReasoningEvent post) {
// 异步发送指标,不阻塞
sendMetricsAsync(post)
.subscribeOn(Schedulers.boundedElastic())
.subscribe(
result -> logger.debug("指标已发送"),
error -> logger.error("指标发送失败", error)
);
}
// 立即返回,不等待异步操作完成
return Mono.just(event);
}
private Mono<Void> sendMetricsAsync(PostReasoningEvent event) {
return metricsClient.post()
.uri("/metrics")
.bodyValue(Map.of(
"duration", event.getExecutionTime(),
"tokens", event.getUsage().getTotalTokens()
))
.retrieve()
.bodyToMono(Void.class)
.timeout(Duration.ofSeconds(5))
.onErrorResume(error -> {
logger.error("发送指标失败", error);
return Mono.empty();
});
}
}
8.5 生产场景:完整的Hook系统
让我们通过一个完整的生产级示例,展示多个Hook协同工作。
/**
* 生产级Hook配置
* 集成日志、监控、RAG、安全等功能
*/
public class ProductionHookConfiguration {
public static List<Hook> createProductionHooks(
MeterRegistry registry,
Knowledge knowledge) {
return List.of(
// 1. 安全检查(最高优先级)
new SecurityHook(),
// 2. 日志记录
new LoggingHook(),
// 3. 成本控制
new CostControlHook(100000, 0.002),
// 4. RAG增强
new RAGHook(knowledge, 5, 0.7),
// 5. 性能监控
new MetricsHook(registry),
// 6. 错误追踪
new ErrorTrackingHook()
);
}
}
// 使用示例
public class ProductionAgentSetup {
public static void main(String[] args) {
// 创建监控注册表
MeterRegistry registry = new PrometheusMeterRegistry(
PrometheusConfig.DEFAULT
);
// 创建知识库
Knowledge knowledge = createKnowledge();
// 创建生产级Agent
ReActAgent agent = ReActAgent.builder()
.name("ProductionAgent")
.model(model)
.toolkit(toolkit)
.memory(new InMemoryMemory())
.hooks(ProductionHookConfiguration.createProductionHooks(
registry, knowledge
))
.build();
// Agent现在具备:
// ✓ 安全检查
// ✓ 完整日志
// ✓ 成本控制
// ✓ RAG增强
// ✓ 性能监控
// ✓ 错误追踪
}
}
8.6 本章总结
关键要点
-
Hook系统设计
- 责任链模式实现
- 6种核心事件类型
- 可修改和只读事件
-
Hook接口
- onEvent()方法处理事件
- getPriority()定义优先级
- 响应式编程支持
-
实际应用
- 日志记录:LoggingHook
- 性能监控:MetricsHook
- RAG增强:RAGHook
- 安全检查:SecurityHook
- 成本控制:CostControlHook
-
最佳实践
- 单一职责原则
- 最小副作用
- 异步执行
- 错误隔离
Hook开发检查清单
设计阶段:
☐ 明确Hook的单一职责
☐ 确定需要处理的事件类型
☐ 设计Hook的优先级
实现阶段:
☐ 实现Hook接口
☐ 使用switch表达式处理不同事件
☐ 避免阻塞操作
☐ 添加错误处理
测试阶段:
☐ 测试Hook对各种事件的处理
☐ 测试Hook的性能影响
☐ 测试Hook的错误处理
☐ 测试Hook的优先级
部署阶段:
☐ 配置合适的优先级
☐ 添加监控和告警
☐ 文档化Hook的作用
下一章预告
第9章将深入讲解Formatter与多模型适配,探讨如何自动转换消息格式以适配不同的LLM厂商,实现真正的多模型支持。