ナンモワカランアザラシ

完全に理解した

最近のプロンプトの大半が「どれが事実ですか?」である

生成AI技術が全盛を極め続けている昨今、という書き出しでこれまでに文章を10本以上書いただろう。

業務ではシステムのトラブルシューティングにClaude CodeとCodexを活用することが多い。トラシュー業務に使ったセッションログを分析したところ、「どれが事実ですか?」という叱責が大半であった。

「全容が解明されました」「根本原因を特定しました」「完全に理解しました」これらのフレーズが出てから本当に原因究明が完了するまでにかかる時間は、これらフレーズが出てくるまでにかかった時間の5倍である。最後のフレーズは人間がよく出す。あいつらを含めた我々知的主体は、すぐに完全理解わかろうとする。我々知的主体はなんて愚かなんだろう。完全理解した気持ちになってからが頭脳労働の本番である。どれが事実でどれが仮説なのかを明示的に分離して出力させる必要がある。

「可能性」という語彙が登場したらそのセッションはすでに腐っているので即時破棄すべきである。多くの場合、それはただの検証不足のための言い訳、留保、excuseである。~の場合はxxx、そうでない場合はyyy、のように出力できるようになるまで推敲をすべきだ。あるいは「確率」と換言させてn%と表現できるべきだ。

断言された事実は、すべて検証可能な根拠を付随させるべきである。たとえばコマンドの入出力、オブザーバビリティツールのURL、ドキュメントのURLとその引用。検証可能な形で出されたら多くの場合は正しいが、現代のハイエンドモデルでもたまーに盲言が含まれるので注意しなければいけない。

「演繹」「推論」の語彙は禁止したほうがいい。なぜこのような挙動になるのかまだ理解できていないのだが、あいつらは演繹と帰納の区別がつかないらしい。「妥当な推論」と言いながらただの仮説が提示されることも多い。「事実」か「仮説」かに分類させるとうまくいきやすい。演繹手続きが人間に残される。何だこの仕事は。AIが出した生ゴミを咀嚼して吐き出したり排泄したりする仕事である。

マルチエージェントで敵対的レビュワーを作ってこのような観点で議論させてうまくいってほしいのだけど、全員生成AIだとどうしても同じ罠にハマり続ける。いつか解消されるのだろうか。

AIエージェントとうまく距離をとるためのソフトウェアを作っている

github.com

もともとのモチベーションは、作業の密度を上げたいことだった。仕事のload averageを上げるためにqueue機構を導入するという意図を込めてworqloadと名付けた。作っていくうちに、設計意図が「AIと密に連携したくない」になっていった。

特徴的な設計は次の通りである。

  • 対称対話インターフェースではなく、レポートとフィードバックの非対称非同期インターフェース
  • AIによる生ゴミを見ないための強制推敲
  • 判断を人間に仰ぐためのエスカレーション

レポートとフィードバック

人間がエージェントにinitial prompt を与えたら、あとは非同期にやり取りをする。
AIはよきときにレポートを提出する。人間はよきときにフィードバックを与える。AIはよきときにフィードバックをpullして作業の軌道修正をする。

人間とAIが対称な位置にいる対話UIだと、相手の出力を待ったり遮ったりする必要がある。これがめんどくさい。なので非同期にやり取りをすることにした。

また、anchor機能があり、これはレポートの特定の行数を指定してその部分に関するフィードバックを与えることができる。気に入らない言い回しがあるときに毎回コピペして引用して嫌味を言うのが面倒なので、相手のレポートに対して部分指定ができるようにした。

さらに、コードベース上では、現状のコードファイルやそのdiffに対してもanchorができる。現状のdiffをレポートとして扱い、その一部分にanchorしてフィードバックすることで、コードレビューがやりやすくなった。

強制推敲

レポート形式のメリットの一つが、「推敲」ができることにあると思っている。

現在のほとんどのテキスト生成AIは逐次生成である。どれだけthinkingをさせても発話時に「勘で喋る」ような挙動がよく見られる。そこで成果物を一度ファイルにして、それを読ませたうえで考えさせてpatchさせることにより推敲を達成した。 たとえば一度目のレポートは必ずrejectして推敲させる指示を自動で出すなどができる。カスタマイズもできて、reject時に与える観点promptを自分で作れたり、禁止ワードを設定することもできる。私は「可能性」という語を禁止している。「可能性」がレポート上に表れた際には「可能性という語が統計事実を指す場面以外で使われる場合、そのほとんどがただの調査不足である。どれが事実でどれが仮説か、その仮説を棄却するために必要な作業を実施したのか自問しろ。」というフィードバックが自動で与えられる。

