IBM BobとのAIペアプログラミング

BobをAIペアプログラミングアシスタントとして使い、FastAPI To-Do APIを構築する — 要件からプラン、生成コード、テスト、ドキュメントまで。

AIペアプログラミングでは、計画・コーディング・テスト・ドキュメント作成といったすべての段階でサポートするアシスタントと共にソフトウェアを構築します。単なる行補完ツールとは異なります。このチュートリアルでは、IBM Bobと共に一連の要件からFastAPI To-Do APIを構築します。

要件から始め、レビュー済みのプラン、生成されたコード、実装の説明、コード品質の改善、ユニットテスト、技術ドキュメントへと順に進めます。データストアはインメモリのPythonリストなので、データベースのセットアップは不要です。

このチュートリアルを終えると、動作するコンテナ化されたTo-Do APIが完成し、各段階(プラン、生成、説明、リファクタリング、テスト、ドキュメント作成)でペアプログラミングのレビューループを実践できます。

このチュートリアルは、Pythonの基本とRESTの概念を理解しており、AIアシスタントと共にソフトウェアを構築するための反復可能なレビューループを習得したい開発者を対象としています。FastAPIの経験は不要です。

このチュートリアルでは、新しいプロジェクトでのビルドループをエンドツーエンドで網羅します。既存のコードベースで大規模な機能の計画と実装をより深く学ぶには、複雑な機能の計画と実装 を参照してください。

前提条件

このチュートリアルを完了するには、以下が必要です:

  • Bob IDE がインストールおよび設定済みであること。
  • コメントからコードを生成するリテラルコーディングの使用 に慣れていること。
  • この複数ステップのワークフロー全体でBobのコンテキストを管理できるよう、新しいコンテキストウィンドウの作成 を完了していること。
  • Docker がワークステーションにインストールおよび起動済みであること。BobがDockerfileを生成するため、Pythonやその依存関係をローカルにインストールせずにコンテナでAPIをビルド・実行できます。
  • Pythonの基本的な知識。
  • REST APIの基本的な理解。FastAPIの事前経験は不要です。BobがFastAPIのコードを生成し、ワークフローの一部としてリクエストに応じて説明します。

BobとのAIペアプログラミングを理解する

以降の各段階では、計画、生成、説明、リファクタリング、テスト、ドキュメント作成をカバーします。すべての段階において、BobはBobが変更を適用する前に、あなたが承認・拒否・修正する提案を行います。

ペアプログラミングのワークフロー

このチュートリアルでは次のワークフローを使用します:

Requirements

Bob creates a plan

You review and refine the plan

Bob generates code

You review the output

Run and validate

Bob explains the implementation

Bob suggests code-quality improvements

Generate tests

Generate documentation

ワークスペースをセットアップする

Bobを起動し、空のプロジェクトフォルダを開き、ファイルを変更する前に承認を求めるようBobを設定します。

IBM Bobを起動する

IBM Bob IDEを起動します。

Bobチャットインターフェースを開く

Bobチャットインターフェースが表示されていない場合は、ナビゲーションバー横のBobアイコンを選択して開きます。Macでは Option + Command + B、WindowsとLinuxでは Ctrl + Alt + B を押すこともできます。

IBM Bob IDEで開いたBobチャットパネル

空のプロジェクトフォルダを開く

todo-api という名前の空のフォルダを作成し、File > Open Folder でBobで開きます。Bobがフォルダ内のファイルの作成者を信頼するかどうか確認してきたら、Yes, I trust the authors を選択します。

Bobは生成したアプリケーションをこのフォルダに書き込みます。このチュートリアルでは既存のリポジトリは不要です。

自動承認を無効にする

Permissions を開き、自動承認がオフになっていることを確認します。自動承認をオフにすると、Bobがファイルの読み取り、編集、コマンドの実行を行う前に許可を求めます。このチュートリアルのすべての変更をあなたがコントロールできます。

