CrawlForge
首页Playground应用场景集成价格文档博客
如何在 LangGraph 智能体中使用 CrawlForge
Tutorials
返回博客
教程

如何在 LangGraph 智能体中使用 CrawlForge

C
CrawlForge Team
工程团队
2026年4月24日
阅读时长 8 分钟

本页内容

LangGraph 是 LangChain 用于构建有状态、基于图的 AI 智能体的框架。通过把 CrawlForge 工具作为图节点集成进来,你可以构建出能够智能决策的智能体:决定爬取什么、何时深入挖掘,以及如何在多个步骤中综合网页数据。

本指南将向你展示如何用 LangGraph 和 CrawlForge 在 TypeScript 中构建一个完整的爬取智能体。

目录

  • 什么是 LangGraph?
  • 前置条件
  • 第 1 步:项目搭建
  • 第 2 步:为 LangGraph 定义 CrawlForge 工具
  • 第 3 步:设计智能体状态
  • 第 4 步:构建图节点
  • 第 5 步:连接整个图
  • 第 6 步:运行智能体
  • credits 成本参考
  • LangGraph 与直接使用 LangChain 的对比
  • 后续步骤

什么是 LangGraph?

LangGraph 是一个用于构建可靠 AI 智能体的低层编排框架。与简单的链式架构不同,LangGraph 将智能体逻辑建模为一个有向图,其中:

  • 节点代表动作(工具调用、LLM 调用、数据处理)
  • 边定义节点之间的转移,包括条件路由
  • 状态在整个图的执行过程中持续存在

这种架构非常适合爬取智能体,因为网页爬取本质上涉及决策:我应该爬得更深吗?这个页面被拦截了吗?我需要切换到隐身模式吗?LangGraph 让你能够把这些决策建模为图中的条件边。

前置条件

  • Node.js 18+ 和 TypeScript 5+
  • 一个带有 API key 的 CrawlForge 账户(1,000 个免费 credits)
  • 熟悉 LangChain 基础知识

第 1 步:项目搭建

Bash
mkdir langgraph-scraper && cd langgraph-scraper
npm init -y
npm install @langchain/langgraph @langchain/anthropic @langchain/core zod dotenv
npm install -D typescript @types/node tsx

创建 tsconfig.json:

Json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "esModuleInterop": true,
    "outDir": "dist"
  },
  "include": ["src/**/*"]
}

将你的 API key 添加到 .env:

Bash
CRAWLFORGE_API_KEY=cf_live_your_key_here
ANTHROPIC_API_KEY=sk-ant-your_key_here

第 2 步:为 LangGraph 定义 CrawlForge 工具

创建 LangGraph 可以调用的带类型的工具包装器:

Typescript
// src/tools.ts
import { tool } from '@langchain/core/tools';
import { z } from 'zod';

const CRAWLFORGE_API = 'https://crawlforge.dev/api/v1/tools';

