🤖

自律型AIソフトウェアエンジニア『Devin AI』を試してみた:実践レビューとリアルな所感

2025/02/14に公開

はじめに

Rehab for JAPANでCTOを務めている@rkyuragiです!
最近話題のAIエージェントの『Devin AI』。
月額$500という個人で使うには少しハードルが高い価格設定ですが、好奇心には勝てず、思い切って個人で契約し使ってみました。
まだ使い始めて間もないですが、実際に使ってみた感想や、Devin AIについて理解したことを荒く共有し、興味ある方の参考になれば幸いです!

本記事のターゲット

  • Devin AIが気になっているが試すことに踏み切れないエンジニア
  • Devin AIにどのようなタスクを依頼すればいいのかわからないエンジニア
  • どのような効果があるのか知りたいエンジニア

Devin AIとは

Devin AIは、Cognition AI社が開発した自律型AIソフトウェアエンジニアです。SlackやGitHubと連携した上で自然言語での指示に基づき、コードの計画、作成、デバッグ、テスト、さらにはウェブ検索を通じて情報収集を行い、ソフトウェア開発タスクを自律的に遂行します。

使ってみての所感

まだ50ACUsくらい(おおよそ$100分)しか使っていませんが、かなりの開発効率化につながると感じました。月$500分の効果は十分発揮できている。むしろ安いという印象です。
特に、簡単なタスクを依頼する際には、Devin AIを使うことで、自分の手を動かすことなく、タスクを進めることができるので、非常に魅力的です。
大きな作業やタスクはこれからと思いますが、現時点でも段階的にタスクを渡してさえいけば、相当なことができると思いワクワクしてます。
あと、SlackとGitHubで完結するのもいいですね。あとはJiraとの連携があれば嬉しいです。

Devin AIについて理解したこと

使っている中で理解したことを雑にまとめてみました。
(Devin AIのドキュメントを読めばわかるものかと思いますが、習うより慣れよな性分なもので...)
公式ドキュメント

  • Slackのスレッド=Devinのセッション
  • 複雑なタスクを進める前に、承認を必要とするのかの設定がある
  • SlackでDevinくんとやりとりしていく中で、スレッドが深くなっていくと、意図した動きをとってくれなくなることがある
    • 実際にあった現象として、新たに実装した後にすでにマージ済みのPRのリンクをDevinが共有してくるといったものがありました。
  • CIが通るまで自ら対応し続けてくれる時もあれば、途中で投げ出すこともある
    • Knowledgeに追加すると安定してCIが通るまで対応し続けてくれるようになるのかも?
    • タスクを振るときにCIが通るまで対応し続けてという指示を出せばCI通るまで粘り強く対応してくれた
      • これが再現性あるのかは不明。
  • Devin's WorkspaceとRepositoryは1:1の関係
    • Devin's WorkspaceはDevinが作業を行うための仮想開発環境のこと
  • Knowledgeは個別のRepositoryに紐づくこともできるし、全体(all)に影響を与える設定もできる
  • データコントロール設定があるので、Devinとのやりとりを学習に使われないようにすることも可能
    • We never train on your code.と書いてあり、ソースコード自体はデフォルトで学習されない模様(安心)

Q&A

社内でDevin AIについて共有したところ、いくつか質問があったので、それに対する回答を以下に記載します。

Q. 1時間以内に作業完了するレベルなのか。夜依頼して朝確認するレベルなのか
A.ものによるが、PR作成まで5~10分くらい。
シンプルなAPIを1本開発するくらいのタスクを5分くらいでやってくれる感覚。
試してないが、作業時間が長くなるようなタスクは依頼できないと思われる。(おそらく途中でDevinが方針を確認してくるかと)

Q. どの程度、人によるレビューのやりとりが必要なのか
A. 方針を決めるのは人間なので、やりとりは必要。タスクが大きいとDevinから確認がくる。(また、PRマージ対応は人しかできないよう設計されてる?)
そのため、Devinを使うにはPM的なスキルが必要になる。

Q. Devinが早期に立ち上がってバリューを発揮するまでに何が必要か
A. Devinの管理画面でリポジトリを登録する際にセットアップがあるので、それを実行するだけで、細かいタスクはすぐに対応できる。

Q. 継続的にバリューを発揮してもらうために必要なプロセス
A. 一つのスレッドが深くなると、Devinが意図した動きをとってくれなくなることがあるため、タスクごとにスレッドを立てるとよさそう。

Q. 作業を依頼する粒度
定量的には示ないが、実際にソースコード10ファイル程度のBEのリポジトリに対して「足りないテストコードを作成してください。」といったタスクは難なくやってくれた。

alt text
テストコードを作成してもらうタスクを依頼

Devinくんが考えたテストコード作成プラン

## Task description
Create a comprehensive test suite for the xxxxx_api project, covering all existing endpoints, models, schemas, and error cases. The project currently has no tests, so we need to set up the testing infrastructure and create the necessary test files.

