【ChatDev】AI従業員が運営する仮想ソフトウェア開発会社に、シューティグゲームの開発を依頼してみた

ChatDev 開発会社

皆さんは、ChatDevというフレームワークをご存じですか?

これは、バーチャル上のソフトウェア開発会社として、ユーザーのテキストでの指示に従って、ソフトウェアを開発してくれるAIツールなんで
す!

今までにないユニークなものでワクワクしますよね。

現在、このフレームワークは大注目のされており、Githubのスター数は12,000を超えています!

今回は、ChatDevの概要や仕組み、実際に使ってみた感想をお伝えします。

是非最後までご覧ください!

目次

ChatDevの概要

ChatDevは、最高経営責任者やプログラマーなど、さまざまな役割を持つ複数の知的エージェントを通じて動作する仮想ソフトウェア会社として開発されています。

ソフトウェアを開発する過程にLLMを取り入れており、ユーザーがテキストで指示した内容のソフトウェアを、実際のソフトウェア開発と同じような感じで、設計、コーディング、テスト、ドキュメント作成などのタスクに分割し、それぞれのエージェントがそれぞれの役割を果たしつつ、コミュニケーションをとりながら開発を進めるという仕組みになっています。

そんなChatDevの特徴は以下の4点です。

  • 仮想ソフトウェア開発会社
    • ChatDevは、複数の知的エージェントが協力して動作する仮想ソフトウェア会社として機能します。
    • それぞれのエージェントは、CEO、CPO、CTO、プログラマ、レビュアー、テスター、アートデザイナーなどの役割を持っています。
    • 設計、コーディング、テスト、ドキュメント作成に作業を分割し、実際のソフトウェア開発チームのように開発してくれます。
  • 高度なカスタマイズ性
    • ユーザーは、自分のニーズに合わせてソフトウェア開発プロセスを設計するためのガイドを提供できます。
    • これにより、ChatDevにさせたいソフトウェア開発に最適な動きをするように、エージェントの動作を調整できます。
  • OpenAI APIの統合: 
    • OpenAI APIを活用して、ChatGPTで自然言語の指示に基づいてソフトウェアを開発します。
    • これにより、ユーザーは自然言語での指示や要求をエージェントに伝えることで、具体的なコードやソフトウェアを生成させることができます。
  • コミュニティとの協力:
    • ChatDevはオープンソースプロジェクトとして提供されており、ユーザー同士で情報の共有や協力が可能です。
    • ユーザーは自分が開発したソフトウェアやツールを共有することができ、他のユーザーからのフィードバックを受け取ることができます。

仮想環境内での開発は、プロンプト上でそのやり取りをリアルタイムで見ることができるのですが、開発が完了した後、納品されたlogファイルを入力すると、開発の過程をすべて見ることができるWebアプリも公開されています。

後ほど、使い方と実際に使ってみた結果をお伝えしますが、まずはChatDevの仕組みについて詳しく見ていきましょう。

ChatDevの仕組み

ChatDevは、設計、コーディング、テスト、ドキュメント作成の4つのフェーズに分けて開発を行います。この開発手法は、現実のソフトウェア開発でも広く採用されている、ウォーターフォール開発と同じ手法です。

ただ、このような開発手法は、メンバー同士の積極的なコミュニケーションが必要不可欠になります。そこで、ChatDevでは、「Chat Chain」というアーキテクチャを導入することで、各エージェントが協力して作業をするようにしました。

Chat Chain

このアーキテクチャは、設計などの各フェーズをさらに細かく「アトミックチャット」というサブタスクとして分解し、各エージェントが協力してサブタスクを完了させるために協力する仕組みです。

Chat Chainは以下の図のように、Phase-LevelChat-Levelに分かれています。

Phase-Levelは、前述したウォーターフォール開発のように、開発工程を4つのフェーズに分ける工程です。

Chat-Levelは、各フェーズがアトミックチャットに分解され、それぞれのアトミックチャットでは、2人のエージェントがタスクを達成するために、積極的なコミュニケーションを取り、ロールプレイ形式で開発を進めます。

そのため、円滑に開発が進み、品質の高いアウトプットが迅速にできます。

このアトミックチャットで作業するエージェントは、以下の図のような仕組みで過去の会話や行動を蓄積して記憶することで、それを参照しながら次の作業の意思決定を行うため、本当に人間のような効果的な開発を行います。

このほかにも、品質の高いアウトプットをするための仕組みとして、一時的に役割を入れ替えてレビューを行う仕組みがあります。

