世界を動かす技術を、日本語で。

エージェントにはプロンプトを増やすのではなく、制御フローが必要です

概要

  • 信頼性の高いエージェント には 決定論的な制御フロー が必要
  • プロンプトチェーン は複雑なタスクでは限界
  • ソフトウェア的な構成 で予測可能性と検証性を確保
  • LLMは部品 として扱い、全体のシステムではない
  • エラー検出と検証 の仕組みが不可欠

複雑なタスクにおける信頼性と制御フロー

  • 複雑なタスク を扱うエージェントには 決定論的な制御フロー の実装が必要
  • プロンプトチェーン (MANDATORYやDO NOT SKIPなど)では 信頼性の限界 に直面
  • プログラミング言語で命令が「提案」にすぎず、関数が「Success」と返しつつ 幻覚応答 する世界の想像
  • 推論の困難化信頼性の崩壊、タスクが複雑になるほど顕著

ソフトウェアのスケーラビリティとプロンプトの限界

  • ソフトウェア再帰的な合成 (ライブラリ・モジュール・関数から構築)によって拡張
  • コード は予測可能な振る舞いを持ち、 局所的な推論 が可能
  • プロンプトチェーン はこの性質がなく、狭い用途では有用だが
    • 非決定論的
    • 仕様が曖昧
    • 検証が困難

信頼性向上のためのアプローチ

  • 信頼性向上 には 論理をプロンプトからランタイムへ 移す必要
  • 決定論的な足場 (明示的な状態遷移・バリデーションチェックポイント)の設計
  • LLMはシステムの一部品 として利用し、全体の制御はコードで管理

エラー検出と検証の重要性

  • 決定論的なオーケストレーション だけでは不十分
  • サイレントエラー が発生しやすい環境で、積極的な エラー検出 が不可欠
  • プログラムによる検証 がなければ、選択肢は3つのみ
    • ベビーシッター:人間が逐次監督し、エラーを事前に発見
    • 監査人:実行後にエンドツーエンドで徹底的な検証
    • 祈り:出力をそのまま受け入れる「祈る」運用

結論

  • 本質的な信頼性決定論的なソフトウェア設計プログラム的検証 によってのみ実現
  • LLMの活用 は「部品」としての位置づけが最適解

Hackerたちの意見

その気持ちはわかるけど、結論はちょっと変えるべきだと思う。プロンプトの限界に達したら、タスクを達成するためにLLMを使うのから、LLMを使ってソフトウェアを書く方向に移る必要があるよ。実行時のLLMの役割は、厳格なビジネスルールを具現化したソフトウェアシステムに対して、ユーザーが適切な入力を選ぶ手助けをすることに縮小されると思う。

このフォーラムでは、将来のソフトウェアは、genAIを使って実行時に作成・適応されるプログラムにあるという意見が出ているね。どれくらいその状態から遠いのかはわからないけど。

最近、仕事が少し暇だったから、エージェントを作業プロセスに取り入れることにしたんだ。メモ取り、タスク追跡、ドキュメント管理みたいなやつね。君のコメントは、まさに私の経験そのものだよ。1週目はどんどんプロンプトが広がって、パフォーマンスが落ちていった。2週目は、実際にオブジェクト(メモ、タスク、プロジェクト、人など)を正確に定義して、それに対して明確に定義された操作を行う方法を定義することに集中している。エージェントの表面は、君が指摘した通り、自然言語をコマンドや引数に変換する翻訳レイヤーに縮小された。

フルサークルのシステムプロンプトは、「自分の仕事を自動化して、できるだけ早く手放すチャンスを見つけること。コードで答えられる質問が来たら、その質問にコードを書いて実行して結果を得ること。」って感じかな。そんなLLMなら、いちごテストでももっと良い結果が出たかもね。

モデルが特定の問題解決モードにハマってしまって、新しいモードに移るためのちょっとした後押しが必要なケースを見たことがある。例えば、オーディオストリームのホットプラグ/アンプラグを処理するために、システムサービスの設定をいじるのではなく、実際には数十行のPythonを書くだけで済むことが必要だった。Claudeに、私のワークフローで効率的に解決できない一般的なケース(テストを実行するなど)を処理するためのシェルスクリプトをいくつか書かせたら、今では無駄に30分もぐるぐる回ることなく、そのツールを実行して設定するようになった。毎回、何かをするために一回限りのクレイジーなシェルやPythonのワンライナーを実行できるか聞いてくるたびに、代わりに自動承認できるツールを書かせるべきか考えるようになったよ。

