如何用 AI SDK 的 ToolLoopAgent 定义可复用的聊天 Agent
2026/9/13 17:01:54 网站建设 项目流程

如何用 AI SDK 的 ToolLoopAgent 定义可复用的聊天 Agent

【免费下载链接】aiThe AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and agents项目地址: https://gitcode.com/GitHub_Trending/ai/ai

如果你的应用里有多处需要「模型 + 工具 + 固定行为」的组合(聊天接口、后台任务、脚本),把模型、系统指令和工具在每次调用点各自拼装,很快就会改一处漏一处。AI SDK(Vercel 出品的 TypeScript AI 工具包)提供的ToolLoopAgent类解决的就是这个问题:把 LLM 配置、工具和 Agent 循环封装成一个可复用组件,定义一次后,同一实例可以同时用于一次性生成、流式输出和聊天 UI 接口。本文基于仓库内文档,走一遍「定义 Agent → 验证 → 挂到聊天接口」的完整路径。

前提:一个 TypeScript 项目,已安装ai包、你选择的模型 provider 包(下文示例使用@ai-sdk/openai)和zod。本文代码示例沿用了仓库文档的模板写法:__PROVIDER_IMPORT____MODEL__是文档占位符,分别替换为你自己的 provider 导入语句(如import { openai } from '@ai-sdk/openai')和模型实例(如openai('gpt-4o'))。下文代码块会直接写成可运行的形式。

定义一个带工具的 Agent

在 Agents 概览 中,Agent 由三部分组成:LLM 负责决策、工具扩展能力、循环负责上下文管理与停止条件。ToolLoopAgent替你管理后两者。下面这个 Agent 带两个工具:查天气(返回华氏度)和摄氏度换算。模型会先调weather,再调convertFahrenheitToCelsius,最后生成文本回答:

import { ToolLoopAgent, tool } from 'ai'; import { openai } from '@ai-sdk/openai'; import { z } from 'zod'; const weatherAgent = new ToolLoopAgent({ model: openai('gpt-4o'), instructions: 'You are a helpful assistant.', tools: { weather: tool({ description: 'Get the weather in a location (in Fahrenheit)', inputSchema: z.object({ location: z.string().describe('The location to get the weather for'), }), execute: async ({ location }) => ({ location, temperature: 72 + Math.floor(Math.random() * 21) - 10, }), }), convertFahrenheitToCelsius: tool({ description: 'Convert temperature from Fahrenheit to Celsius', inputSchema: z.object({ temperature: z.number().describe('Temperature in Fahrenheit'), }), execute: async ({ temperature }) => { const celsius = Math.round((temperature - 32) * (5 / 9)); return { celsius }; }, }), }, });

构造参数中常用的几个配置,均可在 ToolLoopAgent API 参考中查到完整定义:

  • model(必填):语言模型实例,来自 provider 包;
  • instructions:Agent 的系统指令,用来定义角色和行为边界;
  • toolsRecord<string, Tool>,键是工具名。注意文档明确说明工具调用要求底层模型支持 tool calling;
  • stopWhen:循环停止条件,默认isStepCount(20),即最多 20 步;
  • toolChoice:工具选择策略,'auto'(默认,由模型决定)、'none'(禁用工具)、'required'(强制使用工具),或{ type: 'tool', toolName: '...' }强制使用某个具体工具;
  • allowSystemInMessages:是否允许prompt/messages中出现role: "system"消息。文档说明其未设置时会被拒绝,理由是存在 prompt injection 风险,并建议改用instructions——对聊天 Agent 这是一个值得知道的默认行为。

用 stopWhen 控制 Agent 循环

每个 step 对应一次模型生成:要么产出文本(Agent 结束),要么调用工具(SDK 执行工具后进入下一个 step)。默认 20 步的上限对多数聊天场景足够,任务链更长时用isStepCount调整:

