セットアップ
Copy
Ask AI
npm install @langchain/langgraph @langchain/openai @mendable/firecrawl-js
Copy
Ask AI
FIRECRAWL_API_KEY=your_firecrawl_key
OPENAI_API_KEY=your_openai_key
注: Node 20 未満を使用している場合は、dotenvをインストールし、コードにimport 'dotenv/config'を追加してください。
基本的なワークフロー
Copy
Ask AI
import FirecrawlApp from '@mendable/firecrawl-js';
import { ChatOpenAI } from '@langchain/openai';
import { StateGraph, MessagesAnnotation, START, END } from '@langchain/langgraph';
// Firecrawlを初期化
const firecrawl = new FirecrawlApp({ apiKey: process.env.FIRECRAWL_API_KEY });
// LLMを初期化
const llm = new ChatOpenAI({
model: "gpt-5-nano",
apiKey: process.env.OPENAI_API_KEY
});
// スクレイプノードを定義
async function scrapeNode(state: typeof MessagesAnnotation.State) {
console.log('スクレイピング中...');
const result = await firecrawl.scrape('https://firecrawl.dev', { formats: ['markdown'] });
return {
messages: [{
role: "system",
content: `スクレイプしたコンテンツ: ${result.markdown}`
}]
};
}
// 分析ノードを定義
async function analyzeNode(state: typeof MessagesAnnotation.State) {
console.log('分析中...');
const response = await llm.invoke(state.messages);
return { messages: [response] };
}
// グラフを構築
const graph = new StateGraph(MessagesAnnotation)
.addNode("scrape", scrapeNode)
.addNode("analyze", analyzeNode)
.addEdge(START, "scrape")
.addEdge("scrape", "analyze")
.addEdge("analyze", END);
// グラフをコンパイル
const app = graph.compile();
// ワークフローを実行
const result = await app.invoke({
messages: [{ role: "user", content: "ウェブサイトを要約" }]
});
console.log(JSON.stringify(result, null, 2));
マルチステップワークフロー
Copy
Ask AI
import FirecrawlApp from '@mendable/firecrawl-js';
import { ChatOpenAI } from '@langchain/openai';
import { StateGraph, Annotation, START, END } from '@langchain/langgraph';
const firecrawl = new FirecrawlApp({ apiKey: process.env.FIRECRAWL_API_KEY });
const llm = new ChatOpenAI({ model: "gpt-5-nano", apiKey: process.env.OPENAI_API_KEY });
// カスタム状態を定義
const WorkflowState = Annotation.Root({
urls: Annotation<string[]>(),
scrapedData: Annotation<Array<{ url: string; content: string }>>(),
summary: Annotation<string>()
});
// 複数のURLをスクレイピング
async function scrapeMultiple(state: typeof WorkflowState.State) {
const scrapedData = [];
for (const url of state.urls) {
const result = await firecrawl.scrape(url, { formats: ['markdown'] });
scrapedData.push({ url, content: result.markdown || '' });
}
return { scrapedData };
}
// スクレイピングしたすべてのコンテンツを要約
async function summarizeAll(state: typeof WorkflowState.State) {
const combinedContent = state.scrapedData
.map(item => `Content from ${item.url}:\n${item.content}`)
.join('\n\n');
const response = await llm.invoke([
{ role: "user", content: `Summarize these websites:\n${combinedContent}` }
]);
return { summary: response.content as string };
}
// ワークフローグラフを構築
const workflow = new StateGraph(WorkflowState)
.addNode("scrape", scrapeMultiple)
.addNode("summarize", summarizeAll)
.addEdge(START, "scrape")
.addEdge("scrape", "summarize")
.addEdge("summarize", END);
const app = workflow.compile();
// ワークフローを実行
const result = await app.invoke({
urls: ["https://firecrawl.dev", "https://firecrawl.dev/pricing"]
});
console.log(result.summary);

