Integrate You.com web tools with Vercel AI SDK技能使用说明
将AI SDK与You.com工具集成
使用以下工具将You.com工具添加到您的Vercel AI SDK应用程序的交互式工作流程@youdotcom-oss/ai-sdk-plugin。
工作流程
-
询问:包管理器

- 选择哪种包管理器?(npm、bun、yarn、pnpm)
- 使用他们选择的包管理器安装包:
npm install @youdotcom-oss/ai-sdk-plugin # or bun add @youdotcom-oss/ai-sdk-plugin # or yarn add @youdotcom-oss/ai-sdk-plugin # or pnpm add @youdotcom-oss/ai-sdk-plugin
-
询问:环境变量名称
- 使用标准
YDC_API_KEY? - 还是自定义名称?(如果自定义,请获取名称)
- 他们是否已在环境中设置?
- 如果没有:引导他们从以下网址获取密钥https://you.com/platform/api-keys
- 使用标准
-
询问:使用哪些AI SDK函数?
- 他们是否使用
generateText()? - 他们是否使用
streamText()? - 两者都要?
- 他们是否使用
-
询问:现有文件还是新文件?
- 现有:询问要编辑哪个(哪些)文件
- 新建:询问在何处创建文件以及如何命名
-
针对每个文件,询问:
- 要添加哪些工具?
youSearch(网络搜索)youExpress(AI代理)youContents(内容提取)- 多个?(哪种组合?)
- 使用
generateText()还是streamText()在此文件中? - 使用哪个AI提供商模型?(以确定是否需要stopWhen)
- 要添加哪些工具?
-
参考集成示例
完整的代码模式请参见下方的"集成示例"部分:
- generateText() - 使用工具进行基本文本生成
- streamText() - 与Web框架流式响应(Next.js, Express, React)
-
更新/创建文件
针对每个文件:
- 参考集成示例(根据其回答使用 generateText 或 streamText)
- 添加所选工具的导入
- 如果是现有文件:找到其 generateText/streamText 调用并添加工具对象
- 如果是新文件:使用示例结构创建文件
- 基于环境变量名的工具调用模式:
- 标准
YDC_API_KEY:youSearch() - 自定义名称:
youSearch({ apiKey: process.env.CUSTOM_NAME })
- 标准
- 将所选工具添加到工具对象
- 如果是 streamText + Anthropic:添加 stopWhen 参数
集成示例
generateText() - 基础文本生成
环境变量设置:
import { anthropic } from '@ai-sdk/anthropic';
import { generateText } from 'ai';
import { youContents, youExpress, youSearch } from '@youdotcom-oss/ai-sdk-plugin';
// Reads YDC_API_KEY from environment automatically
const result = await generateText({
model: anthropic('claude-sonnet-4-5-20250929'),
tools: {
search: youSearch(),
},
prompt: 'What are the latest developments in quantum computing?',
});
console.log(result.text);
多工具:
const result = await generateText({
model: anthropic('claude-sonnet-4-5-20250929'),
tools: {
search: youSearch(), // Web search with citations
agent: youExpress(), // AI answers with web context
extract: youContents(), // Content extraction from URLs
},
prompt: 'Research quantum computing and summarize the key papers',
});
自定义API密钥:
const result = await generateText({
model: anthropic('claude-sonnet-4-5-20250929'),
tools: {
search: youSearch({ apiKey: 'your-custom-key' }),
},
prompt: 'Your prompt here',
});
完整示例:
import { anthropic } from '@ai-sdk/anthropic';
import { generateText } from 'ai';
import { youSearch } from '@youdotcom-oss/ai-sdk-plugin';
const main = async () => {
try {
const result = await generateText({
model: anthropic('claude-sonnet-4-5-20250929'),
tools: {
search: youSearch(),
},
maxSteps: 5,
prompt: 'What are the latest developments in quantum computing?',
});
console.log('Generated text:', result.text);
console.log('\nTool calls:', result.steps.flatMap(s => s.toolCalls));
} catch (error) {
console.error('Error:', error);
process.exit(1);
}
};
main();
streamText() - 流式响应
基础流式处理与 stopWhen 模式:
import { anthropic } from '@ai-sdk/anthropic';
import { streamText, type StepResult } from 'ai';
import { youSearch } from '@youdotcom-oss/ai-sdk-plugin';
// CRITICAL: Always use stopWhen for Anthropic streaming
// Anthropic's SDK requires explicit stop conditions
const stepCountIs = (n: number) => (stepResult: StepResult<any>) =>
stepResult.stepNumber >= n;
const result = streamText({
model: anthropic('claude-sonnet-4-5-20250929'),
tools: { search: youSearch() },
stopWhen: stepCountIs(3), // Required for Anthropic
prompt: 'What are the latest AI developments?',
});
// Consume stream
for await (const chunk of result.textStream) {
process.stdout.write(chunk);
}
Next.js 集成(应用路由器):
// app/api/chat/route.ts
import { anthropic } from '@ai-sdk/anthropic';
import { streamText, type StepResult } from 'ai';
import { youSearch } from '@youdotcom-oss/ai-sdk-plugin';
const stepCountIs = (n: number) => (stepResult: StepResult<any>) =>
stepResult.stepNumber >= n;
export async function POST(req: Request) {
const { prompt } = await req.json();
const result = streamText({
model: anthropic('claude-sonnet-4-5-20250929'),
tools: { search: youSearch() },
stopWhen: stepCountIs(5),
prompt,
});
return result.toDataStreamResponse();
}
Express.js 集成:
// server.ts
import express from 'express';
import { anthropic } from '@ai-sdk/anthropic';
import { streamText, type StepResult } from 'ai';
import { youSearch } from '@youdotcom-oss/ai-sdk-plugin';
const app = express();
app.use(express.json());
const stepCountIs = (n: number) => (stepResult: StepResult<any>) =>
stepResult.stepNumber >= n;
app.post('/api/chat', async (req, res) => {
const { prompt } = req.body;
const result = streamText({
model: anthropic('claude-sonnet-4-5-20250929'),
tools: { search: youSearch() },
stopWhen: stepCountIs(5),
prompt,
});
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
res.setHeader('Transfer-Encoding', 'chunked');
for await (const chunk of result.textStream) {
res.write(chunk);
}
res.end();
});
app.listen(3000);
React 客户端(配合 Next.js):
// components/Chat.tsx
'use client';
import { useChat } from 'ai/react';
export default function Chat() {
const { messages, input, handleInputChange, handleSubmit } = useChat({
api: '/api/chat',
});
return (
<div>
{messages.map(m => (
<div key={m.id}>
<strong>{m.role}:</strong> {m.content}
</div>
))}
<form onSubmit={handleSubmit}>
<input value={input} onChange={handleInputChange} />
<button type="submit">Send</button>
</form>
</div>
);
}
完整流式处理示例:
import { anthropic } from '@ai-sdk/anthropic';
import { streamText, type StepResult } from 'ai';
import { youSearch } from '@youdotcom-oss/ai-sdk-plugin';
const stepCountIs = (n: number) => (stepResult: StepResult<any>) =>
stepResult.stepNumber >= n;
const main = async () => {
try {
const result = streamText({
model: anthropic('claude-sonnet-4-5-20250929'),
tools: {
search: youSearch(),
},
stopWhen: stepCountIs(3),
prompt: 'What are the latest AI developments?',
});
// Stream to stdout
console.log('Streaming response:\n');
for await (const chunk of result.textStream) {
process.stdout.write(chunk);
}
console.log('\n\nDone!');
} catch (error) {
console.error('Error:', error);
process.exit(1);
}
};
main();
工具调用模式
基于步骤2中的环境变量名称:
标准 YDC_API_KEY:
import { youSearch } from '@youdotcom-oss/ai-sdk-plugin';
tools: {
search: youSearch(),
}
自定义环境变量:
import { youSearch } from '@youdotcom-oss/ai-sdk-plugin';
const apiKey = process.env.THEIR_CUSTOM_NAME;
tools: {
search: youSearch({ apiKey }),
}
使用标准环境变量的多工具:
import { youSearch, youExpress, youContents } from '@youdotcom-oss/ai-sdk-plugin';
tools: {
search: youSearch(),
agent: youExpress(),
extract: youContents(),
}
使用自定义环境变量的多工具:
import { youSearch, youExpress, youContents } from '@youdotcom-oss/ai-sdk-plugin';
const apiKey = process.env.THEIR_CUSTOM_NAME;
tools: {
search: youSearch({ apiKey }),
agent: youExpress({ apiKey }),
extract: youContents({ apiKey }),
}
可用工具
youSearch
网络与新闻搜索 - 模型决定参数(查询、数量、国家等)
youExpress
具备网络上下文的AI代理 - 模型决定参数(输入、工具)
youContents
网页内容提取 - 模型决定参数(网址、格式)
关键集成模式
以上示例展示了:
- 导入语句(AI SDK + 提供商 + You.com工具)
- 环境变量验证(对新文件可选)
- 基于环境变量的工具配置
- 结合工具使用generateText/streamText
- 结果处理(特别是streamText的textStream解构)
- Anthropic流式处理模式(stopWhen: stepCountIs(3))
- Web框架集成(Next.js, Express, React)
实施检查清单
针对每个正在更新/创建的文件:
- 已添加选定工具的导入
- 若使用自定义环境变量:已用正确名称声明变量
- 已将tools对象添加到generateText/streamText
- 每个选定工具已正确调用:
- 标准环境:
toolName() - 自定义环境:
toolName({ apiKey })
- 标准环境:
- 若使用streamText:已解构
const { textStream } = ... - 如果 Anthropic + streamText: 已添加
stopWhen: stepCountIs(3)
全局检查清单:
- 使用他们的包管理器安装的包
- 在他们的环境中设置的环境变量
- 所有文件已更新/创建
- 准备测试
常见问题
问题: "无法找到模块 @youdotcom-oss/ai-sdk-plugin"修复: 使用他们的包管理器安装
问题: "需要 YDC_API_KEY(或自定义名称)环境变量"修复: 在他们的环境中设置(获取密钥:https://you.com/platform/api-keys)
问题: "工具执行失败,错误代码 401"修复: 验证 API 密钥是否有效
问题:"响应不完整或缺失"修复方法:如果使用 streamText,请增加步骤数。从 3 开始,并根据需要逐步增加(请参阅 README 故障排除部分)
问题:"textStream 不可迭代"修复方法:使用解构赋值:const { textStream } = streamText(...)
问题:"自定义环境变量无效"修复方法:传递给每个工具:youSearch({ apiKey })
进阶:工具开发模式
适用于创建自定义 AI SDK 工具或为 @youdotcom-oss/ai-sdk-plugin 做贡献的开发者:
工具函数结构
每个工具函数遵循以下模式:
export const youToolName = (config: YouToolsConfig = {}) => {
const apiKey = config.apiKey ?? process.env.YDC_API_KEY;
return tool({
description: 'Tool description for AI model',
inputSchema: ZodSchema,
execute: async (params) => {
if (!apiKey) {
throw new Error('YDC_API_KEY is required');
}
const response = await callApiUtility({
params,
YDC_API_KEY: apiKey,
getUserAgent,
});
// Return raw API response for maximum flexibility
return response;
},
});
};
输入模式支持智能查询
始终使用来自@youdotcom-oss/mcp的模式:
// ✅ Import from @youdotcom-oss/mcp
import { SearchQuerySchema } from '@youdotcom-oss/mcp';
export const youSearch = (config: YouToolsConfig = {}) => {
return tool({
description: '...',
inputSchema: SearchQuerySchema, // Enables AI to use all search parameters
execute: async (params) => { ... },
});
};
// ❌ Don't duplicate or simplify schemas
const MySearchSchema = z.object({ query: z.string() }); // Missing filters!
这为何重要:
- 丰富的模式使AI能够使用高级查询参数(过滤器、时效性、国家等)
- AI能够基于用户意图构建更智能的查询
- 防止在多个包中重复定义模式
- 确保与MCP服务器模式的一致性
API密钥处理
始终提供环境变量备选方案并在API调用前进行验证:
// ✅ Automatic environment variable fallback
const apiKey = config.apiKey ?? process.env.YDC_API_KEY;
// ✅ Check API key in execute function
execute: async (params) => {
if (!apiKey) {
throw new Error('YDC_API_KEY is required');
}
const response = await callApi(...);
}
响应格式
始终返回原始API响应以获得最大灵活性:
// ✅ Return raw API response
execute: async (params) => {
const response = await fetchSearchResults({
searchQuery: params,
YDC_API_KEY: apiKey,
getUserAgent,
});
return response; // Raw response for maximum flexibility
}
// ❌ Don't format or transform responses
return {
text: formatResponse(response),
data: response,
};
为何采用原始响应?
- 为AI SDK处理结果提供最大灵活性
- 避免因格式化造成信息丢失
- AI SDK处理展示层
- 更易于调试(查看实际的API响应)
工具描述
编写能指导AI行为的描述:
// ✅ Clear guidance for AI model
description: 'Search the web for current information, news, articles, and content using You.com. Returns web results with snippets and news articles. Use this when you need up-to-date information or facts from the internet.'
// ❌ Too brief
description: 'Search the web'
附加资源
- 包README:https://github.com/youdotcom-oss/dx-toolkit/tree/main/packages/ai-sdk-plugin
- Vercel AI SDK 文档:https://ai-sdk.dev/docs
- You.com API:https://you.com/platform/api-keys


微信扫一扫,打赏作者吧~