当前位置: 首页 > article >正文

Strands Agents TypeScript SDK:模型驱动的AI智能体开发框架深度解析

1. Strands Agents TypeScript SDK一个模型驱动的AI智能体开发框架深度解析最近在探索如何用TypeScript构建更可靠、更易维护的AI智能体时我深度体验了Strands Agents的TypeScript SDK。作为一个长期在Node.js和前端领域耕耘的开发者我对市面上各种AI工具链的“玩具感”一直不太满意——要么封装过度失去了灵活性要么过于底层写起来像是在重复造轮子。Strands Agents的出现让我感觉找到了一个不错的平衡点。它提出的“模型驱动”理念本质上是通过强类型和模式化的方式把智能体开发从“提示词工程”的玄学拉回到了我们熟悉的软件工程轨道上。今天我就结合自己近一个月的实际项目踩坑经验来聊聊这个框架的核心设计、最佳实践以及那些官方文档里没写的细节。简单来说Strands Agents TypeScript SDK是一个用于在TypeScript/JavaScript环境中构建、运行和编排AI智能体的框架。它最大的特点是模型驱动和类型安全。所谓模型驱动是指它用Zod模式Schema来定义工具Tools的输入输出、结构化响应Structured Output的格式甚至多智能体之间的协作流程。这带来的直接好处是你的智能体行为可以被清晰地定义和验证而不是依赖大语言模型LLM的自由发挥。类型安全则贯穿始终从工具回调函数的参数到最终响应的解析结果你都能获得完整的TypeScript类型推断和编译时检查这在大中型项目中简直是救命稻草。这套框架适合谁呢如果你正在用Node.js后端或浏览器环境开发需要集成AI能力的应用比如智能客服、自动化工作流、数据分析助手或者想实验多智能体协作Multi-Agent的复杂场景那么Strands Agents值得你花时间研究。它尤其适合那些对代码质量、可测试性和系统可观测性有要求的团队。接下来我会从设计思路拆解开始带你一步步深入这个框架的肌理。1.1 核心设计思路为什么是“模型驱动”初次接触“模型驱动”这个词可能会觉得有点抽象。在Strands Agents的语境里它指的不仅仅是使用大语言模型LLM更是用数据模式Schema来驱动整个智能体的交互逻辑。这与传统的、主要依靠精心设计的提示词Prompt来引导LLM的方式有本质区别。传统的智能体开发我们往往写一个很长的系统提示词告诉LLM“你可以使用A、B、C这些工具它们的用法是……”然后在代码里解析LLM返回的文本判断它想调用哪个工具再手动拼接参数、调用函数、把结果塞回上下文。这个过程充满了不确定性LLM可能不按你期望的格式返回参数解析可能出错工具执行结果的结构也可能五花八门。Strands Agents的做法是把这一切都“契约化”。你用Zod定义一个工具包括它的名字、描述、输入参数的模式。框架在生成给LLM的提示词时会将这些模式转换成模型能理解的结构化描述比如OpenAI的function calling格式或Anthropic的tool use格式。当LLM决定调用工具时它返回的是一个结构化的调用请求框架能直接、安全地将其解析成强类型的JavaScript对象然后调用你定义的回调函数。同样回调函数的返回值也会被框架包装成结构化的结果送回给LLM作为下一步思考的上下文。这种设计带来的几个关键优势可靠性提升输入输出验证从“运行时字符串解析”变成了“模式验证”。Zod会在调用前验证参数是否符合模式不符合的直接抛出清晰的错误避免了因格式错误导致的工具调用失败或副作用。开发体验飞跃全程类型安全。你在写工具回调函数时input参数的类型就是Zod模式推断出来的类型IDE能提供完美的自动补全和类型检查。这极大地减少了低级错误。意图理解更精准LLM对于结构化的工具描述理解得更好、更一致。相比于用自然语言描述工具用法结构化的模式减少了歧义提高了工具调用的准确率。组合与复用性增强工具成为了一个个拥有明确定义接口的“组件”可以像乐高一样在不同的智能体之间轻松组合和复用。实操心得从“提示词驱动”转向“模型驱动”需要一点思维转变。一开始你可能会不习惯为每个工具都写Zod模式觉得有点繁琐。但坚持下来会发现这前期的一点投入在后续的调试、扩展和维护阶段会带来巨大的回报。尤其是在团队协作中一个定义清晰的工具模式就是最好的文档。2. 环境准备与核心概念落地理论说再多不如动手跑一遍。我们从一个最基础的智能体开始逐步添加功能来感受Strands Agents的工作方式。首先确保你的环境是Node.js 20或更高版本这是SDK的硬性要求因为它使用了一些较新的ES模块特性。2.1 基础安装与智能体初始化创建一个新的项目目录初始化并安装SDKmkdir my-strands-agent cd my-strands-agent npm init -y npm install strands-agents/sdk zod这里我们同时安装了zod因为定义工具和结构化输出离不开它。接下来创建一个index.ts文件写入最基本的智能体调用代码import { Agent } from strands-agents/sdk; // 创建一个最简单的智能体使用默认配置 const agent new Agent(); async function main() { try { const result await agent.invoke(What is the capital of France?); console.log(Agent Response:, result.content); } catch (error) { console.error(Error:, error); } } main();运行前你需要配置模型访问。SDK默认使用Amazon Bedrock作为模型提供商并且默认尝试调用Claude 3.5 Sonnet模型。因此你需要确保拥有一个AWS账户并在目标区域如us-east-1启用了Bedrock服务且对Claude模型有访问权限。本地配置了有效的AWS凭证。通常可以通过aws configure命令设置或设置AWS_ACCESS_KEY_ID和AWS_SECRET_ACCESS_KEY环境变量。如果你更习惯使用OpenAI切换起来也非常简单import { Agent } from strands-agents/sdk; import { OpenAIModel } from strands-agents/sdk/models/openai; // 设置你的OpenAI API Key process.env.OPENAI_API_KEY your-api-key-here; const model new OpenAIModel({ api: chat, // 使用Chat Completions API model: gpt-4o, // 指定模型默认为gpt-4 }); const agent new Agent({ model });注意事项关于模型提供商的选择这里有个细节。BedrockModel在初始化时modelId参数需要严格按照Bedrock控制台提供的模型ID来填写例如anthropic.claude-3-5-sonnet-20241022-v2:0。不同区域、不同版本的模型ID可能不同填错了会直接导致调用失败。而OpenAIModel则相对简单使用通用的模型名称即可。2.2 理解智能体的核心循环与配置Agent类是这个框架的核心。当你调用agent.invoke(prompt)时背后触发了一个标准的“思考-行动”循环ReAct模式的一种实现思考将用户输入、系统提示词、对话历史如果启用和可用工具的描述组合成一个提示发送给LLM。决策LLM返回一个包含“最终答案”或“工具调用请求”的响应。行动如果是工具调用框架会解析参数、执行对应的工具函数并将结果作为新的上下文附加到对话中。循环带着工具执行的结果回到第1步让LLM继续思考直到它决定给出最终答案。你可以通过配置项来精细控制这个循环import { Agent } from strands-agents/sdk; const agent new Agent({ // 系统提示词定义智能体的角色和行为准则 systemPrompt: 你是一个专业、简洁的助手。回答要准确如果不知道就说不知道。, // 最大迭代次数防止智能体陷入无限的工具调用循环 maxSteps: 10, // 是否启用对话历史管理 enableConversationHistory: true, // 对话历史的Token数量上限用于控制上下文窗口 maxConversationTokens: 4000, });maxSteps是一个非常重要的安全阀。在复杂任务中智能体可能会在多个工具之间来回调用或者陷入“我再查一下”的循环。设置一个合理的上限比如10-20次可以防止单个请求消耗过多的Token和API费用并在智能体“卡住”时及时抛出错误。3. 构建类型安全的工具Tools工具是智能体与外部世界交互的桥梁。Strands Agents让创建类型安全的工具变得异常优雅。3.1 创建你的第一个工具假设我们要构建一个查询城市天气的智能体。首先我们定义一个getWeather工具import { Agent, tool } from strands-agents/sdk; import { z } from zod; // 使用 tool() 高阶函数创建工具 const getWeatherTool tool({ name: get_weather, // 工具名称LLM通过这个名称来调用 description: 获取指定城市的当前天气信息。, // 清晰的描述帮助LLM理解工具用途 // 使用Zod定义输入参数的模式 inputSchema: z.object({ location: z.string().describe(城市名称例如北京、San Francisco, CA), unit: z.enum([celsius, fahrenheit]).optional().default(celsius).describe(温度单位), }), // 回调函数input的类型会自动推断为 { location: string; unit?: celsius | fahrenheit } callback: async (input) { console.log([Tool Called] get_weather with input:, input); // 这里应该是真实的API调用例如调用OpenWeatherMap // 为了示例我们模拟一个返回 const mockTemperatures: Recordstring, number { 北京: 22, San Francisco, CA: 18, 纽约: 25, }; const temp mockTemperatures[input.location] || 20; const finalTemp input.unit fahrenheit ? (temp * 9/5) 32 : temp; const unitSymbol input.unit fahrenheit ? °F : °C; return 当前${input.location}的天气为晴气温${finalTemp}${unitSymbol}湿度65%风速10km/h。; }, }); // 将工具装配给智能体 const agent new Agent({ systemPrompt: 你是一个天气助手可以帮助用户查询全球城市的天气。, tools: [getWeatherTool], }); // 测试调用 async function test() { const result await agent.invoke(上海今天天气怎么样); console.log(result.content); // 输出可能为当前上海的天气为晴气温20°C湿度65%风速10km/h。 // 注意智能体可能会先调用get_weather工具然后将工具返回的结果整合成最终回答。 } test();当你运行这段代码时观察控制台日志你会看到[Tool Called]的打印信息。这证实了智能体确实解析了用户问题中的“上海”生成了符合inputSchema的调用参数{location: ‘上海’ unit: ‘celsius’}并执行了你的回调函数。避坑技巧工具的描述description至关重要。它不仅是给后续维护者看的更是LLM决定是否以及如何调用该工具的主要依据。描述要简洁、准确、无歧义最好能包含一两个调用示例。模糊的描述会导致工具被误用或弃用。3.2 处理异步操作与错误现实中的工具大多是异步的比如网络请求、数据库查询。你的工具回调函数完全可以是一个async函数。框架会妥善处理异步操作。更重要的是错误处理如果工具执行中抛出错误框架会捕获这个错误并将其作为“工具执行失败”的信息反馈给LLMLLM可以据此决定重试或调整策略。const riskyTool tool({ name: fetch_data, description: 从一个可能不稳定的API获取数据。, inputSchema: z.object({ url: z.string().url() }), callback: async (input) { const response await fetch(input.url); if (!response.ok) { // 抛出错误智能体会收到“工具调用失败”的信号 throw new Error(HTTP ${response.status}: ${await response.text()}); } return response.json(); }, });3.3 使用内置的“已供应工具”Vended Tools为了提升开发效率SDK预置了一些常用工具可以通过单独的包引入。例如文件编辑工具和HTTP请求工具npm install strands-agents/toolsimport { FileEditorTool, HttpRequestTool } from strands-agents/tools; const fileTool new FileEditorTool({ // 可以限制文件操作的根目录增强安全性 basePath: ./workspace, }); const httpTool new HttpRequestTool(); const agent new Agent({ tools: [fileTool, httpTool], systemPrompt: 你可以帮我读写文件或者从网上获取信息。, }); // 现在智能体可以理解“请创建一个名为note.txt的文件内容为Hello World”或“获取https://api.example.com/data的信息”这样的指令。安全警告像FileEditorTool和HttpRequestTool这类拥有系统级或网络访问权限的工具必须谨慎使用。在生产环境中至少应该通过basePath限制文件访问范围或者为HTTP工具设置允许列表allowlist来限制可访问的域名避免智能体被恶意提示词诱导执行危险操作。4. 实现结构化输出Structured Output让LLM返回自由的文本固然灵活但在很多自动化场景下我们需要它返回结构化的数据以便后续的程序处理。例如从一段文本中提取联系人信息、生成JSON配置、或者格式化一个任务列表。Strands Agents的结构化输出功能通过结合Zod模式和自动重试机制优雅地解决了这个问题。4.1 定义输出模式与基础使用假设我们需要从一个自由格式的文本中提取会议信息import { Agent } from strands-agents/sdk; import { z } from zod; // 1. 用Zod定义我们期望的输出结构 const MeetingSchema z.object({ title: z.string().describe(会议主题), participants: z.array(z.string()).describe(参会人名单), scheduledTime: z.string().datetime().describe(会议时间ISO 8601格式), durationMinutes: z.number().int().positive().describe(会议时长分钟), location: z.string().optional().describe(会议地点可选), }); // 2. 在创建智能体时指定结构化输出模式 const agent new Agent({ systemPrompt: 你是一个信息提取助手请从文本中提取结构化的会议信息。, structuredOutputSchema: MeetingSchema, // 关键配置 }); async function extractMeeting() { const text 明天下午两点2024-06-15T14:00:00Z我们团队要开一个季度复盘会预计开90分钟。参加的人有张三、李四和王五。地点在301会议室。; const result await agent.invoke(请从以下文本中提取会议信息\n${text}); // 3. 访问结构化结果类型是 MeetingSchema 推断出的类型 const meeting result.structuredOutput; console.log(提取的会议信息:); console.log(主题: ${meeting.title}); // 季度复盘会 console.log(时间: ${meeting.scheduledTime}); // 2024-06-15T14:00:00.000Z console.log(时长: ${meeting.durationMinutes}分钟); // 90 console.log(参会人: ${meeting.participants.join(, )}); // 张三, 李四, 王五 console.log(地点: ${meeting.location}); // 301会议室 // result.content 仍然包含模型的原始文本回复 console.log(\n模型原始回复:, result.content); } extractMeeting();这个过程的核心是验证与重试。当LLM第一次返回文本时框架会尝试将其解析为JSON然后用MeetingSchema进行验证。如果验证失败比如缺少必填字段、时间格式不对框架不会直接抛出错误给用户而是会自动构造一个新的提示词其中包含验证错误的具体信息例如“scheduledTime字段必须是有效的ISO 8601日期时间字符串”然后重新调用LLM。这个循环会持续进行直到返回有效的结构化数据或者达到重试上限默认3次。4.2 错误处理与重试控制你可以捕获结构化输出失败的错误并获取详细的验证信息import { StructuredOutputError } from strands-agents/sdk; try { const result await agent.invoke(一些模糊的文本...); // 处理成功结果 } catch (error) { if (error instanceof StructuredOutputError) { console.error(结构化输出失败); console.error(错误信息:, error.message); console.error(验证详情:, error.cause?.errors); // Zod的详细错误数组 console.error(LLM最后一次返回的原始内容:, error.rawResponse); console.error(已重试次数:, error.retryCount); } else { // 处理其他类型的错误如网络错误、模型错误等 console.error(其他错误:, error); } }你还可以在创建智能体时配置重试行为const agent new Agent({ structuredOutputSchema: MeetingSchema, structuredOutput: { maxRetries: 5, // 最大重试次数 retryDelayMs: 1000, // 每次重试的延迟毫秒 }, });实操心得结构化输出功能极大地提升了AI集成到生产流水线中的可靠性。但要注意复杂的模式如嵌套对象、联合类型可能会增加LLM的理解难度和重试概率。我的经验是模式设计要尽量简单、扁平。如果确实需要复杂结构可以考虑拆分成多个步骤先让LLM提取原始文本片段再用专门的解析逻辑进行处理。5. 集成模型上下文协议MCP模型上下文协议Model Context Protocol, MCP是一个新兴的开放协议旨在标准化AI应用与外部工具、数据源之间的连接方式。你可以把它想象成AI世界的“驱动程序”标准。Strands Agents内置了MCP客户端支持让你能轻松地将任何MCP服务器提供的工具集成到你的智能体中。5.1 连接本地MCP服务器假设你本地运行了一个提供数据库查询工具的MCP服务器。集成步骤如下import { Agent, McpClient } from strands-agents/sdk; import { StdioClientTransport } from modelcontextprotocol/sdk/client/stdio.js; // 1. 创建MCP客户端通过标准输入输出stdio连接到本地服务器进程 const dbClient new McpClient({ transport: new StdioClientTransport({ command: node, // 启动服务器的命令 args: [./path/to/your-mcp-server.js], // 服务器脚本参数 }), }); // 2. 在连接客户端之前通常需要初始化例如交换密钥 await dbClient.connect(); // 3. 将MCP客户端作为一个工具源传递给智能体 const agent new Agent({ systemPrompt: 你是一个数据分析助手可以使用数据库工具。, tools: [dbClient], // 直接传入客户端SDK会自动发现其提供的所有工具 }); // 4. 现在智能体就可以使用数据库工具了 const result await agent.invoke(查询用户表中最近10条记录); console.log(result.content); // 5. 任务完成后断开连接 await dbClient.disconnect();5.2 使用现成的MCP服务器社区已经有很多优秀的MCP服务器。例如aws-documentation-mcp-server可以提供AWS服务的官方文档搜索工具。你可以通过uvx一个Python工具运行器快速启动它# 首先确保安装了 uv pip install uvimport { Agent, McpClient } from strands-agents/sdk; import { StdioClientTransport } from modelcontextprotocol/sdk/client/stdio.js; const awsDocsClient new McpClient({ transport: new StdioClientTransport({ command: uvx, args: [awslabs.aws-documentation-mcp-serverlatest], }), }); const agent new Agent({ tools: [awsDocsClient], systemPrompt: 你是一个AWS专家可以查阅最新的AWS官方文档来回答问题。, }); // 智能体现在可以回答“S3的PutObject API最近有什么更新”这类问题 // 它会自动调用MCP服务器提供的文档搜索工具注意事项MCP服务器通常运行在独立的进程中。你需要管理好这些进程的生命周期确保在智能体不再需要时正确关闭它们避免资源泄漏。另外MCP工具的动态性很强智能体在运行时才能知道具体有哪些工具可用这为构建高度可扩展的插件化系统提供了可能但也增加了对提示词设计的挑战——你需要让智能体学会“探索”和“选择”可用的工具。6. 多智能体编排实战Graph与Swarm模式当单个智能体无法胜任复杂任务时我们就需要多个智能体协同工作。Strands Agents提供了两种内置的编排模式Graph图和Swarm蜂群。这是框架最强大的功能之一。6.1 Graph模式确定性的工作流Graph模式允许你定义一个确定性的执行流程图。智能体作为图中的节点Node节点之间的边Edge定义了执行顺序。一个节点只有在它的所有前置依赖节点都执行完毕后才会开始运行。这种模式适合步骤清晰、流程固定的任务比如“研究 - 分析 - 撰写报告”。import { Agent, BedrockModel, Graph } from strands-agents/sdk; // 使用同一个模型实例节省成本并保持上下文一致性 const sharedModel new BedrockModel({ maxTokens: 2048 }); // 定义三个各司其职的智能体 const researcher new Agent({ model: sharedModel, id: researcher, // 节点必须有唯一ID systemPrompt: 你是一个研究专员。根据用户问题从提供的上下文或知识中提炼关键事实和要点。输出要简洁、客观。, }); const analyst new Agent({ model: sharedModel, id: analyst, systemPrompt: 你是一个分析师。接收研究员提供的事实进行深入分析识别趋势、矛盾或深层含义。输出你的分析结论。, }); const writer new Agent({ model: sharedModel, id: writer, systemPrompt: 你是一个文案写手。接收研究员的事实和分析师的结论将其整合成一篇结构清晰、语言流畅的简短报告。输出最终报告。, }); // 构建执行图researcher - analyst - writer const workflow new Graph({ nodes: [researcher, analyst, writer], edges: [ [researcher, analyst], // researcher 完成后analyst 开始 [analyst, writer], // analyst 完成后writer 开始 ], }); async function runGraphWorkflow() { const topic 人工智能在气候变化应对中的作用; console.log(开始处理主题: ${topic}); // invoke 方法会将初始提示传给第一个节点researcher // 每个节点的输出会自动成为下一个节点的输入的一部分 const finalResult await workflow.invoke(topic); // finalResult 包含了整个图的最终输出即writer节点的输出 console.log(\n 最终报告 ); console.log(finalResult.content); // 你还可以访问每个节点的独立输出 // console.log(workflow.getNodeOutput(researcher)); // console.log(workflow.getNodeOutput(analyst)); } runGraphWorkflow();在这个例子中执行流程是线性的、确定的。researcher先工作它的输出被传递给analystanalyst的输出再传递给writer。Graph模式也支持并行执行只需将没有依赖关系的节点同时作为起点即可。6.2 Swarm模式动态的、模型驱动的路由Swarm模式则把执行路径的决定权交给了智能体本身。每个智能体在完成任务后可以自主决定是“移交”handoff给另一个智能体还是直接给出最终响应。这模拟了人类团队协作的场景一个同事处理完他的部分后根据情况决定把任务转给更合适的另一位同事。import { Agent, BedrockModel, Swarm } from strands-agents/sdk; const sharedModel new BedrockModel({ maxTokens: 1024 }); // 定义一群智能体每个都有明确的职责描述 const receptionist new Agent({ model: sharedModel, id: receptionist, description: 接待员负责接收用户请求并进行初步分类和分流。, systemPrompt: 你是前台接待员。请分析用户请求 - 如果是简单的信息查询如天气、时间、定义请直接回答。 - 如果是需要复杂分析或创作的任务如写文章、分析数据请说“我将为您转接给专家”然后移交handoff给 specialist。 - 如果是技术性非常强的编程问题请移交handoff给 technician。 你的回答必须非常简短。, }); const specialist new Agent({ model: sharedModel, id: specialist, description: 通用专家处理复杂的分析和创作任务。, systemPrompt: 你是通用问题专家。请深入处理接收到的任务提供详细、专业的回答。这是最终步骤完成後不要移交。, }); const technician new Agent({ model: sharedModel, id: technician, description: 技术专家解决编程和深度技术问题。, systemPrompt: 你是技术专家。请解决编程或技术架构问题提供代码示例或详细方案。这是最终步骤完成後不要移交。, }); // 创建蜂群指定起始节点和最大步数防止无限循环 const swarm new Swarm({ nodes: [receptionist, specialist, technician], start: receptionist, // 所有请求都先发给接待员 maxSteps: 6, // 最多允许6次“思考-行动”步骤包括移交 }); async function runSwarm() { const queries [ 今天天气怎么样, 写一篇关于海洋塑料污染的短评。, 如何在TypeScript中实现一个安全的深拷贝函数, ]; for (const query of queries) { console.log(\n 用户提问: ${query}); const result await swarm.invoke(query); console.log( 最终回答 (来自 ${result.lastNodeId}):\n${result.content}\n); } } runSwarm();运行这段代码你会看到对于“今天天气怎么样”receptionist可能直接回答。对于“写短评”receptionist会将其移交给specialist由specialist生成最终回答。对于“TypeScript深拷贝”receptionist会将其移交给technician。Swarm模式的强大之处在于其动态性。你无需预先定义完整的流程智能体们会根据对任务的理解实时决定协作路径。当然这也对每个智能体的提示词设计提出了更高要求必须清晰地定义其职责和移交规则。编排模式选择指南选择Graph模式当任务流程固定、步骤清晰、需要严格保证执行顺序和阶段产出物。例如数据处理流水线、审核流程、多阶段内容生成。选择Swarm模式当任务类型多变、难以预先规划所有路径、需要智能体自主协作。例如智能客服路由、开放式问题解决、创意头脑风暴。混合使用在复杂系统中可以外层用Graph定义几个大的阶段每个阶段内部再用Swarm进行动态任务分配。7. 高级特性与生产实践掌握了核心功能后我们来看看那些能让你的智能体更健壮、更易观测的高级特性和实践。7.1 流式响应与实时交互对于需要长时间运行或希望提供实时反馈的应用流式响应Streaming至关重要。Strands Agents的agent.stream()方法返回一个异步迭代器让你可以实时接收处理过程中的各种事件。const agent new Agent({ systemPrompt: 你是一个讲故事的人。, }); async function streamStory() { console.log(开始生成故事...\n); for await (const event of agent.stream(讲一个关于星辰与猫的短故事。)) { switch (event.type) { case llm_start: console.log([LLM] 开始思考...); break; case llm_token: // 逐词输出模型生成的内容实现打字机效果 process.stdout.write(event.token); break; case tool_call_start: console.log(\n[工具调用] 开始调用工具: ${event.toolName}); break; case tool_call_end: console.log([工具调用] 工具“${event.toolName}”调用完成。); break; case agent_step: console.log(\n[步骤] 第${event.step}步完成。); break; case agent_end: console.log(\n\n[完成] 故事生成完毕。); break; case error: console.error(\n[错误], event.error); break; } } } streamStory();流式响应不仅提升了用户体验也是调试复杂智能体行为的利器。你可以清晰地看到智能体在每一步做了什么决定调用了什么工具。7.2 生命周期钩子与监控SDK提供了丰富的生命周期钩子Hooks让你能在智能体运行的关键节点注入自定义逻辑用于日志记录、性能监控、修改中间结果等。import { Agent } from strands-agents/sdk; const agent new Agent({ systemPrompt: ..., }); // 注册钩子 agent.hooks.on(llmStart, (context) { console.log([监控] 开始调用LLM提示词长度: ${context.messages.length}); }); agent.hooks.on(llmEnd, (context, response) { console.log([监控] LLM调用结束消耗Token数: ${response.usage?.totalTokens}); console.log([监控] 模型回复首句: ${response.content?.substring(0, 50)}...); }); agent.hooks.on(toolCallStart, (context, toolCall) { console.log([监控] 即将调用工具: ${toolCall.name}参数:, JSON.stringify(toolCall.arguments)); }); agent.hooks.on(toolCallEnd, (context, toolCall, result) { console.log([监控] 工具 ${toolCall.name} 执行完毕结果长度: ${result?.length || 0}); }); agent.hooks.on(agentEnd, (context, finalResult) { console.log([监控] 智能体运行结束总步数: ${context.step}最终结果长度: ${finalResult.content.length}); });通过这些钩子你可以轻松集成像OpenTelemetry这样的分布式追踪系统为每个智能体调用生成详细的追踪链路便于在生产环境中定位性能瓶颈和异常。7.3 对话历史管理与上下文窗口控制智能体的记忆力来自对话历史。SDK提供了灵活的对话历史管理策略。import { Agent, TokenBufferConversationHistory } from strands-agents/sdk; const agent new Agent({ systemPrompt: ..., conversationHistory: new TokenBufferConversationHistory({ maxTokens: 3000, // 历史记录的最大Token数 strategy: lru, // 当超出限制时采用LRU最近最少使用策略移除最早的消息 }), }); // 进行多轮对话 await agent.invoke(你好我叫小明。); await agent.invoke(你还记得我的名字吗); // 智能体会记得“小明”TokenBufferConversationHistory会自动计算每条消息的Token消耗使用近似算法并确保总历史不超过maxTokens限制。这对于控制API成本和使用长上下文模型至关重要。你也可以实现自己的ConversationHistory类来实现更复杂的逻辑比如将历史存储到数据库。8. 常见问题、排查技巧与性能优化在实际使用中你肯定会遇到各种问题。下面是我总结的一些常见坑点和解决思路。8.1 智能体不调用工具问题你明明定义了工具但智能体总是直接回答而不去调用工具。排查步骤检查工具描述这是最常见的原因。工具的描述是否清晰、无歧义是否准确说明了工具的用途和输入用更具体、更具操作性的语言重写描述。检查系统提示词你的系统提示词是否明确指示智能体“可以使用工具”尝试在提示词中加入“你可以使用我提供的工具来获取信息或执行操作。如果你需要的信息不在你的知识范围内请优先考虑使用工具。”降低温度Temperature将模型配置中的temperature参数调低如从0.7调到0.2。较低的温度使模型输出更确定、更遵循指令可能更倾向于调用工具。查看完整日志启用调试日志或使用流式API查看llmEnd事件中的完整模型响应。有时模型在思考过程中提到了工具但最终选择了不调用。这能帮你理解模型的“决策过程”。8.2 结构化输出验证持续失败问题配置了结构化输出但LLM始终无法返回有效的格式达到重试上限后抛出StructuredOutputError。解决思路简化模式你的Zod模式是否太复杂包含太多嵌套、联合类型或高级校验尝试先用一个极其简单的模式如z.object({ answer: z.string() })测试确认基础功能正常。增强提示在系统提示词中明确强调输出格式。例如“你必须严格按照指定的JSON格式回应。只输出JSON不要有任何额外的解释或标记。”提供示例在用户提示词中提供一个输出示例。例如“请提取信息并以如下JSON格式输出{\”name\”: \”示例人名\”, \”age\”: 30}”更换模型不同的LLM在遵循结构化指令方面能力有差异。Claude系列和GPT-4通常比一些小型或旧模型表现更好。8.3 多智能体协作陷入循环或停滞问题在Swarm模式中智能体之间来回移交无法产生最终答案或者在Graph模式中某个节点卡住。调试方法设置maxSteps这是最重要的安全网。为Agent和Swarm都设置一个合理的maxSteps如10-15防止无限循环。分析节点输出使用Graph的getNodeOutput方法或监听Swarm的流式事件查看每个节点的输入和输出。问题可能出在某个节点的输出质量不高导致下一个节点无法处理。优化节点提示词在Swarm中确保每个节点的systemPrompt和description清晰定义了其边界和移交条件。例如明确写明“这是最终步骤完成后不要移交handoff”。引入“裁判”或“终结者”在Swarm中设置一个专用的coordinator或finalizer智能体其职责就是分析当前状态并决定是否应该结束流程。8.4 性能优化与成本控制复用模型实例在创建多个Agent或编排多个智能体时尽可能复用同一个BedrockModel或OpenAIModel实例。这有助于内部连接的复用和潜在的性能优化。精细控制Token设置合理的maxTokens参数防止单次请求生成过长的内容。使用TokenBufferConversationHistory并设置合适的maxTokens自动修剪旧历史。在工具描述和系统提示词中力求简洁减少不必要的Token消耗。异步与并行对于Graph中可并行执行的节点确保它们之间没有不必要的依赖边以充分利用计算资源。实现缓存层对于频繁查询且结果不变的工具如某些数据查询可以在工具回调函数中实现简单的内存缓存或使用外部缓存如Redis避免重复调用昂贵的外部API或模型。经过上面八个部分的拆解你应该对Strands Agents TypeScript SDK有了一个从入门到进阶的全面认识。从我个人的使用体验来看它最大的价值在于将AI智能体开发从“脚本小子”的玩具级别提升到了“软件工程”的严肃级别。类型安全、模式验证、清晰的架构这些特性使得构建可靠、可维护的AI应用成为可能。当然框架目前还处于公开预览阶段API可能会有变动但核心的设计理念已经非常稳固。如果你正在寻找一个既强大又务实的TypeScript智能体框架Strands Agents绝对值得你投入时间深入探索。

