跳到正文

CrawlForge Team工程团队

阅读时长 12 分钟更新于

在 LangChain 中使用 CrawlForge 的 5 种方式:AI web scraping 教程

LangChain 是构建 LLM 应用的首选框架。CrawlForge MCP 则提供了 LangChain 应用常常需要的网络数据层。两者结合,是 AI 工程师手中的强大组合。

本教程将向你展示 5 种实用的集成模式,并附带可运行的代码示例。

前置条件

Bash
npm install langchain @anthropic-ai/sdk dotenv
Bash
# .env
ANTHROPIC_API_KEY=sk-ant-xxxxx
CRAWLFORGE_API_KEY=cf_live_xxxxx

在 crawlforge.dev/signup 获取你的 CrawlForge API key——已包含 1,000 个免费 credits。

1. 网络增强的 RAG 流水线

最常见的使用场景:用新鲜的网络数据增强你的 RAG 系统。

问题所在

静态 RAG 系统无法回答有关以下内容的问题:

  • 时事
  • 更新后的文档
  • 实时价格
  • 最新发布

解决方案

使用 CrawlForge 按需获取并索引网络内容。

Typescript
import { ChatAnthropic } from "@langchain/anthropic";
import { RecursiveCharacterTextSplitter } from "langchain/text_splitter";
import { MemoryVectorStore } from "langchain/vectorstores/memory";
import { OpenAIEmbeddings } from "@langchain/openai";

// CrawlForge client helper
async function fetchWebContent(url: string): Promise<string> {
  const response = await fetch('https://crawlforge.dev/api/v1/tools/extract_content', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.CRAWLFORGE_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ url })
  });

  const data = await response.json();
  return data.content || '';
}

// Web-augmented RAG
async function webAugmentedRAG(query: string, urls: string[]) {
  // 1. Fetch web content (2 credits per URL)
  const contents = await Promise.all(urls.map(fetchWebContent));

  // 2. Split into chunks
  const splitter = new RecursiveCharacterTextSplitter({
    chunkSize: 1000,
    chunkOverlap: 200
  });

  const docs = await splitter.createDocuments(contents);

  // 3. Create vector store
  const vectorStore = await MemoryVectorStore.fromDocuments(
    docs,
    new OpenAIEmbeddings()
  );

  // 4. Retrieve relevant chunks
  const relevantDocs = await vectorStore.similaritySearch(query, 4);

  // 5. Generate answer with context
  const llm = new ChatAnthropic({
    modelName: "claude-3-5-sonnet-20241022"
  });

  const context = relevantDocs.map(d => d.pageContent).join("\n\n");

  const response = await llm.invoke([
    {
      role: "system",
      content: "Answer based on the provided context. Cite sources when possible."
    },
    {
      role: "user",
      content: `Context:\n${context}\n\nQuestion: ${query}`
    }
  ]);

  return response.content;
}

// Usage
const answer = await webAugmentedRAG(
  "What are the new features in Next.js 15?",
  [
    "https://nextjs.org/blog/next-15",
    "https://nextjs.org/docs/app/building-your-application/upgrading"
  ]
);

credits 成本: 每获取一个 URL 收取 2 credits

2. 带工具调用的研究 agent

构建一个能够自主搜索和研究主题的 agent。

Typescript
import { ChatAnthropic } from "@langchain/anthropic";
import { DynamicStructuredTool } from "@langchain/core/tools";
import { AgentExecutor, createOpenAIFunctionsAgent } from "langchain/agents";
import { z } from "zod";

// Define CrawlForge tools for the agent
const searchTool = new DynamicStructuredTool({
  name: "search_web",
  description: "Search the web for information on a topic",
  schema: z.object({
    query: z.string().describe("The search query"),
    limit: z.number().optional().describe("Number of results (default 5)")
  }),
  func: async ({ query, limit = 5 }) => {
    const response = await fetch('https://crawlforge.dev/api/v1/tools/search_web', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.CRAWLFORGE_API_KEY}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ query, limit })
    });

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

const extractTool = new DynamicStructuredTool({
  name: "extract_content",
  description: "Extract the main content from a webpage URL",
  schema: z.object({
    url: z.string().describe("The URL to extract content from")
  }),
  func: async ({ url }) => {
    const response = await fetch('https://crawlforge.dev/api/v1/tools/extract_content', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.CRAWLFORGE_API_KEY}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ url })
    });

    const data = await response.json();
    return data.content || 'Failed to extract content';
  }
});

