ChatDevを使用して、仮想ソフトウェア会社にソフトウェア開発を外注する

## 概要

ChatDevを使用して、Pythonの計算機アプリを生成してみたので紹介します。

## ChatDev

https://arxiv.org/abs/2307.07924

ChatDevは、ソフトウェアを開発する過程にLLMを取り入れたシステムです。ソフトウェアを開発する過程を4つのステップ(設計、コーディング、テスト、ドキュメント作成)に分けて、それぞれの工程でチャットのようにコミュニケーションを取りながら進めていく仕組みです。

https://github.com/OpenBMB/ChatDev

GitHubによると、ChatDevは、CEO、CTO、プログラマ、テスターなどが在籍する仮想のソフトウェア会社であり、「プログラミングを通してデジタル世界に革命を起こす」ことを理念としています。
仮想のソフトウェア会社ってなんだ？と思いますが、簡単にいうとChatGPTなどのLLMを使用して、ソフトウェアを生成してくれるツールです。

## 外注してみる

### 環境構築

以下の環境で確認しました。
* Windows
* Python 3.9.15
  + 公式によるとPython3.9以上が必要です

以下のコマンドで構築します。

```shell
$ git clone https://github.com/OpenBMB/ChatDev.git
$ cd ChatDev
$ pip install -r requrements.txt
Linux
$ export OPENAI_API_KEY="your_OpenAI_API_key"
Windows
$env:OPENAI_API_KEY="your_OpenAI_API_key"
```

### 計算機アプリを開発してもらう

ソフトウェアを生成してもらうには以下のコマンドを使用します。

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

`--task`に生成してもらいたいソフトウェアの説明、`--name`にプロジェクト名を指定します。
`--model`で`GPT_3_5_TURBO`や`GPT_4`を指定することもできます。
今回は「シンプルな計算機GUIアプリ」を開発してもらいます。

```shell
$ python run.py --task "Create a simple calculator GUI application." --name "calc"
```

実行するとザーっとログが流れ始め、しばらく待ちます。今回は500秒ほどかかりました。
成果物は`WareHouse`ディレクトリに作成されており、`--name`で指定した名前がついています。
中身は以下のようになっていて、コード、マニュアル、生成時のログなどが置かれています。

```
calc.prompt
calc_DefaultOrganization_20230901134458.log
calculator.py
ChatChainConfig.json
main.py
manual.md
meta.txt
PhaseConfig.json
requirements.txt
RoleConfig.json
```

マニュアルにしたがって、依存ライブラリをインストールして実行してみます。

```shell
$ cd WareHouse\todo__DefaultOrganization_20230901134458
$ pip install -r requirements.txt
ERROR: Could not find a version that satisfies the requirement tkinter==8.6 (from versions: none)
ERROR: No matching distribution found for tkinter==8.6
```

が、tkinterのインストールに失敗しました。requirements.txtには書かれていますが、tkinterは標準ライブラリに含まれているためここはスキップします。

```shell
$ python main.py
```

![GUI](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248216/a39f6215-aa17-e7d3-9b3a-81f9e14d7ddd.png)

まさにtkinterで作られたような画面が出ました。
ボタンを押して計算してみましたが、ちゃんと計算できています。
ただし、クリアボタンが無いため、テキストボックスの部分をバックスペースで消す必要があります。
いじわるして0除算をしてみところ、

![エラー](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248216/e2962691-53c2-8a6f-1c29-79f18239e0ea.png)

クラシュせずにエラーメッセージが表示されました。エラー処理もできているようです。

### 納品されたコード

コードを見てみましょう。`main.py`と`calculator.py`の2つが生成されています。

```python:main.py
'''
This is the main file of the calculator application.
'''
import tkinter as tk
from calculator import Calculator
def main():
    root = tk.Tk()
    calculator = Calculator(root)
    root.mainloop()
if __name__ == "__main__":
    main()
```

 ```python:calculator.py
 '''
This file contains the Calculator class which represents the GUI calculator.
'''
import tkinter as tk
class Calculator:
    def __init__(self, root):
        self.root = root
        self.root.title("Calculator")
        self.entry = tk.Entry(self.root, width=30)
        self.entry.grid(row=0, column=0, columnspan=4, padx=10, pady=10)
        self.create_buttons()
    def create_buttons(self):
        buttons = [
            '7', '8', '9', '/',
            '4', '5', '6', '*',
            '1', '2', '3', '-',
            '0', '.', '=', '+'
        ]
        row = 1
        col = 0
        for button in buttons:
            tk.Button(self.root, text=button, width=5, command=lambda button=button: self.button_click(button)).grid(row=row, column=col, padx=5, pady=5)
            col += 1
            if col > 3:
                col = 0
                row += 1
    def button_click(self, button):
        current = self.entry.get()
        if button == '=':
            try:
                result = eval(current)
                self.entry.delete(0, tk.END)
                self.entry.insert(tk.END, str(result))
            except ZeroDivisionError:
                self.entry.delete(0, tk.END)
                self.entry.insert(tk.END, "Error: Division by zero")
            except Exception:
                self.entry.delete(0, tk.END)
                self.entry.insert(tk.END, "Error")
        else:
            self.entry.insert(tk.END, button)
```

「シンプルな計算機GUIアプリを作って」とお願いしたとおりなのか、かなりシンプルなコードですね。ボタンをグリッド表示して、計算式は文字列をそのまま`eval`で評価しているようです。(任意コードを実行できてしまいますね...)
`manual.md`には使い方と仕様が記載されてました。ドキュメントも整備されていて、しっかり開発してくれています。

### 開発の様子

生成中はログが高速で流れますが、このときにソフトウェアを開発するための議論が行われています。
その様子をWebアプリ上で再生することができます。再生するためには、ChatDevのルートディレクトリで以下を実行します。

```shell
$ python online_log/app.py
please visit http://127.0.0.1:8000/ for demo
 * Serving Flask app 'app'
 * Debug mode: on
please visit http://127.0.0.1:8000/ for demo
```

Flaskでサーバが立ち上がるので、ブラウザでアクセスし、`Chat Replay`ボタンをクリックします。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248216/945c72ad-413b-d0d4-e2cd-d26bef513c6d.png)

左下の`File Upload`ボタンをクリックし、先ほど生成されたログファイル(`calc_DefaultOrganization_20230901134458.log`)を指定後、`Replay`ボタンをクリックするとログが再生されます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248216/3954c934-d4aa-7a9c-17ab-f1e677cb03cc.png)

おおまかには、CEO、CPO、CTOが仕様を決めた後、プログラマーとレビュアーでコードをブラッシュアップする、という流れでした。
これを見ると本当に会社として動いている感じがします。

## カスタマイズ

ChatDevのアーキテクチャは以下のようになっており、生成された`ChatChainConfig.json`、`PhaseConfig.json`、`RoleConfig.json`を変更することで、ChatDevソフトウェア会社をカスタマイズすることができるようです。

![image-lm05bw9j.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248216/2f925a0e-9057-6d47-3680-a1db4010d519.png)

詳細は[Wiki](https://github.com/OpenBMB/ChatDev/blob/main/wiki.md)に記載されていますが、公開されているサンプルのコンフィグを参考にするのがよいかもしれません。

## まとめ

ChatDevを使用して、仮想ソフトウェア会社(実態はChatGPT)に計算機アプリを開発してもらいました。
付属のWebアプリ上で開発の履歴を見ることができました。
カスタマイズの方法を理解して、もう少し複雑なものを作らせてみたいと思います。

## 参考

* https://note.com/sumeragi_0258/n/ncf0c1bd92375