Skip to main content

CrewAI で GitHub リポジトリ要約ツールを構築する

CrewAI によるマルチエージェント連携と Weave を用いたリアルタイムのデバッグと可観測性を備えた、完全自動の GitHub ドキュメント生成システムを構築するための実践ガイド。この記事は AI による翻訳です。誤訳の可能性があれば、コメント欄でお知らせください。
Created on August 26|Last edited on August 26
マルチエージェントシステム複数の AI エージェントが専門化されたタスクで協調して働くマルチエージェントシステムは、複雑なワークフローの自動化における中核的な手法になりつつあります。 CrewAI は、こうしたシステムを設計するためのプラットフォームで、開発者がタスクを割り当て、エージェントの役割を定義し、ツールを接続して実世界のプロジェクトを処理できるようにします。これに加えて、 W&B Weave、各エージェントの挙動を追跡・デバッグするためのツールで、結果として完全な可視化とコントロールが可能になります エージェント型ワークフロー全体
このハンズオンでは、GitHub のリポジトリを自動でドキュメント化するマルチエージェントシステムを構築します。エージェントはリポジトリを探索し、コードを要約し、使い方ガイドを作成し、アーキテクチャ図を生成し、すべてを HTML ページにまとめます。フローの管理には CrewAI を、各意思決定の過程を観測・監視するために Weave を使用します。


目次



エージェントとは何か?

AIエージェント は、計画立案、外部ツールの活用、メモリの保持、そして時間経過に伴う適応を通じて特定の目標を達成するよう設計された知的なシステムです。硬直的で事前定義のルールに従う従来の自動化とは異なり、AI エージェントは情報を動的に処理し、意思決定を行い、フィードバックに基づいて手法を洗練していきます。
一方で チャットボット は主に対話に従事し、各ステップでユーザー入力を必要としますが、AI エージェントは自律的に動作します。単に応答を生成するだけでなく、実際に行動し、外部システムと連携し、 マルチステップのエージェント型ワークフローを管理する 常時の監督なしで。
AIエージェントの主な構成要素は次のとおりです。
  • ツール機能を拡張するために、API、データベース、ソフトウェアに接続します。
  • メモリタスク間で情報を保持し、一貫性と想起性を向上させます。
  • 継続学習過去の成果に基づいて戦略を適応・洗練する。
  • オーケストレーション複数ステップのプロセスを管理し、タスクを分解して、他のエージェントと連携します。

マルチエージェントシステムの理解

基本的には、マルチエージェントシステムとは、…のネットワークです。 自律型AIエージェント 互いに通信し、連携することで、単一のエージェントでは成し得ない複雑なタスクをより効率的に達成します。各エージェントには明確な役割と責務が割り当てられ、専門性が生まれ、必要に応じて並列処理も可能になります。たとえばニュース集約システムでは、あるエージェントが最新の見出しを収集し、別のエージェントが詳細な分析を行う、といった分担が考えられます。効果的なマルチエージェント設計の要は、モジュール性、明確なタスク委譲、そしてシームレスなデータ交��にあります。これにより、人間のチームダイナミクスを反映した、スケーラブルで適応可能なAIソリューションが実現します。
複数の専門特化したエージェントを活用することで、開発者は大規模で複雑な課題を小さく明確に定義されたサブタスクに分解できます。ワークフローのあらゆる側面を1つのモノリシックなシステムで処理するのではなく、各コンポーネントや各フェーズを、その責務に最適化されたエージェントに割り当てられます。たとえば、 要約するテキストコードスニペットの生成感情分析、または 出力の整形この分業化により、システムは理解しやすくなるだけでなく、保守性と堅牢性も高まります。個々のエージェントはパイプライン全体を乱すことなく、更新・置換・スケールが可能です。
また、モデルのコンテキスト制限を管理しやすくなり、特定のタスクごとに異なるモデルを差し替えたり、システム全体でプロンプトの使い方を細かく調整・制御したりできます。これにより、各段階でリソース効率と精度を最適化できます。