相关文章:

Strands Agents TypeScript SDK:模型驱动的AI智能体开发框架深度解析

1. Strands Agents TypeScript SDK:一个模型驱动的AI智能体开发框架深度解析最近在探索如何用TypeScript构建更可靠、更易维护的AI智能体时,我深度体验了Strands Agents的TypeScript SDK。作为一个长期在Node.js和前端领域耕耘的开发者,我对市…...

5分钟学会fre:ac音频转换器:免费批量转换MP3、FLAC、AAC终极指南

5分钟学会fre:ac音频转换器:免费批量转换MP3、FLAC、AAC终极指南 【免费下载链接】freac The fre:ac audio converter project 项目地址: https://gitcode.com/gh_mirrors/fr/freac fre:ac是一款功能强大的免费开源音频转换器,支持MP3、FLAC、AAC…...

如何在5分钟内掌握Illustrator批量对象替换脚本ReplaceItems.jsx

如何在5分钟内掌握Illustrator批量对象替换脚本ReplaceItems.jsx 【免费下载链接】illustrator-scripts Adobe Illustrator scripts 项目地址: https://gitcode.com/gh_mirrors/il/illustrator-scripts 还在为Adobe Illustrator中繁琐的对象替换操作而烦恼吗&#xff1f…...

Crossplane Helm Provider:统一云原生基础设施与应用部署的声明式管理