要件とプランを定義する

To-Do APIの要件をBobに伝え、Bobがコードを書く前にBobが提案するプランをレビューします。

Planモードに切り替える

Bobサイドバーの下部にあるモードドロップダウンを開き、Plan を選択します。

IBM BobのモードドロップダウンでPlanモードが選択されている

Modes は最小権限の原則を適用します。Planモードでは、BobはあなたのコードをAして Markdownのプランを作成します。Bobはコマンドを実行したり実装上の変更を加えたりしません。Bobがアプリケーションコードを書く前にアプローチをレビューできます。

アプリケーション要件を定義する

Bobチャットインターフェースに次のプロンプトを入力します:

Create a simple FastAPI To-Do API.

Requirements:

- Store tasks in a Python list.
- Each task should contain:
    - id
    - task_name

Implement these endpoints with explicit HTTP status codes:

- GET /tasks: list all tasks. Return 200.
- POST /tasks: create a task from a JSON body containing only task_name. Return 201 with the created task.
- DELETE /tasks/{task_id}: delete a task. Return 204 on success and 404 if no task has that id.

Use FastAPI and Pydantic. Use Pydantic model validation so an invalid request body returns 422.

Include a requirements.txt and a Dockerfile. The Dockerfile must start Uvicorn bound to 0.0.0.0 on port 8000 so the API is reachable through a published container port.

Save the plan as Markdown files in a folder named `plans`.

Put the FastAPI application in a single file named `main.py` at the project root.

Keep the implementation simple.

Don't install any dependencies locally or run local tests. Everything will run in a Docker container.

プランを構築するために、Bobはプランニングスキルを実行します。プロンプトが表示されたら、Approve skill tools for taskApprove subagent tools for task を選択して、Bobがワークスペースを調査しプランを作成できるようにします。

プランを洗練する

Bobがコードを書く前にプランを変更できます。Bobチャットインターフェースにフォローアッププロンプトを入力します:

Update the plan to reject a task whose task_name is empty or longer than 200 characters.

Bobが追加の入力バリデーションを含むようにプランを修正します。更新されたプランをレビューします。

プランをレビューする

Bobは順序付けられたプランを提示し、プロジェクト内のMarkdownファイルとして保存する場合があります。続ける前にレビューしてください:

  • スコープ: プランは追加したバリデーションルールを含むすべてのエンドポイントをカバーしており、依頼していないものは含まれていません。
  • 名前付きファイル: 各ステップが作成または変更するファイルの名前が示されています。
  • 曖昧な表現: 「エラーを適切に処理する」などのフレーズは前提を隠しています。Bobに具体的にするよう依頼してください。

これらの設計上の決定はあなたが責任を持ちます。アプリケーションを生成してレビューする でAgentモードに切り替えるまで、Bobは何も実装しません。

アプリケーションを生成してレビューする

新しいコンテキストウィンドウを開始し、Agentモードに切り替えて、Bobに承認済みのプランを実装させます。

新しいコンテキストウィンドウを開始する

チャットボックスの New task またはチャットパネル上部の + を選択して、新しいコンテキストウィンドウを開始します。背景については 新しいコンテキストウィンドウの作成 を参照してください。Bobはプランを plans フォルダに保存したので、計画中の会話をコンテキストに残す必要はありません。クリーンなコンテキストにより、実装が承認済みのプランに集中します。

Agentモードに切り替えてプランを実行する

Bobサイドバーの下部にあるモードドロップダウンを開き、Agent を選択します。次に、プランを実装するようBobに伝えます:

Implement the plan in the plans folder.
@plans/

Agentモードでは、Bobがファイルの書き込みとコマンドの実行ができます。自動承認を無効にしているため、Bobは各変更の前に承認を求めます。Bobがプランを進める際にステップを承認します。

生成されたアプリケーションをレビューする

実装が完了したら、生成されたコードをレビューします。Bobの出力は確率的であるため、コードのスタイルや内部の名前がここに示した例と異なる場合があります。アプリケーションは次の部分で構成されています。