CrewAI プラットフォームの主な特長

CrewAI プラットフォーム は、構造化された抽象化と柔軟なオーケストレーション機構を提供することで、スケーラブルなエージェント型ワークフローの構築を容易にします。
  • オートメーションフレームワークCrewAI の中核には、エージェント・タスク・ツールを明確に分離する設計があります。エージェントは、役割と目標が定義された自律的な存在を表し、タスクはエージェントに割り当てられる個別の作業単位です。ツールは、エージェントがタスクを実行したり強化したりするために用いる外部 API、検索エンジン、あるいはカスタム関数を指します。エージェント、タスク、ツールからなるこの三位一体が、モジュール化され保守しやすい AI ワークフローの基盤を成します。
  • クルーとフロー:CrewAI では、複数のエージェントとそのタスクをオーケストレーションするために Crew(クルー)を使用します。クルーは、エージェント間の全体的な実行フローとデータの受け渡しを制御します。プラットフォームは、Process クラスを通じて複数のワークフロー処理戦略をサポートします。
  • 逐次:タスクは逐次的に、1つずつ実行され、前のタスクの出力が後続のタスクに引き継がれます。
  • 階層型:タスクを入れ子や依存関係のある構造に編成でき、エージェント間で複雑な調整や委譲を可能にします。
  • 柔軟なデプロイメント:CrewAI は、俊敏な開発のためのインライン Python スクリプトと、より構造化されスケーラブルな YAML 設定ファイルの両方をサポートします。こうした柔軟性により、開発者は迅速にプロトタイプを作成し、その後はより複雑なマルチエージェントシステムにも途切れなくスケールさせることができます。
  • 外部ツールとの統合:CrewAI のエージェントは、Web 検索 API、データベース、その他のサービスなど、外部のデータや機能へのインターフェースとして機能する各種ツールを接続することで拡張できます。ツールを活用することで、エージェントは最新情報の取得、専門的な計算の実行、サードパーティシステムとの連携が可能になり、自動化ワークフローの適用範囲を大きく広げられます。
  • 明示的なタスク割り当て:CrewAI では、タスクを明確に定義し、エージェントに明示的に割り当てる必要があります。自律的な自己監視や自動委譲に頼るのではなく、各タスクの責務と担当するエージェントを開発者が指定します。この明示性により、透明性と予測可能性が高まり、複雑なマルチエージェント間のやり取りのデバッグも容易になります。

チュートリアル:CrewAI と Weave で構築する GitHub リポジトリ・ドキュメンターのマルチエージェントシステム

このチュートリアルでは、CrewAI を用いて、GitHub リポジトリを自動で探索・理解・ドキュメント化し、可視化するマルチエージェント AI システムの構築方法を解説します。目的は、生のコードベースを包括的な利用ガイドとアーキテクチャ図に変換し、整った HTML ドキュメントとしてまとめ上げる、完全自動のパイプラインを作ることです。
AI エージェントを作成する前に、まず GitHub リポジトリとやり取りするために必要な機能をエージェントに提供する、特化型ツール群を用意する必要があります。ツールは、ファイル検索、内容の読み取り、コードの要約などの特定機能を実行するために、エージェントが呼び出せる外部インターフェース/ユーティリティとして機能します。
このチュートリアルでは、コアとなる3つのツールを実装します。
  1. Repo Explorer ツールユーザーのクエリを受け取り、リポジトリ全体のファイル構造を検索し、分析の焦点を特定できるよう、クエリに関連するファイルパスを返します。
  2. View File ツール指定したファイルパスの内容を全文読み取り、エージェントに生のソースコードやドキュメントへのアクセスを提供します。
  3. Summarize File ツール言語モデルを用いてファイル内容を要約し、簡潔なサマリーを生成します。これにより、エージェントはすべてを逐一読むことなく、複雑なコードやドキュメントの要点を把握できます。
import os
import subprocess
from typing import Type
from pydantic import BaseModel, Field
from crewai.tools import BaseTool
from langchain_openai import ChatOpenAI

