AI 支援開発

シェル・フロントエンドとして、エイリアスではなくAIエージェントを使用する

忘れ去られたシェルスクリプトの墓場には、代替案があります。タスクを平易な言葉で記述すれば、AIがあなたのためにgrep、awk、jqを組み立ててくれます。

この記事は英語の原文をAIモデルが翻訳したものです。表現が原文と異なる場合があります。 英語の原文を読む

長年にわたり、繰り返し実行するコマンドへの対処法は、それを保存することでした。エイリアスやシェル関数として、あるいは後で名前を忘れてしまうような ~/bin ディレクトリのスクリプトとして。その習慣は、今や見直すべきものです。AIエージェントが平易な英語を解釈し、その場で標準ツールを適切に組み合わせたパイプラインを構築できるようになった今、そうした個人的なスクリプト層の大部分は、もはやその手間をかける価値がなくなります。この投稿では、この変化が当てはまるのはどこか、当てはまらないのはどこか、そしてそれを決定するルールについて述べます。

この主張は限定的なものです。スクリプトが時代遅れになったわけではありません。しかし、人々が書く小さなスクリプトの大部分は、パイプラインを手入力するのが面倒であるという理由だけでスクリプト化された、一度きり、あるいはめったに繰り返されないタスクのためのものです。その面倒さこそ、AIフロントエンドが取り除いてくれるものなのです。

忘れられたスクリプトの墓場

長年使われている~/bin.zshrcの中を覗いてみると、同じパターンが見つかります。何十ものエイリアスや関数があり、その半分は使われておらず、ほとんどはドキュメント化されていません。gsgit statusであることは覚えていても、ログを追跡するものはerrlogだったかlogtailだったでしょうか?6ヶ月前に、アクセスログから失敗したリクエストを抽出するスクリプトを書きました。それを再び見つけ出すには、書き直すよりも時間がかかります。

ここには3つのコストが積み重なります。第一に、名前と引数の順序を覚えておく必要があります。これは参照の問題ですが、その解決策としてさらに参照すべきものを増やしてしまっているのです。第二に、フラグが変更されたり、パスが移動したりしてスクリプトが静かに壊れるため、それらをメンテナンスする必要があります。第三に、他の誰もそれを読むことができないため、その知識は一人の頭の中にしか存在せず、その人がチームを去ったり、自分自身のショートハンドを忘れたりしたときに死んでしまいます。

これらのスクリプトを書いたこと自体は、どれも間違いではありませんでした。それぞれが、その時々の現実的な摩擦を解決してくれました。問題は、その蓄積です。個人の自動化レイヤーは、誰もがそれを剪定できるよりも速く成長し、そのほとんどは1年以内に死重となります。

AIを通じてシェルを操作するとはどのようなものか

代替案は、意図を伝え、エージェントにコマンドを構築させることです。ツール名を指定したり、フラグを思い出したりする必要はありません。望む結果を説明すると、エージェントがgrepawkjqfindsortなど、適合するものを選んで実行し、その出力を表示します。最初の試みがうまくいかなかった場合、構文ではなく言葉で修正します。

その形は次のとおりです。左側に意図、右側にエージェントが組み立てるパイプラインの種類を示します。

あなたが言うこと エージェントが実行すること
先週のログからエラーを抽出し、3行で要約して 日付範囲でフィルタリングされたgrep -i error app.log、その後エージェントが読み取って要約
現在最もメモリを使用しているプロセスはどれか ps aux | sort -nrk4 | head
アクセスログ内の一意のIPアドレスを数えて awk '{print $1}' access.log | sort -u | wc -l
ここの各サブフォルダーのサイズはどれくらいか、大きい順に du -sh */ | sort -rh
今月追加されたすべてのTODOコメントを見つけて git log --since='1 month ago' -p | grep '+.*TODO'
これらのファイルの名前を変更、スペースをハイフンに mv "$f" "${f// /-}" を含むforループ
このツリー配下で最も大きいファイルを10個表示して find . -type f -printf '%s %p\n' | sort -nr | head