エスカレーション

事前に決定ロジックが定められていない場合、最終的な決定は人間がすべきである。その際にはレポートの特殊ケースとして「エスカレーション」ができるようになっている。レポートは人間が何かアクションをしなくてもいいもの、エスカレーションは人間による何かしらの返答が必要になるものという区分けをしている。

現状のつらみ

worqload自体をworqload越しに開発することで十分なドッグフーディングができている。かなり快適になってきた。しかしまだ解決しない課題がある。

  • worqloadのプロトコルがモデルに十分に伝わらない
    • レポートを出さずにターンを終了したり、エスカレーションでなく通常レポートで判断を仰いできたり
    • 特に安いモデルだとこうなりがち
  • 推敲が下手
    • 推敲ができるようになったとはいえ、AIは人間が読みやすいレポートを書くのが下手くそである。最近のお気に入りプロンプトは「何を出力しないかによって品性が表れます。上品であれ。」である。

TUIコードリーダがほしい

イデアスケッチ。

現代では、もはやコードエディタでコードエディットをすることがなくなった。 大抵の場合、ターミナルを左右に分割してどちらかにエージェントプロセス、どちらかにエディタプロセスを立てている。エディタはコードを編集するためでなくコードを確認するために使っている。全体像を把握したり、エージェントが変更を加えた箇所の整合性をチェックしたり、diffを見たりといった具合だ。これをするためにはエディット機能はもはやtoo muchなのである。nvimでiを押してインサートモードに入る必要がない。

そこで、コードリーダだけあればいいのではないかと思った。従来のエディタからエディット機能をなくしてリードに必要な機能を足したようなものがほしい。できればターミナルで開きたいのでTUIで動くとうれしい。ほしい機能を列挙してみる。

  • ファイルを指定してその内容を表示する
  • ディレクトリ・ファイルの親子関係を一覧できる
  • コードジャンプ
  • lintエラー表示
  • シンボル同士の依存関係を可視化する
  • git diffをいい感じに(GitHub PRのdiffみたいに左右分かれて出るとうれしい)
  • git周りの操作ができる
  • パッケージ間の依存関係を可視化する
  • コードやファイルを選択してGitHub permlinkをクリップボードにコピー
  • コードを選択してクリップボードにコピー
  • テストがどこまでカバーしているかの可視化
  • テスト実行と結果表示

こんな感じだろうか。可視化がむずかしそうだと思った。それ以外は既存ツールの組み合わせで十分に実現できるが可視化だけどうすればいいかの見当がついていない。

オブザーバビリティデータへのクエリと可視化を標準化する

イデアスケッチ。

生成AIをトラブルシュートに使うためのあれこれを考えている。
あれこれやらせてみて、壁はクエリと可視化にあると感じた。

まず、クエリについて。現状だと多くのクラウドプラットフォームで、Web API経由でクエリしやすいような設計になっていない。また、クラウドプラットフォームごとに、クエリ言語が異なることも大いなる壁として立ちはだかっている。たとえばGoogle CloudのCloud LoggingではWeb API経由だとまともにクエリが機能しない。また、MQLとPromQLとでの内部の混乱が見られる。MQLって本当に廃止されるんですか?
AWS CloudWatchでもDatadogでも似たような傾向にある。これでは、AIエージェントを自立させてテレメトリデータをクエリさせて一次対応させることができない。

いま考えていることとしては、基本的にすべてSQLでいいのではないかということだ。OpenObserveというプロダクトを私は気にかけている。parquetでデータを保存することでデータの保存を安く済ませることに長けているらしい。parquetということはつまりカラムナーだな。ここまでくればあとはDuckDBの領分なのではないか?SQLなら十分に枯れている。現代AIの得意領域だろう。列志向データウェアハウスに対してもLIMIT 10とかしやがる癖があるがご愛敬だ。

また、可視化も鬼門である。インサイトを得るにはグラフにするのが手っ取り早いことが多い。現代AIなら画像から情報を得ることもできる。しかし可視化のためのリクエスト形式が統一されていない、あるいはAIフレンドリー(≒システムフレンドリー)でなければその恩恵は得られない。可視化インターフェースのよい統一方法はまだ私には思いついていない。何がいいんだろうなあ。すぐにAIが習得できて、うまく枯れてくれそうなものがいい。 Vegaとggplotを今知った。どちらもGrammer of Graphicsという思想の上にあるらしい。原著『The Grammar of Graphics』を読もうかと思ったけど2.5万円するらしいので躊躇......。