# Clone the repo if not already cloned
REPO_URL = "https://github.com/karpathy/nanogpt.git"
REPO_DIR = "./nanogpt"

if not os.path.exists(REPO_DIR):
subprocess.run(["git", "clone", REPO_URL])

# --- Define the Repo Explorer Tool ---
class RepoQueryInput(BaseModel):
query: str = Field(..., description="Describe what you are looking for in the codebase.")

class RepoExplorerTool(BaseTool):
name: str = "Repo Explorer"
description: str = "Given a query, find relevant file paths from the nanogpt repo."
args_schema: Type[BaseModel] = RepoQueryInput

def _run(self, query: str) -> str:
file_list = []
for root, _, files in os.walk(REPO_DIR):
for file in files:
full_path = os.path.join(root, file)
file_list.append(full_path)

llm = ChatOpenAI(model_name="gpt-4o-mini", temperature=0)
prompt = f"""
You are a codebase expert. Here is a list of files:\n{file_list}\n\n
Based on the user query "{query}", return ONLY the full file paths that are most relevant.
Respond with one file path per line, no extra text.
"""
response = llm.invoke(prompt)
return response.content.strip()

# --- Define the View File Content Tool ---
class ViewFileInput(BaseModel):
filepath: str = Field(..., description="Full path to the file you want to read.")

class ViewFileTool(BaseTool):
name: str = "View File Content"
description: str = "Reads the full content of a given file path from the nanogpt repo."
args_schema: Type[BaseModel] = ViewFileInput

def _run(self, filepath: str) -> str:
filepath = filepath.strip() # <<< add this
try:
with open(filepath, "r", encoding="utf-8") as f:
content = f.read()
return content
except Exception as e:
return f"Error reading file: {str(e)}"

# --- Instantiate the tools ---
repo_explorer_tool = RepoExplorerTool()
view_file_tool = ViewFileTool()

# --- Example usage ---
if __name__ == "__main__":
# Step 1: Find files related to training loop
query = "Where is the training loop defined?"
result_paths = repo_explorer_tool._run(query=query)
print("Relevant Files:\n", result_paths)

# Step 2: Read the first file found
first_file = result_paths.splitlines()[0]
file_content = view_file_tool._run(filepath=first_file)
print("\nContent of the first relevant file:\n")
print(file_content[:3000]) # only print first 3000 chars to keep output readable

これで、構築したツールを活用しつつ、AI エージェントとその担当タスクを定義する準備が整いました。
このシステムは、複数の専門特化したエージェントが順に連携し、最終的なドキュメントを生成する構成になっています。
  • デモジェネレーターリポジトリ向けに、初心者にもわかりやすい入門用の使用ガイドを作成し、最小限の例となるコマンドも含めます。
  • フォローアップアナリスト生成された使用ガイドをレビューし、抜け漏れを特定して確認の質問を投げかけ、改善に向けた具体的な提案を行います。
  • リポジトリ要約器リポジトリ内の主要なファイルを走査して要約し、開発者の理解を助ける簡潔な説明を提供します。
  • ダイアグラムジェネレーター:ファイル要約に基づいて、PlantUML や ASCII などでテキスト形式のアーキテクチャ図を作成し、リポジトリの高レベルな構造概要を示します。
  • シェルスクリプト自動化エンジニア:依存関係のインストール、環境構築、デモの実行を含むリポジトリのセットアップ手順をすべて自動化し、再実行しても安全な(冪等な)包括的な Bash スクリプトを生成します。開発者は1つのコマンドで作業を開始できます。
  • HTML コーダー:改良した使用ガイド、アーキテクチャ図、生成したセットアップスクリプトを統合し、読みやすく整えたスタイル付きのHTMLドキュメントページとして出力します。
コードは次のとおりです。
import os
import subprocess
from typing import Type, List
from pydantic import BaseModel, Field
from crewai import Agent, Task, Crew, Process
from crewai.tools import BaseTool
from langchain_openai import ChatOpenAI
import weave; weave.init("crewai_git_documenter")
# --- Repo Setup ---

