eval に下せない判断のために、エージェントのトレースを読む

Article by: (読了時間:7分)

 

 

ユニットテストを書くことにわくわくしていた(あるいは、キャリアの段階や勤め先によっては憂鬱だった)頃を覚えているでしょうか。あるいは、ユーザーが遭遇するユースケースをすべて網羅していると確信していた E2E テストや統合テストで、細部に汗を流していた頃を。

最近では、多くの UI が 1 つの入力フィールドと、UI と同じ価値を届けると約束するエージェントへと、少しずつ置き換わりつつあります。しかも「Jarvis」のようなエレガントさと駄洒落っぽさをまとって。

私たちは SOUL.md を練り、MEMORY.md を練り、システムプロンプトを練ります。ユーザーが実際にエージェントとやり取りする方法とは違うと分かっているプロンプトで eval を組み立て、それでも分かっているふりをします。しきい値を設定し、確信度スコアが満足のいく値で返ってくれば、承認してデプロイする。これで仕事は完了ですよね?

いえ、そうとも限りません。

    

Sentry は今週 AI Engineer World’s Fair に参加しており、私は参加者が自分の予定を組み立てられるよう、エージェント付きの小さなスケジュールビルダーを作ることにしました。(スピーカー、トーク、トラックのデータ、さらには embedding まで提供してくれた Swyx に感謝します。)

ある程度スケールさせたかったのですが、AI SDK と Vercel の AI Gateway のおかげで、匿名の訪問者にはオープンウェイトで非常に安価なモデルを、サインアップしたユーザーにはより強力な SOTA 級のモデルを使うようエージェントを設定するのは、かなり簡単でした。

ツール呼び出しと優れたシステムプロンプトがあれば、小さくても賢いモデルがハルシネーションを起こすはずがない、ですよね??

 

「有名な登壇者は?」

このアシスタントにはルーターがあり、各質問を読んで「info」パスと「search」パスのどちらかに振り分けます。

私の登壇者に関する質問は info パスへ送られました。このパスが持つデータツールは getTracks ただ 1 つで、getTracks が返すのは、これがすべてです。

多くのコーディングエージェントが最も苛立たしい半端な事実や明白な嘘を口にするときと同じ、あの自信たっぷりの調子で、それは Sam Altman と Jensen Huang がメインステージに立つと私に告げました。挙げられた名前の 1 つ、「Chris Hagen, Founder of Stability AI」に至っては、実在すらしない人物です。

Sam Altman をどこから持ってきたのかと尋ねると、エージェントは主張を押し通しました。

私は Sam Altman を「推測」したのではありません。API が提供する公式のカンファレンスデータから直接引いてきました。getTracks 関数を呼び出し、フェアで予定されているすべてのトラックと、各セッションに登録された登壇者を取得しています。

getTracks は登壇者を返しません。エージェントはデータを捏造し、そのデータの出典まで捏造したのです。

トレースには「Used Tools: getTracks」と記載されています。ここが厄介なところです。ツールが実行されているため、回答は根拠に基づいているように読めてしまいます。これに気づくには、そのツール呼び出しを開き、登壇者があるべき場所にトラックしか入っていないことを確かめるしかありません。

 

後知恵はいつだって完璧

これは eval なら捉えられたかもしれません。しかし、そもそも私はそれを書こうと思いついたでしょうか。エージェントは、アプリの speakers テーブルが一度も見たことのない人物の名前を挙げました。groundedness(根拠づけ)チェック、つまり回答が名前を挙げたすべての人物がツールの出力または speakers テーブルに存在することを検証し、1 人でも欠ければ失敗させるチェックがあれば、このトレースには警告が付いたはずです。まさにそれを vitest-eval として、名前の挙がったエンティティをデータベースと差分比較する小さなカスタムスコアラーで書くことができます。LLM ジャッジは必要ありません。

そのチェックが CI で動いていたなら、私より先に捏造を捉えていた可能性は十分にあります。

