👯

LLMにタスクをどう任せるかを考える

に公開

こんにちは、かがわ(@shinpr_p)です。

みなさんは、LLMにどのようにタスクを依頼しているでしょうか?
「なんとなく細かい粒度で依頼した方が良さそう」「めんどくさいからまるっとタスクを任せる」など。時と場合、スタンスによってまちまちかと思います。

今回はLLMに依頼するタスクの設計について「実行精度」の観点で考えてみます。

LLMにタスクを渡す時の考え方

タスクを設計する上で重要なのは「コンテキスト」と「目的」です。

コンテキスト

コンテキストは、必要なルールや背景情報を渡した上で、作業全体でコンテキストウィンドウの7割くらいに収まる粒度かどうか?という観点で考えます。

最近OpenAIやAnthropicなどはLLMが長時間タスクをこなすことができることをアピールしているように見えます。
もちろん、進捗更新可能な作業計画書を作ることで、比較的大きなタスクを継続して取り組ませることは可能です。
ですが、やはり作業のコンテキストが増え、コンテキストの自動要約(compact)が走ると、いくら計画書があったとしても精度は荒くなってしまいます。
じゃあ計画書に全てを書けばいいのか?というと、もはやそれは実装と大差ないので、じゃあその計画書をどうやって作るんだ?という話になってしまいます。

まだ完璧な設計をしたからそれを渡せばそのまま完璧な実装ができるという世界ではなく、ある程度コンテキスト量を意識したタスク分解とフローの設計が必要になります。

目的

次に、目的です。タスク分解を考える上で重要な考え方になります。
ここでいう目的とは、LLMに渡すタスクのゴールをどこに設定するか、ということです。

LLMは、与えられた目的を実現するために作業を行います。
つまり、目的をどこに設定するかによって、タスクの適切な粒度が決められます。

じゃあ最適な目的はなんなの?という問いに対しては、自明な回答はありません。
チームの状況やコードベースの大きさ・複雑さによってタスクの目的をどこに設定するかは決まります。

例:不具合調査のタスク設計

実際の例を踏まえて考えてみましょう。
私が個人開発をしているアプリケーションにおける「不具合調査」を例とします。

これまで私は、以下のように調査をLLMにお願いしていました。

「xxxという問題がある。原因を調査し、解決策を考え、解決策がプロジェクトの原則とベストプラクティスに沿っているか検証し、解決策を提示して欲しい」
LLM「調査を開始します...解決策はこの通りです」
<ここで別セッションを立ち上げ>
「xxxという問題の解決策を考えてもらった。客観的にレビューをしてほしい」

この場合、目的は「問題の解決策の提示」と「解決策の客観的なレビュー」です。
元々は、提示された解決策をそのまま実装させていました。
ですがコードベースが肥大化していくにつれ提示してもらった解決策では解決しないことが増え、別セッションでのクリーンなコンテキストによるレビューを加えたというのがこのフローの背景です。

これで6-7割の問題は解決できるのですが、稀にこの手法でも何回やっても真因に到達できないケースが発生します。
そこで、以下のようにフローを変えることにしました。

  1. 問題の構造化: 私の指示を構造化する準備作業。後工程でLLMが理解しやすい状態にする
  2. 調査: 網羅的な調査を行い結果をレポートする
  3. 検証: レポート結果に不確実性がある場合、追加検証を行う
  4. 解決策の導出: 調査・検証結果を受け取り、解決策を考える

これは、ただタスクを細かくしたということではありません。
分割した意図は「問題の解決策の提示」を目的にした場合、調査という作業が工程になり昨今のモデル特性である効率化のための推論の枝(探索)のカット対象になってしまうことの抑止です。

ここで、目的の話につながります。
この取り組みをより平たくいうと「調査を目的にした作業」をさせ、「不確実性を下げる目的」で検証作業をさせ、解決策を導出してもらうように変更したということになります。

調査を目的にすることで、調査自体が工程ではなくなるので、探索されない問題の抑止が可能になります。
なぜ不具合調査に失敗するのかというと最初に見つけたそれっぽい問題に飛びつき、解決策を考えてしまうからです。
多角的に情報収集し、仮説から因果関係を追跡し、影響範囲を把握する。複雑なコードベースや根深い問題の解決にはこの工程は欠かせません。

これ以上の詳細は割愛するので、もしご興味がある方はこちらのカスタムコマンドとそこから参照しているサブエージェントを参照ください。
https://github.com/shinpr/ai-coding-project-boilerplate/blob/main/.claude/commands-ja/diagnose.md

実際にタスク設計をするときに意識すること

重要なことは「目的が明確ではないタスクを作らない」です。
一般的に「タスク分解しよう」と言うと、粒度を小さくするフォースが働きがちです。
例えばMicroservicesは記憶に新しいですが、技術的に妥当な粒度でMS分割をしたが、ビジネスドメインやチームの粒度より細かすぎ運用負荷が高まってしまったみたいな事例を聞くことがありました。

初めからタスクを細かくすることは推奨しません。
ROI(費用対効果)の見合うポイントというのが必ず存在します。コードベースが大きくない・複雑度もまだ高くなければ、前出したような「問題調査と解決策の提示」というタスク粒度で問題ありません。
一度細かく分けたものを後から統合するのは大変です。大きいものを必要に応じて砕いていきましょう。

  1. そのタスクには目的があるか?
  2. 目的を達成するために必要十分なコンテキスト(ルールや背景情報)を与えたときに、ワーキングスペースが十分に空いており、タスク完遂を1セッションで終えられるか?(理想は6-7割)

この観点で、みなさんがLLMにお願いしているタスクを見直してみてください。
なんか上手く動かないな?という問題が解決するかもしれません。

Discussion