データモデル。 Bobは2つのPydanticモデルを生成します。1つはタスク作成時のリクエストボディ用、もう1つは保存されたタスク用です。createモデルは計画中に追加した長さのルールを適用します:

class TaskCreate(BaseModel):
    task_name: Annotated[str, Field(min_length=1, max_length=200)]


class Task(BaseModel):
    id: int
    task_name: str

エンドポイントのパスとステータスコードはBobに渡した要件と一致しますが、モデルクラス名とファイルレイアウトは異なる場合があります。このチュートリアルでは TaskTaskCreate モデルを想定しています。Bobが異なる名前を選んだ場合は、以降のプロンプトを調整してください。

インメモリデータストア。 Bobはタスクを空のPythonリストに格納し、各新しいタスクに増分する id を割り当てます:

tasks: list[dict] = []
id_counter = 0

API操作。 アプリケーションは次のエンドポイントを提供します:

  • GET /tasks
  • POST /tasks
  • DELETE /tasks/{task_id}

POST /tasks はリクエストボディに task_name のみを受け取り、作成されたタスクと共に 201 を返します。DELETE /tasks/{task_id} は成功時に 204、その task_id のタスクがない場合に 404 を返します。

依存関係。 Bobは FastAPI、Uvicorn、Pydantic を記載した requirements.txt ファイルを生成します。

コンテナ。 Bobは依存関係をインストールし、UvicornでAPIをポート 8000 で実行するDockerfileを生成します。

HTTPコントラクトはメソッド、パス、ステータスコードを含む要件プロンプトに従います。以下の検証ステップはそのまま適用されます。

リテラルコーディングでエンドポイントを追加する

リテラルコーディングモードを使用して、チャットウィンドウに切り替えることなく、エディタ内の自然言語の指示から直接更新エンドポイントを追加します。

リテラルコーディングモード は、エディタ内に直接書かれた自然言語の指示からコードを生成します。

アプリケーションファイルを開く

Bobが生成した main.py ファイルを開き、ファイルの末尾、最後のルートハンドラの後の空の行にカーソルを置きます。

リテラルコーディングモードを有効にする

Macでは Command + I、WindowsとLinuxでは Ctrl + I を押します。エディタツールバーのマジックワンドアイコンを選択することもできます。

指示を書く

空の行に次の指示を入力します。残りのコードとは異なる色でハイライト表示されます。

Add a PUT /tasks/{task_id} endpoint that updates the task_name of an existing task, matching the style and conventions of the existing routes. Return 200 with the updated task, or 404 if no task has that id.

Bobは周囲のコードからパラメータ名、リクエストモデル、エラー処理を推論するため、メソッドとパスのみを指定するだけで済みます。

コードを生成して承認する

Generate を選択するか、Macでは Command + Enter、WindowsとLinuxでは Ctrl + Enter を押します。Bobが指示を実装に置き換え、インラインdiffを表示します。

diffをレビューし、Accept All を選択して変更を適用します。Macでは Command + I、WindowsとLinuxでは Ctrl + I を再度押してリテラルコーディングモードを終了します。

説明、実行、検証

Bobに実装を説明させ、アプリケーションを実行してその動作を検証します。

Bobにコードを説明させる

New task で新しいコンテキストウィンドウを開始し、モードドロップダウンから Ask を選択します。Askモードはファイルを編集せずに質問への回答とコードの分析を行います。変更を加えずに説明が欲しいときに使用します。

生成されたコードを理解することは、AIペアプログラミングの重要な部分です。Bobに聞きます:

Explain the generated To-Do API.

Bobはアプリケーションのアーキテクチャ、データフロー、FastAPIコンポーネント、Pydanticモデル、エンドポイントの動作、設計上の決定を説明できます。説明を使って、変更や拡張を行う前にコードが期待どおりに動作することを確認します。

