0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「こんなアプリが欲しいな」と思ったとき、AIに頼んで一瞬でコードを書いてもらえたら最高ですよね。今回は、そんな夢を叶えるツール「AI-Code-Swarm」の作り方をご紹介します。

このツールは、複数のAIエージェントが「President」「Project Manager」「Engineer」といった役割を分担し、チームで協力してコーディングを進めてくれる面白い仕組みです。しかも、超高速な推論が魅力の Groq API を使っているので、AIの思考時間がほとんどなく、リアルタイムでコードが生成されていく様子は圧巻です!

この記事を読めば、あなたも自分だけのAI開発チームを手に入れられます。
このツールの魅力

🤖 AIによるチーム開発: 1体のAIに丸投げするのではなく、役割分担することで、より計画的で精度の高い開発が期待できます。

🚀 驚異的なスピード: Groq API(Llama3やMixtralなど)を利用することで、AIの応答が非常に速く、ストレスフリーな開発体験が可能です。

🌍 多言語対応: Pythonだけでなく、JavaScript、HTML/CSS、Goなど、あなたが使いたい言語で開発を指示できます。

🔧 簡単セットアップ: 必要なのはGroqのAPIキーだけ。数ステップで誰でもすぐに試せます。

仕組み:AIチームの仕事の流れ

このツールには3種類のAIエージェントが登場します。

👑 President (社長)

    あなたの「こんなもの作って」という曖昧なリクエスト(request.txt)を読み取り、開発プロジェクトの基本方針を決定します。

📋 Project Manager (PM)

    Presidentの指示を受け、具体的な開発タスクリストを作成します。このタスクリストはプロジェクトフォルダ内の README.md に書き込まれます。

👷 Engineer (エンジニア)

    PMが作成した README.md を見て、タスクを上から一つずつ実行します。コードを書き、ファイルを更新し、タスクが完了したらチェックマークを付けます。

この流れをすべてのタスクが完了するまで自動で繰り返し、最終的にプログラムを完成させます。
使い方:AI開発チームを動かしてみよう!
ステップ1:必要なものを準備する

Pythonのインストール
もしPCにPythonが入っていなければ、公式サイトからインストールしてください。インストーラーでは「Add Python to PATH」にチェックを入れると便利です。

Groq APIキーの取得

    GroqCloud にアクセスし、アカウントを作成します(Googleアカウントで簡単)。

    「Create API Key」ボタンを押し、表示されたAPIキーをコピーしておきます。このキーは一度しか表示されないので、必ず控えておきましょう。

ステップ2:プロジェクトのセットアップ

好きな場所にプロジェクト用のフォルダを作成します(例: my-ai-project)。

作成したフォルダ内に、以下の3つのファイルを作成します。

    main.py (後述するPythonコードを貼り付けます)

    .env (APIキーを保存するファイル)

    request.txt (開発してほしい内容を書くファイル)

ターミナル(WindowsならコマンドプロンプトやPowerShell)を開き、作成したフォルダに移動します。
Generated bash

      
cd path/to/my-ai-project

    

IGNORE_WHEN_COPYING_START

Use code with caution. Bash
IGNORE_WHEN_COPYING_END

必要なライブラリをインストールします。
Generated bash

pip install groq python-dotenv

IGNORE_WHEN_COPYING_START
Use code with caution. Bash
IGNORE_WHEN_COPYING_END

.env ファイルに、先ほど取得したGroqのAPIキーを記述します。
Generated dotenv

.env ファイルの中身

GROQ_API_KEY="ここにあなたのGroq APIキーを貼り付け"

IGNORE_WHEN_COPYING_START

Use code with caution. Dotenv
IGNORE_WHEN_COPYING_END

ステップ3:開発リクエストの作成

request.txt ファイルを開き、AIチームに作ってほしいアプリケーションの要望を自由に書きます。

例1: Pythonで簡単なタイマーアプリ
Generated text

request.txt の中身

シンプルなコマンドラインタイマーを作って。
ユーザーが秒数を指定したら、カウントダウンして「時間です!」と表示するもの。

IGNORE_WHEN_COPYING_START
Use code with caution. Text
IGNORE_WHEN_COPYING_END

例2: HTML/CSSで自己紹介ページ
Generated text

request.txt の中身

私の自己紹介ページを作ってください。

  • 名前は「AIマスター」
  • 趣味は「コーディングと散歩」
  • 簡単な挨拶文「こんにちは!AIと一緒に未来を作るのが好きです。」
  • 背景は薄い青色で、テキストは中央揃えにしてほしい。

IGNORE_WHEN_COPYING_START
Use code with caution. Text
IGNORE_WHEN_COPYING_END
ステップ4:実行!