『ゼロトラストネットワーク 第2版 ―境界防御の限界を超えるためのセキュアなシステム設計』を読んだ

www.oreilly.co.jp

いわゆる「ザリガニ本」だ。「ゼロトラスト」概念と具体的な戦略の二つを大局的に理解するのによい本だと思った。

ざっくりとした自分の理解を書いていく。

境界モデルのペインから発展した形でゼロトラスト概念が広まっていった。ゼロトラストはモデルというより設計哲学である。「すべてのリクエストは検証されるべきである」。

ゼロトラストネットワークを実現するためのシステムを構成するために、複数のコンポーネントが出てきた。実際に認可を試行するエンフォースメント、定められたポリシーにリクエストを照らし合わせて認可判断をするポリシーエンジン、リクエストの内容から信頼度(トラストスコア)を弾き出すトラストエンジン、データを永続化するためのデータストア。これをゼロから自分ですべて実装・運用すると骨が折れると思った。

バイス、実行主体(アイデンティティ)、アプリケーション、トラフィック、検証すべき要素は複数ある。そのいずれも、手放しに信用すべきではない。コストとトレードオフにはなるが、一発食らってしまったときの損害がバカでかいのでそのリスクは高く見積もって防御に投資すべきである。

「トラストアンカー」概念の現実味が興味深かった。「すべて検証するべきである」が「これだけは信頼する」対象がトラストアンカーである。信頼錨。コギト・エルト・スムを想起した。それ以上疑ってもしょうがないので、信頼する起点を決めなければ何も考えることができない。

さまざまな境界モデルがハッカーに殺されていく中でゼロトラストモデルは伸長していくだろうが、どの企業にどのような需要があるのかはあまりわからない。まず投資の必要性を啓蒙するところからでは?

ユーザーからのシグナルを信頼性指標として取り入れる

思考のスケッチ。

SRE、サイト信頼性エンジニアリングのプラクティスにおいては大抵の場合にサービスレベル指標を測定する。サービスレベル指標は、SLI、Service Level Indicatorの和訳である。こう見るとServiceと対応する日本語ってないのだね。

では何のためにSLIを測定するかというと、リリース頻度と信頼性のバランスをとりたい、とかビジネスチーム内での共通言語として使える客観指標がほしい、とか世の中にはいろいろ書かれているが、畢竟、ユーザーに満足してほしいからだ。
「信頼性こそがあらゆるプロダクトの基本的な機能」とGoogleは表現した。基本的な機能が満たされていないのに別の新機能を作ってもユーザーには届かないだろうという意味だ。まず信頼性ありき。
さてこのSLIとしてよく使われるのは、可用性としてエラーレートやパーセンタイルレイテンシ、また完全性としてデータ耐久性である。後者はS3のeleven nine, 99.999999999%が有名だ。
これらSLIに目標を設けてSLOとすれば、SLOを達成することがユーザーが満足することの必要条件であると見なせる。

そう、「必要条件であると見なせる」だけである。十分条件であるかはわからない。必要条件を満たしていると断言することも難しい。
データがクライアントのもとに100%の確率で0.1s以内に届いても、例えばUIデザインの不具合によってユーザーが正しくサービスを使えないがゆえに不満かもしれない。そもそもユーザーはレイテンシを気にしないかもしれない。その測定しているSLIが「正しく測定できている」かどうかもわからない。適当にクエリ書いてみたらそれっぽい数字になったのでこれをSLIとしよう!なんてことはよくあるのではないだろうか。

ここから一歩進んで、ユーザーの満足の十分条件により近い指標条件を見つけたい。
それにはユーザーの生の声を得るのが手っ取り早そうだ。

この考えに沿ったプラクティスとして、CRE、Customer Reliability Engineeringという技法があることを私は知っている。 GoogleGoogle の新しい専門職 : CRE が必要な理由で次のように書いている。

今、この時代において、真に適切なサポート チームのミッションはたった 1 つです。それは、お客様の不安をゼロにすることなのです。 (中略) 不安は 1 を信頼性で割った数値に等しい

