AIエージェントとの作業には鋼の神経が必要
You'll need nerves of steel to work with AI agents (orchidfiles.com)
要約
AIエージェント、特にComposer 2.5 in Cursorは、その速度と低コストの反面、コードの削除、意図しない変更、テストの不備、応答スタイルの問題など、多くの不安定さやバグを抱えています。これらの問題は、AIモデルの進化に伴って変化する可能性があり、ユーザーはこれらのAIツールを効果的に使用するために、忍耐と注意深さが求められます。
全文翻訳
AIエージェントとの作業には鋼の神経が必要
この記事は主にCursorのComposer 2.5に焦点を当てます。これらの問題はopus-5.5やgpt-6.1-sol-pro-max-ultra-thinking-fastには存在しないかもしれませんが、例えばgpt-6.1-lunaにはここにリストされている問題がすべて存在します。私も以前、gpt-5.5やopus-4.6でこれらの問題の多くに遭遇しました。最近リリースされた新しいAIモデルにこれらの問題が存在するかどうかはわかりません。
Composer 2.5で気に入っている点:使用制限と速度。
比較のために、GPTとCursorのそれぞれ20ドルのサブスクリプションを考えてみましょう。gpt-6.1-solでは、5時間の制限が数回の要求で使い果たされます。readmeファイルに数行の変更を依頼すると、制限の10%が消費されます。大規模なコードベースの変更を依頼すると、コードを一行も書かずに、数十ファイルを読み込むだけで制限全体が使い果たされます。
しかし、GPTは使用制限が5倍になる100ドルのプランも提供しています。それは私にどれくらい持つのだろうか?私は複雑なモノレポプロジェクトを扱っています。あるサービスに変更を加えるには、エージェントは他のサービスやいくつかのスキルで数十ファイルを読み込む必要があります。20ドルのプランが20ファイルを読み込んだ後に使い果たされるなら、100ドルのプランは100ファイルを読み込んだ後に使い果たされるのだろうか?
だから私はSolを使わず、Lunaを使っています。しかし、それは非常に遅いです。Composer 2.5と比較すると、数十倍遅いです。
だから私はGPT Lunaを使わず、Composer 2.5を使っています。非常に高速で非常に安価です。そして、その速度と節約の代償として、私は時間を無駄にし、ストレスを感じることになります。Deepseekやその他のオープンモデルでもこれらの問題のいくつかに遭遇しました。一部のモデルには特定の問題がありますが、他の問題はありません。同じモデルを使用しても、月の満ち欠けによって問題の数と頻度は異なります。
以下は、CursorでComposerを100時間以上使用して遭遇した問題のリストです。
削除
エージェントはコードを書き、数十ファイルを変更します。コードのレビューを始めると、次のような会話になります。
— なぜこの関数はここにあるのですか?
— その通りです。この関数はここには必要ありません。(関数を削除し、多くのファイルを変更します)
— なぜ削除したのですか?
— その通りです。あの関数を削除すべきではありませんでした。元に戻します。(再び多くのファイルを変更します)
そして、なぜその関数が必要だったのかという質問には、結局答えを得られませんでした。
今では、何かを尋ねるたびに、エージェントモードをオフにするか、何も削除しないように明示的に指示する必要があります。しかし、それを忘れると、単純な質問に答える形でコードの一部を削除し始めます。
時にはコードのレビューに多くの時間を費やし、一つの関数だけを変更するように依頼します。それはすでにレビューされたすべてのファイルを変更します。そして、これらの変更はその関数とは関係ありません。
このチャットで行われたすべての作業を削除することさえあります。そして、このチャットだけでなく。コミットするように依頼すると、他のファイルへの変更が混ざっているのを見つけます。そして、それを削除します。たとえそれが他のチャットで行われた作業であっても。
また、コードのリファクタリングを依頼した場合、例えば50ファイルでメソッド名を変更するなど、見つけたコメントをすべて削除する可能性があります。それはメソッドのリファクタリングとは全く関係ありません。
それでも、削除するように依頼したものを削除しません。メソッド名を変更する際、古いメソッドをそのままにして、新しい名前の新しいメソッドを追加します。それが彼のリファクタリングプロセス全体です。古いメソッドが呼び出されたすべてのファイルを変更する必要がないためです。古いメソッドを非推奨とマークしてアクセス可能にしておきます。これに気づくと、最終的にリファクタリングを行いますが、テストとドキュメントには古いメソッド名を残します。テストは失敗し、タスクは完了したと述べますが、テストは失敗しています。エージェントの関心事としては、テストの失敗はタスクが未完了である証拠とはみなされません。
また、タスクの作業中に、タスクとは全く関係のない設定ファイルやメソッドから重要なパラメータを削除する可能性があります。なぜパラメータを削除したのか尋ねると、エージェントは何も削除しなかったと主張します。それ自身ではそれを考えないので、git diffをチェックするように明示的に依頼する必要があります。
参考資料のようにしてください
私はすでに、イベントをリッスンし、データベースの値を更新し、Redisに書き込む、動作中のサービスを持っています。エージェントに別のサービスでまったく同じことをするように依頼します。
それは実行しますが、Redisに書き込むのを忘れます。または、データベースの値を更新しません。または、ファイル名とクラス名を完全に異なるものにします。または、インターフェースと型を間違った場所に配置します。その後、すべて完了したと述べます。それをチェックするように依頼します。チェックし、再びすべて完了したと主張します。そして、もちろん、すべてのテストはグリーンであり、それが完了したという結論を確認します。間違いを指摘して修正してもらうために、多くのラウンドをこなす必要があります。一つの間違いを修正している間に、新しい間違いを導入します。
もう一度コードを確認し、すべてが他のサービスと一致していることを確認するように依頼します。多くのファイルを変更し、すべて完了したと述べます。最初のファイルを開くと、すべて間違っていることがわかります。もう一度書き込み、すべて完了したと返信します。次のファイルを開くと、同じ話です。さらに、単一のファイル内の特定の関数を指摘し、それが参照とどのように異なるかを説明することさえできます。一つ修正し、次の関数に進み、それも修正します。参照と一致させることさえできません。
イベントをリッスンするサービスに戻りましょう。メッセージブローカーを操作するための共有可能で再利用可能なメソッドがあります。エージェントはすべて正しく行い、それらのメソッドを複製せずに使用します。しかし、型を追加するのを忘れるので、それを指摘します。そして、インターフェースを追加する代わりに、なぜか共有メソッドから数百行のコードを複製することにします。
テスト
一般的にテストに苦労しています。明確な指示を与えます:まず、テストを追加します。テストを実行します。失敗することを確認します。なぜ失敗したのか教えてください。その後、コードを修正し、すべてのテストがパスするように再度テストを実行します。
AIエージェントが行うこと:すぐにコードを変更します。その後、失敗しないテストを作成し、タスクが完了したと伝えます。その結果、コードが修正される前にテストが失敗したかどうかを確認できません。または、コードが実際に何かを修正したかどうかを確認できません。
これが何度も起こったので、私は別のコマンドを作成しました。そして、エージェントが指示に従い始める前に、それを何度も修正する必要がありました。しかし、それでも完璧には機能しません。惑星の配置に応じて、ランダムな時点で、まずテストを作成せずにコードの編集を開始します。
そして時々、失敗するテストを作成するために、巧妙なトリックを使用します。チャットではすでにJSONデータのパーサーに関する議論があります。新しい、小さな20行のJSON入力を送信し、まず失敗するテストを書くように依頼します。テストにインプットデータとパーサーからの期待される出力を追加します。テストを失敗させるために、期待される出力のランダムなフィールドを変更し、テストが失敗したこととコードを今変更できることを報告します。
プロジェクトには確立されたテスト構造があります。各パーサーメソッドのテストフィクスチャは別々のディレクトリに保存されています。パーサーに新しいメソッドを追加する必要がある場合は、フィクスチャの新しいディレクトリを追加し、パーサーコードを修正します。テストはすべてのフィクスチャを実行し、何も壊れていないことを確認します。
これらすべてがエージェントのスキルとルールに説明されています。そして、エージェントがテストの作業を開始すると、まずそれらのスキルを読んでいるのがわかります。そしてほとんどの場合、この構造に従います。しかし、ランダムな時点で、それに従うのをやめ、テストコードに直接フィクスチャを追加します。これに気づく必要があり、別のファイルに移動させます。同じチャットで数メッセージ後、同じ間違いを再び犯します。
APIリクエストにパラメータを追加すると、テストを実行したときにスキーマ検証が失敗します。別の巧妙なトリックを使用します。スキーマ検証を無効にするか、スキーマで未知のパラメータをすべて許可します。そして、テストは再びパスします。
別のケースがありました。APIリクエスト経由でデータを追加するためのテストを書くようにエージェントに依頼しました。エージェントはテストをパスさせるために長い時間を費やしました。そこで、テストでAPIルートを呼び出すのを単純にスキップし、代わりにデータベースに直接データを書き込むことにしました。テストはパスし始め、データはデータベースに追加されましたが、APIリクエストは実際には行われませんでした。
応答スタイルの変更ができない
ここ数ヶ月、文の構造に新しいパターンがますます多く見られるようになっています。例を挙げます。
「テキストを読んだ」と「テキストの意味を理解した」の間には違いがあります。
私たちは「これに慣れている」を「これが好き」と間違えすぎます。
「間違いを犯すのが怖い」から「試す準備ができている」までの道のりは何年もかかることがあります。
各文には、同じスタイルパターンに従う2つの引用符付きフレーズが含まれています。このパターンがどこから来たのかはわかりませんが、以前は見たことがありませんでした。今ではAIモデルはこのようにコミュニケーションしており、記事やビデオでこのスタイルに気づいています。おそらくこれは「XではなくY」の改良版でしょうか?ただし、これらは正確には対義語ではありません。
エージェントのルールやスキルを変更しようとしても、彼らはこのテクニックを使い続けます。さらに、Composerはこれらの2つのテクニックの最悪の部分を取り込み、今では次のようなものを書いてきます。
これは「APIが起動しない」ではありません。これは「フロントエンドが接続できない」です。
ほとんどすべての返信で引用符を使用します。引用符は、まったく使用すべきでない場所で使用されます。例えば、ここでは:
サービスに「APIを接続しました」。
サービスは「起動」しますが、「処理」できません。
リクエストを送信する前に「ステータスチェック」を追加しました。
エージェントからこのようなテキストを読むのにうんざりしています。そして、これを指摘すると、次のような会話になります。
— ルールではテキストに引用符を使用することは禁止されています。なぜ再び使用したのですか?
— その通りです、引用符を使用すべきではありませんでした。あなたが私に指摘してくれたので、二度と引用符を使用しません。
— しかし、あなたの記憶はチャット間で引き継がれません。
— あなたは完全に正しいです。私が新しいチャットで常にこのルールに従うことを保証するために、これをリストの最上部に移動する必要があります。
わかりました、ルールを一番上に移動しましょう。次の返信で、同じチャット内で、引用符付きのテキストが再び表示されます。
記事の終わり
これで、CursorでComposer 2.5を使用することになった場合に何が期待できるかがわかりました。
そして、これらの問題を回避するために、この記事を読んでいる時期に関係なく、数日前にリリースされた新しいフロンティアモデルを使用するだけで済みます。