アプリケーションを実行する

Bobがコマンドを実行できるように Agent モードに戻ります。コンテナでAPIをビルドして実行するようBobに依頼します:

Build the Docker image and run the container with port 8000 mapped to the host. Confirm the API is reachable.

Bobがビルドと起動コマンドを実行し、コンテナが起動したことを報告します。

ブラウザで http://localhost:8000/docs を開きます。

FastAPIは /docs でインタラクティブなSwagger UIを提供します。各エンドポイントの調査、リクエストとレスポンスのスキーマの確認、ブラウザからのAPI呼び出しの実行に使用します。

APIを検証する

/docs のSwagger UIを使用して各操作を試します。すべてのエンドポイントで:

  1. 行を展開し、Try it out を選択します。
  2. パスパラメータまたはリクエストボディを入力します。
  3. Execute を選択します。
  4. Server response のコードとボディを確認します。

タスクを追加する

  1. POST /tasks を展開し、Try it out を選択します。

  2. リクエストボディを次のように置き換えます:

    {
      "task_name": "My first API item!"
    }
  3. Execute を選択します。レスポンスコードが 201 で、レスポンスボディに割り当てられた id を持つ作成済みタスクが表示されていることを確認します。

タスクを取得する

  1. GET /tasks を展開し、Try it out を選択します。
  2. Execute を選択します。レスポンスコードが 200 で、レスポンスボディに追加時に割り当てられた id を持つタスク My first API item! がリストされていることを確認します。

タスクを更新する

  1. PUT /tasks/{task_id} を展開し、Try it out を選択します。

  2. 作成したタスクの task_id を入力します。

  3. リクエストボディを次のように置き換えます:

    {
      "task_name": "Build and ship a To-Do API"
    }
  4. Execute を選択します。レスポンスコードが 200 で、返されたタスクに更新された task_name が表示されていることを確認します。

  5. task_id を存在しない値に変更して再度 Execute を選択します。レスポンスコードが 404 であることを確認します。

タスクを削除する

  1. DELETE /tasks/{task_id} を展開し、Try it out を選択します。
  2. 作成したタスクの task_id を入力して Execute を選択します。レスポンスコードが 204 であることを確認します。
  3. GET /tasks を展開し、Execute を選択して、レスポンスにタスクが表示されなくなっていることを確認します。
  4. 再び DELETE /tasks/{task_id} を展開し、同じ task_id を入力して Execute を選択します。レスポンスコードが 404 であることを確認します。

実装は、リテラルコーディングで追加した更新エンドポイントを含め、元の要件を満たしています。

コード品質を改善する

Bobに生成されたコードの品質の問題をレビューさせ、同意できる変更を適用します。このステップでは、Bobを単なるコード生成器ではなくレビュアーとして使用します。

Bobに改善提案を求める

New task で新しいコンテキストウィンドウを開始し、次のように入力します:

Review the To-Do API and suggest improvements to code quality, error handling, and HTTP status codes.

Bobは、単一タスクを取得するエンドポイントの欠如、バリデート済みの Task モデルの代わりにプレーンな辞書を保持するインメモリストア、リセットやテストが難しいモジュールレベルの id_counter などのギャップを特定します。

改善を適用する

保持したい提案をBobに実装させます:

Add a GET /tasks/{task_id} endpoint that returns 404 when the task ID does not exist, and store tasks as Task models instead of dictionaries.

提案された変更をレビューして承認し適用します。Bobにイメージを再ビルドしてコンテナを再起動させ、検証ステップを繰り返します。有効なIDのタスクに対して GET /tasks/{task_id}200 を返し、不明なIDに対して 404 を返すこと、および既存のエンドポイントが以前と同様に動作することを確認します。

テストとドキュメントを生成する

BobにAPIのテストスイートと技術ドキュメントを生成させます。

ユニットテストを生成する

New task で新しいコンテキストウィンドウを開始し、Bobに聞きます:

