@@ -17,9 +17,9 @@ Agent Hooks 是在 Agent 运行特定节点执行的回调方法。所有 Hook
1717- ** Termination Hooks** :自定义完成条件强制执行
1818- ** Request Preparation** :动态系统提示和工具修改
1919
20- ## 核心 Hook 类别
20+ ## 核心 Hook
2121
22- ### LLM 通信 Hooks
22+ ### LLM 交互 Hook
2323
2424拦截和监控 LLM 请求和响应:
2525
@@ -30,32 +30,32 @@ class MonitoringAgent extends Agent {
3030 // 在每个 LLM 请求之前调用
3131 override async onLLMRequest(id : string , payload : LLMRequestHookPayload ) {
3232 console .log (` [${id }] 发送请求到 ${payload .model } ` );
33- console .log (' 消息数量 :' , payload .messages .length );
33+ console .log (' Messages count :' , payload .messages .length );
3434
3535 // 记录 token 使用估算
3636 const tokenEstimate = this .estimateTokens (payload .messages );
37- console .log (' 预估 tokens:' , tokenEstimate );
37+ console .log (' Estimated tokens:' , tokenEstimate );
3838 }
3939
4040 // 在每个 LLM 响应之后调用
4141 override async onLLMResponse(id : string , payload : LLMResponseHookPayload ) {
4242 const response = payload .response ;
4343 console .log (` [${id }] 收到响应: ` );
44- console .log (' 使用情况 :' , response .usage );
45- console .log (' 完成原因 :' , response .choices [0 ]?.finish_reason );
44+ console .log (' Usage :' , response .usage );
45+ console .log (' Finish reason :' , response .choices [0 ]?.finish_reason );
4646
4747 // 如果存在工具调用则记录
4848 const toolCalls = response .choices [0 ]?.message ?.tool_calls ;
4949 if (toolCalls ?.length ) {
50- console .log (' 工具调用 :' , toolCalls .map (tc => tc .function .name ));
50+ console .log (' Tool calls :' , toolCalls .map (tc => tc .function .name ));
5151 }
5252 }
5353
5454 // 在流式响应期间调用
5555 override onLLMStreamingResponse(id : string , payload : LLMStreamingResponseHookPayload ) {
56- // 实时监控流式块
56+ // 实时监控 streaming chunks
5757 const chunks = payload .chunks ;
58- console .log (` [${id }] 收到 ${chunks .length } 个流式块 ` );
58+ console .log (` [${id }] 收到 ${chunks .length } 个 streaming chunks ` );
5959 }
6060}
6161```
@@ -74,16 +74,16 @@ class ToolMonitoringAgent extends Agent {
7474 toolCall : { toolCallId: string ; name: string },
7575 args : any
7676 ) {
77- console .log (` [${id }] 执行工具 : ${toolCall .name } ` );
78- console .log (' 参数 :' , JSON .stringify (args , null , 2 ));
77+ console .log (` [${id }] Executing tool : ${toolCall .name } ` );
78+ console .log (' Arguments :' , JSON .stringify (args , null , 2 ));
7979
8080 // 跟踪工具使用情况
8181 const currentCount = this .toolUsageStats .get (toolCall .name ) || 0 ;
8282 this .toolUsageStats .set (toolCall .name , currentCount + 1 );
8383
8484 // 验证参数或应用速率限制
8585 if (toolCall .name === ' expensive_api' && currentCount >= 5 ) {
86- throw new Error (' expensive_api 超出速率限制 ' );
86+ throw new Error (' Rate limit exceeded for expensive_api ' );
8787 }
8888
8989 // 返回可能修改的参数
@@ -96,14 +96,14 @@ class ToolMonitoringAgent extends Agent {
9696 toolCall : { toolCallId: string ; name: string },
9797 result : any
9898 ) {
99- console .log (` [${id }] 工具 ${toolCall .name } 完成 ` );
100- console .log (' 结果类型 :' , typeof result );
99+ console .log (` [${id }] Tool ${toolCall .name } completed ` );
100+ console .log (' Result type :' , typeof result );
101101
102102 // 记录错误或成功结果
103103 if (result ?.error ) {
104- console .error (' 工具执行失败 :' , result .error );
104+ console .error (' Tool execution failed :' , result .error );
105105 } else {
106- console .log (' 工具执行成功 ' );
106+ console .log (' Tool execution successful ' );
107107 }
108108
109109 // 返回可能修改的结果
@@ -116,14 +116,14 @@ class ToolMonitoringAgent extends Agent {
116116 toolCall : { toolCallId: string ; name: string },
117117 error : any
118118 ) {
119- console .error (` [${id }] 工具 ${toolCall .name } 失败 : ` , error );
119+ console .error (` [${id }] Tool ${toolCall .name } failed : ` , error );
120120
121121 // 实现重试逻辑或错误转换
122122 if (error .message ?.includes (' timeout' )) {
123- return ' 工具执行超时。请稍后重试。 ' ;
123+ return ' Tool execution timed out. Please try again later. ' ;
124124 }
125125
126- return ` 错误 : ${error .message || error }` ;
126+ return ` Error : ${error .message || error }` ;
127127 }
128128
129129 // 完全覆盖工具调用处理
@@ -138,7 +138,7 @@ class ToolMonitoringAgent extends Agent {
138138 if (process .env .NODE_ENV === ' test' ) {
139139 return toolCalls .map (tc => ({
140140 toolCallId: tc .id ,
141- result: ` ${tc .function .name } 的模拟结果 ` ,
141+ result: ` Mocked result for ${tc .function .name }` ,
142142 success: true
143143 }));
144144 }
@@ -148,7 +148,7 @@ class ToolMonitoringAgent extends Agent {
148148}
149149```
150150
151- ### 循环生命周期 Hooks
151+ ### 循环生命周期 Hook
152152
153153控制 Agent 循环迭代和终止:
154154
@@ -159,30 +159,30 @@ class LoopControlAgent extends Agent {
159159 // 在每个循环迭代开始时调用
160160 override async onEachAgentLoopStart(sessionId : string ) {
161161 this .iterationStartTimes .set (sessionId , Date .now ());
162- console .log (` [${sessionId }] 开始迭代 ${this .getCurrentLoopIteration ()} ` );
162+ console .log (` [${sessionId }] Starting iteration ${this .getCurrentLoopIteration ()} ` );
163163
164164 // 注入额外上下文或执行设置
165165 const currentTime = new Date ().toISOString ();
166- console .log (` 当前时间 : ${currentTime }` );
166+ console .log (` Current time : ${currentTime }` );
167167 }
168168
169169 // 在每个循环迭代结束时调用
170170 override async onEachAgentLoopEnd(context : EachAgentLoopEndContext ) {
171171 const startTime = this .iterationStartTimes .get (context .sessionId );
172172 if (startTime ) {
173173 const duration = Date .now () - startTime ;
174- console .log (` [${context .sessionId }] 迭代在 ${duration }ms 内完成 ` );
174+ console .log (` [${context .sessionId }] Iteration completed in ${duration }ms ` );
175175 }
176176
177177 // 记录迭代结果
178- console .log (' 此迭代中的事件 :' , context .events ?.length || 0 );
179- console .log (' 进行的工具调用 :' , context .toolCallResults ?.length || 0 );
178+ console .log (' Events in this iteration :' , context .events ?.length || 0 );
179+ console .log (' Tool calls made :' , context .toolCallResults ?.length || 0 );
180180 }
181181
182182 // 当整个 Agent 循环结束时调用
183183 override async onAgentLoopEnd(id : string ) {
184- console .log (` [${id }] Agent 循环完成 ` );
185- console .log (' 总迭代次数 :' , this .getCurrentLoopIteration ());
184+ console .log (` [${id }] Agent loop completed ` );
185+ console .log (' Total iterations :' , this .getCurrentLoopIteration ());
186186
187187 // 清理迭代跟踪
188188 this .iterationStartTimes .delete (id );
@@ -399,105 +399,10 @@ class ResilientAgent extends Agent {
3993999. [否则从步骤 2 重复]
400400```
401401
402- ## 测试 Hooks
403-
404- ### 单元测试单个 Hooks
405-
406- ``` typescript
407- import { Agent , AgentOptions } from ' @tarko/agent' ;
408-
409- class TestableAgent extends Agent {
410- public hookCallLog: string [] = [];
411-
412- override async onLLMRequest(id : string , payload : any ) {
413- this .hookCallLog .push (` onLLMRequest:${id } ` );
414- }
415-
416- override async onBeforeToolCall(id : string , toolCall : any , args : any ) {
417- this .hookCallLog .push (` onBeforeToolCall:${toolCall .name } ` );
418- return args ;
419- }
420- }
421-
422- describe (' Agent Hooks' , () => {
423- let agent: TestableAgent ;
424-
425- beforeEach (() => {
426- agent = new TestableAgent ({});
427- });
428-
429- it (' should call Hook in correct order' , async () => {
430- // 测试 hook 执行顺序
431- await agent .onLLMRequest (' test-session' , { model: ' gpt-4' , messages: [] });
432- await agent .onBeforeToolCall (' test-session' , { name: ' test-tool' }, {});
433-
434- expect (agent .hookCallLog ).toEqual ([
435- ' onLLMRequest:test-session' ,
436- ' onBeforeToolCall:test-tool'
437- ]);
438- });
439- });
440- ```
441-
442- ### 集成测试
443-
444- ``` typescript
445- describe (' Hook Integration' , () => {
446- it (' should prevent termination when required' , async () => {
447- const agent = new ValidatingAgent ({
448- tools: [/* 必需工具 */ ]
449- });
450-
451- // 模拟未调用所有必需工具的场景
452- const result = await agent .onBeforeLoopTermination (
453- ' test-session' ,
454- { content: ' 最终答案' } as any
455- );
456-
457- expect (result .finished ).toBe (false );
458- expect (result .message ).toContain (' 必须调用必需工具' );
459- });
460- });
461- ```
462-
463- ## 最佳实践
464-
465- ### 1. Hook 设计
466- - 保持 Hook 专注和轻量级
467- - 重写时始终调用 ` super.hookMethod() `
468- - 优雅处理错误而不破坏 Agent 执行
469- - 对异步操作使用 async/await
470-
471- ### 2. 状态管理
472- - 在实例变量中存储 hook 特定状态
473- - 在 ` onAgentLoopEnd ` 中清理状态
474- - 使用会话 ID 跟踪每个对话的状态
475-
476- ### 3. 性能
477- - 避免在关键 Hook 中阻塞操作
478- - 对昂贵的计算使用缓存
479- - 为外部调用实现超时
480-
481- ### 4. 错误处理
482- - 始终优雅处理 hook 错误
483- - 在可能的情况下提供回退行为
484- - 记录错误以便调试,但不暴露敏感数据
485-
486- ### 5. 测试
487- - 单独单元测试 Hook
488- - 测试 hook 组合和顺序
489- - 模拟外部依赖
490- - 测试错误场景
491402
492403## 实际示例
493404
494- 查看我们的[ 示例] ( /examples/custom-hooks ) 部分以获取完整实现:
495-
496- - 分析和指标收集
497- - 用户权限强制执行
498- - 速率限制和配额管理
499- - 多步骤工作流验证
500- - 错误恢复和重试机制
405+ WIP
501406
502407## 下一步
503408
0 commit comments