本页内容
Mastra 是一个 TypeScript 优先的 AI agent 框架,专为构建可投入生产的 AI 应用而设计。CrawlForge 则赋予这些 agent 抓取、提取和分析实时网页数据的能力。两者结合,你便能构建出可以研究主题、监控竞品、并从任意网站提取结构化数据的 agent。
本指南将通过可运行的 TypeScript 示例,向你展示如何把 CrawlForge 工具接入 Mastra agent。
目录
- 什么是 Mastra?
- 前置条件
- 步骤 1:设置 Mastra 项目
- 步骤 2:创建 CrawlForge 工具定义
- 步骤 3:构建一个 web 研究 agent
- 步骤 4:构建数据提取工作流
- 步骤 5:添加错误处理与重试
- credits 成本参考
- 架构概览
- 后续步骤
什么是 Mastra?
Mastra 是面向 AI 应用与 agent 的现代 TypeScript 框架。它提供了用于 agent 创建、工具集成、工作流和记忆的基础组件 —— 全部具备完整的类型安全。可以把它看作 AI agent 领域的 Express.js:精简、可组合、面向生产。
Mastra agent 可以通过标准化的工具接口使用外部工具。CrawlForge 工具能直接映射到该接口,让你的 agent 无需编写 HTTP 客户端代码即可拥有 20 项 web scraping 能力。
前置条件
- Node.js 18+ 与 TypeScript 5+
- 一个带 API key 的 CrawlForge 账户(1,000 个免费 credits)
- 对 TypeScript 和 async/await 的基本了解
步骤 1:设置 Mastra 项目
创建一个新的 Mastra 项目并安装依赖:
npm create mastra@latest my-web-agent
cd my-web-agent
# Install additional dependencies
npm install dotenv node-fetch将你的 CrawlForge API key 添加到 .env:
CRAWLFORGE_API_KEY=cf_live_your_key_here
ANTHROPIC_API_KEY=sk-ant-your_key_here步骤 2:创建 CrawlForge 工具定义
创建一个工具文件,将 CrawlForge 的 API 封装为与 Mastra 兼容的工具:
// src/tools/crawlforge.ts
import { createTool } from '@mastra/core';
import { z } from 'zod';
const CRAWLFORGE_BASE = 'https://crawlforge.dev/api/v1/tools';
async function callCrawlForge(tool: string, params: Record<string, unknown>) {
const response = await fetch(`${CRAWLFORGE_BASE}/${tool}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.CRAWLFORGE_API_KEY}`,
},
body: JSON.stringify(params),
});
if (!response.ok) {
throw new Error(`CrawlForge ${tool} failed: ${response.status}`);
}
return response.json();
}
// Extract clean content from a URL (2 credits)
export const extractContent = createTool({
id: 'crawlforge-extract-content',
description: 'Extract clean, readable content from any web page. Costs 2 credits.',
inputSchema: z.object({
url: z.string().url().describe('The URL to extract content from'),
}),
execute: async ({ context }) => {
return callCrawlForge('extract_content', { url: context.url });
},
});
// Search the web (5 credits)
export const searchWeb = createTool({
id: 'crawlforge-search-web',
description: 'Search the web using Google. Returns titles, URLs, and snippets. Costs 5 credits.',
inputSchema: z.object({
query: z.string().describe('Search query string'),
limit: z.number().optional().default(10).describe('Max results to return'),
}),
execute: async ({ context }) => {
return callCrawlForge('search_web', {
query: context.query,
limit: context.limit,
});
},
});
// Fetch raw HTML (1 credit)
export const fetchUrl = createTool({
id: 'crawlforge-fetch-url',
description: 'Fetch raw HTML content from a URL. Cheapest option at 1 credit.',
inputSchema: z.object({
url: z.string().url().describe('The URL to fetch'),
}),
execute: async ({ context }) => {
return callCrawlForge('fetch_url', { url: context.url });
},
});
// Extract structured data with CSS selectors (2 credits)
export const scrapeStructured = createTool({
id: 'crawlforge-scrape-structured',
description: 'Extract data using CSS selectors. Costs 2 credits.',
inputSchema: 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 ({ context }) => {
return callCrawlForge('scrape_structured', {
url: context.url,
selectors: context.selectors,
});
},
});步骤 3:构建一个 web 研究 agent
创建一个能够搜索网页并提取内容以完成研究任务的 agent:
// src/agents/researcher.ts
import { Agent } from '@mastra/core';
import { searchWeb, extractContent, fetchUrl } from '../tools/crawlforge';
export const researcherAgent = new Agent({
name: 'Web Researcher',
instructions: `You are a web research agent. When asked to research a topic:
1. Use search_web to find relevant pages (5 credits)
2. Use extract_content on the top 2-3 results (2 credits each)
3. Synthesize findings into a structured summary
Always report the total credits used.
Prefer fetch_url (1 credit) over extract_content (2 credits) when you only need raw HTML.
Never use search_web if the user provides a specific URL.`,
model: {
provider: 'ANTHROPIC',
name: 'claude-sonnet-4-20250514',
},
tools: {
searchWeb,
extractContent,
fetchUrl,
},
});运行该 agent:
// src/index.ts
import { researcherAgent } from './agents/researcher';
async function main() {
const result = await researcherAgent.generate(
'Research the current state of MCP protocol adoption. ' +
'Which companies are using it and for what use cases?'
);
console.log(result.text);
// Output: Structured research summary with sources
// Credits used: ~11 (1 search + 3 extractions)
}
main();步骤 4:构建数据提取工作流
Mastra 工作流让你能够把多个工具串联成确定性的流水线。下面是一个竞品价格监控器:
// src/workflows/pricing-monitor.ts
import { Workflow, Step } from '@mastra/core';
import { searchWeb, scrapeStructured } from '../tools/crawlforge';
const findCompetitors = new Step({
id: 'find-competitors',
execute: async ({ context }) => {
// Search for competitors (5 credits)
const results = await searchWeb.execute({
context: { query: `${context.product} pricing plans`, limit: 5 },
});
return { urls: results.results.map((r: { link: string }) => r.link) };
},
});
const extractPricing = new Step({
id: 'extract-pricing',
execute: async ({ context }) => {
const pricingData = [];
// Extract pricing from each competitor (2 credits each)
for (const url of context.urls.slice(0, 3)) {
try {
const data = await scrapeStructured.execute({
context: {
url,
selectors: {
planNames: '.plan-name, .pricing-tier h3',
prices: '.price, .plan-price',
features: '.feature-list li, .plan-features li',
},
},
});
pricingData.push({ url, ...data });
} catch (error) {
pricingData.push({ url, error: 'Extraction failed' });
}
}
return { pricingData };
// Total: 5 + (3 * 2) = 11 credits
},
});
export const pricingMonitorWorkflow = new Workflow({
name: 'Pricing Monitor',
steps: [findCompetitors, extractPricing],
});步骤 5:添加错误处理与重试
生产环境的 agent 需要稳健的错误处理。下面是一个用于 CrawlForge 工具调用的模式:
// src/tools/resilient-crawlforge.ts
import { createTool } from '@mastra/core';
import { z } from 'zod';
const CRAWLFORGE_BASE = 'https://crawlforge.dev/api/v1/tools';
async function callWithRetry(
tool: string,
params: Record<string, unknown>,
maxRetries = 2
): Promise<unknown> {
let lastError: Error | null = null;
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(`${CRAWLFORGE_BASE}/${tool}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.CRAWLFORGE_API_KEY}`,
},
body: JSON.stringify(params),
});
if (response.status === 429) {
// Rate limited -- wait and retry
const retryAfter = parseInt(response.headers.get('Retry-After') || '2');
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
continue;
}
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}
return response.json();
} catch (error) {
lastError = error as Error;
if (attempt < maxRetries) {
await new Promise(resolve => setTimeout(resolve, 1000 * (attempt + 1)));
}
}
}
throw lastError;
}
export const resilientExtractContent = createTool({
id: 'crawlforge-extract-content-resilient',
description: 'Extract content with automatic retry on failure. 2 credits per successful call.',
inputSchema: z.object({
url: z.string().url(),
}),
execute: async ({ context }) => {
return callWithRetry('extract_content', { url: context.url });
},
});credits 成本参考
| Credits | 工具 | Mastra 使用场景 |
|---|---|---|
| 1 | fetch_url、extract_text、extract_links、extract_metadata | agent 工具中的快速数据抓取 |
| 2 | scrape_structured、extract_content、map_site、process_document、localization | 工作流提取、站点审计、文档处理 |
| 3 | track_changes、analyze_content | 变更检测、内容分析 |
| 4 | summarize_content、crawl_deep | 摘要生成、多页面爬取 |
| 5 | search_web、batch_scrape、scrape_with_actions、stealth_mode | 研究 agent、批量操作 |
| 10 | deep_research | 综合分析 agent |
架构概览
| 组件 | 职责 |
|---|---|
| Mastra Agent | 编排工具调用,维护对话上下文 |
| Mastra Tools | 围绕 CrawlForge API 端点的带类型封装 |
| Mastra Workflow | 用于批量操作的确定性多步骤流水线 |
| CrawlForge API | 执行 web scraping,返回结构化数据 |
| Credit System | 按 API key 跟踪用量,强制执行限额 |
Mastra agent 会根据任务决定调用哪个 CrawlForge 工具。工具封装负责处理 HTTP 通信,CrawlForge 则执行实际的抓取。每次工具调用成功后,credits 都会被原子性地扣除。
后续步骤
- Mastra 快速上手指南 —— Mastra 官方文档
- CrawlForge API 参考 —— 完整的端点文档
- 构建一个研究助手 —— 直接使用 Claude 的类似模式
- 深度研究自动化 —— 进阶研究工作流
今天就构建你的第一个具备网络感知能力的 AI agent。 注册 CrawlForge(1,000 个免费 credits),脚手架生成一个 Mastra 项目,让你的 agent 拥有抓取整个网络的能力。
亲自试一试——无需注册
在 Playground 中运行 CrawlForge 的 27 个抓取与提取工具中的任意一个,然后免费开始,获取 1,000 credits。
1,000 免费 credits • 每月补充 • 无需信用卡
标签
及时获取最新洞察
将教程、产品更新与 Web 抓取技巧直接发送到你的收件箱。
拒绝垃圾邮件,随时可取消订阅。