使用 Vercel AI SDK 构建智能对话应用:从基础到多工具集成
引言:AI 应用开发的新范式
在人工智能快速发展的今天,构建一个智能对话系统不再需要复杂的底层实现。想象一下,你只需几行代码就能让应用具备与用户自然交互的能力,并且能够调用各种工具完成特定任务。这正是 Vercel AI SDK 带给开发者的便利。本文将带你探索如何利用这一强大工具包,从零开始构建一个功能完善的 AI 应用,不仅能进行流畅对话,还能集成实用工具扩展能力边界。
为什么选择 Vercel AI SDK?
Vercel AI SDK 提供了统一的 API 接口,让开发者可以轻松集成各种 AI 模型提供商的服务,而无需针对每个提供商编写特定代码。它支持流式响应(Streaming Response),能提供实时交互体验,同时内置了工具调用框架,让 AI 不仅能"思考",还能"行动"。
核心功能解析:构建 AI 应用的基石
环境搭建与依赖管理
要开始使用 Vercel AI SDK,首先需要准备好开发环境。我们需要 Node.js 18 或更高版本,以及一个包管理器。以下是初始化项目的完整步骤:
# 创建项目目录并进入
mkdir intelligent-assistant
cd intelligent-assistant
# 初始化项目
pnpm init -y
# 安装核心依赖
pnpm add ai @ai-sdk/openai zod dotenv
# 安装开发依赖
pnpm add -D @types/node tsx typescript
知识点卡片:
核心依赖解析:
ai:Vercel AI SDK 核心库,提供对话和工具调用功能@ai-sdk/openai:OpenAI 模型集成适配器zod:TypeScript 优先的模式验证库,确保类型安全dotenv:环境变量管理工具,安全存储 API 密钥
基础架构:构建对话系统的核心组件
一个完整的 AI 对话系统包含几个关键组件:模型配置、消息管理和响应处理。让我们通过一个基础示例来理解这些组件如何协同工作。
首先,创建 .env 文件存储 API 密钥:
# .env 文件
OPENAI_API_KEY=your_api_key_here
然后创建 src/main.ts 文件,实现基础对话功能:
import { openai } from '@ai-sdk/openai';
import { CoreMessage, streamText } from 'ai';
import dotenv from 'dotenv';
import * as readline from 'node:readline/promises';
// 加载环境变量
dotenv.config();
// 创建命令行交互界面
const terminal = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
// 存储对话历史
const messages: CoreMessage[] = [];
async function startConversation() {
console.log('欢迎使用智能助手!输入"退出"结束对话。\n');
while (true) {
// 获取用户输入
const userInput = await terminal.question('你: ');
// 检查是否退出
if (userInput.toLowerCase() === '退出') {
console.log('再见!');
terminal.close();
break;
}
// 将用户消息添加到对话历史
messages.push({ role: 'user', content: userInput });
try {
// 调用 AI 模型获取响应
const result = streamText({
model: openai('gpt-4o'), // 指定使用的模型
messages: messages, // 传递对话历史
});
// 处理流式响应
process.stdout.write('\n助手: ');
let fullResponse = '';
// 逐块接收并显示响应
for await (const chunk of result.textStream) {
fullResponse += chunk;
process.stdout.write(chunk);
}
// 添加换行以美化输出
console.log('\n');
// 将助手响应添加到对话历史
messages.push({ role: 'assistant', content: fullResponse });
} catch (error) {
console.error('\n发生错误:', error);
}
}
}
// 启动对话
startConversation().catch(console.error);
💡 重点提示:
流式响应是提升用户体验的关键特性。通过 streamText 函数,我们可以在模型生成完整响应前就开始接收并显示内容,让对话感觉更加自然流畅。
扩展思考:
如何实现对话历史的持久化存储?可以考虑使用文件系统或数据库保存对话记录,以便用户下次使用时可以继续之前的对话。
知识点卡片:
对话系统核心流程:
- 收集用户输入
- 维护对话历史上下文
- 调用 AI 模型生成响应
- 处理并展示流式输出
- 更新对话历史
功能模块:扩展 AI 的能力边界
工具集成框架:让 AI 拥有"行动力"
虽然大型语言模型(LLM)知识渊博,但在处理实时数据或执行特定任务时仍有局限。工具集成功能让 AI 能够调用外部 API 或函数,极大扩展了其应用范围。
实现股票查询工具
让我们为 AI 添加一个股票价格查询工具。首先,定义工具函数:
import { tool } from 'ai';
import { z } from 'zod';
// 股票价格查询工具
const stockPriceTool = tool({
description: '获取指定股票代码的当前价格(美元)',
parameters: z.object({
symbol: z.string().describe('股票代码,如AAPL表示苹果公司'),
}),
execute: async ({ symbol }) => {
// 在实际应用中,这里会调用真实的股票API
// 此处使用模拟数据
const mockPrices = {
AAPL: 189.5,
MSFT: 410.25,
GOOGL: 172.3,
AMZN: 182.7
};
// 模拟网络延迟
await new Promise(resolve => setTimeout(resolve, 800));
return {
symbol,
price: mockPrices[symbol as keyof typeof mockPrices] || null,
currency: 'USD',
timestamp: new Date().toISOString()
};
},
});
然后,修改对话逻辑以支持工具调用:
// 修改streamText调用,添加tools配置
const result = streamText({
model: openai('gpt-4o'),
messages,
tools: {
getStockPrice: stockPriceTool
},
// 启用多步骤工具调用
maxSteps: 3,
onStepFinish: (step) => {
console.log('\n工具调用信息:', JSON.stringify(step, null, 2));
}
});
💡 重点提示:
工具定义中的 description 和参数描述非常重要,它们帮助 AI 理解何时以及如何使用工具。清晰的描述可以显著提高工具调用的准确性。
扩展思考:
如何处理工具调用失败的情况?可以添加错误处理逻辑,让 AI 能够重试或向用户说明无法获取数据的原因。
添加单位转换工具
为了展示多工具协作,我们再添加一个单位转换工具:
// 单位转换工具
const unitConversionTool = tool({
description: '进行不同单位之间的转换',
parameters: z.object({
value: z.number().describe('要转换的数值'),
fromUnit: z.string().describe('原始单位,如"cm"、"kg"、"celsius"'),
toUnit: z.string().describe('目标单位,如"inch"、"lb"、"fahrenheit"'),
}),
execute: async ({ value, fromUnit, toUnit }) => {
// 实现常见单位转换逻辑
let result: number | null = null;
// 长度转换
if (fromUnit === 'cm' && toUnit === 'inch') {
result = value / 2.54;
} else if (fromUnit === 'inch' && toUnit === 'cm') {
result = value * 2.54;
}
// 温度转换
else if (fromUnit === 'celsius' && toUnit === 'fahrenheit') {
result = (value * 9/5) + 32;
} else if (fromUnit === 'fahrenheit' && toUnit === 'celsius') {
result = (value - 32) * 5/9;
}
// 重量转换
else if (fromUnit === 'kg' && toUnit === 'lb') {
result = value * 2.20462;
} else if (fromUnit === 'lb' && toUnit === 'kg') {
result = value / 2.20462;
}
return {
original: { value, unit: fromUnit },
converted: result !== null ? { value: parseFloat(result.toFixed(2)), unit: toUnit } : null,
success: result !== null
};
},
});
// 更新工具配置
tools: {
getStockPrice: stockPriceTool,
convertUnit: unitConversionTool
}
现在,AI 可以根据用户问题决定调用哪个工具,甚至在需要时组合使用多个工具。
知识点卡片:
工具调用工作流:
- AI 分析用户问题,决定是否需要调用工具
- 如果需要,生成工具调用请求
- 执行工具并获取结果
- AI 根据工具返回结果生成自然语言响应
- 如需进一步信息,可进行多轮工具调用
实战案例:构建智能投资助手
现在,让我们整合所学知识,构建一个智能投资助手,它能够回答股票问题并进行货币转换。
完整实现代码
import { openai } from '@ai-sdk/openai';
import { CoreMessage, streamText, tool } from 'ai';
import { z } from 'zod';
import dotenv from 'dotenv';
import * as readline from 'node:readline/promises';
// 加载环境变量
dotenv.config();
// 创建命令行交互界面
const terminal = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
// 存储对话历史
const messages: CoreMessage[] = [];
// 股票价格查询工具
const stockPriceTool = tool({
description: '获取指定股票代码的当前价格(美元)',
parameters: z.object({
symbol: z.string().describe('股票代码,如AAPL表示苹果公司'),
}),
execute: async ({ symbol }) => {
// 模拟股票价格API
const mockPrices = {
AAPL: 189.5,
MSFT: 410.25,
GOOGL: 172.3,
AMZN: 182.7
};
await new Promise(resolve => setTimeout(resolve, 800));
return {
symbol,
price: mockPrices[symbol as keyof typeof mockPrices] || null,
currency: 'USD',
timestamp: new Date().toISOString()
};
},
});
// 单位转换工具
const unitConversionTool = tool({
description: '进行不同单位之间的转换',
parameters: z.object({
value: z.number().describe('要转换的数值'),
fromUnit: z.string().describe('原始单位,如"cm"、"kg"、"celsius"'),
toUnit: z.string().describe('目标单位,如"inch"、"lb"、"fahrenheit"'),
}),
execute: async ({ value, fromUnit, toUnit }) => {
let result: number | null = null;
// 实现单位转换逻辑
if (fromUnit === 'cm' && toUnit === 'inch') {
result = value / 2.54;
} else if (fromUnit === 'inch' && toUnit === 'cm') {
result = value * 2.54;
} else if (fromUnit === 'celsius' && toUnit === 'fahrenheit') {
result = (value * 9/5) + 32;
} else if (fromUnit === 'fahrenheit' && toUnit === 'celsius') {
result = (value - 32) * 5/9;
} else if (fromUnit === 'kg' && toUnit === 'lb') {
result = value * 2.20462;
} else if (fromUnit === 'lb' && toUnit === 'kg') {
result = value / 2.20462;
}
return {
original: { value, unit: fromUnit },
converted: result !== null ? { value: parseFloat(result.toFixed(2)), unit: toUnit } : null,
success: result !== null
};
},
});
async function startInvestmentAssistant() {
console.log('欢迎使用智能投资助手!我可以帮你查询股票价格和进行单位转换。');
console.log('输入"退出"结束对话。\n');
while (true) {
const userInput = await terminal.question('你: ');
if (userInput.toLowerCase() === '退出') {
console.log('感谢使用,再见!');
terminal.close();
break;
}
messages.push({ role: 'user', content: userInput });
try {
const result = streamText({
model: openai('gpt-4o'),
messages,
tools: {
getStockPrice: stockPriceTool,
convertUnit: unitConversionTool
},
maxSteps: 3,
onStepFinish: (step) => {
console.log('\n[工具调用信息]:', JSON.stringify(step, null, 2));
}
});
process.stdout.write('\n助手: ');
let fullResponse = '';
for await (const chunk of result.textStream) {
fullResponse += chunk;
process.stdout.write(chunk);
}
console.log('\n');
messages.push({ role: 'assistant', content: fullResponse });
} catch (error) {
console.error('\n发生错误:', error);
}
}
}
startInvestmentAssistant().catch(console.error);
运行与测试
添加一个启动脚本到 package.json:
{
"scripts": {
"start": "tsx src/main.ts"
}
}
运行应用:
pnpm start
尝试以下问题来测试功能:
- "苹果公司的股票价格是多少?"
- "把100美元转换成人民币是多少?"
- "微软股票价格用人民币计算是多少?"(这将触发多工具调用)
扩展思考:
如何添加更多金融相关工具,如汇率查询、市场新闻获取等,使助手更具实用性?考虑集成真实的金融 API 来提供实时数据。
场景扩展:从命令行到生产环境
常见问题排查
在开发 AI 应用时,你可能会遇到以下常见问题:
-
API 密钥错误
- 症状:无法连接到 OpenAI 服务,出现认证错误
- 解决方案:检查
.env文件中的 API 密钥是否正确,确保没有额外的空格或引号
-
工具调用不触发
- 症状:AI 应该调用工具但没有调用
- 解决方案:改进工具描述,确保问题明确需要工具支持,增加
maxSteps值
-
流式响应中断
- 症状:响应突然停止或不完整
- 解决方案:检查网络连接,添加超时处理,实现断点续传机制
-
对话历史管理
- 症状:对话上下文丢失或超出模型 token 限制
- 解决方案:实现对话历史截断机制,只保留最近的关键对话
-
工具返回结果处理
- 症状:AI 无法正确解析工具返回的结果
- 解决方案:标准化工具返回格式,提供更详细的结果描述
部署与扩展建议
要将你的 AI 应用从开发环境推向生产,可以考虑以下步骤:
- Web 界面转换:使用 React、Vue 或其他前端框架构建友好的用户界面
- API 封装:将功能封装为 REST 或 GraphQL API,供多个客户端使用
- 用户认证:添加用户系统,为不同用户保存个性化对话历史
- 性能优化:实现缓存机制,减少重复的 AI 模型调用
- 监控与日志:添加应用监控和日志系统,追踪性能和使用情况
进阶学习路径
掌握了基础之后,你可以通过以下路径进一步提升:
- 多模态交互:学习如何处理图像、音频等非文本输入,构建更丰富的交互体验
- 检索增强生成(RAG):结合知识库实现更准确、最新的 AI 响应
- 自定义模型微调:根据特定领域数据微调模型,提高专业任务表现
- 多模型协作:学习如何组合使用不同专长的模型,如文本模型、图像模型等
- AI 代理系统:构建能够自主规划、执行复杂任务的 AI 代理
总结
通过本文,你已经了解了如何使用 Vercel AI SDK 构建功能丰富的 AI 应用。从基础的对话系统到集成实用工具,再到处理复杂的多步骤任务,Vercel AI SDK 提供了一套完整的解决方案。随着 AI 技术的不断发展,这些工具和技术将帮助你构建更智能、更有用的应用。
记住,最好的学习方式是实践。尝试扩展本文中的示例,添加新的工具,改进用户体验,或者将其部署为一个真正的产品。AI 应用开发正处于快速发展阶段,掌握这些技能将为你打开新的可能性。
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 StartedRust099- DDeepSeek-V4-ProDeepSeek-V4-Pro(总参数 1.6 万亿,激活 49B)面向复杂推理和高级编程任务,在代码竞赛、数学推理、Agent 工作流等场景表现优异,性能接近国际前沿闭源模型。Python00
MiMo-V2.5-ProMiMo-V2.5-Pro作为旗舰模型,擅⻓处理复杂Agent任务,单次任务可完成近千次⼯具调⽤与⼗余轮上 下⽂压缩。Python00
GLM-5.1GLM-5.1是智谱迄今最智能的旗舰模型,也是目前全球最强的开源模型。GLM-5.1大大提高了代码能力,在完成长程任务方面提升尤为显著。和此前分钟级交互的模型不同,它能够在一次任务中独立、持续工作超过8小时,期间自主规划、执行、自我进化,最终交付完整的工程级成果。Jinja00
Kimi-K2.6Kimi K2.6 是一款开源的原生多模态智能体模型,在长程编码、编码驱动设计、主动自主执行以及群体任务编排等实用能力方面实现了显著提升。Python00
MiniMax-M2.7MiniMax-M2.7 是我们首个深度参与自身进化过程的模型。M2.7 具备构建复杂智能体应用框架的能力,能够借助智能体团队、复杂技能以及动态工具搜索,完成高度精细的生产力任务。Python00