準備が整いました!ターミナルで以下のコマンドを実行して、AI開発チームを始動させましょう。
Generated bash

python main.py

IGNORE_WHEN_COPYING_START
Use code with caution. Bash
IGNORE_WHEN_COPYING_END

実行すると、最初に「開発言語」と「使用するAIモデル」を聞かれます。
Generated code

--- 開発言語の選択 ---
1: Python
2: JavaScript
...

使用する言語の番号を選択してください (1-6) [Enterで1]: 1

--- AIモデル選択 ---
1: llama3-70b-8192
2: mixtral-8x7b-32768
...

使用するモデルの番号を選択してください (1-4) [Enterで1]: 1

IGNORE_WHEN_COPYING_START
Use code with caution.
IGNORE_WHEN_COPYING_END

番号を選んでEnterキーを押すと、あとはAIたちが自動で開発を進めてくれます。ターミナルに流れるログを見ながら、コードが完成していく様子をお楽しみください!

開発が完了すると、Project というフォルダの中に成果物が生成されています。
プログラムの全コード

こちらが main.py の全コードです。コピーして使ってください。
Generated python

--- START OF FILE main.py ---

import os
import re
import time
import shutil
from dotenv import load_dotenv
from groq import Groq

--- 設定 ---

load_dotenv()
GROQ_API_KEY = os.getenv("GROQ_API_KEY")

--- Groqクライアント初期化 ---

try:
if not GROQ_API_KEY:
raise ValueError("環境変数 GROQ_API_KEY が設定されていません。")
client = Groq(
api_key=GROQ_API_KEY,
)
except Exception as e:
print(f"Groqクライアントの初期化に失敗しました: {e}")
client = None

--- Groqで利用可能なモデル ---

AVAILABLE_GROQ_MODELS = [
"llama3-70b-8192",
"mixtral-8x7b-32768",
"llama3-8b-8192",
"gemma-7b-it",
]

--- 対応言語の定義 ---

SUPPORTED_LANGUAGES = ["Python", "JavaScript", "Go", "HTML/CSS", "Ruby", "TypeScript"]

プロジェクト設定

PROJECT_DIR = "Project"
REQUEST_FILE = "request.txt"

--- ヘルパー関数 ---

def clean_project_dir():
if not os.path.exists(PROJECT_DIR): return
for filename in os.listdir(PROJECT_DIR):
file_path = os.path.join(PROJECT_DIR, filename)
try:
if os.path.isfile(file_path) or os.path.islink(file_path): os.unlink(file_path)
elif os.path.isdir(file_path): shutil.rmtree(file_path)
except Exception as e: print(f"Error while deleting file/directory: {e}")

def create_project_dir():
if not os.path.exists(PROJECT_DIR): os.makedirs(PROJECT_DIR)

def read_file(filepath):
try:
with open(filepath, "r", encoding="utf-8") as f: return f.read()
except FileNotFoundError: return ""

def write_file(filepath, content):
os.makedirs(os.path.dirname(filepath), exist_ok=True)
with open(filepath, "w", encoding="utf-8") as f: f.write(content)

--- AIエージェントの定義 ---