1. 项目概述与核心价值如果你正在使用 Crossplane 来构建和管理你的云原生基础设施,并且希望将 Helm Chart 的部署也纳入到这套声明式的、以 API 为中心的管理范式中,那么crossplane-contrib/provider-helm就是你一直在寻找的那块拼图。简单来说&#xf…...

深入Linux内核:图解UBIFS文件系统如何通过UBI层管理“裸”Flash设备

深入Linux内核:图解UBIFS文件系统如何通过UBI层管理“裸”Flash设备 1. 闪存存储技术的底层挑战 在嵌入式系统和物联网设备中,NAND Flash因其非易失性、高密度和低成本特性成为主流存储介质。但直接操作原始NAND Flash面临三大核心难题:物理特…...

实时语音翻译质量评估工具Simulstream的技术解析

1. 项目背景与核心价值去年在开发一个跨国会议系统时,我深刻体会到实时语音翻译质量评估的痛点。传统测试方法要么依赖人工听写对比(效率极低),要么只能获得延迟的统计指标(无法即时调整参数)。这就是为什么…...

多模态大语言模型动态评估:强化学习实践指南

1. 项目背景与核心价值去年我在参与一个跨模态对话系统项目时,遇到了一个棘手的问题:现有的评估体系无法准确衡量模型在复杂多轮对话中的表现。传统单指标评估就像用体温计测血压,完全无法反映真实能力。这促使我开始探索如何将强化学习的动态…...

