使用 AI SDK DevTools 调试与检视 AI SDK 应用:遥测集成、数据流与源码级原理
AI SDK DevTools 是 AI SDK(The AI Toolkit for TypeScript)生态中的本地开发调试工具,用于检视 AI SDK 应用的 LLM 请求、响应、工具调用与多步交互过程。本文以仓库中的 packages/devtools/README.md 为骨架,结合其源码实现,讲解如何安装、接入、运行 DevTools,深入剖析其数据捕获链路、存储结构与运行原理,并给出 monorepo、流式输出等实际场景下的使用建议。
适用前提:本包当前处于实验性阶段,仅用于本地开发调试,严禁在生产环境使用(源码在 integration.ts 中会在
NODE_ENV === 'production'时直接抛错);要求 AI SDK v7 canary(ai@canary)与 Node.js 兼容运行时(包的engines声明为node >= 22,见 package.json)。
一、安装与接入:两条捕获路径
1.1 安装
在项目根目录执行:
npm install @ai-sdk/devtools
# 或
pnpm add @ai-sdk/devtools
在 monorepo 场景下,请使用 pnpm add -w 或在运行 AI SDK 代码的同一 workspace 中安装。安装后包会暴露两个入口(见 src/index.ts):DevToolsTelemetry(遥测集成)与 devToolsMiddleware(模型中间件),同时注册 devtools 二进制命令(见 package.json 与 bin/cli.js)。
1.2 路径一:全局注册遥测集成(推荐)
DevToolsTelemetry 挂接 AI SDK 的遥测生命周期,可自动捕获应用内所有 generateText、streamText、generateObject、streamObject 调用:
import { registerTelemetry } from 'ai';
import { DevToolsTelemetry } from '@ai-sdk/devtools';
registerTelemetry(DevToolsTelemetry());
注册后遥测自动生效,后续调用无需任何额外配置:
import { generateText } from 'ai';
const result = await generateText({
model: yourModel,
prompt: 'What cities are in the United States?',
});
需要注意,DevToolsTelemetry 会对 ai.embed、ai.embedMany、ai.rerank 等嵌入/重排操作直接忽略(见 integration.ts),因此捕获范围聚焦于文本生成与对象生成类调用。
1.3 路径二:按调用传入集成
如果不希望全局捕获,可将集成显式传给单次调用:
import { streamText } from 'ai';
import { DevToolsTelemetry } from '@ai-sdk/devtools';
const result = streamText({
model: yourModel,
prompt: 'Hello!',
telemetry: {
integrations: [DevToolsTelemetry()],
},
});
1.4 路径三:语言模型中间件(面向流式调试)
除了遥测集成,包还导出 devToolsMiddleware,以 LanguageModelV4Middleware 形式包装模型,可在不依赖遥测系统的场景下捕获 generate 与 stream 两个阶段:
import { streamText, wrapLanguageModel } from 'ai';
import { devToolsMiddleware } from '@ai-sdk/devtools';
const result = streamText({
model: wrapLanguageModel({
middleware: devToolsMiddleware(),
model: yourModel,
}),
prompt: '...',
});
从源码看,该中间件会强制开启 includeRawChunks 以便收集 provider 原始分片,并区分三种结束路径——正常完成(flush)、流被取消(cancel)、抛出异常——分别写入不同的结果状态(见 middleware.ts)。生产环境下调用它会同样抛错拒绝。
1.5 runId 选项:关联跨请求的多步交互
DevToolsTelemetry 支持一个可选参数 runId,用于将多个 AI SDK 调用归并到同一条 DevTools run 中(见 integration.ts):
registerTelemetry(DevToolsTelemetry({ runId: 'my-session-1' }));
当传入 runId 时,源码会复用该 run 并依据已有步骤数设置 stepNumberOffset,保证续写交互的步骤编号连续(见 integration.ts)。在中断后恢复交互时,复用同一 runId 即可在视图中看到完整链路。
二、启动查看器(Viewer)
2.1 启动命令
npx @ai-sdk/devtools@latest
启动后打开 http://localhost:4983 即可查看 AI SDK 交互记录。CLI 实际是调用 startViewer(port) 启动 Hono 服务(见 bin/cli.js),默认端口为 4983。
端口可通过环境变量覆盖:
AI_SDK_DEVTOOLS_PORT=4984 npx @ai-sdk/devtools@latest
当端口被占用时,服务会给出明确报错并提示该用法(见 server.ts)。
2.2 界面与主题
查看器默认使用深色主题,可通过头部主题按钮切换深色/浅色,浏览器会记住同一 origin 下的选择(主题逻辑与测试见 theme.ts 与 theme.test.ts)。
2.3 monorepo 使用建议
在 monorepo 中,应从运行 AI SDK 代码的同一 workspace 启动 DevTools。文档特别强调使用显式 @latest 标签:这能确保 npx 安装一个可执行副本,而不是选中某个传递依赖中的二进制文件(该依赖的 binary 未被链接进当前 workspace,会导致启动失败)。
2.4 开发模式
仓库内自带开发脚本(见 package.json):
pnpm install
pnpm dev # 并发启动 API 与 Vite 客户端,UI 位于 http://localhost:5173
AI_SDK_DEVTOOLS_DEV=true 时 API 仅监听 4983 端口并重定向到 Vite dev server;未设置该标志时则直接托管构建好的 dist/client 静态产物(见 server.ts)。
三、工作原理:捕获、存储与实时推送
3.1 数据流
AI SDK call -> DevToolsTelemetry -> JSON file -> Hono API -> React UI
更精确地说,链路为:AI SDK 遥测事件 → 集成捕获并序列化 → 写入 .devtools/generations.json → 通过 HTTP 通知 Hono API → 服务端通过 SSE 广播 → React 查看器渲染。
3.2 本地存储与自愈机制
数据以 JSON 文件形式存储在项目根目录的 .devtools/generations.json(见 db.ts)。写入时有几个值得注意的实现细节:
- 内存缓存:
dbCache避免每次读写都解析整个文件,提升高频步骤写入性能(db.ts)。 - 损坏自愈:若 JSON 解析失败则从空数据库重新开始(db.ts)。
- gitignore 保护:首次创建
.devtools目录时,若存在.gitignore且未包含.devtools,会自动追加一行(db.ts),防止调试数据误提交。 - 跨目录读取:notify 请求携带
dbPath,服务端校验其文件名与父目录必须严格匹配.devtools/generations.json,且文件大小上限 100 MB,避免同步读卡死或 OOM(db.ts)。这使查看器即使从不同目录启动也能正确读取数据。 - 进程退出兜底:集成与中间件都会注册 SIGINT/SIGTERM 处理器,进程退出前将仍在执行中的步骤标记为
Request aborted并完成最后一次 notify(见 integration.ts)。
3.3 实时更新:SSE 推送
AI SDK 调用写入数据库后,通过 POST /api/notify 通知服务端重新加载数据库,并向所有已连接客户端广播 update 事件(server.ts)。客户端通过 /api/events 的 SSE 长连接接收更新,服务端每 30 秒发送一次心跳保活(server.ts)。此外 /api/runs、/api/runs/:id、/api/clear 分别提供运行列表、单条 run 详情(含递归子 run)与清空数据的能力,API 层同时校验 Host 与 Origin 白名单(server.ts)。
3.4 关键概念:Run 与 Step
- Run:一次完整的、可能包含多步的 AI 交互,按初始 prompt 分组。每次
generateText/streamText等顶层调用生成一个 run,run ID 由时间戳前缀 + UUID 片段构成,天然可按时间排序(integration.ts)。 - Step:run 内的一次单次 LLM 调用。工具调用中嵌套的
generateText/streamText会被关联为父 run 的子 run(源码通过toolContextMap跟踪嵌套上下文,见 integration.ts),查看器据此渲染父子层级。
四、捕获的数据内容
DevToolsTelemetry 为每个 step 捕获以下数据(见 integration.ts 与 db.ts):
| 类别 | 内容 |
|---|---|
| 输入参数与提示词 | promptMessages/messages、工具定义(名称/描述/参数 schema)、toolChoice |
| 生成设置 | maxOutputTokens、temperature、topP、topK、presencePenalty、frequencyPenalty、seed |
| 输出内容与工具调用 | 文本内容、finishReason、响应元信息(id/modelId/timestamp/messages) |
| 用量与耗时 | usage(token 用量 JSON)、duration_ms 耗时 |
| Provider 原始数据 | raw_request(请求 body)、raw_response(响应 body)、raw_chunks(流式原始分片)、provider_options |
| 错误信息 | error 字段记录异常消息 |
4.1 二进制媒体数据的序列化处理
消息中包含图片、音频等二进制内容时,直接 JSON.stringify 会产生大量乱码。仓库提供了专门的序列化工具 serializeForDevTools:它递归扫描消息结构,识别 file、reasoning-file、image、media、file-data、image-data 等媒体承载字段,将其中 ArrayBuffer/TypedArray 转为 base64 保留,其余二进制值保持默认 JSON 表示(见 serialize.ts)。这意味着查看器中可以直接查看多模态消息的二进制附件。
4.2 流式输出如何被“收拢”
对于 streamText 这类流式调用,集成记录的是 step 开始时的输入;中间件路径下,流式分片通过 TransformStream 被汇总:text-delta 拼接成完整文本、reasoning-delta 拼接推理内容、tool-call 收集工具调用、finish 记录结束原因与用量,同时保存完整分片序列与原始分片供回放检视(见 middleware.ts)。
五、在 AI SDK 应用中的典型集成示例
仓库自带可运行的示例(examples/basic/index.ts),展示了带工具调用与 stopWhen 停止条件的多步交互:
import { gateway, isStepCount, registerTelemetry, streamText } from 'ai';
import { tools } from './tools';
import { DevToolsTelemetry } from '../../src';
import { print } from './utils';
import 'dotenv/config';
registerTelemetry(DevToolsTelemetry());
const result = streamText({
model: gateway('anthropic/claude-haiku-4.5'),
system: 'Always call the weather before recommending plans.',
prompt: 'Whats the weather in SF and London in C?',
tools,
stopWhen: isStepCount(5),
providerOptions: {
anthropic: {
thinking: {
type: 'enabled',
budgetTokens: 10000,
},
},
},
});
print(await result.content);
运行该示例(pnpm example 或 tsx examples/basic/index.ts)后,在查看器中即可看到:一个 run 下包含多次 step——首轮调用返回工具调用,随后每轮工具结果回填触发新一轮 LLM 调用,直到满足 isStepCount(5) 停止条件。这正是调试多步 Agent 工作流时最常用的检视场景。
六、常见问题与注意事项
- 生产环境误用:
DevToolsTelemetry与devToolsMiddleware在NODE_ENV === 'production'下都会直接抛错,构建生产包前必须移除遥测注册或中间件包装。 - 端口冲突:4983 被占用时服务会提示“DevTools is already running”,改用
AI_SDK_DEVTOOLS_PORT指定新端口即可。 - 查看器与应用目录不一致:得益于 notify 携带并校验
dbPath的设计,查看器可从任意目录启动并读取正确数据;数据文件需位于以.devtools/generations.json结尾的路径,且不超过 100 MB。 - 实验性状态:本包标注为实验性(见 README 顶部 Note),接口与行为可能随 AI SDK 演进调整,请以当前仓库实现为准。
七、进一步阅读
- 集成实现: integration.ts
- 中间件实现: middleware.ts
- 存储与通知: db.ts
- 查看器服务端(Hono API + SSE): server.ts
- 序列化工具: serialize.ts
- 单元测试: integration.test.ts、db.test.ts、middleware.test.ts、serialize.test.ts
- E2E 测试: theme.e2e.test.ts
- 运行示例: examples/basic/index.ts
结合上述源码与测试,你可以在本地快速搭建起完整的 AI SDK 调用检视环境,定位多步 Agent 中工具调用、参数传递与原始 provider 数据的问题。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust4.21 K637- DDeepSeek-V4.1-FlashDeepSeek-V4.1-Flash 是一个多模态混合专家(MoE)模型,拥有 5520 亿骨干参数,并支持最多一百万 token 的上下文长度。该模型原生支持图像和文本输入,并以自回归方式生成文本Python320
cherry-studio🍒 Cherry Studio 是一款支持多个 LLM 提供商的桌面客户端TypeScript2 K146
hello-agents📚 《从零开始构建智能体》——从零开始的智能体原理与实践教程Python46567
new-apiAI模型聚合管理中转分发系统,一个应用管理您的所有AI模型,支持将多种大模型转为统一格式调用,支持OpenAI、Claude、Gemini等格式,可供个人或者企业内部管理与分发渠道使用。🍥 A Unified AI Model Management & Distribution System. Aggregate all your LLMs into one app and access them via an OpenAI-compatible API, with native support for Claude (Messages) and Gemini formats.Go20043
JeecgBoot🔥企业级低代码平台集成了AI应用平台,帮助企业快速实现低代码开发和构建AI应用!前后端分离架构 SpringBoot,SpringCloud、Mybatis,Ant Design4、 Vue3.0、TS+vite!强大的代码生成器让前后端代码一键生成,无需写任何代码! 引领AI低代码开发模式: AI生成->OnlineCoding-> 代码生成-> 手工MERGE,显著的提高效率,又不失灵活~Java33951