Pada halaman ini
LangGraph ialah rangka kerja LangChain untuk membina agen AI berkeadaan berasaskan graf. Dengan mengintegrasikan alat CrawlForge sebagai nod graf, anda boleh membina agen yang membuat keputusan bijak tentang apa yang hendak di-scrape, bila perlu menggali lebih dalam, dan bagaimana mensintesis data web merentas berbilang langkah.
Panduan ini menunjukkan kepada anda cara membina agen scraping yang lengkap dengan LangGraph dan CrawlForge dalam TypeScript.
Kandungan
- Apakah Itu LangGraph?
- Prasyarat
- Langkah 1: Persediaan Projek
- Langkah 2: Takrifkan Alat CrawlForge untuk LangGraph
- Langkah 3: Reka Bentuk Keadaan Agen
- Langkah 4: Bina Nod Graf
- Langkah 5: Sambungkan Graf
- Langkah 6: Jalankan Agen
- Rujukan Kos Credits
- LangGraph berbanding LangChain Terus untuk Scraping
- Langkah Seterusnya
Apakah Itu LangGraph?
LangGraph ialah rangka kerja orkestrasi peringkat rendah untuk membina agen AI yang boleh dipercayai. Tidak seperti seni bina berasaskan rantaian yang ringkas, LangGraph memodelkan logik agen sebagai graf berarah di mana:
- Nod mewakili tindakan (panggilan alat, seruan LLM, pemprosesan data)
- Tepi mentakrifkan peralihan antara nod, termasuk penghalaan bersyarat
- Keadaan kekal merentas keseluruhan pelaksanaan graf
Seni bina ini sesuai untuk agen scraping kerana web scraping secara semula jadi melibatkan keputusan: Patutkah saya scrape lebih dalam? Adakah halaman ini disekat? Adakah saya perlu beralih ke mod senyap? LangGraph membolehkan anda memodelkan keputusan ini sebagai tepi bersyarat dalam graf.
Prasyarat
- Node.js 18+ dan TypeScript 5+
- Akaun CrawlForge dengan kunci API (1,000 credits percuma)
- Kebiasaan dengan asas LangChain
Langkah 1: Persediaan Projek
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 tsxCipta tsconfig.json:
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"outDir": "dist"
},
"include": ["src/**/*"]
}Tambah kunci API anda ke .env:
CRAWLFORGE_API_KEY=cf_live_your_key_here
ANTHROPIC_API_KEY=sk-ant-your_key_hereLangkah 2: Takrifkan Alat CrawlForge untuk LangGraph
Cipta pembalut alat bertaip yang boleh diseru oleh LangGraph:
// 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,
];Langkah 3: Reka Bentuk Keadaan Agen
Agen LangGraph mengekalkan keadaan merentas pelaksanaan graf. Takrifkan bentuk keadaan yang menjejaki kemajuan scraping:
// 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,
}),
});Langkah 4: Bina Nod Graf
Setiap nod dalam graf melaksanakan tindakan tertentu dan mengemas kini keadaan:
// 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 };
}Langkah 5: Sambungkan Graf
Sambungkan nod dengan tepi dan penghalaan bersyarat:
// 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();Langkah 6: Jalankan Agen
// 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);Jalankannya:
npx tsx src/index.tsAgen akan mencari di web, menemui halaman yang berkaitan, mengekstrak kandungan daripada hasil yang paling menjanjikan, dan mensintesis perbandingan -- semuanya sambil menjejaki penggunaan credit dalam keadaan graf.
Rujukan Kos Credits
| Credits | Tools | LangGraph Node Role |
|---|---|---|
| 1 | fetch_url, extract_text, extract_links, extract_metadata | Nod pengumpulan data ringan |
| 2 | scrape_structured, extract_content, map_site, process_document, localization | Nod ekstraksi, penemuan, dan pemprosesan dokumen |
| 3 | track_changes, analyze_content | Nod penjejakan perubahan dan analisis |
| 4 | summarize_content, crawl_deep | Nod ringkasan dan crawling berbilang halaman |
| 5 | search_web, batch_scrape, scrape_with_actions, stealth_mode | Nod penyelidikan dan operasi pukal |
| 10 | deep_research | Analisis menyeluruh (gunakan sebagai subgraf nod tunggal) |
Larian agen LangGraph biasa: 5 (carian) + 6 (3 ekstraksi) + 0 (analisis LLM) = 11 credits.
LangGraph berbanding LangChain Terus untuk Scraping
| Aspect | LangGraph | Direct LangChain |
|---|---|---|
| Pengurusan Keadaan | Terbina dalam, bertaip, berkekalan | Manual, memerlukan kod tersuai |
| Logik Bersyarat | Tepi bersyarat kelas pertama | If/else dalam fungsi rantaian |
| Penjejakan Credit | Jejak dalam keadaan graf secara automatik | Pembilang manual |
| Pemulihan Ralat | Halakan ralat ke nod sandaran | Try/catch dalam rantaian |
| Kerumitan | Persediaan awal lebih tinggi | Lebih ringkas untuk aliran kerja linear |
| Paling Sesuai Untuk | Penyelidikan berbilang langkah dengan logik bercabang | Saluran ambil-dan-proses yang ringkas |
Gunakan LangGraph apabila agen scraping anda perlu membuat keputusan berdasarkan hasil pertengahan. Gunakan LangChain terus (lihat panduan integrasi LangChain kami) apabila aliran kerja adalah linear.
Langkah Seterusnya
- LangGraph Documentation -- panduan rasmi LangGraph
- 5 Ways to Use CrawlForge with LangChain -- corak LangChain yang lebih ringkas
- Build a Research Assistant -- seni bina agen berkaitan
- CrawlForge API Reference -- dokumentasi penuh titik akhir alat
Bina agen scraping yang bijak hari ini. Sign up for CrawlForge dengan 1,000 credits percuma, sambungkan alat ke dalam graf LangGraph anda, dan biarkan agen anda memutuskan apa yang hendak di-scrape seterusnya.
Cuba sendiri — tiada pendaftaran diperlukan
Jalankan mana-mana daripada 27 alat scraping dan pengekstrakan CrawlForge dalam playground, kemudian mula secara percuma dengan 1,000 credits.
1,000 credits percuma • Isi semula setiap bulan • Tiada kad kredit diperlukan
Tag
Tentang Penulis
Kekal dikemas kini dengan pandangan terkini
Dapatkan tutorial, kemas kini produk dan petua web scraping terus ke peti masuk anda.
Tiada spam. Berhenti melanggan bila-bila masa.