OpenOrch:云原生时代的轻量级服务编排引擎实践指南

1. 项目概述:从开源项目到企业级编排引擎的蜕变在云原生和微服务架构席卷全球的当下,如何高效、可靠地管理成百上千的服务实例,协调它们之间的依赖关系,并确保整个应用系统能够平滑地发布、回滚与扩缩容,成为了每一个技…...

手机连校园网总弹认证页?教你用Shizuku+CaptiveMgr彻底关掉它(OPPO/小米实测)

彻底解决安卓手机校园网认证弹窗的终极指南 每次连接校园WiFi时,那个烦人的认证页面总会不合时宜地跳出来打断你的工作?即使已经设置了自动登录,系统依然固执地弹出验证窗口。这背后其实是安卓系统的Captive Portal检测机制在作祟——它会定期…...

AMBA AXI TrustZone内存适配器架构与动态分区技术解析

1. AMBA AXI TrustZone内存适配器架构解析在SoC安全架构设计中,内存隔离是最基础的安全防线。传统固定分区方案面临两大挑战:一是安全区域容量预估困难,过早固化分区会导致资源浪费或安全容量不足;二是安全策略调整需要硬件重新流…...

通过 Taotoken 用量分析功能回顾历史请求优化模型调用策略

通过 Taotoken 用量分析功能回顾历史请求优化模型调用策略 1. 用量分析功能概览 Taotoken 控制台提供了完整的用量分析功能,帮助开发者追踪和管理模型调用情况。登录控制台后,在「用量分析」页面可以查看指定时间范围内的详细数据。系统会按模型、项目…...