左側にあるものに注目してください。これらは平易なリクエストで、どれも覚える必要はありませんでした。右側のツールは、熟練したシェルユーザーがすでに知っているものですが、それらを知っていることと、時間的プレッシャーの中で正確なフラグを思い出すことは、異なるスキルです。エージェントが思い出す部分をカバーします。あなたは出力が正しいかどうかを判断する役割を担います。

要約のケースは、生のスクリプトでは太刀打ちできないものです。grepはエラー行を抽出できますが、100のスタックトレースを、実際に何が失敗したかを述べる3つの文に変えるのは、言語的な作業です。パイプラインと言語モデルを同じループに組み合わせることで、どちらか一方だけではできないことが可能になります。

なぜ標準ツールがAIの得意分野なのか

これが機能するのは、AIが何を求められているかによります。Unixのツールセットは小規模で古く、うんざりするほど文書化されています。grepsedawkfindsortjq、そしてそれらを結びつけるシェルは、何十年も安定しており、何百万もの例で説明されています。モデルがこれらの部品からパイプラインを組み立てるとき、それは自身が持つ最もよくカバーされたドメインの1つの中で作業していることになります。コマンドは設計上構成可能であるため、モデルは何かを発明するのではなく、既知の部品を組み合わせているだけです。

これを、モデルに新しいアルゴリズムを書かせたり、プライベートで文書化されていない内部APIを操作させたりすることと比較してみてください。そこでは、モデルが依拠できるものはほとんどなく、エラー率が上昇します。シェルの構成は、その対極にあります。構成要素は公開されており、構成ルールは単純で、間違った推測は通常、静かに失敗するのではなく、大きな音を立てて安価に失敗します。

これが適合するのには、2つ目の理由があります。タスクが一度きりで可変性が高いほど、スクリプトは役に立たなくなり、委任がより効果的になります。スクリプトは、作成と保守のコストを償却できるほど同じ操作が頻繁に繰り返される場合にのみ、その価値が生まれます。ほとんどのシェルのニーズはそのようなものではありません。毎回わずかに異なります。日付範囲が違う、フィールドが違う、ファイルが違う、といった具合です。自然言語はそのバリエーションを無償で吸収しますが、スクリプトの場合はバリアントごとに新しいフラグや書き換えが必要になります。

スクリプトが依然として有効な場合

委任がすべての答えというわけではなく、そうであるかのように振る舞うことは、逆の間違いにつながります。いくつかの明確なケースでは、書かれたスクリプトが自然言語のリクエストに勝ります。

  • 高頻度の繰り返し。1日に20回同じ操作を実行する場合、毎回言葉で説明する手間は、2文字のエイリアスよりも時間がかかります。固定的で、頻繁で、同一の操作こそ、エイリアスが作られた目的です。これらは維持しましょう。
  • 正確な再現性。cronジョブ、デプロイステップ、またはCIパイプラインで、同じコマンドを毎回同じ方法で実行する必要がある場合、わずかに異なる結果になる可能性のあるプロンプトから再構成するのではなく、リテラルなコマンドをファイルに固定したいと思うでしょう。
  • 正確性が重要なパイプライン。わずかな違いがデータを破損させたり、誤った結果を生み出したりする可能性のあるものはすべて、レビューされ、バージョン管理されたスクリプトに含めるべきです。そこでの価値は利便性ではなく、正確な手順が固定され、監査可能であることです。
  • 共有され、名前が付けられたワークフロー。チーム全体が依存するデプロイステップは、各個人の言い回しの中に存在するのではなく、名前の付いた単一の正規の形式を持つべきです。

パターンは単純です。スクリプトは、安定的で、頻繁で、そして変化してはならないもののためのものです。委任は、探索的で、時折発生し、そして毎回異なるもののためのものです。「それをスクリプトにすべきだ」という昔からのアドバイスは、繰り返される作業のほとんどが最初のカテゴリに分類される場合には正しかったのです。その作業が、二度と同じ方法で繰り返されることのない動く標的である場合には、それは間違いです。

危険なコマンドの問題