だから、私は「次世代AI」と呼ぶことが多いんだ。単なるLLMじゃないやつね。LLMはかなりクールだし、今後も基盤となる進展がなくても、もっと面白い使い方がされて、最適化されていくと思う。今のモデルがそのまま凍結しても、まだまだ価値を引き出せる方法があるはず。でも、いくつかは次世代の基盤的な改善が必要だと思う。LLMが「絶対にXをするな」をぼやかしてしまうのは、彼らの仕組みの根本的な部分に関わっている気がする。私たちが彼らの可能性を探っている初期段階だからこそ、見失いやすいけど、LLMはAIに求めているすべてではないと思う。「絶対にXをするな」を人間のように扱えるようなアーキテクチャが必要だよね。「コンテキストウィンドウ」の代わりに、私たちのようなメモリ階層を持つアーキテクチャが必要だと思う。もし二人が最初は同じAIと十分に長い会話をしたら、結果として二つのAIはコンテキストウィンドウだけでなく、実際に二つの個体になってしまう。もちろん、これがどうなるかは私も他の誰もわからないけど、LLMがAIの最後の答えだとは思わない。

これ面白いよ! https://www.youtube.com/watch?v=kYkIdXwW2AE&t=315s

問題の一部は、そもそもLLMの誤用にあるんじゃないかな。どこかで言われていたけど、エージェントのプロンプトは、できるだけ繰り返し可能で検証可能、決定論的な方法でタスクを達成するためのコードを書くことにすべきだと思う。これにはエージェントの出力の検証も含まれるといいね。全体の目標は、LLMがプログラム的にもっと効率的(かつ正確に)処理できることを避けることだと思う。

そうだね、エージェントについての標準的な考え方は逆で、コストがかかりそう。LLMを使ってスクリプトを書いて、それを自分のループハーネスに入れて、最後に決定論的な検証が難しい部分はLLMに呼び出すって感じかな。

問題は、プログラムが解釈を必要とするエッジケースに遭遇することが多いってことだね。その時、LLMにそのエッジケースを処理させたくなる。そうすると、全体のループをLLMに任せて、ツールコールもやらせたくなるんだ。

100%同意。90%の確率で正しい非決定論的なものを使って、100%の確率で正しい決定論的なものを生成するっていうのがいいよね。プロンプトに追加する重要なことの一つは、「- あいまいなエッジケースに遭遇したら相談してね」ってこと。AIを直接APIコールで動かすのは良くないと思う。アプリがAIを使うべき唯一のケースは、読んだり分類したりする時だけだね。要するに、古いCRUDアプリの「R」を置き換える感じ。もしその新しいAIベースの「R」エンドポイントを使って、「C」、「U」、「D」を自動で埋めるのはいいけど、人間がレビューする前に顧客のために何かを変更するべきじゃない。基本的にCRUDアプリはCRUDアプリのままだし(これは永遠に変わらない)、ただ非常に賢い「R」エンドポイントがあって、顧客のためにフォームを自動で埋めたり(内部ツールやJenkinsパイプラインなど)、アクションを提案したり(でも実行はしない)するって感じ。

ほとんどの組織では、流れがこうなってると思う:LLM -> プロンプト -> 結果 LLM -> プロンプト + スキルとしてエンコードされたプロンプト -> 結果 LLM -> プロンプト + スキルとしてエンコードされた決定論的コード -> 結果 早い段階でコードを生成するためにプロンプトを使うことで、その決定論的コードへの道をショートカットできると思うけど、基本的には非決定論的なラッパーの中に決定論的なコードを埋め込んでる感じだね。多くの場合、長期的なタスクを成功させるために必要な決定論的な層が欠けてる。エージェントループやフレームワークを通じて、非決定論的な境界の外に決定論的なコードが必要だよ。これによって、非決定論的な意思決定が決定論的な層の間に挟まれることになる:決定論的なエージェントフロー -> 非決定論的な意思決定 -> 決定論的なツール。これは私の実験で非常に強力なパターンで、エージェントがauto-researcherのようなツールを使って自分の決定論を構築することで、さらに強力になる。

うちのエージェントはよく自分でスクリプトを書くんだよね。それって、実質的に君が求めてることじゃない?スクリプトを促すのも、うまくいくときには時間と精度を上げるための便利な手段だよ。