ARM嵌入式开发环境搭建与调试实战指南

1. ARM嵌入式开发环境搭建与目标设备连接在嵌入式系统开发中,将编译好的软件部署到目标硬件是开发流程中最关键的环节之一。作为一名有十年经验的嵌入式工程师,我经常需要面对各种ARM架构设备的程序烧录和调试工作。这个过程看似简单,但实际上…...

构建内容生成应用时如何用 Taotoken 灵活切换不同大模型

构建内容生成应用时如何用 Taotoken 灵活切换不同大模型 1. 多模型统一接入的价值 在内容生成类应用中,不同模型往往具备差异化优势。例如某些模型擅长创意写作,另一些则精于技术文档生成。传统方案需要为每个模型供应商维护独立的 API 接入逻辑&#…...

LLM技能文件解析:自动化自学习闭环

LLM 技能文件目录解析:带有js,ts文件的是配置到IDE 工具中的 目录 LLM 技能文件目录解析:带有js,ts文件的是配置到IDE 工具中的 二、`.sh` Shell脚本文件:钩子自动化执行核心 三、`.ts`/`.js` 文件:跨平台通用钩子处理器 3.1 两者的关系 3.2 核心作用 3.3 核心执行逻辑与…...

ahk2_lib:重构AutoHotkey V2开发边界的全能扩展套件