REPO_URL = os.getenv('REPO_URL', 'https://github.com/LiveCodeBench/LiveCodeBench')
REPO_NAME = REPO_URL.split("/")[-1].replace(".git", "")
REPO_DIR = f"./{REPO_NAME}"

if not os.path.exists(REPO_DIR):
subprocess.run(["git", "clone", REPO_URL])

# --- Tools ---

class RepoQueryInput(BaseModel):
query: str = Field(..., query="Describe what you are looking for in the codebase.")

class RepoExplorerTool(BaseTool):
name: str = "Repo Explorer"
description: str = "Given a query, find relevant file paths from the repo."
args_schema: Type[BaseModel] = RepoQueryInput

def _run(self, query: str) -> str:
file_list = []
for root, _, files in os.walk(REPO_DIR):
for file in files:
full_path = os.path.join(root, file)
file_list.append(full_path)

llm = ChatOpenAI(model_name="gpt-4o-mini", temperature=0)
prompt = f"""
Here is a list of files:\n{file_list}\n\n
User query: "{query}"
Return ONLY full file paths that match. One per line.
"""
response = llm.invoke(prompt)
return response.content.strip()

class ViewFileInput(BaseModel):
filepath: str = Field(..., description="Full path to the file you want to read.")

class ViewFileTool(BaseTool):
name: str = "View File Content"
description: str = "Reads the full content of a given file path from the repo."
args_schema: Type[BaseModel] = ViewFileInput

def _run(self, filepath: str) -> str:
filepath = filepath.strip()
try:
with open(filepath, "r", encoding="utf-8") as f:
return f.read()
except Exception as e:
return f"Error reading file: {str(e)}"

class SummarizeFileTool(BaseTool):
name: str = "Summarize File Content"
description: str = "Summarizes a given file's content into a short description."
args_schema: Type[BaseModel] = ViewFileInput

def _run(self, filepath: str) -> str:
filepath = filepath.strip()
try:
with open(filepath, "r", encoding="utf-8") as f:
content = f.read()
llm = ChatOpenAI(model_name="gpt-4o-mini", temperature=0)
prompt = f"Summarize the following code file in 5 sentences:\n\n{content}"
response = llm.invoke(prompt)
return response.content.strip()
except Exception as e:
return f"Error summarizing file: {str(e)}"

# --- Instantiate tools ---
repo_explorer_tool = RepoExplorerTool()
view_file_tool = ViewFileTool()
summarize_file_tool = SummarizeFileTool()

# --- Agents ---

demo_generator_agent = Agent(
role="Demo Generator",
goal="Write and expand a basic usage example for the repo.",
backstory="Expert technical writer.",
tools=[repo_explorer_tool, view_file_tool],
allow_delegation=False,
verbose=True,
llm=ChatOpenAI(model_name="gpt-4o-mini", temperature=0.5)
)

followup_analyst_agent = Agent(
role="Follow-Up Analyst",
goal="Analyze the usage guide, find missing info, suggest improvements.",
backstory="Developer experience expert.",
allow_delegation=False,
verbose=True,
llm=ChatOpenAI(model_name="gpt-4o-mini", temperature=0.3)
)

html_coder_agent = Agent(
role="HTML Coder",
goal="Turn the improved usage guide into a clean HTML page.",
backstory="Frontend dev specializing in docs websites. DO NOT GENERATE IMAGES MAN eg dont do src=data:image/png etc etc",
allow_delegation=False,
verbose=True,
llm=ChatOpenAI(model_name="gpt-4o-2024-08-06", temperature=0.4)
)

repo_summarizer_agent = Agent(
role="Repo Summarizer",
goal="Summarize all important files in the repo for easier understanding.",
backstory="Documentation architect.",
tools=[repo_explorer_tool, view_file_tool, summarize_file_tool],
allow_delegation=False,
verbose=True,
llm=ChatOpenAI(model_name="gpt-4o-mini", temperature=0.4)
)