これが、サーバーとモバイルアプリの間のインターフェースライブラリを自動生成する最後のプロジェクトでやったことなんだ。ハードウェア制御チームが仕様書をドキュメントとスプレッドシートで提供して、モバイルチームがそれを使ってインターフェースライブラリをコーディングして、サーバーに対してコードを検証してた。私はそのドキュメントをTSVに変換して、一部をClaudeに送って、TSVのパーサーを書かせたんだ。人間が書いた仕様のニュアンスを全部保ったままね。パーサーがすべてのエッジケースを処理してJSONとして中間出力を生成するのに150回以上のイテレーションがかかったよ。それからClaudeに、Apolloの上にカスタムグルーを使ってモバイルアプリが消費するコードを生成するコードジェネレーターを書いてもらった。この全体のパイプラインはGitHub Actionsの一部として動いていて、ライブラリのバリデーターが失敗したときだけClaudeを呼び出すんだ。失敗時にはmdファイルをClaudeに送って、何が悪かったのかを調べてもらい、解決策を提案してPRを作成するんだ。その後に人間のレビュー、再作業、マージが行われる。ここまでの総コストは$350未満だよ。

できるだけ繰り返し可能で検証可能、決定論的な方法でタスクを達成するためのコードを書く 正解。確率的な出力を持ちながら決定論的な受け入れの「ガードレール」を持つという概念は論理的じゃないよ。もしその領域が決定論的なモデル化に抵抗するなら、LLMを使っている時点で、そのガードレールがその能力を持つわけじゃないからね。

完全に同意!人間も非決定論的だってことを忘れがちだよね!でも、ツールを使えばちゃんとコードを書けるし、結構信頼性もある。AIに関する問題は、結局そのやらせたいことを決定論的にテストできるかどうかに集約されると思う。私たちの中で、作ったものをまず確認せずに作業を見せることがない人はどれくらいいるかな?

これめっちゃ真実だよ!まさにこの原則に基づいたプロジェクトに取り組んでるんだ - https://www.decisional.com/blog/workflow-automation-should-b... 根本的なインセンティブの問題があると思う。コード + LLM + ハーネスは効率的になるはずなのに、ラボはトークンを消費させたいから、コードを使うようには言わないんだ。ただトークンをもっと消費させようとしてる。彼らは今はトークンのコストや信頼性を忘れろって言ってるけど、モデルは良くなるって。だからほとんどの人は、自分のエージェントがプロンプトとスキルの助けで何でもできるはずだと信じてる。残念ながら、みんなが自分のエージェントが本番環境で失敗するのを見ないと、正しい結論にたどり着けないんだよね。

「命令が提案で、関数が“成功”を返しながら幻覚を見ているプログラミング言語を想像してみて。推論が不可能になり、複雑さが増すにつれて信頼性が崩壊する。これは本質的に宣言型プログラミングだ。ほとんどの伝統的なプログラミングは命令型で、ほとんどの開発者が慣れている - 私は正確な指示を出して、それが守られることを期待する。エージェントは命令型よりもずっと宣言型だ - 結果を与えると、それを得るために働く。もちろん問題は、SQLのような宣言型のもので、この結果はかなり一貫していて明確であることだが、結局はその背後のエンジンにどうやってやるかを信頼しているってこと。エージェントを宣言的に考えることで、彼らの周りにルーブ・ゴールドバーグ的な「制御」システムを設計しようとするよりも、ずっと助けられた。うまくいかなかった?じゃあ、正しくないことを確認したから、もう一度やってみるか、違うアプローチを試そう。もし本当に命令型が必要なら、命令型のものを書けばいい!それともエージェントにやらせればいい。この話は、仕事に合わない道具を使おうとしているように感じる。

宣言的なものを考えてたんだけど、SQLじゃなくてPROLOGの方がいいかな。実際の制御フローと推論能力がある感じで。そうすると、LLMが抱えるのと似たような問題に直面するよね。例えば、静かな失敗やループ、矛盾が起きる。気をつけないといけないけど、要は同じ閉じた世界の仮定の問題かも。LLMの場合、これはハルシネーションとして現れるけど、自分が知らないことを認めることはない。

SQLの宣言的な性質は、関係代数の数学に基づいてるから、毎回同じ結果を返すんだ。でも、毎回同じ時間で返すかっていうと、それはインデックスやデータベースのサイズによるからね。クエリ自体は、LLMのように変わることはないよ。

