本页内容
Vercel AI SDK 为你提供一个统一接口,可从任意框架——Next.js、SvelteKit、Nuxt 或纯 Node——调用 LLM。CrawlForge 则通过 20 个专用 scraping 工具让你的 LLM 获得实时网页数据访问能力。两者结合,你便能构建可以实时搜索、抓取、提取和分析网页内容的 AI 应用。
本教程向你展示如何用 Vercel AI SDK 的 tool() API 注册 CrawlForge 工具,让你的 AI 能像生成文本一样自然地抓取网络。
目录
- 前置条件
- 工作原理:Vercel AI SDK 中的工具
- 步骤 1:创建 CrawlForge 工具 wrapper
- 步骤 2:用 generateText 注册工具
- 步骤 3:构建带网页访问的流式聊天
- 进阶:多工具研究 agent
- credits 成本明细
- 最佳实践
- 后续步骤
前置条件
npm install ai @ai-sdk/anthropic zod dotenv# .env.local
ANTHROPIC_API_KEY=sk-ant-xxxxx
CRAWLFORGE_API_KEY=cf_live_xxxxx在 crawlforge.dev/signup 获取你的 CrawlForge API key——含 1,000 个免费 credits。
工作原理:Vercel AI SDK 中的工具
Vercel AI SDK 让你定义 工具,LLM 可在对话过程中调用它们。每个工具都有名称、描述、参数 schema(使用 Zod)以及一个 execute 函数。LLM 读取工具描述,决定何时调用它们,并将结果整合进自己的回复中。
CrawlForge 的 REST API 完美契合这一模式:26 个工具 中的每一个都成为一个带类型参数的可调用函数。
步骤 1:创建 CrawlForge 工具 wrapper
首先,构建一个可复用的 helper,用于调用任意 CrawlForge endpoint:
// lib/crawlforge.ts
const CRAWLFORGE_BASE = 'https://crawlforge.dev/api/v1/tools';
export async function callCrawlForge<T>(
toolName: string,
params: Record<string, unknown>
): Promise<T> {
const response = await fetch(`${CRAWLFORGE_BASE}/${toolName}`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.CRAWLFORGE_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(params),
});
if (!response.ok) {
throw new Error(`CrawlForge ${toolName} failed: ${response.status}`);
}
return response.json() as Promise<T>;
}步骤 2:用 generateText 注册工具
现在用 Vercel AI SDK 的 tool() 函数注册 CrawlForge 工具:
// app/api/chat/route.ts
import { generateText, tool } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
import { z } from 'zod';
import { callCrawlForge } from '@/lib/crawlforge';
const result = await generateText({
model: anthropic('claude-sonnet-4-20250514'),
tools: {
// Fetch and extract clean content from any URL (2 credits)
extractContent: tool({
description: 'Extract the main content from a web page as clean text. Use this when you need to read an article, documentation page, or any web content.',
parameters: z.object({
url: z.string().url().describe('The URL to extract content from'),
}),
execute: async ({ url }) => {
return callCrawlForge('extract_content', { url });
},
}),
// Search the web (5 credits)
searchWeb: tool({
description: 'Search the web using Google. Returns titles, URLs, and snippets for the top results.',
parameters: z.object({
query: z.string().describe('The search query'),
limit: z.number().optional().default(5).describe('Number of results'),
}),
execute: async ({ query, limit }) => {
return callCrawlForge('search_web', { query, limit });
},
}),
// Extract structured data with CSS selectors (2 credits)
scrapeStructured: tool({
description: 'Extract specific data from a web page using CSS selectors. Use when you need structured data like prices, names, or lists.',
parameters: z.object({
url: z.string().url().describe('The URL to scrape'),
selectors: z.record(z.string()).describe('CSS selectors mapping field names to selectors'),
}),
execute: async ({ url, selectors }) => {
return callCrawlForge('scrape_structured', { url, selectors });
},
}),
},
prompt: 'Find the current pricing for Vercel Pro plan and compare it to Netlify Pro.',
});
console.log(result.text);当 LLM 遇到需要网页数据的问题时,它会自动调用合适的 CrawlForge 工具,接收结果,并将其整合进回复。无需手动编排。
步骤 3:构建带网页访问的流式聊天
要获得实时聊天体验,使用 streamText 而非 generateText:
// app/api/chat/route.ts
import { streamText, tool } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
import { z } from 'zod';
import { callCrawlForge } from '@/lib/crawlforge';
export async function POST(req: Request) {
const { messages } = await req.json();
const result = streamText({
model: anthropic('claude-sonnet-4-20250514'),
system: `You are a research assistant with access to live web data.
When users ask about current information, use your tools to fetch it.
Always cite the URLs you retrieved data from.`,
messages,
tools: {
extractContent: tool({
description: 'Extract main content from a URL as clean text',
parameters: z.object({
url: z.string().url(),
}),
execute: async ({ url }) =>
callCrawlForge('extract_content', { url }),
}),
searchWeb: tool({
description: 'Search the web and return top results',
parameters: z.object({
query: z.string(),
limit: z.number().optional().default(5),
}),
execute: async ({ query, limit }) =>
callCrawlForge('search_web', { query, limit }),
}),
},
maxSteps: 5, // Allow up to 5 tool calls per response
});
return result.toDataStreamResponse();
}maxSteps: 5 参数允许 LLM 串联多次工具调用;例如,先在网络上搜索,然后从排名靠前的结果中提取内容。
前端组件
// app/page.tsx
'use client';
import { useChat } from 'ai/react';
export default function Chat() {
const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat();
return (
<div className="max-w-2xl mx-auto p-4">
{messages.map((m) => (
<div key={m.id} className="mb-4">
<strong>{m.role === 'user' ? 'You' : 'AI'}:</strong>
<p>{m.content}</p>
</div>
))}
<form onSubmit={handleSubmit}>
<input
value={input}
onChange={handleInputChange}
placeholder="Ask anything about the web..."
className="w-full p-2 border rounded"
disabled={isLoading}
/>
</form>
</div>
);
}进阶:多工具研究 agent
组合多个 CrawlForge 工具,实现更深入的研究工作流:
import { generateText, tool } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
import { z } from 'zod';
import { callCrawlForge } from '@/lib/crawlforge';
const research = await generateText({
model: anthropic('claude-sonnet-4-20250514'),
tools: {
searchWeb: tool({
description: 'Search Google for information',
parameters: z.object({ query: z.string(), limit: z.number().default(5) }),
execute: async ({ query, limit }) =>
callCrawlForge('search_web', { query, limit }),
}),
extractContent: tool({
description: 'Read the full content of a web page',
parameters: z.object({ url: z.string().url() }),
execute: async ({ url }) =>
callCrawlForge('extract_content', { url }),
}),
analyzeContent: tool({
description: 'Analyze text for topics, sentiment, and key entities',
parameters: z.object({ text: z.string() }),
execute: async ({ text }) =>
callCrawlForge('analyze_content', { text }),
}),
},
maxSteps: 10,
prompt: `Research the current state of MCP server adoption in 2026.
Search for recent articles, read the top 3, and analyze the key trends.
Provide a summary with citations.`,
});
console.log(research.text);
// Returns a cited research summary using live web data这个 agent 会执行以下操作:
- 在 Google 上搜索相关文章(5 credits)
- 从排名靠前的结果中提取内容(每个 2 credits)
- 分析内容以提取主题(每个 3 credits)
一次 3 来源研究的总成本:约 20 credits。
credits 成本明细
| 工具 | Credits | 最适合 |
|---|---|---|
| fetch_url | 1 | 抓取原始 HTML |
| extract_text | 1 | 提取干净文本 |
| extract_links | 1 | 发现链接 |
| extract_metadata | 1 | 页面元数据(标题、OG 标签) |
| extract_content | 2 | 提取可读内容 |
| scrape_structured | 2 | 基于 CSS 选择器的数据提取 |
| summarize_content | 2 | 文本摘要 |
| analyze_content | 3 | 主题与情感分析 |
| search_web | 5 | Google 搜索结果 |
| deep_research | 10 | 带引用的多来源研究 |
查看 完整定价明细 了解全部 26 个工具。
最佳实践
尽量减少 credits 使用。 当你只需要一个页面时,用 extract_content(2 credits)而非 deep_research(10 credits)。工具描述会引导 LLM 选择能满足查询的最便宜选项。
谨慎设置 maxSteps。 更高的 maxSteps 值允许每次回复进行更多工具调用,但会消耗更多 credits。从 3-5 开始,只有在 LLM 持续需要更多时才调高。
缓存频繁访问的页面。 如果你的应用反复抓取同一个 URL,把 CrawlForge 的响应缓存到 Redis 或数据库中,而不是每次都重新抓取。
使用 Zod 描述。 Zod 参数中的 .describe() 字符串能帮助 LLM 理解应当传入什么值。要具体:"完整的 URL,包含 https://" 比 "URL" 更好。
后续步骤
现在你已经拥有一个带实时网页访问的 Vercel AI SDK 应用。从这里继续扩展:
- 按需添加其余的 20 个 CrawlForge 工具
- 为带反爬虫保护的网站实现 stealth 模式
- 构建一个 深度研究 agent 用于自动化市场分析
- 查看 CrawlForge 快速上手指南 配置 MCP 客户端
构建能看见网络的 AI 应用。 用 1,000 credits 免费开始,无需信用卡。
亲自试一试——无需注册
在 Playground 中运行 CrawlForge 的 27 个抓取与提取工具中的任意一个,然后免费开始,获取 1,000 credits。
1,000 免费 credits • 每月补充 • 无需信用卡
标签
及时获取最新洞察
将教程、产品更新与 Web 抓取技巧直接发送到你的收件箱。
拒绝垃圾邮件,随时可取消订阅。