import { ToolLoopAgent, isStepCount } from 'ai'; import { openai } from '@ai-sdk/openai'; const agent = new ToolLoopAgent({ model: openai('gpt-4o'), stopWhen: isStepCount(50), // Increase default from 20 to 50. });

也可以组合多个条件,满足任一条件即停止:

import { ToolLoopAgent, isStepCount } from 'ai'; import { openai } from '@ai-sdk/openai'; const agent = new ToolLoopAgent({ model: openai('gpt-4o'), stopWhen: [ isStepCount(20), // Maximum 20 steps yourCustomCondition(), // Custom logic for when to stop ], });

除步数条件外,循环还会在以下情况提前结束(引自 Building Agents):模型返回非 tool-calls 的 finish reasoning;被调用的工具没有execute函数;工具调用需要审批。更多停止条件与prepareStep的用法见 Loop Control。

调用 generate() 并核对结果

最直接的验证方式是generate()。它返回GenerateTextResult,其中result.text是最终回答,result.steps是 Agent 走过的所有步骤:

const result = await weatherAgent.generate({ prompt: 'What is the weather in San Francisco in celsius?', }); console.log(result.text); // agent's final answer console.log(result.steps); // steps taken by the agent

按 Agents 概览 的说明,上面的 prompt 会触发 Agent 自动完成三步:调用weather获取华氏度、调用convertFahrenheitToCelsius换算、生成最终文本。你可以检查result.steps里是否依次出现了这两个工具调用。

如果需要观测日志,generate()支持生命周期回调onStartonStepStartonToolExecutionStartonToolExecutionEndonStepEndonEnd。这些回调既可以写在构造器里(Agent 级跟踪),也可以写在generate()/stream()调用里(单次调用跟踪),两处同时提供时构造器回调先执行。例如记录每一步的 token 用量:

const result = await weatherAgent.generate({ prompt: 'What is the weather in NYC?', onStepEnd({ stepNumber, usage }) { console.log(`Step ${stepNumber}:`, { inputTokens: usage.inputTokens, outputTokens: usage.outputTokens, }); }, onEnd({ usage, steps }) { console.log('Agent finished:', { totalSteps: steps.length, totalTokens: usage.totalTokens, }); }, });

流式输出与聊天 UI 复用

同一个 Agent 实例可以直接用于流式响应,无需重新定义配置:

const stream = weatherAgent.stream({ prompt: 'What is the weather in NYC and what is 100 * 25?', }); for await (const chunk of stream.textStream) { process.stdout.write(chunk); }

要把它接成聊天接口,在 API 路由(如app/api/chat/route.ts)中用createAgentUIStreamResponse,把 Agent 的流式输出包装成 UI message stream 返回。该函数只用于服务端上下文,且要求 Agent 实现.stream({ prompt, ... })并定义tools属性(即使为空对象也要定义),ToolLoopAgent天然满足。路由代码来自 createAgentUIStreamResponse 参考:

import { createAgentUIStreamResponse } from 'ai'; import { weatherAgent } from '@/agent/weather-agent'; export async function POST(request: Request) { const { messages } = await request.json(); return createAgentUIStreamResponse({ agent: weatherAgent, uiMessages: messages, // Optional: support cancellation (aborts on disconnect, etc.) // abortSignal: abortController.signal, }); }

它的内部流程(引自同一篇参考文档):先按 Agent 的工具配置校验uiMessages,再转换为模型消息,然后调用 Agent 的.stream(),最后把输出流包成可读的 HTTPResponse。你的平台需要支持 HTTP 流式消费。

客户端用useChat对接这个端点。UI 消息推荐使用parts属性渲染(支持 text、tool invocation、tool result 等类型),见 Chatbot 指南:

'use client'; import { useChat } from '@ai-sdk/react'; import { DefaultChatTransport } from 'ai'; import { useState } from 'react'; export default function Page() { const { messages, sendMessage, status } = useChat({ transport: new DefaultChatTransport({ api: '/api/chat', }), }); const [input, setInput] = useState(''); return ( <> {messages.map(message => ( <div key={message.id}> {message.role === 'user' ? 'User: ' : 'AI: '} {message.parts.map((part, index) => part.type === 'text' ? <span key={index}>{part.text}</span> : null, )} </div> ))} <form onSubmit={e => { e.preventDefault(); if (input.trim()) { sendMessage({ text: input }); setInput(''); } }} > <input value={input} onChange={e => setInput(e.target.value)} disabled={status !== 'ready'} placeholder="Say something..." /> <button type="submit" disabled={status !== 'ready'}> Submit </button> </form> </> ); }

useChatstatus取值:submitted(已发送、等待响应流开始)、streaming(正在接收流)、ready(响应完成,可发送新消息)、error(请求出错)。用status !== 'ready'禁用输入框就是文档示例的做法。出错时可显示通用错误提示并用regenerate重试,流式过程中可用stop中止请求。

用 InferAgentUIMessage 获得端到端类型安全

Agent 的工具和输出类型可以直接推导成 UI 消息类型,供useChat使用。定义在 Agent 所在模块并导出,客户端组件导入:

import { ToolLoopAgent, InferAgentUIMessage } from 'ai'; const myAgent = new ToolLoopAgent({ // ... configuration }); // Infer the UIMessage type for UI components or persistence export type MyAgentUIMessage = InferAgentUIMessage<typeof myAgent>;
'use client'; import { useChat } from '@ai-sdk/react'; import type { MyAgentUIMessage } from '@/agent/my-agent'; export function Chat() { const { messages } = useChat<MyAgentUIMessage>(); // Full type safety for your messages and tools }

边界与限制

  • 工具调用依赖模型能力:tools配置要求底层模型支持 tool calling,换成不支持的模型时工具不会生效;
  • 步数上限不是失败:stopWhen命中时循环直接结束,如果你的任务经常在第 20 步被截断,先用result.steps确认步数分布再调大isStepCount
  • prepareStep中返回的模型调用设置(如temperature)只作用于当前 step,后续 step 回到 Agent 顶层设置,除非再次返回覆盖;
  • createAgentUIStreamResponse仅限服务端使用,不能在浏览器中调用。

工具审批(toolApproval)、runtimeContext/toolsContext的传递规则分别是独立的进阶主题,参见 Tool Approvals 和 Runtime and Tool Context;需要可预测的显式控制流时,可以看 Workflow Patterns 了解用核心函数构建结构化工作流的方式。

【免费下载链接】aiThe AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and agents项目地址: https://gitcode.com/GitHub_Trending/ai/ai

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询