私が見る限り、すべてのハーネスはこの点で間違ってるし、中にはかなり深刻なものもある。例えば、スラッシュコマンドはミスフィーチャーだよね。チャットボットがターンを終えるのを待たなくても、コンテキストウィンドウの状態やこのセッションで使ったお金を確認できるべきだと思う。コントロールはチャットループとは独立しているべきだよ。テキスト生成器の入力や出力を制御することとは関係ないことまで、チャットアクションと絡まってるのは無意味だよね。「チャットだから、IRCボットを操作してるふりをしよう」って感じで。今は無数のLLMエージェントがあるけど、どれもコントロールとエージェントループ、プレゼンテーションをうまく分けてないよ。(少なくともいくつかはヘッドレスモードを持ってるから、それはいいけど。)

例えば、スラッシュコマンドはミスフィーチャーだよね。チャットボットがターンを終えるのを待たなくても、コンテキストウィンドウの状態やこのセッションで使ったお金を確認できるべきだと思う。コントロールはチャットループとは独立しているべきだ。あなたが言おうとしていることはわかるけど、実際に提案しているものを設計するのはかなり難しいよ。どうせならそれを作って、大手企業に雇われることを目指してみたら?

Codexのデスクトップアプリを使ってるよ。GUIではコンテキストインジケーターや使用状況の統計が見えるし、会話を行き来するのも楽だね。時々、ターミナルでClaude Codeやopencodeを使うけど、Codexのデスクトップアプリと比べると体験はかなり劣る。

codex CLIでは、/statusはターン中にちゃんと動くよ。でも他のものはそうじゃないけどね。

ベビーシッター: エラーが広がる前に人間が介入するのが大事。これがAIを使うときに失敗しないための唯一の方法だよ。これ以上の自動化はただの演技に過ぎない。どんなにそれを聞くのが辛くても、ビジネスモデルを揺るがすことになるからね。鳥は歌い、アヒルは鳴く。アヒルが今歌い始めるなんて期待しないよね?

それには同意できないな。すべての確率過程と同じように、LLMのエラーは定量化できるよ。それによって、各ユースケースはリスクとリターンのトレードオフになる。ユーザーはそのトレードオフが自分にとって意味があるかどうかを判断できるんだ。リスクが低い場合や、エラーが許容されるシナリオもあるし、リターンがそれを補うこともある。これはビジネスと技術の具体的な問題だね。

1000%同意だわ。Anthropicの「未来のモデルの能力に合わせて構築しよう、もっと良くなるから」っていう戦鼓を信じるのがだんだんためらわれてきた。例えば、QAエージェントがブラウザセッションで200のマークダウンファイルの要件を処理する必要があるんだ。これはすごく効率的にチームの作業を改善してくれるクールなシステムなんだけど、ずっと前から次のようなプロンプトを使おうと試みてたんだ。「このディレクトリの要件ファイルを見て、それぞれの要件ファイルについてアプリケーションがそのファイルに記載された要件を満たしているかどうかを判断するためのTODOリストアイテムを作成して」ってね。つまり、モデルに高レベルの制御フローを管理させるってこと。これが約30ファイルを超えたあたりから崩れ始めた。時々ファイルを見逃したり、時にはファイルの束を三重にテストして3分ではなく10分かかったりすることもあった。一つのファイルのエラーが、理由もなく前の4つのファイルを再テストする必要があると信じ込ませたりして、本当にイライラしたよ。テスト中に、(Opus 4.6とGPT 5.4だったと思うけど)そのワークフローを実際に調整する能力に一貫性がないことがすぐにわかった。うまくいくこともあれば、そうでないこともあった。Opus 4.7とGPT 5.5でも一度か二度テストしたけど、そこまで広範にはやってないけど、同じ問題があるみたい。結局、モデルの周りに超基本的な決定論的なハーネスを作ることにしたんだ。各テストケースごとに、モデルをトリガーしてそのテストケースをテストさせて、結果を配列に保存して、結果をファイルに書き込む。これでシステムが億倍も信頼性が増したよ。でも、そのせいでエージェントを管理されたエージェントプラットフォーム(Cursor Cloud AgentsやAnthropicなど)で動かすのが不可能になった。みんな「エージェントはすべてを実行しなければならない」と考えすぎてて、ちょっとした決定論を適切な場所に加えれば、これらのシステムがどれだけ価値があるか見えなくなってるんだ。

今、古典的なタスクグラフとAIエージェントを組み合わせたハイブリッドシステムを作ってて、お互いにインスタンス化させるようにしてるんだ。いずれ他の人もやると思うよ。