この図のように、コーディングのフェーズで、CTOとプログラマーが入れ替わってコードの評価をしたり、テストフェーズで、テスターとプログラマーが入れ替わってテストを行ったりします。

こうすることにより、複数の視点からの評価が行えるので、品質の高いコードが生成できます。

このようにして、開発されたソフトウェアは最終的にマニュアルなども同梱されたフォルダでアウトプットされます。

それでは早速使ってみて、どのような結果になったのか見ていきましょう。

まずは使い方からです。

ChatDevと同じように、ChatGPTを活用してチャットボットの開発ができるツールもあります。
【DocsBot】ChatGPTで簡単に自社AIチャットボットを作れる神ツール【使い方~実践まで】

ChatDevの使い方

公式GithubのREADMEを参考にして、導入していきます。なお、READMEは日本語のものが公開されています。

README-Japanese.md

今回は、Anaconda環境で実行します。

まず、GIthubのリポジトリをクローンします。

git clone https://github.com/OpenBMB/ChatDev.git

次に、Python3.9の仮想環境を作成します。

conda create -n ChatDev_conda_env python=3.9 -y
conda activate ChatDev_conda_env

ChatDevのディレクトリに移動し、以下のコマンドで必要なパッケージのインストールを行います。

cd ChatDev
pip3 install -r requirements.txt

次に、OpenAI API Keyを環境変数としてセットします。

OpenAI API Keyの取得は、以下のリンクにアクセスしてログインした後、View API keysから取得できます。

Platform OpenAI

取得出来たら、以下のコードでセットします。”your_OpenAI_API_key”は実際のAPI keyに置き換えてください。

Linux

export OPENAI_API_KEY="your_OpenAI_API_key"

Windows

set OPENAI_API_KEY "your_OpenAI_API_key"

ここまで完了したら、次はソフトウェアの生成を実行するコードを入力します。

Linux

python3 run.py --task "[description_of_your_idea]" --name "[project_name]"

Windows

python run.py --task "[description_of_your_idea]" --name "[project_name]"

“[description_of_your_idea]”に生成したいソフトウェアの説明を、”[project_name]”に適当なプロジェクト名を入れてください。

これを実行すると、ソフトウェア開発がスタートします。

これで導入は完了です。早速使っていきましょう!

ChatDevを実際に使ってみた

今回は、簡単な時計を作ってもらうことにしました。

先ほどのコードの、”[description_of_your_idea]”を”Create a simple clock”に、”[project_name]”を”clock”に変更します。

python run.py --task "Create a simple clock" --name "clock"

この際、以下のコードでモデルを指定することもできるようなのですが、今回は特に指定はせずに進めます。

--model MODEL    GPT Model, choose from {'GPT_3_5_TURBO','GPT_4','GPT_4_32K'}

実行すると、開発が始まり、ログが流れ始めます。

すると、3分ほどで開発が完了して、フォルダがアウトプットされました。

それと同時に、かかったコストや時間コードファイルの個数などの情報もアウトプットしてくれるので、本当の会社にプロジェクトを発注したような感覚になります。

アウトプットされたフォルダには、以下のものが入っていました。

コードファイルのほかに、logファイルやマニュアルなどが入っています。

生成されたmain.pyとclock.pyの中身はこのようになっていました。

import tkinter as tk
from clock import Clock

root = tk.Tk()
clock = Clock(root)
clock.pack()
root.mainloop()
import tkinter as tk
from time import strftime

class Clock(tk.Label):
        def __init__(self, parent=None, **kwargs):
            super().__init__(parent, **kwargs)
            self.time_string = strftime('%H:%M:%S')
            self.configure(text=self.time_string)
            self.after(1000, self.update_clock)

        def update_clock(self):
            self.time_string = strftime('%H:%M:%S')
            self.configure(text=self.time_string)
            self.after(1000, self.update_clock)

コードを見ると、tkinterのウィンドウに時計を表示させるもののようで、現在時刻を取得して表示し、その後update_clockで毎秒時刻を更新しています。

このコードを見る限り、指示通りのシンプルな時計が生成されると思います。

実際に実行して確かめていきましょう!

まず、この生成されたフォルダまで移動します。フォルダのパスは、皆さんの環境のものを指定してください。

cd WareHouse/clock_DefaultOrganization_20231009060754

そして、マニュアルにtkinterをインストールしてくださいとあったので、インストールします。

pip install tkinter

インストールが完了し、main.pyを実行すると、tkinterのウィンドウに時計が表示されました。

python main.py

すごいシンプルです笑

ただ、ちゃんとした時計になっているので、指示通りに正しく生成されたことが分かります。