## Procedure
1. Add testing dependencies to Pipfile:
```Pipfile:1-15
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
fastapi = "*"
alembic = "*"
sqlalchemy = "*"
sqlalchemy-utils = "*"
uvicorn = "*"
mysqlclient = "*"
pymysql = "*"

[dev-packages]
pytest = "*"
pytest-asyncio = "*"
httpx = "*"
pytest-cov = "*"
  1. Create test configuration file:
import pytest
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.pool import StaticPool

from app.database import Base, get_db
from app.main import app

SQLALCHEMY_DATABASE_URL = "sqlite:///:memory:"

@pytest.fixture
def test_db():
    engine = create_engine(
        SQLALCHEMY_DATABASE_URL,
        connect_args={"check_same_thread": False},
        poolclass=StaticPool,
    )
    TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
    Base.metadata.create_all(bind=engine)
    
    def override_get_db():
        try:
            db = TestingSessionLocal()
            yield db
        finally:
            db.close()
    
    app.dependency_overrides[get_db] = override_get_db
    yield TestingSessionLocal()
    Base.metadata.drop_all(bind=engine)

@pytest.fixture
def client(test_db):
    def get_test_db():
        try:
            yield test_db
        finally:
            pass
    app.dependency_overrides[get_db] = get_test_db
    return TestClient(app)
  1. Create test fixtures file:
TEST_USER = {
    "id": 1,
    "username": "testuser"
}

TEST_USERS = [
    TEST_USER,
    {
        "id": 2,
        "username": "testuser2"
    }
]
  1. Create model tests:
import pytest
from sqlalchemy.exc import IntegrityError

from app.models import User

def test_create_user(test_db):
    user = User(username="testuser")
    test_db.add(user)
    test_db.commit()
    assert user.id is not None
    assert user.username == "testuser"

def test_username_required(test_db):
    with pytest.raises(IntegrityError):
        user = User(username=None)
        test_db.add(user)
        test_db.commit()
  1. Create schema tests:
import pytest
from pydantic import ValidationError

from app.schemas.user import User as UserSchema, UserDetail

def test_user_schema():
    user = UserSchema(id=1, username="testuser")
    assert user.id == 1
    assert user.username == "testuser"

def test_user_detail_schema():
    user = UserDetail(id=1, username="testuser", books=[])
    assert user.id == 1
    assert user.username == "testuser"
    assert user.books == []
  1. Create API endpoint tests:
from fastapi import status

from .fixtures import TEST_USER, TEST_USERS

def test_read_users(client, test_db):
    response = client.get("/users/")
    assert response.status_code == status.HTTP_200_OK
    assert response.json() == []

    # Add test users
    from app.models import User
    for user_data in TEST_USERS:
        user = User(username=user_data["username"])
        test_db.add(user)
    test_db.commit()

    response = client.get("/users/")
    assert response.status_code == status.HTTP_200_OK
    assert len(response.json()) == len(TEST_USERS)

def test_read_user(client, test_db):
    # Test non-existent user
    response = client.get("/users/999")
    assert response.status_code == status.HTTP_404_NOT_FOUND

    # Add test user
    from app.models import User
    user = User(username=TEST_USER["username"])
    test_db.add(user)
    test_db.commit()

    response = client.get(f"/users/{user.id}")
    assert response.status_code == status.HTTP_200_OK
    assert response.json()["username"] == TEST_USER["username"]
  1. Create GitHub Actions workflow for CI:
name: Tests

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Set up Python
      uses: actions/setup-python@v2
      with:
        python-version: '3.12'
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install pipenv
        pipenv install --dev
    - name: Run tests
      run: |
        pipenv run pytest --cov=app tests/
  1. Create PR with changes:
  • Create new branch with timestamp
  • Add all new files
  • Commit with descriptive message
  • Push and create PR
  • Wait for CI to run tests

Details

  • Tests are organized by component type (models, schemas, API)
  • Using SQLite in-memory database for tests to avoid MySQL setup
  • Mocking database session using FastAPI's dependency override
  • Including both happy path and error cases
  • Test fixtures provide consistent test data
  • CI will run tests on PR creation and main branch pushes
  • Coverage report will be generated in CI

Note: As per the repository notes, we won't run tests locally and will rely on CI for verification.


Q. 並行して複数プロジェクトで活用できるのか
A. できる。複数リポジトリを並行して可能だし、リポジトリを横断してタスクを依頼することも可能。
例えば、APIリポジトリを参照し、フロントのリポジトリのタスクを依頼できた。(逆は試してない)

apiのリポジトリを分析し必要なフロントの画面を提案
APIリポジトリを分析し、必要なフロントの画面をDevinが提案(提案までは2分ほど)

おわりに

まだまだ使いこなせていないですが、今時点でもDevin AIは、開発効率化に非常に役立つツールであると感じました。
個人で試してみても、かなりの効果があると感じたので、これから会社のプロダクトレベルのタスクでも使えるのか検証していきます!

Rehab Tech Blog

Discussion