🤖 第十一章:CrewAI マルチエージェントクローラー:台湾全土のキャンプ場自動収集
基礎編では、地図上にマーカーを配置する方法を学びました。 しかし、もしあなたが「台湾で最も充実したキャンピングカーマップ」を作ろうとする起業家だとしたら、毎日「キャンプ場」をGoogle検索して、手作業で住所や緯度経度、価格をコピー&ペーストするようなことはできません。 そんなことをしていたら、500件のデータを入力し終わる前に、競合他社に市場を奪われてしまいます!
AI時代において、最も貴重な資源は「プログラミングスキル」ではなく、「クリーンで構造化された高品質データ」です。 この章では、Vibe Codingの最深部である自動データ収集の世界へご案内します。 従来のPythonクローラー(BeautifulSoup/Scrapy)は書きません - それらはサイトの改訂で簡単に壊れてしまいます。 代わりに、現在世界で最も注目されているマルチエージェントフレームワークCrewAIを導入します。
6000字に及ぶこの深い解析章では、原理からPrompt設計、フェイルセーフ機構、最終的な構造化出力まで、「疲れ知らずのAIボット軍団」を構築する方法をステップバイステップで解説します。
🏭 CrewAIとは?なぜ従来のクローラーは時代遅れなのか?
従来のクローリングロジックは「このURLへ行く -> titleというIDのHTMLタグを見つける -> 中のテキストを抽出する」というものでした。 しかし、現代のウェブサイトはほとんどがReact/Vueで書かれた動的ページで、Cloudflareなどのアンチクローリング対策も施されています。サイトのHTMLがclass名を少し変更しただけで、あなたのクローラーはすぐにエラーを吐いて停止し、バグ修正に一日を費やすことになります。
CrewAIの革命的思考: 私たちはもはや硬直したHTMLタグに依存しません。代わりに「AI従業員チーム(Crew)」を構築します。
- Agent A (検索専門家): 「南投 おすすめキャンプ場」をGoogle検索し、上位10記事を読む
- Agent B (データ抽出専門家): Agent Aが読んだ長文記事をLLMで理解し、「施設名、住所、価格帯」を正確に抽出
- Agent C (座標変換専門家): 住所をGoogle Maps APIに渡し、正確な緯度経度(Latitude/Longitude)に変換
あなたは高レベルの「人間の指示」を出すだけで、これらのAIは自分たちで会議を開き、仕事を分配し、例外を処理し、最終的に完璧なJSONファイルを提出してくれます!
🛠️ 実践1: 最初のAI従業員(Agent)を作成
CrewAIを使用する前に、各AI従業員の役割(Role)、目標(Goal)、バックストーリー(Backstory)を明確に定義する必要があります。こ���は従業員を面接するようなもので、設定が詳細であればあるほど、出力は正確になります。
💡 Vibe Prompt 実践1: 「データ検索専門家」の定義
Agentの設定方法がわからない場合は、大規模言語モデルに書かせましょう!
[!IMPORTANT] 以下のPromptをAI(Claude 3.5やChatGPT-4oなど)に送信してください:
私はPythonのCrewAIフレームワークを使ってキャンプ場データ自動収集システムを開発しています。最初のAgent(AI従業員)を定義するのを手伝ってください。彼の任務は: 台湾の主要掲示板(PTT、Dcard、Mobile01)やブログからキャンプ場推薦記事を検索することです。このAgentのPythonコードを以下を含めて提供してください:1. role (役割名)2. goal (最終目標)3. backstory (背景ストーリー、AIに性格と専門性を与えるため)4. verbose=True (詳細ログを有効化)5. allow_delegation=False (仕事を他人に委任しない)backstoryは専門的で生き生きとした文体で書いてください。
🤖 AIが生成した完璧なAgent設定:
from crewai import Agent
# データ検索専門家��作成
search_expert = Agent(
role='シニアキャンプ場情報スペシャリスト',
goal='広大なインターネットから、台湾全土の最新・人気・隠れたキャンプ場情報、特に「車中泊」に適した穴場を発掘すること',
backstory=(
'あなたはアウトドア活動を愛し、15年のキャンプ経験を持つベテランであり、トップクラスのネット情報アナリストです。'
'主要なアウトドア掲示板の専門用語に精通し、PTTのCamping板、Dcardの旅行板、数多くのキャンプブロガーの記事から、'
'宣伝記事と本当に質の高いキャンプ場を見分けることができます。'
'鋭い直感を持ち、美しい星空や清潔なシャワー施設を備えたキャンプ場を見逃すことはありません。'
),
verbose=True,
allow_delegation=False,
# ここではネット検索可能なTool(SerperDevToolなど)を設定していると仮定
# tools=[search_tool]
)
🔍 深い解析: これがCrewAIの強力な点です。「if/else」ロジックを書くのではなく、「魂を吹き込む」のです。 このようなバックストーリーを与えると、検索やウェブページの閲覧時に、大規模言語モデルは自動的に「ベテランキャンパー」の視点に切り替わり、詐欺や低品質な情報を自動的にフィルタリングします。これは従来のPythonクローラーでは絶対に不可能なことです!
🎯 実践2: AIに具体的なタスク(Task)を割り当て
従業員ができたら、具体的な仕事(Task)を割り当てます。 Taskの定義も極めて正確で、「何をするか」「期待される出力形式」を明確にする必要があります。
💡 Vibe Prompt 実践2: 精密なクローリングタスクの定義
[!IMPORTANT] 以下のPromptをAIに送信してください:
search_expertという名前のAgentが既にあります。CrewAIのTaskクラスを使って、具体的なタスクを割り当ててください。タスク要件:1. description (説明): 「新竹県」で評価の高い車中泊キャンプ場5つを検索。詳細な住所、価格、最大の特徴(雲海、蛍など)を含める2. expected_output (期待出力): 構造化されたリストを出力3. agent: search_expertに紐付けPythonコードを提供し、expected_outputの重要性をコメントで説明してください
🤖 AIによる高度なタスク設計:
from crewai import Task
# タスク割り当て: 新竹県車中泊徹底調査
hsinchu_camping_task = Task(
description=(
'検索ツールを使用し、「新竹県」で現在最も人気があり評価の高い5つの車中泊/キャンプ場を特定してください。'
'関連するブログ記事や掲示板評価を読み、以下の情報を抽出してください:'
'1. キャンプ場の正式名称'
'2. 完全な住所(少なくとも市区町村レベル)'
'3. 価格帯(���: 1サイト1000~1200元)'
'4. キャンプ場の最大の特徴(20字以内、例: 秋冬限定の絶景雲海)'
),
expected_output=(
'5つの新竹キャンプ場を含むMarkdown箇条書きリスト。'
'各キャンプ場は以下の形式に厳密に従うこと:'
'- 名称: [キャンプ場名]'
'- 住所: [完全な住所]'
'- 価格: [価格]'
'- 特徴: [特徴]'
),
agent=search_expert
)
/*
【AIによるexpected_outputの重要性の深い解析】:
大規模言語モデル(LLM)でdescriptionだけを与えると、AIは数千字にも及ぶ「散文」を返す可能性があります。
`expected_output`はCrewAIフレームワークがAI出力を「制約」するための緊箍呪です。
形式(MarkdownリストやJSON形式など)を厳密に定義すると、AIはこの条件を満たすために、長い思考結果を収束・整形します。
これは後でデータベースにデータを投入する際に生死を分けるステップです!
*/
🔄 実践3: 最も困難なステップ - 座標変換(Geocoding)
地図システムでは「住所」だけでは役に立ちません。Leaflet.js地図は緯度経度(Latitude, Longitude)しか理解しません。 「新竹県五峰郷桃山村...」のような住所を地図に渡しても、地図はエラーを吐くだけです。
そこで、第二のAI従業員地理座標変換専門家が必要です。 ただし、LLMの脳だけで緯度経度を推測させることはできません(これは幻覚(Hallucination)と呼ばれ、AIが推測した緯度経度は太平洋の真ん中を指すことがよくあります)。 彼は実際のツール(Tool)を使ってGoogle Maps APIを呼び出す方法を学ぶ必要があります。
💡 Vibe Prompt 実践3: AIに外部APIツールの使用方法を教える
これが上級Vibe Codingの核心です: API呼び出しを自分で書くのではなく、ツールボックスを作成し、AIに呼び出させます!
[!IMPORTANT] 以下のPromptをAIに送信してください:
CrewAIでカスタムツール(Custom Tool)を作成し、Agentが住所を緯度経度に変換できるようにしたいです。Pythonの@toolデコレータを使ってgeocode_address(address: str)関数を書いてください。ロジック:1. requestsパッケージでGoogle Maps Geocoding APIを呼び出す2. APIキーは環境変数GOOGLE_MAPS_API_KEYに格納3. 変換成功時はlatとlngを含む辞書文字列を返す4. 失敗時または住所が見つからない場合はエラーメッセージを返す完全なコードとコメントを提供し、docstringの重要性を強調してください
🤖 AIが生成した最強ツール関数:
import os
import requests
from langchain.tools import tool
# 🔥 これが魂です!docstring(関数の下のコメント)はAIのために書かれます!
# AIはこのdocstringを読み、いつこのツールを使い、どんなパラメータを渡すべきかを決定します
@tool("住所緯度経度変換ツール")
def geocode_address(address: str) -> str:
"""
これは強力なジオコーディングツールです。
場所や住所の正確な緯度経度(LatitudeとLongitude)が必要な時に使用してください。
パラメータは明確な文字列住所である必要があります(例: "台北市信義区市府路1号" または "武陵農場")。
"""
api_key = os.environ.get("GOOGLE_MAPS_API_KEY")
if not api_key:
return "エラー: GOOGLE_MAPS_API_KEY環境変数が見つかりません"
# Google Maps Geocoding APIエンドポイント
url = f"https://maps.googleapis.com/maps/api/geocode/json?address={address}&key={api_key}&language=zh-TW"
try:
response = requests.get(url)
data = response.json()
# APIが正常にデータを返したか確認
if data['status'] == 'OK':
location = data['results'][0]['geometry']['location']
lat = location['lat']
lng = location['lng']
# AI従業員に明確な文字列結果を返す
return f"住所 '{address}' の緯度経度: 緯度 {lat}, 経度 {lng}"
else:
return f"'{address}' の緯度経度が見つかりません。API応答ステータス: {data['status']}"
except Exception as e:
return f"API呼び出し中にネットワークエラーが発生: {str(e)}"
🔍 深い解析:
LangChainやCrewAIの@toolを使用する際、ほとんどの初心者は"""docstring"""を書くのを忘れます。
AI Agentの世界では、関数のコメントは人間のためではなく、AIのための説明書です!
このツールが「緯度経度変換」のためにあることをAIに伝えないと、AIは住所を見てもこの強力なツールを使うべきだと気づきません。
これで、この@toolを第二のAgentに割り当てることができます。
🧩 実践4: 上流と下流を接続 - AI従業員に連携作業させる
「検索専門家(データ取得)」と「座標変換専門家(ツールで緯度経度変換)」ができました。 実際の会社では、これをパイプラインと呼びます。Agent Aがレポートを作成し、Agent Bに処理を渡します。
💡 Vibe Prompt 実践4: CrewチームとJSON構造出力の作成
最終的に必要なのはMarkdown文書���はなく、Supabaseデータベースに直接投入できるJSON形式(例: [{"name": "...", "lat": 24.1, "lng": 121.2}])です。
[!IMPORTANT] 以下のPromptをAIに送信してください:
上記のプロセスを統合し、完全なCrewAI実行スクリプトを作成してください。1. geocode_expert(座標変換専門家)を作成し、先ほどのgeocode_addressツールを割り当て2. 第二のタスク(format_to_json_task)を作成: geocode_expertが最初のタスク(hsinchu_camping_task)で整理された5つのキャンプ場リストを受け取る3. ツールを使って各キャンプ場の緯度経度を調べ、最終的に標準JSON Array形式に統合4. Crewを作成し、これら2つのタスクを順番に実行5. 完全なPythonコードを提供し、このチームを起動する方法を示してください
🤖 AI自動化チームの完成形:
from crewai import Agent, Task, Crew, Process
import json
# 1. 第二の従業員: 座標変換とデータクリーニング専門家
geocode_expert = Agent(
role='シニア地理データエンジニア',
goal='人間が読む住所を、地図システムが必要とする緯度経度に正確に変換し、完璧なJSON構造を出力する',
backstory='あなたは重度の完璧主義者で、括弧や引���符の誤りを許しません。JSONデータフォーマットの達人です。',
verbose=True,
tools=[geocode_address] # 先ほど作成したツールを割り当て!
)
# 2. 第二のタスク: 変換とフォーマット
format_to_json_task = Task(
description=(
'前のタスクで整理された5つのキャンプ場リストを受け取ってください。'
'各キャンプ場について、[住所緯度経度変換ツール]を使用して正確なlatとlngを調べてください。'
'ツールが住所を見つけられない場合、緯度経度は0とします。'
'最後に、これら5つのキャンプ場の全情報をJSON Array形式に変換してください。'
),
expected_output=(
'完全に有効なJSON文字列で、Markdownマークアップ(```jsonなど)を含んではいけません。形式例:\n'
'[\n'
' {\n'
' "name": "キャンプ場名",\n'
' "address": "住所",