ローカルデモ

今回は、シンプルな時計を生成してもらいましたが、その開発過程はコマンドプロンプト上でログとして確認できましたが、アウトプットされたフォルダの中に格納されているlogファイルを読み込ませることで、web上でエージェントのやり取りや開発の様子をリプレイで確認できるappが用意されています。

このappを起動するには、ChatDevディレクトリ内で以下のコード実行します。

python online_log/app.py

すると、flaskでサーバーが立ち上がるので、アクセスします。

Please visit http://127.0.0.1:8000/ for the front-end display page.

すると、以下のような画面になるので、Chat Replayをクリックします。

File Uploadをクリックし、生成されたlogファイルを指定してReplayをクリックします。

すると、チャット形式でログが流れだし、誰が作業しているか分かりやすくなっています。

ログを見ていると、プログラマーとテスターが交互にコードをテストしている場面もあり、先ほど説明した仕組みが実際に行われていることが分かります。

サービス紹介資料

生成系AIの業務活用なら!

・生成系AIを活用したPoC開発

・生成系AIのコンサルティング

・システム間API連携

ChatDevにシューティングゲームの開発依頼をしてみた

先ほどは、本当にシンプルなソフトウェアを作ってもらいましたが、もっと複雑なソフトウェアが開発できるのか試してみます。

python run.py --task "Create a simple shooting game" --name "shooting game"

このように入力し、シンプルなシューティングゲームを開発してもらいます。

時計より大幅にスクリプトの数が増えて、複雑さも増すと思うので、どうなるのか気になります。

まず、ソフトウェア開発の情報です。

コストも時間も3倍程度増えていますね。

出力されたフォルダの中身です。

出力された5つのコードの中身です。

'''
This is the main file of the shooting game.
'''
import tkinter as tk
from game import Game
def main():
    root = tk.Tk()
    game = Game(root)
    game.start()
    root.mainloop()
if __name__ == "__main__":
    main()
'''
This file contains the Game class which manages the game logic.
'''
import tkinter as tk
from player import Player
from enemy import Enemy
class Game:
    def __init__(self, root):
        self.root = root
        self.root.title("Shooting Game")
        self.canvas = tk.Canvas(self.root, width=800, height=600, bg="black")
        self.canvas.pack()
        self.player = Player(self.canvas)
        self.enemies = []
        self.canvas.bind("<Button-1>", self.player.shoot)

    def start(self):
        self.player.draw()
        self.spawn_enemy()
        self.update()

    def spawn_enemy(self):
        enemy = Enemy(self.canvas)
        self.enemies.append(enemy)
        enemy.draw()
        self.canvas.after(2000, self.spawn_enemy)

    def update(self):
        self.player.update()

        enemies_to_remove = []
        bullets_to_remove = []

        for enemy in self.enemies:
            enemy.update()
            if self.player.collides_with(enemy):
                self.game_over()
                return
            for bullet in self.player.bullets:
                if bullet.collides_with(enemy):
                    enemies_to_remove.append(enemy)
                    bullets_to_remove.append(bullet)

        for enemy in enemies_to_remove:
            self.enemies.remove(enemy)
            enemy.destroy()

        for bullet in bullets_to_remove:
            self.player.bullets.remove(bullet)
            bullet.destroy()

        self.canvas.after(10, self.update)

    def game_over(self):
        self.canvas.delete(tk.ALL)
        self.canvas.create_text(400, 300, text="Game Over", font=("Arial", 36), fill="white")
'''
This file contains the Player class which represents the player character.
'''
import tkinter as tk
from bullet import Bullet
class Player:
    def __init__(self, canvas):
        self.canvas = canvas
        self.image = tk.PhotoImage(file="player.png")
        self.id = self.canvas.create_image(400, 500, image=self.image)
        self.speed = 5
        self.bullets = []

    def draw(self):
        self.canvas.itemconfig(self.id, state=tk.NORMAL)

    def item_exists(self, item_id):
        return self.canvas.type(item_id) != ""

    def update(self):
        if self.item_exists(self.id):
            self.canvas.move(self.id, self.speed, 0)
            if self.canvas.coords(self.id)[0] < 0 or self.canvas.coords(self.id)[2] > 800:
                self.speed *= -1

    def shoot(self, event):
        x = self.canvas.coords(self.id)[0] + 25
        y = self.canvas.coords(self.id)[1]
        bullet = Bullet(self.canvas, x, y)
        bullet.draw()
        self.bullets.append(bullet)

    def collides_with(self, other):
        if self.item_exists(self.id) and self.item_exists(other.id):
            player_coords = self.canvas.bbox(self.id)
            other_coords = self.canvas.bbox(other.id)
            return (player_coords[0] < other_coords[2] and player_coords[2] > other_coords[0] and
                    player_coords[1] < other_coords[3] and player_coords[3] > other_coords[1])
        return False