AIにコマンドの組み立てを任せることには、明らかなリスクが伴います。モデルが間違ったコマンドを生成する可能性があり、間違ったコマンドの中にはデータを削除したり上書きしたりするものがあるからです。これは現実的な問題であり、このアプローチ全体における限界を定めるものです。

そのガードレールは、注意深いエンジニアがすでに使用しているものと同じです。破壊的な操作は、実行前に人間によるレビューを受けます。ファイルを削除したり、データベースを上書きしたり、ブランチを強制プッシュしたり、権限を変更したりするようなリクエストは、モデルの言葉だけを信じて実行してはなりません。まずコマンドを読み、意図した通りの動作をすることを確認し、その上で初めて実行させるのです。優れたエージェントは、コマンドを闇雲に実行するのではなく、コマンドを提示し、不可逆的な操作の前で一時停止します。

読み取り専用で、簡単に元に戻せる作業であれば、自由に委任できます。一覧表示、カウント、検索、要約、検査などは何も害を及ぼさないため、これらを制限する理由はほとんどありません。頭の中での切り分けは、監視するコマンドと変更するコマンドの間で行います。監視なら実行させ、変更なら実行前によく確認するのです。

非破壊的な作業であっても、検証は重要です。モデルは、クリーンに実行されても、日付フィルターの1つずつのエラーや、awkフィールドの間違った列など、間違った問いに答えるパイプラインを組み立てることがあります。自信を持って生成されたからといって、その出力が自動的に正しいとは限りません。その結果は、同僚が書いた簡単なスクリプトを扱うのと同じように扱ってください。つまり、便利で、おそらく正しく、重要なことに使う前には一瞥する価値がある、ということです。

再現性には依然として記録が必要

対話が提供しないものが一つあります。それは、永続的な記録です。もしタスクが、同じ方法で再実行したり、他の誰かに引き継いだり、事後検証で説明したりするほど重要である場合、チャットに入力した言葉は信頼できる成果物とは言えません。それらは消え去るか埋もれてしまい、モデルは次回、コマンドを異なる言い回しで表現するかもしれません。

したがって、正直な立場は「すべてのスクリプトを削除せよ」ということではありません。何かを書き留めるきっかけが変わるということです。一度入力するのが面倒だという理由だけでタスクをスクリプト化することはもはやありません。再現性が必要なとき、つまり、無人で実行されるとき、他の人がそれに依存するとき、正確な手順が残る必要があるときに、それを書き留めるのです。その時点で、使い捨てのパイプラインを、本物のスクリプトや文書化されたメモに昇格させます。理想的には、エージェントに今実行したばかりの正確なコマンドを保存するように依頼することによってです。エージェントは、成功した一度きりの処理を、名前を付けるに値すると判断した時点で、名前を付けてコミットされたスクリプトに変えることも得意です。

これにより、両方の長所が保たれます。探索的でまれな作業は、高速で使い捨て可能な自然言語のままです。負荷を担うまでに発展したものはすべて、以前とまったく同様に、名前を付けてファイルに固定されます。違いは、古い習慣が想定していたよりも、その飛躍を遂げるタスクがはるかに少ないということです。

私がたどり着いたルール

意図を述べ、ツールのことは考えず、再現しなければならないことだけを書き留める。

シェルでの一日の大半を占める、常に発生し、探索的で、毎回少しずつ異なる作業については、個人的なスクリプト博物館を維持するよりも、結果を記述してエージェントにパイプラインを構成させる方が、速くて手軽です。安定しており、頻繁で、正確性が重要で、共有される作業については、明示的なスクリプトを保持します。なぜなら、そこでの要点は手順が変わらないことだからです。

あらゆるタスクを分類する問いは、それが同じ方法で繰り返されるかどうかです。もし同じように、そして頻繁に繰り返されるのであれば、それを固定します。もしそうでなければ、名前を忘れてしまうようなツールを構築してはいけません。求める結果を伝え、破壊的な処理が実行される前にコマンドを確認し、シェルの最も古く、最もよく文書化されたツールに、その前面に翻訳機を置いた上で、これまで通りのことをさせましょう。