私は「ユーザーの満足を高める」と書いたが、Googleは「ユーザーの不安を低める」としている。さらに、GoogleはCREはSREが開発チームに対して厳しい要求をするように、お客様に対して厳しい要求をすることによってお客さまの環境の信頼性を高めて不安を減らすのだと主張している。なかなかに苛烈だと感じる。Cloud Platformならではの考え方かもしれない。サービス提供者として考えるのなら、やはりユーザーが不安を感じないようにシステムを設計することに尽くしたい。その中の一策として、ユーザー環境を監視して信頼性が低まるような事態があればユーザーに対してアラートを出すなどはよい施策かもしれない。CREとSREとはダブりのない集合ではなく、SREがCREを含んでいるように私には思える。Site Reliabilityをどうにかするためにお客様を監視することは自然な考えだと思う。

具体的な方法には、お問い合わせ指標化とクライアントモニタリングが思いつく。

不満を感じている人のn%がお問い合わせをしてくださると仮定する。アクティブユーザー全体に対する、不具合に関するお問い合わせを出したユーザー数の比率を出す。一定期間内のこの比率がo未満であれば、システムは健全であると捉える。実際にはそんなに確実な指標にはならないだろうが、「エラーレート」も同じように不確実なものだろう。とりあえず可視化してみる分には損をしないだろう。

クライアントモニタリングの方が技術的にはやりがいがある。まず想起するのはDatadogのRUM, Realtime User Monitoringだ。クライアントにエージェントを仕込んで、ブラウザやネイティブアプリでの操作履歴を収集する。クライアントでのエラー率や、「不満度合い」を指標として抽出する。「不満度合い」については定義がむずかしそうだが、たとえば、同じページを何度も行き来する行動や、マウスカーソルが荒ぶったりしていたらそのユーザーは不満を抱えている可能性が高いと考えられないだろうか。そのような「不満率」をモニタリングして、システム変更によって上がったり下がったりする様子を眺めるとインサイトが得られると思う。ビジネスとしてそれをやる意義を説得しやすくするために、会員解約率やアカウントのアクティブ率と紐づけるとおもしろいかもしれない。

以上のようにCREとしてやられている作業をSREの領域に持ち込むことでより高度な信頼性エンジニアリングを実現したい。

エラーバジェットがなくなるまでリリースしまくる

SREの仕事の方法のアイデアとして書く。

直近の仕事では、リリースされて1年も経っていない若いプロダクトに関わっている。このようなプロダクトでは、信頼性が問題になることが少ない。コードベースは(比較的)きれいだし、インフラやCI/CDも最新のプラクティスに沿っている。ここまで「壊れたら直して二度と壊れなくする」でお賃金をいただいてきた身からすると、何をやるといいかなあと少し手持無沙汰な感じを抱いている。

SREは高速なリリースとサービスの信頼性のバランスをとるための技術である。エラーバジェットが余りまくりであるなら、やるべきはリリース頻度の増強だろう。有り体に言えば、「壊れるまでリリースしつづける」。これを実現するためには何が必要だろうか。

大きく分ければ、正確なエラーバジェットの測定と、リリースまでの壁を取っ払いつづけることだろう。

前者は信頼性を守るために必要である。何をもって「壊れている」とみなすか。サーバーがエラーを返したらダメか。それだけではないだろう。お金を扱うサービスなら、その計算方法やトランザクションの整合性は機能として信頼できる必要がある。多くの文脈においてはSREingは非機能要件を相手にしてきた。しかし当たり前だが、機能要件は機能として必要である。「信頼性こそがあらゆるプロダクトの基本的な機能」とGoogleは書いていたが、非機能は非機能であって機能ではない。プロダクトが正しく機能しているかどうかを測定するためには、何を正しいとするかを決める必要がある。
測定指標として、「お問い合わせ」を使うとどうだろうか。信頼とは、意図した通りに動いてくれることである。意図しない動きをしないことである。友人に金を貸せるのは、その友人が意図通りに金を返してくれるという信頼があるからだ。プロダクトにおける「意図」の主語は、ユーザーである。信頼できるかどうかは、ユーザーによって決まる。そのため、ユーザーが「意図通りに機能しない」と言えば、それは信頼性が低いのである。開発者にとっての意図は自動テストで担保するのを前提として、ユーザーにとっての意図はユーザーに聞くしかない。「お問い合わせ」のデータを信頼性指標として使うことを提案する。具体的に何をどのように指標化するかは別記事で書きたい。