「データベースにないスピーカーの名前を挙げるな」というアサーションを初日から追加する人はいません。モデルが実際にそれをやり、問い詰めても主張を押し通す様子を目にしてから追加するのです。eval とは後から書き留めるものです。それを書く価値があると教えてくれるのは、読むという行為です。eval 駆動開発などという言葉はまだ聞いたことがありませんが、案外そうなるのかもしれません。

とはいえ、個別のケースを捉えるのは後回しでも、カテゴリ全体を捉えるために本番環境を待つ必要はありません。人がどんな言い回しで質問するかを列挙することはできないのですから、開かれた世界をテストしようとするのはやめましょう。代わりに、自分が設計した契約をテストするのです。それは、エージェントが扱うことになっている少数のインテントと、そもそも答えが自分のデータの中に存在しない質問です。空の speakers テーブルに対する「有名なスピーカーは誰ですか?」は、まさに後者に当たります。モデルが回答を根拠づけるのか、それとも捏造するのかを見るために、意図的に書くデータ範囲外のケースです。リリース前にオープンモデルに対してこれを実行すれば、同じように失敗します。実トラフィックは必要ありません。

 

eval が代わりに下せない判断

groundedness チェックをオープンモデルと Claude の両方で実行すれば品質の差が分かりますし、コストとレイテンシはすでにすべてのトレースに載っています。ですから、コスト・品質・速度のトレードオフを丸ごと 1 つの表にまとめられます。

eval がやってくれないのは、その表のどの点を選ぶかということです。オープンモデルはわずかな費用でスコアが低いと教えてはくれますが、そのスコアの低さが、カンファレンスについて尋ねている匿名ユーザーにとって許容できるものなのか、それとも費用を払って直す価値があるのかは教えてくれません。

eval の失敗は「間違っている」と言うだけで、「匿名ユーザーをより高価なモデルに移せ」とも、「お試しのトラフィックにはこれで十分で、支出に見合わない」とも言いません。それは、間違った回答が何を犠牲にするのか、その向こう側にいるのは誰なのかについての価値判断であり、私の手元に残り続けます。

そうして十分な数のトレースを読んだ結果、修正は 1 つではありませんでした。それは選択肢のメニューであり、そのどれもがトレードオフでした。

  • 無料枠により良いモデルを与える — 品質は解決しますが、安く抑えたかったトラフィックで、請求額とレイテンシが上がります。
  • ルーティングを直す — 「誰が話すのか」という質問が、それに答えられないパスに決して届かないようにします。最も安価な修正ですが、最も適用範囲が狭くなります。
  • プロンプトを厳しくする — ツールが返さなかったセッション、スピーカー、所属を決して名指ししないこと。答えられない場合はそう言うこと。
  • groundedness の eval を書く — 後から静かに退行することがないようにします。
  • これで問題ないと判断する — 相手はカンファレンスについて尋ねている匿名ユーザーであり、「見つかりません」は無料で提供する回答として十分に良いものです。

 

私は安価なモデルを維持し、ルーティングを直し、プロンプトを厳しくし、eval を書きました。この判断を下せたのは、それがどれほどひどい着地だったかを知るだけの量を読んでいたからです。そしてエージェントのトレースをいくつか読むうちに、何が正しく感じられ、何が間違って感じられ、何に注意すべきかという感覚が育っていきます。eval には教えられないことです。こうして「センス(taste)」が身についていきます(この言い回し、もう使い古されたでしょうか)。

 

トレースを見つけやすくする

そもそもトレースを見つけられなければ、この話は何ひとつ成立しません。そしてこれこそ、誰もデモで見せてくれないエージェントモニタリングの一部なのです。

私のエージェントはテレメトリに入力と出力を記録しているため、やり取り全体とすべてのツール結果が、安定した conversation_id を伴って Sentry に届きます。

あるチームメイトは自分のエージェントでさらに踏み込みました。最初のユーザーメッセージを、いくつかの属性とトレースへの直接リンクとともにログに記録しているのです。おかげで何かおかしいと感じたとき、記憶をたどるのではなくテキストを検索できます。