diagram_generator_agent = Agent(
role="Diagram Generator",
goal="Using file summaries, generate a full architecture diagram of the repo.",
backstory="System architect skilled in explaining large codebases.",
allow_delegation=False,
verbose=True,
llm=ChatOpenAI(model_name="gpt-4o-mini", temperature=0.4)
)


shell_script_agent = Agent(
role="Shell Script Automation Engineer",
goal="Create a working shell script that sets up all requirements and runs the repo's demo or basic usage.",
backstory="Expert in bash scripting, devops, and repo onboarding automations.",
tools=[repo_explorer_tool, view_file_tool, summarize_file_tool], # Optional, useful for reading files
allow_delegation=False,
verbose=True,
llm=ChatOpenAI(model_name="gpt-4o-mini", temperature=0.3)
)

# --- Tasks ---


demo_generation_task = Task(
description=f"Write a beginner-friendly usage guide explaining how to use {REPO_NAME}. Include a minimal example command.",
expected_output="Markdown snippet with instructions.",
agent=demo_generator_agent,
output_file="basic_usage.md"
)

followup_task = Task(
description="Read 'basic_usage.md', find confusing parts, generate 5+ questions and improvements.",
expected_output="List of questions + feedback report.",
agent=followup_analyst_agent,
context=[demo_generation_task],
output_file="feedback_report.md"
)

improvement_task = Task(
description="Use 'feedback_report.md' to expand and improve the usage guide.",
expected_output="New improved guide.",
agent=demo_generator_agent,
context=[followup_task],
output_file="improved_usage.md"
)

repo_summarization_task = Task(
description="Scan the repo, summarize the major files (training, models, data utils, etc.).",
expected_output="List of file summaries.",
agent=repo_summarizer_agent,
output_file="repo_summary.md"
)

diagram_generation_task = Task(
description="Using 'repo_summary.md', create an overall architecture diagram of the repo in text/plantuml format.",
expected_output="Architecture diagram text.",
agent=diagram_generator_agent,
context=[repo_summarization_task],
tools=[repo_explorer_tool, view_file_tool, summarize_file_tool],

output_file="architecture_diagram.md"
)

shell_script_task = Task(
description=(
"Read the improved usage guide and repo summary. Write a BASH shell script that fully sets up the repo from scratch, "
"including dependency installation, environment setup, any required downloads, and running the minimal example demo. "
"The script should be idempotent (safe to rerun), and **explain each step with comments**. Output the script in a codeblock."
),
expected_output="A complete shell script (setup_and_run_demo.sh) with comments.",
agent=shell_script_agent,
context=[improvement_task, repo_summarization_task], # Uses improved usage and file summaries
output_file="setup_and_run_demo.sh"
)



html_generation_task = Task(
description="Combine 'improved_usage.md', and 'architecture_diagram.md' into a final HTML file. Make sure to append the full setup_and_run_demo.sh script at the end",
expected_output="Final styled HTML guide. Follow styling similar to Wandb's website styling",
agent=html_coder_agent,
context=[improvement_task, diagram_generation_task, shell_script_task],
output_file="final_guide.html"
)


# --- Run Crew ---
crew = Crew(
agents=[
demo_generator_agent,
followup_analyst_agent,
repo_summarizer_agent,
diagram_generator_agent,
html_coder_agent,
shell_script_agent, # <-- Add here
],
tasks=[
demo_generation_task,
followup_task,
improvement_task,
repo_summarization_task,
diagram_generation_task,
shell_script_task, # <-- Add here, before html_generation_task
html_generation_task,
],
process=Process.sequential,
verbose=True
)

if __name__ == "__main__":
result = crew.kickoff()
print("\n\nFinal HTML Guide and Repo Diagram Created:\n")
print(result)