後者のリリースまでの壁について書く。開発は、時間がかかる。新機能を提案して、要件をすり合わせて、設計して、コードを書いて、レビュワーがそれを理解して、CIが通ればマージしてCDによってリリースされる。大まかなリリースフローはこのようだろう。
この中で時間の圧縮が比較的簡単そうなのは、コードを書く・CI・CDだろうか。技術者目線だと、ここはいくらでも技術によって圧縮できそうだ。
コードを書くについては2026年には完全に自動化されるだろう。達成したいことがあって、テストを書いて実装することでknown-knownの領域を増やしていく。「達成したいこと」のなかでunkownの領域がゼロになったらコード書きは終わりだ。   一つ飛ばしてCDの高速化は、これは簡単なチューニング問題に思える。現代のリリースエンジニアリングの粋を集めて「がんばれば」終わりだ。
CIの高速化はすごくやりがいがありそうだ。現代のCIはとにかく肥大しがちだと思う。私は過去のCIを知らないのだけど。事故があるたびにポストモーテムとして統合対象を増やしている。今日も一日ご安全に。ヨシッ。その代償にリリースまでの速度が下がる。対策としては、並列化と削除が考えられる。コンピューティングリソースを横に並べられるだけ並べれば時間を支配できる。コンピュートが時間課金の現代でも、1+1+1+1と1*4の値段は同じだ。人間の脳みそは並列稼働しないので、人間以外の脳みそは並列稼働した方が得だ。削除の方がむずかしい。歴史的に生まれた防壁としてのテストがほとんどだろうから、過去に敬意を払えば払うほど削除の心理的ハードルが上がる。簡単なsmall testについては、カバレッジを計算して、削除前後で変わらないよねと示せばよさそう。medium, largeテストを減らすのは難しいぞ~~~。本来はsmall testですべてカバーするのがよいという根拠で、medium, largeなテストを削るべきだろうか?それこそ、信頼性が下がるまでは削って、エラーバジェットを割ったら割ったところから戻していく、とか。この手の削除作業は自動でやられるべきだと思う。人間が提案して人間が決断するのだと先のとおり、情緒が入る。エラーバジェットを見て自動でテストを減らすくんが定期稼働してほしい。 次に難しそうなのは、「レビュワーがコードを理解する」ことだろうか。これは、そもそもレビューの意義から再構築するのがよさそう。これまでに聞いたことのあるレビューの目的は、「コード品質の維持向上」「enbugのガードレール」「共同所有」このあたりだ。コード品質の維持向上については、linterやformatterに寄せていくのがよさそう。コーディング規約の領域を増やしていくことで対応する。いわゆるReadable Code的な「明瞭なことばづかいをする」「一つの関数は一つのことを」みたいなやつも、現代LLMが頑張れる。いわゆるクリーンアーキテクチャ的な、内側のドメインモデルから外側の技術詳細に向けて依存関係を整備するようなコーディングについても同様にLLMが十分にやれそうだ。関数同士の依存について簡単に可視化できると人間もうれしいかもね。enbugのガードレールについては、もうテストを書くしかないのではないだろうか。レビュワーは書かれたテストを見て、テストケースが十分か判断する。コードがテスタブルになっていればそれだけテストコードもリーダブルになる。あと残る仕事は共同所有である。俗人性の排除と換言できそうだ。何か障害があったときに、「ああそういえばあの辺を変えていたな」と関係者が判断できる。新しくコードを書くときに「ああそういえばあの人が便利なメソッドを生やしていたな」と思い出せる。LLMに委託できるだろうか。障害対応文脈でもコーディング文脈でも十分にできそうな気がしてきた。シンプルに、コンテキストウィンドウに直近n PRのdiffを与えれば済む。ここまでできていれば、あとは人間が「達成したいこと」すなわち要件を理解していればテストコードだけ見てレビューは終わりだ。 ここまでくると、新機能提案、要件すり合わせについては、もうやりたい人が自分でコーディングをやるのが一番手っ取り速いんじゃないだろうか。アジャイルチームで言う「顧客」が自分でつくるのだ。そうするのが一番速い。
残った仕事は設計である。現代の生成AIだとまだアーキテクティングは専門家がやるべきである。あなたがもし2026年初頭の最新AIに技術設計相談をして、「AIはなんてすばらしいんだ!」と感じたのなら、あなたは技術の専門家ではない。この「技術」を任意の分野に置き換えても多分よい。

何事も速い方がおもしろい。もっと速くできる。超高速なリリースに向けてやっていきたい。