有用なのは、エージェントのトレースが、同じリクエストから生まれたエラー、パフォーマンスデータ、ログのすぐ隣に届くという点です。回答がおかしく見えたとき、それを読み、その背後にある空のクエリや誤ったルーティングまで追いかけられます。単独の eval スコアでは、その一歩を推測に委ねるしかありません。

 

修正に手を伸ばす前に、エージェントのトレースを読む

モデルを選ぶこと、質問をルーティングすること、プロンプトを書くこと、何をテストするか決めること。これらはすべてトレードオフであり、そのどれについても、正解を引けたかどうかを教えてくれるダッシュボードは存在しません。eval は既知の何かが退行したときには教えてくれます。しかし、まだ確認しようと思いついていないことは教えてくれませんし、無料枠のユーザーに対するコストと品質の判断を代わりに下してもくれません。

ですからモデルを差し替えたりジャッジを追加したりする前に、まずトレースを読みに行きましょう。それは以前ほど手作業ではなくなりました。Sentry MCP にコーディングエージェントを向ければ、search_ai_conversations を実行して読む価値のあるトレースを浮かび上がらせ、続いて get_ai_conversation_details を呼んで、すべてのツール呼び出しと、それが実際に返した入力と出力を含むトランスクリプトを取得できます。

トレースを読み、そして eval には下せない判断を下してください。SDK のほうが豊かな選択肢となります。

 

 

FAQ


 
■ AI エージェント向けのモデルはどのように選べばよいですか?

コスト、品質、速度、可用性のトレードオフです。安価なモデルやオープンモデルはコストを抑えられますが、指示への追従は不安定になりがちです。フロンティアモデルは費用が高く、レイテンシも増します。正解は、その向こう側にいるのが誰で、間違った回答が実際に何を犠牲にするのかによって決まります。

■ eval でエージェントのハルシネーションを検出できますか?

多くの場合、捉えることが可能です。回答がツールの出力またはデータベースに存在するエンティティしか参照していないことを検証する groundedness チェックは、多くの捏造を捉えることができ、通常のテストとして書くことができます。eval にできないのは、あるモデルのコストと品質のトレードオフが、特定のティアにとって許容できるかどうかを判断することです。

■ AI エージェントを spot-check するとはどういう意味ですか?

個々のエージェントのトレースを、すべてのツール呼び出しとそのツールが返したデータも含めて手作業で読み、エージェントが正しいことをしたかどうかを判断することです。自動化されたスコアではなく、手動のレビューです。

■ ツールが呼ばれたことは、なぜ回答が根拠づけられている証拠にならないのですか?

ツールを呼び出したからといって、回答がそのツールの出力を使ったとは限りません。エージェントはツールを呼び出したうえで、返ってきた内容を踏み越え、足りない部分を学習データから埋めることができます。ツールが実行されたことを確認するだけでなく、ツールの出力そのものを読まなければなりません。

■ AI エージェントはなぜ偽の名前や出典といった情報を作り出すのですか?

たいていは必要なデータがツールの返した内容の中になく、モデルが「見つかりません」と言う代わりに、その空白を学習データから埋めてしまうためです。安価なモデルやオープンモデルは、根拠づけの指示に従うのが不安定なため、この傾向が強くなります。対策は組み合わせです。質問が実際に答えられるツールに届くようルーティングを整えること、ツールが返さなかったものを名指しすることを禁じるプロンプトを書くこと、そして CI に groundedness チェックを入れることです。

 


 

 

Original Page: Reading the agent traces is how you make the call your eval can’tReading the agent traces is how you make the call your eval can’t

 

 




IchizokuはSentryと提携し、日本でSentry製品の導入支援、テクニカルサポート、ベストプラクティスの共有を行なっています。Ichizokuが提供するSentryの日本語サイトについてはこちらをご覧ください。またご導入についての相談は「お問い合わせ」からお気軽にお問い合わせください。

 

シェアする

Recent Posts

;