Generate pytest unit tests for this application. Add pytest and httpx to a dev requirements file, build a test image, and run the suite in a container.

Bobは pytesthttpx のテスト依存関係を追加し、それらを含むイメージをビルドし、コンテナでスイートを実行して結果を報告します。コンテナでテストを実行することで、ローカルのPython環境が不要になります。生成されたテストをレビューして洗練させます。

生成されたテストのレビューと保守はあなたの責任です。

技術ドキュメントを生成する

Bobに聞きます:

Generate technical documentation for this To-Do API.

Bobはアプリケーションの概要、アーキテクチャの説明、エンドポイントのサマリー、リクエストとレスポンスの例、使用方法の説明を生成できます。このドキュメントはFastAPIが自動生成するAPIドキュメントを補完します。

トラブルシューティング

よくある問題の解決策を以下に示します:

  • Cannot connect to the Docker daemon: イメージをビルドする前にDocker DesktopまたはDockerサービスを起動します。
  • コンテナは起動したが http://localhost:8000/docs が読み込まれない: DockerfileがコンテナA内で 127.0.0.1 にAPIをバインドしており、公開ポートからは到達できません。Dockerfileが --host 0.0.0.0 でUvicornを起動していることを確認し、イメージを再ビルドします。
  • Bind for 0.0.0.0:8000 failed: port is already allocated: ポート 8000 を使用しているプロセスを停止するか、docker run -d --name todo-api -p 8080:8000 todo-api で別のホストポートにマップして http://localhost:8080/docs を開きます。
  • The container name "/todo-api" is already in use: docker rm -f todo-api を実行し、コンテナを再起動します。
  • pytest is missing when the tests run: アプリケーションイメージにはテスト依存関係が含まれていません。Bobに pytesthttpx をdevのrequirementsファイルに追加し、別のテストイメージをビルドするよう依頼します。

クリーンアップ

コンテナを停止して削除し、ポート 8000 を解放します:

Stop and remove the To-Do API and test container and image.

APIはタスクをメモリ内にのみ保持するため、コンテナを削除するとすべてのデータが破棄されます。その他のクリーンアップは不要です。

次のステップ

このチュートリアルでは、各段階でBobとペアを組み、変更を適用する前にレビューしながら、コンテナ化されたFastAPI To-Do APIを構築・検証しました。

FAQ

FastAPIの知識は必要ですか? 不要です。BobがFastAPIとPydanticのコードを生成し、リクエストに応じて説明します。Pythonの基本とRESTの基礎知識があれば十分です。

なぜ段階ごとにモードを切り替えるのですか? モードは最小権限の原則を適用します。Planモードはコードを読んでプランを書くだけで何も実行しません。Agentモードはファイルの編集とコマンドの実行ができます。Askモードはファイルを変更せずに質問に答えます。切り替えることで、Bobの能力を目の前のタスクに合わせて管理できます。

Bobがファイル名やモデル名を異なる名前にした場合はどうすればよいですか? HTTPコントラクトは要件プロンプトによってパスとステータスコードが固定されているため、そのまま適用されます。クラス名とファイルレイアウトは異なる場合があります。このチュートリアルでは TaskTaskCreate モデルを想定しています。Bobが別の名前を選んだ場合は、以降のプロンプトを調整してください。

なぜ各段階で新しいコンテキストウィンドウを開始するのですか? Bobはプランを plans フォルダに保存するため、それ以前の会話はコンテキストに不要になります。クリーンなコンテキストにより各段階に集中でき、トークンコストを抑えられます。

Dockerなしでこのチュートリアルを実施できますか? 技術的にはDockerなしでも実施できますが、Bobへのプランとプロンプトを編集する必要があります。

Planモードはファイルを変更しますか? しません。Planモードでは、Bobはコードを読んでMarkdownのプランを作成するだけです。Agentモードに切り替えるまでアプリケーションコードは変更されません。

このトピックはいかがですか?