async function callCrawlForge(
  endpoint: string,
  params: Record<string, unknown>
): Promise<string> {
  const response = await fetch(`${CRAWLFORGE_API}/${endpoint}`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${process.env.CRAWLFORGE_API_KEY}`,
    },
    body: JSON.stringify(params),
  });

  if (!response.ok) {
    return JSON.stringify({ error: `HTTP ${response.status}`, endpoint });
  }

  const data = await response.json();
  return JSON.stringify(data);
}

export const searchWebTool = tool(
  async ({ query, limit }) => {
    return callCrawlForge('search_web', { query, limit });
  },
  {
    name: 'search_web',
    description: 'Search the web for information. Costs 5 credits. Use when you need to find URLs for a topic.',
    schema: z.object({
      query: z.string().describe('Search query'),
      limit: z.number().default(5).describe('Max results'),
    }),
  }
);

export const extractContentTool = tool(
  async ({ url }) => {
    return callCrawlForge('extract_content', { url });
  },
  {
    name: 'extract_content',
    description: 'Extract clean readable content from a URL. Costs 2 credits.',
    schema: z.object({
      url: z.string().describe('URL to extract content from'),
    }),
  }
);

export const scrapeStructuredTool = tool(
  async ({ url, selectors }) => {
    return callCrawlForge('scrape_structured', { url, selectors });
  },
  {
    name: 'scrape_structured',
    description: 'Extract structured data using CSS selectors. Costs 2 credits.',
    schema: z.object({
      url: z.string().describe('URL to scrape'),
      selectors: z.record(z.string()).describe('CSS selectors map'),
    }),
  }
);

export const fetchUrlTool = tool(
  async ({ url }) => {
    return callCrawlForge('fetch_url', { url });
  },
  {
    name: 'fetch_url',
    description: 'Fetch raw HTML from a URL. Cheapest option at 1 credit.',
    schema: z.object({
      url: z.string().describe('URL to fetch'),
    }),
  }
);

export const allTools = [
  searchWebTool,
  extractContentTool,
  scrapeStructuredTool,
  fetchUrlTool,
];

第 3 步:设计智能体状态

LangGraph 智能体在图的执行过程中维护状态。定义一个用于跟踪爬取进度的状态结构:

Typescript
// src/state.ts
import { BaseMessage } from '@langchain/core/messages';
import { Annotation } from '@langchain/langgraph';

// Define the graph state
export const AgentState = Annotation.Root({
  // Conversation messages (LLM context)
  messages: Annotation<BaseMessage[]>({
    reducer: (prev, next) => [...prev, ...next],
    default: () => [],
  }),

  // URLs discovered during research
  discoveredUrls: Annotation<string[]>({
    reducer: (prev, next) => [...new Set([...prev, ...next])],
    default: () => [],
  }),

  // Content extracted from URLs
  extractedContent: Annotation<Record<string, string>>({
    reducer: (prev, next) => ({ ...prev, ...next }),
    default: () => ({}),
  }),

  // Total credits consumed
  creditsUsed: Annotation<number>({
    reducer: (prev, next) => prev + next,
    default: () => 0,
  }),

  // Current phase of the scraping pipeline
  phase: Annotation<'search' | 'extract' | 'analyze' | 'complete'>({
    reducer: (_prev, next) => next,
    default: () => 'search' as const,
  }),
});

第 4 步:构建图节点

图中的每个节点执行一个特定的动作并更新状态:

Typescript
// src/nodes.ts
import { ChatAnthropic } from '@langchain/anthropic';
import { HumanMessage, SystemMessage } from '@langchain/core/messages';
import { ToolNode } from '@langchain/langgraph/prebuilt';
import { AgentState } from './state';
import { allTools } from './tools';

const model = new ChatAnthropic({
  model: 'claude-sonnet-4-20250514',
  temperature: 0,
}).bindTools(allTools);

// Node: LLM decides which tool to call next
export async function agentNode(
  state: typeof AgentState.State
) {
  const systemPrompt = new SystemMessage(
    `You are a web research agent. Your goal is to find and extract information efficiently.
    Always prefer cheaper tools: fetch_url (1cr) > extract_content (2cr) > search_web (5cr).
    Track credits used. Stop when you have enough information or reach 20 credits.`
  );

  const response = await model.invoke([systemPrompt, ...state.messages]);

  return { messages: [response] };
}

// Node: Execute tool calls
export const toolNode = new ToolNode(allTools);

// Node: Analyze extracted content and decide next step
export async function analyzeNode(
  state: typeof AgentState.State
) {
  const extractedCount = Object.keys(state.extractedContent).length;

  if (extractedCount >= 3 || state.creditsUsed >= 20) {
    return { phase: 'complete' as const };
  }

  return { phase: 'extract' as const };
}

第 5 步:连接整个图

用边和条件路由把各个节点连接起来:

Typescript
// src/graph.ts
import { StateGraph, END } from '@langchain/langgraph';
import { AgentState } from './state';
import { agentNode, toolNode, analyzeNode } from './nodes';
import { AIMessage } from '@langchain/core/messages';

// Determine if the agent wants to use a tool or is finished
function shouldContinue(state: typeof AgentState.State) {
  const lastMessage = state.messages[state.messages.length - 1];

  // If the LLM returned tool calls, route to tool execution
  if (
    lastMessage instanceof AIMessage &&
    lastMessage.tool_calls &&
    lastMessage.tool_calls.length > 0
  ) {
    return 'tools';
  }

  // Otherwise, analyze what we have
  return 'analyze';
}

// Determine if we should continue scraping or wrap up
function shouldFinish(state: typeof AgentState.State) {
  if (state.phase === 'complete') {
    return 'end';
  }
  return 'agent';
}

// Build the graph
const workflow = new StateGraph(AgentState)
  // Add nodes
  .addNode('agent', agentNode)
  .addNode('tools', toolNode)
  .addNode('analyze', analyzeNode)

  // Set entry point
  .addEdge('__start__', 'agent')

  // Agent -> tools (if tool call) or analyze (if no tool call)
  .addConditionalEdges('agent', shouldContinue, {
    tools: 'tools',
    analyze: 'analyze',
  })

  // Tools -> agent (return results to LLM)
  .addEdge('tools', 'agent')

  // Analyze -> agent (continue) or end (done)
  .addConditionalEdges('analyze', shouldFinish, {
    agent: 'agent',
    end: END,
  });

export const app = workflow.compile();

第 6 步:运行智能体

Typescript
// src/index.ts
import 'dotenv/config';
import { HumanMessage } from '@langchain/core/messages';
import { app } from './graph';

async function main() {
  const result = await app.invoke({
    messages: [
      new HumanMessage(
        'Research the top 3 MCP server implementations for web scraping. ' +
        'Find their websites, extract their key features, and compare pricing.'
      ),
    ],
  });

  // Print final state
  console.log('--- Research Complete ---');
  console.log('Credits used:', result.creditsUsed);
  console.log('URLs discovered:', result.discoveredUrls.length);
  console.log('Pages extracted:', Object.keys(result.extractedContent).length);
  console.log('\nFinal response:');
  console.log(result.messages[result.messages.length - 1].content);
}

main().catch(console.error);

运行它:

Bash
npx tsx src/index.ts

该智能体会搜索网络、发现相关页面、从最有价值的结果中提取内容并综合出一份对比——而这一切都会在图状态中跟踪 credits 的用量。

credits 成本参考

Credits工具LangGraph 中的节点角色
1fetch_url、extract_text、extract_links、extract_metadata轻量级的数据采集节点
2scrape_structured、extract_content、map_site、process_document、localization提取、发现和文档处理节点
3track_changes、analyze_content变更跟踪和分析节点
4summarize_content、crawl_deep摘要和多页爬取节点
5search_web、batch_scrape、scrape_with_actions、stealth_mode研究和批量操作节点
10deep_research全面分析(作为单节点子图使用)

典型的 LangGraph 智能体运行:5(搜索)+ 6(3 次提取)+ 0(LLM 分析)= 11 credits。

LangGraph 与直接使用 LangChain 的对比

维度LangGraph直接使用 LangChain
状态管理内置、带类型、可持久化手动实现,需要自定义代码
条件逻辑一等的条件边链函数中的 if/else
credits 跟踪自动在图状态中跟踪手动计数器
错误恢复将错误路由到回退节点链中的 try/catch
复杂度初始搭建成本较高对线性工作流更简单
最适合带分支逻辑的多步骤研究简单的获取并处理流水线

当你的爬取智能体需要根据中间结果做决策时,使用 LangGraph。当工作流是线性的时候,使用直接的 LangChain(参见我们的 LangChain 集成指南)。

后续步骤

  • LangGraph 文档 —— LangGraph 官方指南
  • 用 CrawlForge 搭配 LangChain 的 5 种方式 —— 更简单的 LangChain 模式
  • 构建研究助手 —— 相关的智能体架构
  • CrawlForge API 参考 —— 完整的工具端点文档

今天就开始构建智能爬取智能体。 用 1,000 个免费 credits 注册 CrawlForge,把工具接入你的 LangGraph 图,让你的智能体决定接下来爬取什么。

亲自试一试——无需注册

在 Playground 中运行 CrawlForge 的 27 个抓取与提取工具中的任意一个,然后免费开始,获取 1,000 credits。

1,000 免费 credits • 每月补充 • 无需信用卡

标签

langgraphlangchainai-agentsmcpintegrationtutorialtypescriptweb-scraping

关于作者

C

CrawlForge Team

工程团队

我们正在打造功能最全面的 Web 抓取 MCP server。我们开发的工具帮助开发者为 AI 应用提取、分析和转换 Web 数据。

及时获取最新洞察

将教程、产品更新与 Web 抓取技巧直接发送到你的收件箱。

拒绝垃圾邮件,随时可取消订阅。

付诸实践

在任意 URL 上测试 CrawlForge 的工具——免费,无需注册。

本页内容

相关文章

如何将 CrawlForge 与 Mastra AI agent 配合使用
Tutorials

如何将 CrawlForge 与 Mastra AI agent 配合使用

使用 Mastra 与 CrawlForge 构建具备 web scraping 能力的 AI agent。包含工具集成、工作流和 agent 示例的 TypeScript 配置指南。

C
CrawlForge Team
|
4月21日
|
7 分钟
如何用 TypeScript 构建一个 web scraping MCP server(2026)
Tutorials

如何用 TypeScript 构建一个 web scraping MCP server(2026)

用 TypeScript 和官方 SDK 构建一个可用的 web scraping MCP server:一台最小化服务器、一个真实的 cheerio 抓取工具、测试,以及 Claude Desktop 配置。

C
CrawlForge Team
|
6月16日
|
12 分钟
如何将 CrawlForge 与 Dify 工作流结合使用
Tutorials

如何将 CrawlForge 与 Dify 工作流结合使用

在 Dify 中将 CrawlForge 添加为自定义工具,让你的 LLM 应用工作流具备 web scraping 能力。附带工作流示例的无代码与 API 集成指南。

C
CrawlForge Team
|
4月22日
|
7 分钟

页脚

CrawlForge

面向 AI Agent 的企业级网页抓取。27 个专业 MCP 工具,专为构建智能系统的现代开发者而设计。

产品

  • 功能
  • Playground
  • 价格
  • 应用场景
  • 集成
  • 替代方案
  • 更新日志

资源

  • 快速上手
  • API 参考
  • 模板
  • 指南
  • 博客
  • 术语表
  • 常见问题
  • 网站地图

开发者

  • MCP 协议
  • Claude Desktop
  • Cursor IDE
  • LangChain
  • LlamaIndex

公司

  • 关于我们
  • 联系我们
  • 隐私政策
  • 服务条款
  • 可接受使用政策
  • Cookie

保持更新

获取新工具和新功能的最新动态。

基于 Next.js 和 MCP 协议构建

© 2025-2026 CrawlForge。保留所有权利。