ahk2_lib:重构AutoHotkey V2开发边界的全能扩展套件 【免费下载链接】ahk2_lib 项目地址: https://gitcode.com/gh_mirrors/ah/ahk2_lib 在当今快速发展的软件开发领域,AutoHotkey V2凭借其简洁的语法和强大的自动化能力,正逐渐从简单…...

保姆级教程:用PyTorch一步步拆解TransUNet的Transformer+CNN混合架构

深入解析TransUNet:从Transformer到CNN的混合架构实现 在医学图像分割领域,TransUNet以其独特的混合架构设计脱颖而出。本文将带您深入理解这一创新模型的核心机制,并通过PyTorch代码逐步拆解其实现细节。不同于简单的代码复现,我…...

别再只看增益了!用INA128/INA821实测,聊聊仪表放大器选型时最该关注的5个参数

仪表放大器实战选型指南:从参数手册到电路设计的五个关键维度 在医疗ECG信号采集或工业压力传感器调理电路中,工程师们常会遇到这样的困境:明明选用了高精度仪表放大器,实测性能却远低于预期。上周调试一款肌电信号采集板时&#…...

保姆级教程:在Windows上用VSCode搭建PX4固件开发环境(含源码编译与调试)

Windows平台VSCode搭建PX4开发环境全指南 第一次接触PX4固件开发时,我被各种交叉编译工具链和依赖关系搞得晕头转向。直到发现VSCode这个神器,才真正让开发流程变得顺畅。本文将带你从零开始,在Windows系统上搭建完整的PX4开发环境&#xff…...