'''
This file contains the Bullet class which represents the bullets fired by the player.
'''
import tkinter as tk
class Bullet:
    def __init__(self, canvas, x, y):
        self.canvas = canvas
        self.id = self.canvas.create_oval(x, y, x + 10, y + 10, fill="white")
        self.speed = 10
    def draw(self):
        self.canvas.move(self.id, 0, -self.speed)
    def is_offscreen(self):
        return self.canvas.coords(self.id)[1] < 0
    def collides_with(self, other):
        bullet_coords = self.canvas.bbox(self.id)
        other_coords = self.canvas.bbox(other.id)
        return bullet_coords[0] < other_coords[2] and bullet_coords[2] > other_coords[0] and \
               bullet_coords[1] < other_coords[3] and bullet_coords[3] > other_coords[1]
'''
This file contains the Enemy class which represents the enemy character.
'''
import tkinter as tk
import random
class Enemy:
    def __init__(self, canvas):
        self.canvas = canvas
        self.image = tk.PhotoImage(file="enemy.png")
        self.id = self.canvas.create_image(random.randint(50, 750), 50, image=self.image)
        self.speed = random.randint(1, 3)
    def draw(self):
        self.canvas.itemconfig(self.id, state=tk.NORMAL)
    def update(self):
        self.canvas.move(self.id, 0, self.speed)
    def is_offscreen(self):
        return self.canvas.coords(self.id)[3] > 600
    def destroy(self):
        self.canvas.delete(self.id)

それでは実行してみましょう。

python main.py

結果は、

IndexError: list index out of range

このようなエラーになり実行できませんでした

恐らくリストにないインデックスを指定しているのが原因のようです。

このように、少し複雑な開発を行わせると、正常に動かないプログラムが出力されることがあるようで、コミュニティでもちらほら報告されていました。

ChatDevは、まだまだ開発段階という印象を受けますね。

今回紹介したChatDevのように、テキストからコードが生成できるStable Codeというものがあります。詳細は以下の記事をご覧ください。
【やってみた】StableCode、Stability AIの自動コード生成を実践解説

ChatDevを使ってソフトウェア開発をしよう!

ChatDevは、最高経営責任者やプログラマーなど、さまざまな役割を持つ複数の知的エージェントを通じて動作する仮想ソフトウェア会社として開発されたフレームワークです。

ウォーターフォール開発に基づいて、開発を4つのフェーズに分割して、さらにそこから細かくサブタスクとして分割し、それぞれを2人のエージェントが綿密なコミュニケーションを取りながら開発することで、品質の高いアウトプットをしてくれます。

実際に使ってみた結果は、少し複雑なソフトウェアを開発させると、動かないプログラムが出力されたので、まだまだ開発段階という印象でした。

ただ、ユーザーが独自でカスタマイズすることもできるので、さらに大規模で高度なソフトウェアの開発も行える可能性を秘めています。

最後に

いかがだったでしょうか?

弊社では

・マーケティングやエンジニアリングなどの専門知識を学習させたAI社員の開発
・要件定義・業務フロー作成を80%自動化できる自律型AIエージェントの開発
・生成AIとRPAを組み合わせた業務自動化ツールの開発
・社内人事業務を99%自動化できるAIツールの開発
ハルシネーション対策AIツールの開発
自社専用のAIチャットボットの開発

などの開発実績がございます。

まずは、「無料相談」にてご相談を承っておりますので、ご興味がある方はぜひご連絡ください。

➡︎生成AIを使った業務効率化、生成AIツールの開発について相談をしてみる。

生成AIを社内で活用していきたい方へ
無料相談

「生成AIを社内で活用したい」「生成AIの事業をやっていきたい」という方に向けて、生成AI社内セミナー・勉強会をさせていただいております。

セミナー内容や料金については、ご相談ください。

また、サービス紹介資料もご用意しておりますので、併せてご確認ください。

投稿者

  • Hiromi Sai

    ChatGPTメディア運営 / テクニカルライター リベラルアーツ専攻。大学休学中は、Webマーケティング会社のマネージャーとしてライター、ディレクター100名のマネジメントをする。南米のチリとタイでの長期居住歴を持つ。

  • URLをコピーしました!
  • URLをコピーしました!
目次