ADK.js核心功能:LlmAgent处理器与钩子系统实战
【免费下载链接】adk-jsAn open-source, code-first Typescript toolkit for building, evaluating, and deploying sophisticated AI agents with flexibility and control.项目地址: https://gitcode.com/GitHub_Trending/ad/adk-js
一、核心概念解析
1.1 LlmAgent基本架构
LlmAgent是ADK.js框架的核心组件,负责协调大型语言模型(LLM)与工具调用之间的交互流程。它通过模块化设计实现了高度可定制性,允许开发者通过处理器和钩子机制介入AI代理的各个工作环节。
1.2 处理器与钩子的定位
- 处理器(Processors):专注于数据转换和流程控制,用于修改LLM请求/响应或实现特定业务逻辑
- 钩子(Hooks):轻量级事件处理机制,允许在代理生命周期的关键节点执行自定义代码
1.3 LlmAgent工作流程
二、处理器开发指南
2.1 处理器接口规范
ADK.js提供了BaseLlmRequestProcessor抽象基类,所有自定义处理器都需要实现其runAsync方法:
import { BaseLlmRequestProcessor, InvocationContext, LlmRequest } from '../core/src/agents/base_llm_processor.ts'; /** * 自定义请求处理器基础结构 * 应用场景:需要系统性修改LLM请求内容时使用,如添加固定指令、格式化输入等 */ class CustomRequestProcessor extends BaseLlmRequestProcessor { /** * 处理LLM请求的主方法 * @param invocationContext 调用上下文 * @param llmRequest LLM请求对象 */ async *runAsync( invocationContext: InvocationContext, llmRequest: LlmRequest ): AsyncGenerator<Event, void, void> { // 处理器逻辑实现 yield createEvent({/* 事件数据 */}); } }2.2 常用内置处理器
ADK.js提供了多个开箱即用的处理器:
| 处理器名称 | 功能描述 | 应用场景 |
|---|---|---|
| BASIC_LLM_REQUEST_PROCESSOR | 设置模型参数和基础配置 | 所有需要自定义模型参数的场景 |
| IDENTITY_LLM_REQUEST_PROCESSOR | 添加代理身份信息 | 需要标识代理角色的场景 |
| INSTRUCTIONS_LLM_REQUEST_PROCESSOR | 处理指令和全局指令 | 需要动态调整系统指令的场景 |
2.3 自定义处理器实现步骤
🔧实现步骤:
- 创建处理器类继承
BaseLlmRequestProcessor - 实现
runAsync方法处理请求 - 在处理器中使用
yield发送事件(可选) - 在LlmAgent配置中注册处理器
/** * 客服请求格式化处理器 * 应用场景:智能客服系统中统一请求格式和添加客服特化指令 */ class SupportRequestProcessor extends BaseLlmRequestProcessor { async *runAsync(invocationContext: InvocationContext, llmRequest: LlmRequest) { // 添加客服系统特有的系统指令 llmRequest.contents.unshift({ role: 'system', parts: [{ text: '你是智能客服助手,需要:1)保持专业友好语气 2)准确解答用户问题 3)无法回答时提供转接人工选项' }] }); // 记录处理过程 yield createEvent({ invocationId: invocationContext.invocationId, author: 'SupportRequestProcessor', content: { parts: [{ text: '已添加客服系统指令' }] } }); // 将处理后的请求传递给下一个处理器 return llmRequest; } }三、钩子应用技巧
3.1 钩子类型与使用场景
ADK.js提供了多种钩子类型,覆盖代理生命周期的关键节点:
- BeforeModelCallback:LLM调用前执行,可修改请求或短路处理
- AfterModelCallback:LLM响应后执行,可处理原始响应数据
- BeforeToolCallback:工具调用前执行,可验证或修改工具参数
- AfterToolCallback:工具响应后执行,可处理工具返回结果
💡关键提示:钩子可以是单个函数或函数数组,按注册顺序执行,返回非undefined值会终止后续钩子执行
3.2 钩子实现示例
/** * 客服响应过滤钩子 * 应用场景:过滤不当内容,确保响应符合客服规范 */ const responseFilterHook = async ({ response, context }) => { if (!response || !response.content) return response; // 检查并过滤敏感内容 const filteredText = response.content.parts[0].text .replace(/不当词汇/g, '***') .replace(/联系方式/g, '隐私信息'); // 返回修改后的响应 return { ...response, content: { ...response.content, parts: [{ text: filteredText }] } }; };3.3 钩子链的组合使用
// 组合多个钩子形成处理链 const agent = new LlmAgent({ // 其他配置... afterModelCallback: [ responseFilterHook, async ({ response }) => { // 添加客服结束语 if (response.content) { response.content.parts[0].text += '\n\n请问还有其他可以帮助您的吗?'; } return response; } ] });四、实战案例分析
4.1 智能客服代理设计
以下是一个完整的智能客服代理实现,结合处理器和钩子实现客服场景特化功能:
import { LlmAgent } from '../core/src/agents/llm_agent.ts'; import { BuiltInCodeExecutor } from '../core/src/code_executors/built_in_code_executor.ts'; import { BASIC_LLM_REQUEST_PROCESSOR, IDENTITY_LLM_REQUEST_PROCESSOR, INSTRUCTIONS_LLM_REQUEST_PROCESSOR } from '../core/src/agents/base_llm_processor.ts'; // 创建客服请求处理器 class SupportRequestProcessor extends BaseLlmRequestProcessor { async *runAsync(invocationContext: InvocationContext, llmRequest: LlmRequest) { // 添加客服系统指令 llmRequest.contents.unshift({ role: 'system', parts: [{ text: '你是智能客服助手,负责解答用户关于产品使用的问题。' + '回答应简洁明了,技术问题需提供操作步骤,复杂问题提供转接人工选项。' }] }); return llmRequest; } } // 创建客服代理 const supportAgent = new LlmAgent({ name: 'customer-support-agent', model: 'gemini-pro', instruction: '你是一名专业的产品客服代表,负责解答用户问题并提供技术支持。', // 注册处理器 requestProcessors: [ BASIC_LLM_REQUEST_PROCESSOR, IDENTITY_LLM_REQUEST_PROCESSOR, INSTRUCTIONS_LLM_REQUEST_PROCESSOR, new SupportRequestProcessor() // 自定义客服处理器 ], // 注册钩子 beforeModelCallback: async ({ request }) => { // 记录用户问题到日志系统 console.log(`客服请求: ${JSON.stringify(request.contents)}`); }, afterModelCallback: [ // 响应过滤钩子 async ({ response }) => { if (response.content) { // 添加客服签名 response.content.parts[0].text += '\n\n—— 智能客服助手'; } return response; } ], // 工具配置 tools: [new KnowledgeBaseTool(), new TicketCreationTool()], // 代码执行器配置 codeExecutor: new BuiltInCodeExecutor() }); // 使用客服代理处理用户请求 async function handleSupportRequest(userMessage: string) { const result = await supportAgent.run({ input: userMessage, context: { userId: 'user123', sessionId: 'session456' } }); return result.response; }4.2 处理器与钩子协同工作
在智能客服代理中,处理器和钩子各自承担不同职责:
处理器:负责系统性的请求修改和预处理
- 添加客服专业指令
- 格式化用户问题
- 注入上下文信息
钩子:负责事件性的处理和监控
- 记录对话日志
- 过滤不当内容
- 添加标准结束语
4.3 常见问题解决
问题:处理器执行顺序导致的冲突
解决:明确处理器注册顺序,基础处理器在前,自定义处理器在后
// 正确顺序:基础处理器 → 自定义处理器 requestProcessors: [ BASIC_LLM_REQUEST_PROCESSOR, // 基础配置 new SupportRequestProcessor() // 自定义处理 ]问题:钩子短路执行
解决:确保不需要终止后续处理的钩子返回undefined
// 错误:会终止后续钩子执行 afterModelCallback: [() => { console.log('处理1'); return {}; }, () => { console.log('处理2'); }] // 正确:继续执行后续钩子 afterModelCallback: [() => { console.log('处理1'); }, () => { console.log('处理2'); }]问题:处理器中异步操作导致的性能问题
解决:优化异步逻辑,避免处理器中执行耗时操作
问题:钩子中修改上下文数据不生效
解决:确保通过返回新对象修改数据,而非直接修改传入参数
问题:工具调用后无法获取更新的上下文
解决:使用
afterToolCallback钩子处理工具结果并更新上下文
五、进阶优化策略
5.1 性能优化技巧
处理器合并:将多个功能相近的处理器合并,减少处理步骤
// 合并多个相关处理逻辑到单一处理器 class UnifiedSupportProcessor extends BaseLlmRequestProcessor { async *runAsync(context, request) { this.addSystemInstructions(request); this.formatUserQuery(request); this.injectContextData(request, context); return request; } // 拆分为私有方法提高可读性 private addSystemInstructions(request) {/* ... */} private formatUserQuery(request) {/* ... */} private injectContextData(request, context) {/* ... */} }条件处理:根据请求类型有条件地应用处理器
class ConditionalProcessor extends BaseLlmRequestProcessor { async *runAsync(context, request) { // 只处理特定类型的请求 if (context.requestType === 'technical_support') { this.addTechnicalInstructions(request); } return request; } }钩子缓存:对频繁调用的钩子结果进行缓存
const createCachedHook = (fn, ttl = 5000) => { const cache = new Map(); return async (params) => { const key = JSON.stringify(params); if (cache.has(key) && Date.now() - cache.get(key).timestamp < ttl) { return cache.get(key).result; } const result = await fn(params); cache.set(key, { result, timestamp: Date.now() }); return result; }; }; // 使用缓存钩子 const cachedKnowledgeHook = createCachedHook(fetchKnowledgeBase);
5.2 最佳实践清单
| 实践要点 | 具体建议 | 重要性 |
|---|---|---|
| 处理器顺序 | 基础处理器在前,自定义处理器在后 | ⭐⭐⭐ |
| 钩子设计 | 单一职责原则,每个钩子只处理一个功能 | ⭐⭐⭐ |
| 错误处理 | 在处理器和钩子中实现try/catch捕获异常 | ⭐⭐⭐ |
| 性能考量 | 避免在处理器中执行耗时操作 | ⭐⭐ |
| 测试策略 | 为自定义处理器和钩子编写单元测试 | ⭐⭐ |
| 代码组织 | 将相关处理器和钩子放在同一模块 | ⭐ |
5.3 扩展与社区资源
ADK.js提供了丰富的扩展机制和社区支持:
- 官方文档:项目中的
README.md文件提供了详细的使用指南 - 示例代码:
dev/samples/目录包含多种场景的实现示例 - 社区支持:通过项目issue系统获取帮助和提交反馈
- 贡献指南:参考项目中的
CONTRIBUTING.md文件参与贡献
要开始使用ADK.js,可通过以下命令克隆项目:
git clone https://gitcode.com/GitHub_Trending/ad/adk-js cd adk-js npm install通过合理使用处理器和钩子系统,开发者可以构建高度定制化的AI代理,满足各种复杂业务场景需求。ADK.js的模块化设计确保了这些扩展能够无缝集成,并保持系统的可维护性和可扩展性。
【免费下载链接】adk-jsAn open-source, code-first Typescript toolkit for building, evaluating, and deploying sophisticated AI agents with flexibility and control.项目地址: https://gitcode.com/GitHub_Trending/ad/adk-js
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考