以前は、トークンのためにプロンプトだけのワークフローに押し込んでるのかと思ってたけど、実際には人がその部分を設計・実装する必要があることを心配してるんだと思う。これが、彼らが全ての人を全てのワークフローやプロジェクトで置き換えると言い張ることの足かせになってる。私は、これが開発者の雇用市場や給与スケールに悪影響を与えるほど生産性を上げるとは思うけど、今のこの技術のバージョンが本当に彼らが言ってることを実現するとは思えない。もし、彼らがこのくらいの金額を使って人間の開発チームの忙しい作業を減らす超便利なものを作ってると言ってたら、投資家たちは彼らに厳しい目を向けるだろうね。細かく制御されたステップがあった方が、小さくて安くて専門的なモデルを実装するのにはずっと優しいと思うよ。巨大なモデルを使ってテストを自動化したり、CSIのファンフィクションを5本一気に書いたりするよりもね。

これは約30ファイル後に壊れ始めた。Codexの短いコンテキストとタスクリストシステムがここでうまく機能するみたい。頻繁にコンパクトになるからね。モデルは、まだやっていないタスクリストの項目や、使うべきワークフロースキルを再確認する必要があったんだ。以前は大掃除に何時間もかけてたけど、特に問題なく終わったよ。

それを自分のためにハーネスを書くようにさせたり、最初のステップにさせたりできないの?必要なところで自分の決定論を押し通せるでしょ。

最小限のマークダウンファイルと、決定論的な作業を行うオーケストレーションスクリプトの組み合わせでスキルを持つことができるよ。エージェントは「すべてを実行する」必要はなくて、ただ正しいスクリプトを起動する方法を知っていればいいんだ。

俺は一つのアップボートしか持ってないけど、そうだね。これらのシステムを信頼性高く機能させる唯一の方法は、問題を小さな部分に分けることだよ。内部の整合性チェックをしても、LLMが期待よりもずっと一貫性がないことがわかるだけだから。

「製造パラメータxが今月と先月で有意に異なるか?」みたいなクエリを受け取る仮説検定エージェントを作らなきゃいけなかったんだ。エージェントがフローチャートに従って統計テストを実行して答えを返すようにね。その時は4oしか使えなくて、プロンプトでフローチャートを言及するだけじゃエージェントが従う保証はなかった。結局、エージェントをループに入れて、次のステップを常に与える形にしたんだ。ある意味、エージェントのためのカスタムハーネスだね。

もっと強力なエージェントハーネスがあれば、エージェントが基本的に自分の決定論的なコードを書いて実行できるようになって、実行されると各サブタスクのためのサブエージェントを生成するってことはないかな?今のところ、エージェントがサブエージェントを直接生成するのは見てきたけど、それでも最終的なフロー制御は非決定論的なオーケストレーターに任せることになるから、君のケースは失敗する典型的な例だと思う。

もし、そういう決定論的なスキャフォールディングや制御フローに興味があるなら、Probityをチェックしてみて。これを解決するために作ったんだ。ベンダーに依存しないESLintスタイルのポリシーエンジンで、現在はClaude Code、Codex、Copilotに対応してるよ。エージェントのフックペイロードとセッション履歴を使ってポリシーを強制するから、チェックが最後に実行されてからファイルが変更されていたらコミットをブロックしたり、文字列や正規表現マッチングを使ってコンテンツやコマンドを禁止したり、余計なレポータの設定なしでTDDを強制できるんだ。どんな言語でも使えるよ。フィードバック待ってるね!: https://github.com/nizos/probity

「フロー」はエージェントをyamlのフローチャートに沿ったプロンプトや決定に導くんだ。Tenstorrentの中で何人かにはうまく機能してるけど、もっと発見があるよ: https://github.com/yieldthought/flow 幸いなことに、5.5は書くのが得意で、それを使うのも上手い。

プロンプト強制 > 決定論的フロー > プロンプト強制を一通り経験した者として、俺は反対だね。「スキップしないで」っていうのが失敗する理由は、エージェントがあまりにも多くのことを担当していて、文脈にあるものがそのガイダンスから注意をそらしてしまうからだよ。でも、強制を行うエージェントが構築するエージェントと同じである必要はないって誰も言ってない。決定論的な制御フローに賢い意思決定ロジックを組み込むことはできるかもしれないけど、そうするとあまりにも硬直的になってうまく機能しなくなるか、逆に複雑すぎて結局エージェントを使った方が安上がりでセットアップやメンテナンスも楽になるかもしれない。基本的に3つのベースエージェントが必要だよ: - ループを管理して、何かが壊れたときに適切に動かすスーパーバイザー - 適切なエージェントに仕事を振り分けて、必要に応じてガードレールを強制するオーケストレーター - 作業ユニットを実行するワーカーたち。これらは色々な形を取るかもしれないね。