このコードは、CrewAI と Weave を用いて GitHub のリポジトリ向けドキュメント作成を自動化するマルチエージェントシステムを構築します。まずリポジトリをクローンし、エージェントがファイル検索・内容の読み取り・要約生成を行えるツール群を初期化します。各エージェントには明確な役割があり、使用ガイドの作成、レビューと改良、ソースファイルの要約、セットアップ用シェルスクリプトの作成、アーキテクチャ図の生成、そしてすべてを HTML ページにまとめる作業を担当します。
これらのタスクは厳密な順序で実行され、使用ガイドやリポジトリ要約など前段のエージェントの出力は、後続エージェントのコンテキストとして受け渡されます。システムはすべてのログを記録します。 LLM インタラクション 可観測性のための Weave の活用一度実行すれば、洗練された使用ガイド、リポジトリ構造のビジュアル概要、実行可能なセットアップスクリプトを含む完全な HTML ドキュメントが、ソースコードから自動生成されます。
ワークフロー全体は、CrewAI の Agent、Task、Crew クラスを用いてオーケストレーションします。各エージェントには専門のタスクを割り当て、すべてのタスクを順番に実行します。これにより、各段階の出力が次の段階の入力となり、情報が段階的に積み上がっていきます。最初の使用ガイドやファイルの要約から始まり、図の生成やシェルスクリプトの作成を経て、最終的にはすべての成果を統合した包括的な HTML ドキュメントページにまとめ上げます。
スクリプトを実行すると、次の名前の新しいファイルが作成されます。 final_guide.html(リポジトリの使い方ガイドが含まれています)こちらが見た目のスクリーンショットです。



LLM の可観測性とデバッグを強化するための Weave の統合

このマルチエージェントシステムを効率的に監視・デバッグするため、冒頭で Weave を次のように初期化して統合します。 import weave; weave.init("crewai_git_documenter"). このセットアップにより、各エージェントが OpenAI のモデルへ行うすべての呼び出しが記録され、プロンプト、応答、関連するコンテキストが中央でログとして収集されます。
〜を用いて Weave の可視化ダッシュボード、開発者は各エージェントによる LLM 呼び出しの詳細なリクエスト/レスポンスの履歴を確認し、エージェントが情報を取得・分析・生成していく流れを追跡できます。これにより、ボトルネックや想定外の出力、チェーン内のエラーを素早く特定し、実際の利用データに基づいてプロンプト指示や各種パラメータをチューニングできます。以下は Weave のスクリーンショットで、エージェントが行う LLM へのすべての呼び出しをどのように可視化できるかを示しています。

このようにエージェント同士のやり取りを細かく可視化できることは、複数のモデルが専門知識を持ち寄る本稿のようなマルチエージェント型ワークフローでとりわけ有用です。ローカルファイルの断片的なログを手作業で追う代わりに、Weave はパイプライン全体の履歴をウェブ上で検索可能な形で提供し、より効果的な反復開発と保守を実現します。
専門化したエージェント間で責務を分担し、Weave で各ステップを追跡することで、CrewAI によるこのマルチエージェントシステムは、拡張性が高く、保守しやすく、透明性のある自動ドキュメント化手法を実現します。

結論

マルチエージェントシステムは、AI エージェントが協調して複雑な課題に取り組めるようにすることで自動化を変革しています。CrewAI はそのために設計されており、開発者は役割を明確に定義したエージェントを作成し、ツールやタスクに接続できます。コードベースと設定ファイルベースの両方のワークフローに対応し、明確なオーケストレーションによりデバッグとスケーリングが容易になります。Weave と組み合わせると、あらゆるモデル呼び出しが追跡・可視化され、エージェントがどのように考え、行動し、連携しているかを開発者が全体像として把握できます。
GitHub のドキュメント化システムでは、各エージェントが特定の役割を担当します。たとえば、コードの要約、ダイアグラムの生成、利用ガイドの作成、セットアップスクリプトの作成などです。システムは各ステップが次のステップに出力を受け渡す形で順次実行されます。Weave を統合することで、開発者はプロンプトとレスポンスの対応を監視し、ロジックを追跡し、エラーを修正し、出力品質を向上できます。CrewAI は自動化を担い、Weave は内部挙動を可視化します。両者を組み合わせることで、保守しやすく透明性の高いマルチエージェントシステムが実現します。