def ai_call(system_prompt, user_prompt, model_id, max_retries=3):
messages = [{"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt}]
for attempt in range(max_retries):
try:
print(f"🧠 AI ({model_id}) is thinking...")
response = client.chat.completions.create(
model=model_id, messages=messages, temperature=0.1, max_tokens=8000,
)
print("✅ AI response received.")
return response.choices[0].message.content.strip()
except Exception as e:
print(f"⚠️ API呼び出しエラー (試行 {attempt + 1}/{max_retries}): {e}")
time.sleep(10)
print("❌ AI呼び出しに失敗しました。")
return None

def president_ai(user_request, model_id):
system_prompt = "あなたは企業のPresidentです。ユーザーの要求を元に、開発プロジェクトの基本方針と概要を決定し、Project Managerに指示を出してください。出力は簡潔な指示形式で、Markdownで記述してください。挨拶や署名などの余計なテキストは一切含めないでください。"
user_prompt = f"ユーザーからの開発要求:\n---\n{user_request}\n---\n上記の要求を元に、Project Managerへの指示を作成してください。"
print("\n===== 👑 President AI's Turn =====")
instruction = ai_call(system_prompt, user_prompt, model_id)
if instruction: print("▶️ PresidentからPMへの指示:\n", instruction)
return instruction

def project_manager_ai(president_instruction, model_id, language):
system_prompt = (
f"あなたは優秀なProject Managerです。これから {language} を使用して開発を行います。"
"Presidentの指示を元に、具体的な開発タスクリストをREADME.mdに書き込むためのコンテンツを作成してください。"
f"重要: 全てのタスクに、対象ファイル名(例: main.py, index.jsなど {language} に適したもの)を必ずバッククォート()で囲んで明記し、未完了を示す [ ]を付けてください。" "良い例: - [ ]app.jsにサーバーの基本設定を記述する。\n" "出力はREADME.md`に書き込むMarkdownタスクリストのみとしてください。余計なテキストは絶対に含めないでください。"
)
user_prompt = f"Presidentからの指示:\n---\n{president_instruction}\n---\n上記の指示を、全てのタスクにファイル名を含む具体的なタスクリストに変換してください。"
print("\n===== 📋 Project Manager AI's Turn =====")
new_readme_content = ai_call(system_prompt, user_prompt, model_id)
if new_readme_content:
new_readme_content = re.sub(r'^(markdown)?\n', '', new_readme_content, flags=re.IGNORECASE) new_readme_content = re.sub(r'\n$', '', new_readme_content)
write_file(os.path.join(PROJECT_DIR, "README.md"), new_readme_content)
print("✅ README.md を作成/更新しました。")
else:
print("❌ PMがREADMEの生成に失敗しました。")
return new_readme_content is not None

def engineer_ai(task, engineer_id, fallback_filename, model_id, language):
lang_for_prompt = "HTML/CSS" if language == "HTML/CSS" else language
lang_for_code_block = "javascript" if language == "JavaScript" else language.lower()
if language == "HTML/CSS": lang_for_code_block = "html"

system_prompt = (
    f"あなたは優秀な **{lang_for_prompt} Engineer** です。指示に従って、コードを生成・修正してください。"
    "あなたの仕事は、指定されたファイルに書き込むための完全なコードを生成することです。"
    "重要: 出力はコードのみを含むMarkdownコードブロック形式にしてください。説明、挨拶、その他のテキストは一切含めないでください。"
    "出力はファイルに書き込むコードそのものでなければなりません。"
)
readme_content = read_file(os.path.join(PROJECT_DIR, "README.md"))
match = re.search(r'`([^`]+)`', task)
if match: target_file = match.group(1)
elif fallback_filename:
    print(f"⚠️ タスクにファイル名がありませんでした。フォールバックファイル `{fallback_filename}` を使用します。")
    target_file = fallback_filename
else:
    print(f"❌ タスク「{task}」から対象ファイル名が見つけられず、フォールバックもありません。スキップします。")
    return False
target_filepath = os.path.join(PROJECT_DIR, target_file)
existing_code = read_file(target_filepath)

if lang_for_code_block == "css" and ".html" in target_file:
    lang_for_code_block = "html"

user_prompt = (
    f"あなたは Engineer #{engineer_id} です。以下のタスクを厳密に実行してください。\n\n"
    f"## プロジェクト全体のREADME:\n---\n{readme_content}\n---\n\n"
    f"## あなたが担当するタスク:\n- {task}\n\n"
    f"## 対象ファイル: `{target_file}`\n\n"
    f"## 現在のファイルの内容:\n```{lang_for_code_block}\n{existing_code}\n```\n\n"
    f"上記の情報を元に、タスクを完了させるための`{target_file}`の完全なコードを、Markdownコードブロック形式で生成してください。"
)
print(f"\n===== 👷 Engineer AI #{engineer_id}'s Turn on: {task} =====")
code = ai_call(system_prompt, user_prompt, model_id)
if code:
    code = re.sub(r'^```[a-zA-Z]*\n', '', code)
    code = re.sub(r'\n```$', '', code)
    write_file(target_filepath, code)
    print(f"✅ Engineer #{engineer_id}が `{target_filepath}` を更新しました。")
    return True
else:
    print(f"❌ Engineer #{engineer_id}がコードの生成に失敗しました。")
    return False

--- 設定選択関数 ---

def select_model():
print("\n--- AIモデル選択 ---")
print("Groqで利用可能なモデル:")
for i, model in enumerate(AVAILABLE_GROQ_MODELS):
print(f" {i+1}: {model}")
while True:
try:
choice = input(f"\n使用するモデルの番号を選択してください (1-{len(AVAILABLE_GROQ_MODELS)}) [Enterで1]: ").strip()
if not choice: choice = "1"
choice_num = int(choice)
if 1 <= choice_num <= len(AVAILABLE_GROQ_MODELS):
return AVAILABLE_GROQ_MODELS[choice_num - 1]
else: print(f"無効な番号です。1から{len(AVAILABLE_GROQ_MODELS)}の間で入力してください。")
except ValueError: print("数値を入力してください。")

def select_language():
print("\n--- 開発言語の選択 ---")
for i, lang in enumerate(SUPPORTED_LANGUAGES):
print(f" {i+1}: {lang}")
while True:
try:
choice = input(f"\n使用する言語の番号を選択してください (1-{len(SUPPORTED_LANGUAGES)}) [Enterで1]: ").strip()
if not choice: choice = "1"
choice_num = int(choice)
if 1 <= choice_num <= len(SUPPORTED_LANGUAGES):
return SUPPORTED_LANGUAGES[choice_num - 1]
else:
print(f"無効な番号です。1から{len(SUPPORTED_LANGUAGES)}の間で入力してください。")
except ValueError:
print("数値を入力してください。")

def main():
print("ようこそ!組織的AIコーディングシステム (AI-Code-Swarm) Groq版へ。")

selected_language = select_language()
selected_model = select_model()

print("\n--- 開発設定の確認 ---")
print(f"言語: {selected_language}")
print(f"モデル: {selected_model}")
print("------------------------\n")

if os.path.exists(PROJECT_DIR) and os.listdir(PROJECT_DIR):
    print(f"⚠️ 警告: '{PROJECT_DIR}' ディレクトリには既にファイルが存在します。")
    while True:
        choice = input("開始前に中身を全て削除しますか? (y/n): ").lower().strip()
        if choice in ['y', 'yes']: print(f"🧹 '{PROJECT_DIR}' ディレクトリの中身を削除しています..."); clean_project_dir(); print("✅ 削除が完了しました。"); break
        elif choice in ['n', 'no']: print("📂 既存のファイルを保持して処理を続行します。"); break
        else: print("無効な入力です。'y' または 'n' を入力してください。")

if not client: print("エラー: クライアントが初期化されていません。"); return

user_request = read_file(REQUEST_FILE)
if not user_request: print(f"エラー: 開発要求ファイル '{REQUEST_FILE}' が見つからないか、内容が空です。"); return
print(f"\n📄 '{REQUEST_FILE}' から開発要求を読み込みました:\n---\n{user_request}\n---")

create_project_dir()

president_instruction = president_ai(user_request, selected_model)
if not president_instruction: print("Presidentが指示を出せませんでした。処理を中断します。"); return

if not project_manager_ai(president_instruction, selected_model, selected_language):
    print("Project Managerがタスク計画を立てられませんでした。処理を中断します。")
    return

engineer_id_counter, main_filename = 1, None
while True:
    readme_content = read_file(os.path.join(PROJECT_DIR, "README.md"))
    tasks = re.findall(r'-\s*\[\s*\]\s*(.*)', readme_content)
    if not tasks: print("\n🎉 全てのタスクが完了しました!"); break
    current_task_text = tasks[0]
    
    if not main_filename:
        all_tasks_in_readme = re.findall(r'-\s*\[[\s|x]\]\s*(.*)', readme_content)
        for t in all_tasks_in_readme:
            match = re.search(r'`([^`]+)`', t)
            if match: main_filename = match.group(1); print(f"💡 プロジェクトのメインファイルを `{main_filename}` と推定しました。"); break
    
    engineer_id = (engineer_id_counter - 1) % 2 + 1
    success = engineer_ai(current_task_text, engineer_id, main_filename, selected_model, selected_language)
    engineer_id_counter += 1

    if success:
        current_task_line = f"- [ ] {current_task_text}"
        new_readme_content = readme_content.replace(current_task_line, f"- [x] {current_task_text}", 1)
        write_file(os.path.join(PROJECT_DIR, "README.md"), new_readme_content)
        print(f"✅ タスクを完了済みに更新: {current_task_text}")
    else:
        print(f"❌ タスクの処理に失敗しました。処理を中断します: {current_task_text}"); break
    
    time.sleep(1)

print("\n===== 最終的なプロジェクト構成 =====")
for root, _, files in os.walk(PROJECT_DIR):
    for name in files: print(os.path.join(root, name).replace('\\', '/'))
print("====================================")
print("開発を終了します。")

if name == "main":
main()

IGNORE_WHEN_COPYING_START
Use code with caution. Python
IGNORE_WHEN_COPYING_END
まとめ

今回は、複数のAIエージェントが連携してコーディングを行うツールを作成しました。AIの役割分担というアイデアと、Groq APIの圧倒的な速度が組み合わさることで、まるで人間と開発しているかのような未来的な体験ができます。

ぜひ、このツールをベースに色々なカスタマイズを試してみてください。例えば、

「QA(品質保証)エンジニア」を追加して、コードのテストを自動化する

各エージェントのプロンプトを改良して、より賢くする

request.txt にもっと複雑なお願いをしてみる

など、可能性は無限大です。AIコーディングの世界をぜひ楽しんでください!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?