// Create the research agent
async function createResearchAgent() {
  const llm = new ChatAnthropic({
    modelName: "claude-3-5-sonnet-20241022"
  });

  const tools = [searchTool, extractTool];

  // Agent will autonomously decide when to search vs extract
  const agent = await createOpenAIFunctionsAgent({
    llm,
    tools,
    prompt: ChatPromptTemplate.fromMessages([
      ["system", "You are a research assistant. Use search_web to find sources, then extract_content to read them in detail."],
      ["human", "{input}"],
      ["placeholder", "{agent_scratchpad}"]
    ])
  });

  return new AgentExecutor({ agent, tools });
}

// Usage
const agent = await createResearchAgent();
const result = await agent.invoke({
  input: "Research the current state of WebAssembly for AI inference"
});

credits 成本: 每次搜索 5 credits + 每次提取 2 credits

3. 竞争情报流水线

监控竞争对手并提取结构化数据。

Typescript
interface CompetitorData {
  name: string;
  pricing: string[];
  features: string[];
  lastUpdated: Date;
}

async function analyzeCompetitor(url: string): Promise<CompetitorData> {
  // Use structured scraping (2 credits)
  const scrapeResponse = await fetch('https://crawlforge.dev/api/v1/tools/scrape_structured', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.CRAWLFORGE_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      url,
      selectors: {
        name: 'h1, .company-name, [data-company]',
        pricing: '.pricing-tier, .plan-price',
        features: '.feature-list li, .features li'
      }
    })
  });

  const scraped = await scrapeResponse.json();

  // Use LLM to structure the data
  const llm = new ChatAnthropic({ modelName: "claude-3-5-sonnet-20241022" });

  const structured = await llm.invoke([
    {
      role: "system",
      content: "Extract competitor data into structured JSON format."
    },
    {
      role: "user",
      content: `Analyze this competitor data: ${JSON.stringify(scraped)}`
    }
  ]);

  return JSON.parse(structured.content as string);
}

// Monitor multiple competitors
async function competitiveIntelligence(competitors: string[]) {
  const results = await Promise.all(
    competitors.map(url => analyzeCompetitor(url))
  );

  // Compare and summarize
  const llm = new ChatAnthropic({ modelName: "claude-3-5-sonnet-20241022" });

  const comparison = await llm.invoke([
    {
      role: "user",
      content: `Compare these competitors and identify market gaps: ${JSON.stringify(results)}`
    }
  ]);

  return { competitors: results, analysis: comparison.content };
}

credits 成本: 每个竞争对手 2 credits

4. 文档处理链

处理来自网络的 PDF 和文档。

Typescript
async function processDocuments(documentUrls: string[]) {
  const documents = [];

  for (const url of documentUrls) {
    // Process document (2 credits)
    const response = await fetch('https://crawlforge.dev/api/v1/tools/process_document', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.CRAWLFORGE_API_KEY}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        source: url,
        sourceType: url.endsWith('.pdf') ? 'pdf_url' : 'url'
      })
    });

    const data = await response.json();
    documents.push({
      url,
      content: data.content,
      metadata: data.metadata
    });
  }

  // Split and index documents
  const splitter = new RecursiveCharacterTextSplitter({
    chunkSize: 1500,
    chunkOverlap: 300
  });

  const chunks = await splitter.createDocuments(
    documents.map(d => d.content),
    documents.map(d => ({ source: d.url, ...d.metadata }))
  );

  return chunks;
}

// Use with LangChain vector store
const chunks = await processDocuments([
  'https://example.com/whitepaper.pdf',
  'https://example.com/technical-spec.pdf'
]);

const vectorStore = await MemoryVectorStore.fromDocuments(
  chunks,
  new OpenAIEmbeddings()
);

credits 成本: 每个文档 2 credits

5. 实时监控链

跟踪变化并对更新做出响应。

Typescript
import { RunnableSequence } from "@langchain/core/runnables";

async function checkForChanges(url: string, lastHash: string) {
  const response = await fetch('https://crawlforge.dev/api/v1/tools/track_changes', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.CRAWLFORGE_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      url,
      operation: 'compare'
    })
  });

  return response.json();
}

// Create a monitoring chain
const monitoringChain = RunnableSequence.from([
  // Check for changes
  async (input: { url: string }) => {
    const changes = await checkForChanges(input.url, '');
    return { ...input, changes };
  },
  // Analyze changes if found
  async (input) => {
    if (!input.changes.hasChanges) {
      return { ...input, analysis: "No changes detected" };
    }

    const llm = new ChatAnthropic({ modelName: "claude-3-5-sonnet-20241022" });
    const analysis = await llm.invoke([
      {
        role: "user",
        content: `Analyze these website changes: ${JSON.stringify(input.changes)}`
      }
    ]);

    return { ...input, analysis: analysis.content };
  },
  // Generate alert if significant
  async (input) => {
    if (input.analysis === "No changes detected") {
      return null;
    }

    return {
      url: input.url,
      timestamp: new Date(),
      analysis: input.analysis,
      raw: input.changes
    };
  }
]);

