CrewAI + Scrapeless: ローカルLLMを使用したマルチエージェントスクレイピングクルーを運営する
Advanced Bot Mitigation Engineer
TL;DR:
- これは実際のマルチエージェントワークフローです。 三つのCrewAIエージェントがライブページを取得し、構造化されたレコードを抽出し、逐次的なタスクの引き渡しを通じて結果を検証します。
- ウェブアクセスを持つのは取得者だけです。 ウェブページフェッチャーはScrapeless MCPの
scrape_markdownツールを受け取り、抽出者と検証者は以前のタスクの出力のみを利用します。 - LLMはローカルで実行されます。 すべてのエージェントはOllamaを介して
qwen2.5:0.5bを使用しているため、ワークフローにはクラウドLLM APIキーは必要ありません。 - 成功した実行は正しい抽出を証明しません。
crew.kickoff()は完了しましたが、キャプチャされた検証者の出力は自己矛盾しており、拒否する必要がありました。 - プロダクションの検証は決定的でなければなりません。 モデルの出力をPythonで解析し、必要なフィールドを検証し、抽出された値と元のMCPレスポンスを比較します。
- 開始は無料。 新しいScrapelessアカウントには、無料のスクレイピングブラウザのランタイムが含まれています — app.scrapeless.comでサインアップ。
イントロダクション: 完成したクルーはまだ信頼できるパイプラインではありません
Scrapeless MCPツールに接続されたCrewAI エージェントはすでにライブページを取得できます。CrewAIのクルーは異なる主張です:二人以上のエージェントが別々の責任を持ち、互いに作業を引き渡し、最終的にcrew.kickoff()が結果を返す必要があります。
このガイドはその2つ目のワークフローを確立します。
あなたは次のことを行う三エージェントのクルーを作成します:
- Scrapeless MCPサーバーを介してライブページを取得します。
- 戻ってきたMarkdownから構造化された引用レコードを抽出します。
- ワークフローを離れる前にそれらのレコードを検証します。
すべてのエージェントはローカルのOllamaモデル上で実行されます。OpenAI、Anthropic、または他のクラウドLLMキーは必要ありません。唯一の外部認証情報はMCPツールによって使用されるScrapeless APIキーです。
統合は成功裏に完了します。ただし、キャプチャされた最終的な答えは内部的に矛盾しています。その区別はこのチュートリアルでの最も重要な教訓です:完了したエージェントワークフローは実行の証拠であり、結果データが信頼できるという証拠ではありません。
このクルーでできること
ワークフローは各エージェントに1つの責任を割り当てます:
- ウェブページフェッチャー: Scrapeless MCPの
scrape_markdownツールをライブURLに対して呼び出し、ページコンテンツを返します。 - データ抽出スペシャリスト: 取得したMarkdownを読み取り、それをJSON配列に変換します。
- QA検証者: 抽出されたレコードに欠落フィールドがないかをチェックし、結果を報告します。
CrewAIはタスク出力を明示的なタスクコンテキストを通じて渡します。抽出者は取得タスクの出力を受け取り、検証者は抽出タスクの出力を受け取ります。
3つのエージェントの間で何も手動でコピーする必要はありません。
これは、1つのローカルモデルを直接取得と抽出のPython関数に配線することとは異なります。 Ollamaのウェブスクレイピングガイドでは、そのシンプルなパターンについて説明しています。
ここでは、CrewAIがオーケストレーションを担当します:
- 三つのエージェント
- 三つの範囲のあるプロンプト
- 三つの異なるトークン制限
- 一つのフレームワーク管理による逐次的な引き渡し
なぜ1つのエージェントではなくクルーを使用するのか?
スクレイピングツールを持つ単一のエージェントは、何を取得するか、ページをどう解釈するか、結果をどうフォーマットするか、その結果が受け入れ可能かどうかを決定しなければなりません。
これらの責任を別々の役割に分割することで、ワークフローに対するより明確なコントロールが得られます。
各エージェントは次のものを受け取ります:
- 一つの狭い目標
- 一つの焦点を絞ったタスク
- 自身の出力制限
- 必要なツールへのアクセスのみ
これは、特に小さなローカルモデルで役立つことがあります。一つのモデルに同時に取得、抽出、フォーマット、検証を行うように頼むのではなく、各ターンがより限られた仕事を扱います。
分離はまた、より明確な検査ポイントを提供します。プロダクションパイプラインでは、各タスク後に出力を保存または検証し、取得、抽出、または検証中に失敗が発生したかどうかを特定できます。
なぜScrapeless MCPサーバーを使用するのか?
モデルコンテキストプロトコルの仕様は、AIクライアントがサーバーによって公開されたツールを発見し、呼び出すための標準的な方法を定義しています。
Scrapeless MCPサーバーは、そのツールインターフェースを通じてウェブデータとブラウザ機能を公開します。CrewAIはページレンダリング、プロキシルーティング、またはブラウザインフラストラクチャを直接実装する必要はありません。サーバーに接続し、エージェントに必要なツールを添付するだけで済みます。
Scrapeless MCPサーバーの概要は、ページの取得、検索、ブラウザ制御ツールを含む、より幅広いツールファミリーを説明しています。
このワークフローでは、クルーは1つのツールのみが必要です:
text
scrape_markdown
ターゲットページを取得し、下流の抽出エージェントが読み取れる形式でコンテンツを返します。
最新のサーバー接続の詳細やツールの引数については、Scrapeless開発者ドキュメントを確認してください。
前提条件
クルーを実行する前に、必要なもの:
- Python 3.10以降
- CrewAIおよびCrewAIツール
- Scrapeless APIキー
- Ollamaがローカルにインストールされ、実行中であること
- Ollamaにダウンロードされた
qwen2.5:0.5bモデル
OPENAI_API_KEY、ANTHROPIC_API_KEY、または他のホスティングされたLLMの資格情報は必要ありません。この例のすべてのCrewAI LLMオブジェクトは、ローカルのOllamaサーバーを指しています。
ステップ1 — CrewAIとMCPサポートのインストール
検証済みの例では、ピン留めされたCrewAIパッケージを使用します:
bash
pip install "crewai==1.15.4" "crewai-tools[mcp]==1.15.4"
[mcp]の追加により、MCPServerAdapterが必要とするMCPクライアント依存関係がインストールされます。アダプターは、MCPツールの定義をCrewAIエージェントが呼び出せるツールに変換します。
ステップ2 — ローカルOllamaモデルの設定
この例で使用されるモデルを取得します:
bash
ollama pull qwen2.5:0.5b
Ollamaがそれを認識していることを確認します:
bash
ollama list
Ollamaは通常、ローカルAPIを以下のアドレスで公開します:
text
http://localhost:11434
Ollamaがインストールされているがクルーが接続できない場合は、Pythonスクリプトを起動する前にOllamaサービスが実行中であることを確認してください。
次に、シェルでScrapeless APIキーを設定します:
bash
export SCRAPELESS_API_KEY="your_api_key_here"
環境変数からキーを読み取ることで、Pythonソースファイルから除外されます。
ステップ3 — CrewAIをOllamaに向ける
各エージェントに対して別々のLLM設定を作成します:
python
from crewai import LLM
fetch_llm = LLM(
model="ollama/qwen2.5:0.5b",
base_url="http://localhost:11434",
max_tokens=180,
temperature=0,
)
extract_llm = LLM(
model="ollama/qwen2.5:0.5b",
base_url="http://localhost:11434",
max_tokens=100,
temperature=0,
)
validate_llm = LLM(
model="ollama/qwen2.5:0.5b",
base_url="http://localhost:11434",
max_tokens=70,
temperature=0,
)
3つの設定はすべて同じモデルを使用していますが、出力制限はそれぞれの責任を反映しています:
- フェッチャーにはページコンテンツを返す余裕があります。
- エクストラクターには短いJSON配列のための十分なトークンが必要です。
- バリデーターはコンパクトなレポートを生成するだけで済みます。
temperature=0に設定すると出力の変動が減少します。これは、特に小さなローカルモデルでは、決定論的または正しい結果を保証するものではありません。
CPUのみのローカル推論では、max_tokensも重要なランタイム制御です。制限を低く設定することで、エージェントが不必要に長い応答を生成するのを防ぎますが、モデルサイズ、ハードウェア、コンテキストの長さ、およびエージェントのターン数も実行時間に影響を与えます。
ステップ4 — CrewAIをScrapeless MCPサーバーに接続する
MCPServerAdapterをインポートし、リモートMCP接続を定義します:
python
import os
from crewai_tools import MCPServerAdapter
server_params = {
"url": "https://api.scrapeless.com/mcp",
"transport": "streamable-http",
"headers": {
"x-api-token": os.environ["SCRAPELESS_API_KEY"]
},
}
この構成には、3つの重要な値が含まれています:
urlはScrapeless MCPエンドポイントを指します。transportはクライアントにStreamable HTTPを使用するよう指示します。x-api-tokenはあなたのScrapelessキーでリクエストを認証します。
キーには次の方法でアクセスします:
python
os.environ["SCRAPELESS_API_KEY"]
環境変数が欠けている場合、Pythonは直ちに停止します。これは、有効なツールの資格情報なしにクルーが静かに起動するよりも好ましい動作です。
ステップ5 — 利用可能なMCPツールの確認
完全なクルーを構築する前に、アダプターがリクエストされたツールを発見できることを確認します:
python
with MCPServerAdapter(server_params, "scrape_markdown") as tools:
print([tool.name for tool in tools])
確認実行の結果は次の通りでした:
text
['scrape_markdown']
これは以下のことを確認します:
- MCPクライアントがサーバーに到達しました。
- サーバーが認証ヘッダーを受け入れました。
- リクエストされたツールがCrewAIで利用可能でした。
これは、今後のすべてのページリクエストに期待されるデータが含まれていることや、下流モデルが応答を正しく解釈することを証明するものではありません。
ここで使用されるMCPツールサーフェス
MCPServerAdapterは、サーバーツールをCrewAIエージェントに公開できます。"scrape_markdown"を渡すことで、このワークフローは必要な単一のツールに制限されます:
python
with MCPServerAdapter(server_params, "scrape_markdown") as tools:
...
このより狭いツールサーフェスは、エージェントの信頼性にとって便利です。フェッチャーは無関係なブラウザや検索ツールから選択する必要がなく、抽出および検証エージェントはまったくツールを受け取ることがありません。
権限の境界は明確です:
| エージェント | ツールアクセス | 責任 |
|---|---|---|
| ウェブページフェッチャー | scrape_markdown |
ターゲットページを取得する |
| データ抽出スペシャリスト | なし | 取得したコンテンツをJSONに変換する |
| QAバリデーター | なし | 抽出したレコードの完全性をチェックする |
ライブウェブリクエストを行えるのはフェッチャーのみです。
実際の使用方法: クルーを構築して実行する
三つのエージェント役割を定義する
各段階のために一つのAgentを作成します:
python
from crewai import Agent
fetcher = Agent(
role="ウェブページフェッチャー",
goal=(
"scrape_markdownツールを使用して指定された正確なURLをフェッチし、その生の出力を返す。"
),
backstory=(
"ウェブを自分でブラウズできないチームメイトのために公開ウェブページを取得する。"
),
tools=tools,
llm=fetch_llm,
max_iter=2,
)
extractor = Agent(
role="データ抽出スペシャリスト",
goal=(
"取得したページのマークダウンをクリーンな構造化された "
"すべての引用とその著者のレコードに変換する。"
),
backstory=(
"生のスクレイピングされたマークダウンを読み取り、"
"データベースに必要なフィールドだけを引き出す。"
),
llm=extract_llm,
max_iter=2,
)
validator = Agent(
role="QAバリデーター",
goal="出荷前に抽出した引用レコードの完全性をチェックする。",
backstory=(
"不完全または不正なレコードを拒否し、"
"正確にチェックした内容を報告する。"
),
llm=validate_llm,
max_iter=2,
)
のみがfetcherにtools=toolsを受け取ります。
エクストラクターとバリデーターは、タスクのコンテキストから作業する必要があります。彼らは独立してターゲットページをブラウズしたり、別のMCPリクエストを行ったりすることはできません。
なぜmax_iter=2を設定するのか?
max_iterは、エージェントがタスク中に実行できる推論とアクションサイクルの数を制限します。
2の値は、フェッチャーにツールコールをリクエストし、その後最終的な回答を生成するのに十分な余地を与えます。また、小さいモデルが過剰な数の内部ループを通過するのを防ぎます。
この制限は制御メカニズムであり、正確性の保証ではありません。エージェントが不完全なJSONを生成したり、空のフィールドを受け入れたりした場合、反復リミットに成功して到達してもその出力が有効になるわけではありません。
MCPツールをフェッチャーのみに接続する
フェッチャーの役割は狭く定義されています:
- ターゲットURLを受け取る。
scrape_markdownを呼び出す。- 追加のコメントなしでツール出力を返す。
エクストラクターは、ブラウジング指示としてライブURLを受け取りません。彼はフェッチャーが返したコンテンツを読み取ります。
バリデーターはMCPツールを受け取りません。彼はエクストラクターからの出力のみを読み取ります。
この分離により、データフローが理解しやすく、監査しやすくなります。
逐次タスクコンテキストを配線する
CrewAIタスクはcontext引数を通じて前のタスクを参照できます:
python
extract_task = Task(
...,
context=[fetch_task],
)
validate_task = Task(
...,
context=[extract_task],
)
従って、引き渡しは次のようになります:
text
fetch_task → extract_task → validate_task
エクストラクターはフェッチタスクの最終的な回答を受け取ります。バリデーターは抽出タスクの最終的な回答を受け取ります。
手動の文字列渡しは必要ありません。
crew.kickoff()でクルーを実行する
次が完全なスクリプトです:
python
import os
from crewai import Agent, Crew, LLM, Process, Task
from crewai_tools import MCPServerAdapter
TARGET_URL = "https://quotes.toscrape.com/tag/obvious/"
server_params = {
"url": "https://api.scrapeless.com/mcp",
"transport": "streamable-http",
"headers": {
"x-api-token": os.environ["SCRAPELESS_API_KEY"]
},
}
fetch_llm = LLM(
model="ollama/qwen2.5:0.5b",
base_url="http://localhost:11434",
max_tokens=180,
temperature=0,
)
extract_llm = LLM(
model="ollama/qwen2.5:0.5b",
base_url="http://localhost:11434",
max_tokens=100,
temperature=0,
)
validate_llm = LLM(
model="ollama/qwen2.5:0.5b",
base_url="http://localhost:11434",
max_tokens=70,
temperature=0,
)
with MCPServerAdapter(server_params, "scrape_markdown") as tools:
fetcher = Agent(
role="ウェブページフェッチャー",
goal=(
f"指定されたURL {TARGET_URL} を "
"scrape_markdownツールを使用して取得し、その生の出力を返す。"
),
backstory=(
"ウェブを自分でブラウズできないチームメイトのために公共のウェブページを取得する。"
),
tools=tools,
llm=fetch_llm,
max_iter=2,
)
extractor = Agent(
role="データ抽出スペシャリスト",
goal=(
"取得したページのマークダウンをクリーンで構造化された "
"すべての引用とその著者のレコードに変換する。"
),
backstory=(
"生のスクレイピングされたマークダウンを読み取り、"
"データベースに必要なフィールドを正確に引き出す。"
),
llm=extract_llm,
max_iter=2,
)
validator = Agent(
role="QAバリデーター",
goal=(
"出荷前に抽出した引用レコードの完全性を確認すること。"
),
backstory=(
"不完全または不正なレコードを拒否し、"
「チェックした内容を正確に報告します。」
),
llm=validate_llm,
max_iter=2,
)
fetch_task = Task(
description=(
f"URL='{TARGET_URL}'を使用してscrape_markdownツールを呼び出します。 "
"ツールの出力を最終的な回答として正確に返してください。 "
"前後にコメントを付けないでください。"
),
expected_output=(
"scrape_markdownツールから返された生のマークダウン。"
),
agent=fetcher,
)
extract_task = Task(
description=(
"コンテキストとして引用ページの生のマークダウンが与えられます。 "
"ページ上のすべての引用を見つけてください。各引用に対して、 "
'「text」(引用)および「author」(「by」の後に名前がある人)というキーを持つ '
'JSONオブジェクトを1つ出力します。これらのオブジェクトのJSON配列のみを返し、 '
"それ以外は何も返さないでください。"
),
expected_output=(
'["text": "...", "author": "..."}]という形式のJSON配列 '
"を各引用に対して1つずつ持つ。"
),
agent=extractor,
context=[fetch_task],
)
validate_task = Task(
description=(
"引用記録のJSON配列がコンテキストとして与えられます。 "
"配列に少なくとも1つのエントリがあり、すべてのエントリに空でないtextとauthorフィールドがあることを確認してください。 "
"合計レコード数、著者リスト、および完全性に関するステートメントを報告します。"
),
expected_output=(
"短いレポート: レコード数、著者リスト、 "
"完全性に関するステートメント。"
),
agent=validator,
context=[extract_task],
)
crew = Crew(
agents=[fetcher, extractor, validator],
tasks=[fetch_task, extract_task, validate_task],
process=Process.sequential,
)
result = crew.kickoff()
print(result)
スクリプトは、fetcherがタスクを実行している間にリモートツール接続を利用できるように、MCPアダプタコンテキスト内でcrew.kickoff()を呼び出します。
3つのタスクがすべて完了すると、スクリプトは最終的なCrewOutputを印刷します。
受け取ったもの
検証実行は、3つの異なる層で証拠を生み出しました:
| 層 | 捕らえられた証拠 | 支持された結論 |
|---|---|---|
| MCP接続 | ['scrape_markdown'] |
CrewAIが要求されたMCPツールを発見した |
| Crew実行 | crew.kickoff() が例外を発生させずに返された |
逐次ワークフローが最終タスクに到達した |
| データ品質 | 最終的な回答が自己矛盾していた | 結果として得られたレコードは拒否されるべきである |
最終的なバリデーターの出力は:
text
0 ["", "", ""] 完全です。JSON配列には1つのエントリがあり、すべてのフィールドは空でありません。したがって、完全性の基準を満たしています。
この出力は内部的に矛盾しています。
それは以下を報告しています:
0のカウント- 3つの空の文字列
- 一見完全なエントリ1つ
- すべてのフィールドが空でない旨のステートメント
これらの主張は同時にすべて真であることはできません。
プロセスは完了しましたが、データは意味のある品質チェックを通過しませんでした。
なぜ最終出力が検証に失敗したのか
MCPハンドシェイクが証明したこと
MCPハンドシェイクは次のように返しました:
text
['scrape_markdown']
これは、CrewAIがScrapeless MCPサーバーに接続し、要求されたツールを発見したことを証明します。
したがって、Web Page Fetcherは実行中に実際のリモートツールが利用可能でした。
crew.kickoff()が証明したこと
crew.kickoff()は例外を発生させずにCrewOutputを返しました。
これは次のことを証明します:
- クルーが正常に構築された。
- 3つのタスクが受け入れられた。
- 逐次的なオーケストレーションがバリデータタスクに到達した。
- CrewAIが最終結果を返した。
取得したコンテンツがすべてのモデルのハンドオフを正確に生き残ったことを証明するものではありません。
最終回答が証明しなかったこと
ターゲットページにはobviousタグの下に1つの引用があります:
text
「太陽のない日は、ナイトのようなものです。」
— スティーブ・マーチン
キャプチャされた最終回答はこれらの値を保持していませんでした。
スクリプトはクルーの最終出力のみを印刷するため、失敗を特定の段階に割り当てることはできません。空の値は以下のときに現れた可能性があります:
- フェッチャーがMCPレスポンスを要約または変更した。
- エクストラクターがMarkdownをJSONに変換した。
- バリデーターがエクストラクターの出力を解釈した。
- 複数の段階でデータが劣化した。
利用可能な証拠は、より狭い結論しか支持しません:クルーは最終タスクに到達しましたが、バリデーターは自己矛盾する結果を受け入れました。
ツール呼び出しクルーにおける小さなローカルモデル:正直な結果
テストされたモデルは約4億9400万のパラメータを含んでいます。それはローカルで実行するには十分に小さく、CrewAIワークフローを完了まで運びました。
完全な実行は、テストしたホストで542秒後にコード0で終了しました。
そのタイミングは、一般的なCrewAIやOllamaのベンチマークではありません。それは1台のマシン、1つのモデル、1つのページ、選択されたプロンプト、およびこの特定のワークフローでのエージェントのターン数を反映しています。
統合結果は依然として有用です:
- CrewAIは3つのエージェントを作成しました。
- フェッチャーはライブのScrapeless MCPツールを受け取りました。
- タスクコンテキストは3つのステージを接続しました。
crew.kickoff()が完了しました。- クラウドLLMキーは使用されませんでした。
ただし、実行結果のフィールドを信頼することはサポートされていません。最終出力はゼロカウント、空の値、および成功のステートメントを組み合わせたものです。
サブ1Bモデルはオーケストレーションのテストに有用ですが、この実行はそれが自動的に信頼できる構造化データ抽出器として扱われるべきでない理由を示しています。
クルーの後に決定論的検証を追加
自然言語による検証は依然としてモデルの出力です。バリデーターエージェントは、誤ったデータを誤解したり、空の値を見逃したり、自身のレポートと矛盾する結論を生成したりする可能性があります。
したがって、プロダクション検証はモデルワークフローの後に通常のコードで行うべきです。
抽出器出力を解析
json.loadsを使用して抽出器の応答を解析します。
次の場合には結果を拒否します:
- 有効なJSONではない。
- 最上位の値が配列ではない。
- 応答にJSONに関する散文が含まれている。
- 配列が予期せず空である。
必要なフィールドを検証
すべてのレコードについて、次を確認します:
textが存在する。authorが存在する。- 両方の値が文字列である。
- 両方の値が空白をトリミングした後も非空である。
- いずれの値も明らかなプレースホルダーでない。
「すべてのフィールドが完了しています」といった自然言語のステートメントが失敗したプログラム的なチェックを上書きしないようにします。
矛盾するカウントを拒否
バリデーターがカウントを報告する場合、それを実際のJSON配列の長さと比較します。
1つの完全なエントリを主張しながら同時にゼロのカウントを報告する場合は、直ちに失敗すべきです。
抽出された値をソースと比較
scrape_markdownによって返された元のMarkdownを保持します。
引用や著者名などのコピーされたフィールドについては、抽出された値がソース応答に現れることを確認します。これにより、幻覚、切り捨て、または置き換えられたコンテンツを検出する手助けになります。
中間タスク出力を保持
例は最終的なクルー出力のみを印刷します。デバッグおよび生産モニタリングのために、すべてのタスクからの出力を保持します。
これにより、次の3つの別々のアーティファクトが得られます:
- 生の取得Markdown
- 抽出されたJSON
- 検証レポート
これらの出力を利用することで、データが失われた正確なステージを特定することができ、最終的な答えから推測する必要がなくなります。
必要に応じてモデル容量を増加させる
強力な検証は悪い結果を拒否できますが、モデルが保持できなかったソーステキストを復元することはできません。
小さなモデルが抽出または検証中にデータを繰り返し失う場合は、より大きなローカルモデルまたはより能力のあるホスティングモデルを使用してください。パイプラインを成功に見せるためだけにチェックを弱めてはいけません。
結論
ローカルのOllamaモデルで実行されるCrewAIクルーは、Scrapeless MCPサーバーに接続し、ライブスクレイピングツールを呼び出し、データを3つのエージェントを通じて受け渡し、クラウドLLMキーなしでcrew.kickoff()を完了できます。
これが統合結果です。
取得された最終出力は依然として拒否されるのに十分な間違いがありました:ゼロのカウントと空の値を報告しながら、同時にデータが完全であると主張しました。
ワークフローの完了とデータの正確性を別々の条件として扱います。中間出力を保持し、Pythonで構造化されたレコードを検証し、抽出された値をMCP応答と比較し、これらのチェックがモデルの結論と異なるときはパイプラインを失敗させます。
ツール呼び出しクルーを作成する準備はできましたか?
無料のScrapelessアカウントを作成して、APIキーを取得し、CrewAIをライブWebデータツールに接続してください。
ワークフローに必要なページ数とエージェントの呼び出しを理解したら、Scrapelessの料金プランを確認してください。
実装に関する質問やコミュニティサポート:
FAQ
Q: CrewAIクルーは実行するのにクラウドLLMキーが必要ですか?
いいえ。model="ollama/qwen2.5:0.5b"とbase_url="http://localhost:11434"を設定することで、各エージェントがローカルのOllamaサーバーを指します。クルーはOpenAI、Anthropic、または他のホスティングLLMキーを必要としません。
このワークフローは、フェッチャーがリモートのScrapeless MCPサーバーを呼び出すため、Scrapeless APIキーが依然として必要です。
Q: CrewAIはどのように出力を1つのエージェントから次のエージェントに渡しますか?
各下流のTaskは、以前のタスクを含むcontextリストを受け取ります。
例えば:
python
extract_task = Task(
...,
context=[fetch_task],
)
CrewAIは、抽出器のコンテキストにフェッチタスクの最終回答を含めます。同じメカニズムが抽出結果をバリデーターに渡します。
Q: なぜフェッチャーだけがMCPツールを受け取るのですか?
フェッチャーは、ライブページコンテンツを取得する唯一のエージェントです。エクストラクターとバリデーターは、既存のタスク出力に基づいて操作する必要があります。
ツールアクセスを制限することで、不必要な選択肢が減り、ワークフローの監査が容易になります。
Q: max_iter=2は何を制御しますか?
max_iterは、一つのタスク中にエージェントが行う推論およびアクションサイクルの回数を制限します。
値が2の場合、フェッチャーはツールコールと最終応答の余地を持ちながら、無限ループを防ぎます。実行を制限しますが、エージェントの最終的な答えが正しいことを保証するものではありません。
Q: 小さいローカルモデルは正しい引用を抽出しましたか?
いいえ。クルーは完了しましたが、最終的なバリデーターの出力は次のように始まりました:
text
0 ["", "", ""]
その後、完全なエントリーが存在し、すべてのフィールドが非空であると主張しました。それらの声明は互いに矛盾しているため、結果は拒否されなければなりません。
Q: クルーがすでにQAエージェントを持っているのに、なぜ決定論的バリデーションを使用するのですか?
QAエージェントもLLMです。欠落しているフィールドを見逃したり、調査するように求められたデータと矛盾する結論を生成する可能性があります。
決定論的なPythonチェックは、JSON構文、配列の長さ、必要なフィールド、およびソースの一致に基づいて、独立した合格/不合格の判断を提供します。
Q: ローカルのOllama実行はどれくらい遅かったですか?
完全な検証実行は、テストホストで542秒かかりました。その測定値は、テストに使用された特定のハードウェア、モデル、ページ、プロンプト、およびエージェント設定にのみ適用されます。
ローカルCPU推論は、複数のエージェントターンが関与する場合、数分かかることがあります。
Q: 生産クルーでログに記録すべきことは何ですか?
少なくとも次を保存してください:
- MCPツールの応答
- すべての中間タスク出力
- 解析された構造化データ
- 決定論的バリデーションエラー
- 最終的なクルーの結果
- 各ステージの実行時間
これにより、ソースデータを変更または削除したステージを特定できるようになります。
Q: ライブウェブサイトをスクレイピングする前に何を確認すべきですか?
ウェブサイトの利用規約と/robots.txt指示を確認してください。これらはロボット排除プロトコルに従います。
対象リストは限られたもので、公開ページを使用し、自律エージェントにオープンエンドのクロール指示を与えることを避けてください。
Scrapelessでは、適用される法律、規制、およびWebサイトのプライバシーポリシーを厳密に遵守しながら、公開されているデータのみにアクセスします。 このブログのコンテンツは、デモンストレーションのみを目的としており、違法または侵害の活動は含まれません。 このブログまたはサードパーティのリンクからの情報の使用に対するすべての責任を保証せず、放棄します。 スクレイピング活動に従事する前に、法律顧問に相談し、ターゲットウェブサイトの利用規約を確認するか、必要な許可を取得してください。