3步解决Windows平台Vosk-API语音识别集成难题:从DLL加载失败到流畅运行的完整指南

3步解决Windows平台Vosk-API语音识别集成难题:从DLL加载失败到流畅运行的完整指南 【免费下载链接】vosk-api Offline speech recognition API for Android, iOS, Raspberry Pi and servers with Python, Java, C# and Node 项目地址: https://gitcode.com/GitHub…...

League-Toolkit:英雄联盟游戏辅助工具的完整自动化解决方案

League-Toolkit:英雄联盟游戏辅助工具的完整自动化解决方案 【免费下载链接】League-Toolkit An all-in-one toolkit for LeagueClient. Gathering power 🚀. 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit League-Toolkit是一款基…...

STM32+ESP8266连接OneNET的完整避坑指南:从固件烧写到APP控制全流程解析

STM32ESP8266连接OneNET的完整避坑指南:从固件烧写到APP控制全流程解析 当你第一次尝试将STM32与ESP8266组合接入OneNET平台时,可能会遇到各种意想不到的问题:AT指令无响应、MQTT连接频繁断开、JSON数据解析失败...这些问题往往消耗开发者大量…...

别再只盯着IPMI了!聊聊服务器带外管理的那些事儿:BMC、Redfish与IPMI 2.0

服务器带外管理技术全景:从IPMI到Redfish的演进与选型指南 凌晨三点,数据中心的告警铃声突然响起——某台关键服务器失去响应。此时,操作系统早已崩溃,传统SSH连接完全失效。但运维工程师通过带外管理接口,依然能查看硬…...