// Usage
const alert = await monitoringChain.invoke({
  url: "https://competitor.com/pricing"
});

if (alert) {
  console.log("Change detected:", alert);
}

credits 成本: 每次检查 2-5 credits

最佳实践

1. 积极使用缓存

Typescript
const cache = new Map<string, { content: string; timestamp: number }>();

async function cachedFetch(url: string, ttl = 3600000) {
  const cached = cache.get(url);
  if (cached && Date.now() - cached.timestamp < ttl) {
    return cached.content;
  }

  const content = await fetchWebContent(url);
  cache.set(url, { content, timestamp: Date.now() });
  return content;
}

2. 尽可能批量处理

Typescript
// Instead of multiple extract_content calls
const urls = ['url1', 'url2', 'url3'];

// Use batch_scrape (1 credit per URL vs 2 per URL)
const response = await fetch('https://crawlforge.dev/api/v1/tools/batch_scrape', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.CRAWLFORGE_API_KEY}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ urls })
});

3. 优雅地处理速率限制

Typescript
async function fetchWithRetry(url: string, retries = 3) {
  for (let i = 0; i < retries; i++) {
    const response = await fetch(url);

    if (response.status === 429) {
      const retryAfter = response.headers.get('Retry-After') || 60;
      await new Promise(r => setTimeout(r, Number(retryAfter) * 1000));
      continue;
    }

    return response;
  }
  throw new Error('Max retries exceeded');
}

开始使用

  1. 在 crawlforge.dev/signup 注册
  2. 获取你的 API key(1,000 个免费 credits)
  3. 安装 LangChain JS 并开始构建

需要帮助? 查看我们的 API 文档,或在 GitHub 上联系我们。

亲自试一试——无需注册

在 Playground 中探索全部 31 个 CrawlForge 抓取与提取工具,然后免费开始,获取 1,000 credits。

1,000 免费 credits • 一次性 • 无需信用卡

标签

  • LangChain
  • Tutorial
  • AI Engineering
  • RAG
  • Python

关于作者

CrawlForge Team

工程团队

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

邮件订阅

及时获取最新洞察

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

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

FAQ

常见问题

01如何在 LangChain 中使用 CrawlForge?

安装 LangChain 和 Anthropic SDK,设置你的 CRAWLFORGE_API_KEY 环境变量,然后在 LangChain 的链或 agent 内部调用 CrawlForge 工具(extract_content、deep_research、search_web)。本文介绍了五种集成模式,包括网络增强的 RAG、带工具调用的研究 agent 以及实时监控链。

02我可以用 CrawlForge 和 LangChain 构建网络增强的 RAG 流水线吗?

可以。使用 CrawlForge 的 extract_content 工具获取 URL(每个 2 credits),用 LangChain 的 RecursiveCharacterTextSplitter 拆分内容,将文本块嵌入到 MemoryVectorStore 这样的向量存储中,并在查询时检索相关的文本块。这样你的 RAG 系统就能回答有关时事、更新文档和实时价格的问题,而不必依赖陈旧的训练数据。

03如何将 CrawlForge 暴露为可供 agent 使用的 LangChain 工具?

将每个 CrawlForge endpoint 封装成一个带 Zod 输入 schema 的 LangChain `DynamicStructuredTool`。agent 会根据用户查询选择合适的工具(search_web、extract_content、deep_research),并通过 CrawlForge 的 API 运行它们。本文给出了一个研究 agent 的完整代码,它将搜索与内容提取串联起来。

04在 LangChain 工作流中使用 CrawlForge 的成本是多少?

定价按工具计费:extract_content 为 2 credits,search_web 为 5 credits,deep_research 为 10 credits。免费套餐包含 1,000 个 credits,足够获取约 500 个页面或运行约 100 次搜索加提取的工作流。付费套餐起价为每月 $19,可获得 5,000 个 credits。

继续阅读

相关文章

教程

4 分钟

Claude Code 的 Reddit 爬虫:Claude 实际调用的是什么

两次工具调用、10 credits、全程不需要任何 Reddit 凭证。还有一个最容易让人栽跟头的机制变化:一旦去掉 subreddit,搜索就会改走网页发现路线,而你传入的日期筛选也会跟着被静默丢弃。