发现城通网盘直连解析的极简艺术:ctfileGet让文件获取回归本质

发现城通网盘直连解析的极简艺术:ctfileGet让文件获取回归本质 【免费下载链接】ctfileGet 获取城通网盘一次性直连地址 项目地址: https://gitcode.com/gh_mirrors/ct/ctfileGet 你是否还记得上次从城通网盘下载文件时的体验?那个漫长的等待页面…...

基于模型预测控制的低温多效蒸馏海水淡化系统建模与控制实现MPC算法【附代码】

✨ 本团队擅长数据搜集与处理、建模仿真、程序设计、仿真代码、EI、SCI写作与指导,毕业论文、期刊论文经验交流。 ✅ 专业定制毕设、代码 ✅ 如需沟通交流,查看文章底部二维码(1)基于机理与数据驱动的混合动态建模:低温…...

PHP 8.9 JIT调优不是玄学:基于137个真实微服务实例的统计模型——jit_hot_func=128 vs 64,TP99降低14.7ms的临界值揭秘

更多请点击: https://intelliparadigm.com 第一章:PHP 8.9 JIT编译器调优的工程范式转型 PHP 8.9 并非官方发布版本(截至 2024 年,PHP 最新稳定版为 8.3),但作为技术前瞻推演场景,本章以“PHP…...

水火弯板机械臂自动化加工的路径规划激光传感器【附代码】

✨ 本团队擅长数据搜集与处理、建模仿真、程序设计、仿真代码、EI、SCI写作与指导,毕业论文、期刊论文经验交流。 ✅ 专业定制毕设、代码 ✅ 如需沟通交流,查看文章底部二维码(1)基于3D线激光传感器的板边对齐与跟踪:采…...

避免Span<T>越界崩溃,3步静态分析法+2个Roslyn Analyzer插件,上线前必检

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;Span<T>越界崩溃的本质与危害 内存安全边界的脆弱性 <T> 是 .NET 中用于零分配、高性能内存访问的核心类型&#xff0c;其本质是**不持有所有权的内存切片视图**。当 Span<T> 指向…...

效率倍增:用快马平台将dify工作流快速转化为可执行代码框架

最近在做一个智能邮件自动回复的项目&#xff0c;发现用dify设计工作流确实能大幅提升效率。不过从流程图到实际代码实现还是需要不少时间&#xff0c;直到发现了InsCode(快马)平台&#xff0c;这个转换过程变得异常轻松。今天就来分享下如何用这个平台快速把dify工作流转化为可…...

SteadyDancer框架:高保真人像动画生成技术解析

1. 项目背景与核心价值在数字内容创作领域&#xff0c;人体图像动画技术一直是热门研究方向。传统方法往往需要复杂的3D建模或依赖大量训练数据&#xff0c;而基于图像到视频&#xff08;I2V&#xff09;的范式正在改变这一局面。SteadyDancer框架的独特之处在于&#xff0c;它…...

2026年权威解读:GEO源码贴牌解决方案怎么选?全面解析TOP5服务商避坑指南

一、GEO源码贴牌是什么&#xff1f;外行也能懂的通俗解释想象一下&#xff0c;你开了一家餐厅&#xff0c;想让更多人知道。过去&#xff0c;你可能在路口发传单&#xff08;传统SEO&#xff09;&#xff0c;或者花钱请美食博主探店&#xff08;KOL营销&#xff09;。但现在&am…...