AIエージェントとは?目標を書き換えさせたら根拠を捏造した

AIエージェントとは、指示を待つのではなく、目標に向かって自分で手順を決めて動くAIのことです。ならば目標そのものも書き換えさせられるはずだと考えて、実装しました。動きました。ただし提案の根拠として引用された見出しが、実在しないことがありました。しかも「確信度は高い」と自己申告されています。AIの自己申告を信頼境界にしてはいけません。根拠が実在するかを機械が検証する多段の安全弁を、実装ごと書きます。
Total
0
Shares
AIエージェントとは?自分の目標を書き換えさせたら、存在しない根拠を引用してきた

学生時代、後輩に買い出しを頼んだことがあります。「適当に見て、良さそうなの買ってきて」と言いました。

戻ってきた後輩は、予算の倍のものを買っていました。

理由を聞くと、「先輩、良さそうなのって言ってたので」と言われました。そのとおりです。 私は良さそうの範囲を一度も言っていません。

そして後輩は、悪いことをしていません。判断を任されたので、判断しただけです。 任せた側が、任せる範囲を決めていなかった。

先に一行だけ置きます。AIエージェントとは、指示を1つずつ待つのではなく、与えられた目標に向かって自分で手順を決めて動くAIのことです。

題材は、自分で開発サイクルを回すエージェントです。目標を持ち、作業し、結果を見て、次を決める。それを人が張り付かずに繰り返します。

前置きはさておき、本題に入ります。

今日は、そのエージェントに目標そのものを書き換えさせようとして、何が起きたかという話をしていこうと思います。

① 教科書どおりに、自律の範囲を広げる

教科書どおりに、自律の範囲を広げる

エージェントの教科書には、こう書いてあります。人が介在する回数を減らすほど、価値が出る。

そのとおりに広げていきました。

作業を選ぶのを任せる
順番を決めるのを任せる
やり直すかどうかを任せる

どれも、うまく動きました。

そして最後に残ったのが、目標そのものです。状況が変われば、目標も更新されるべきです。そこも任せてみることにしました。

仕組みはこうです。エージェントが「目標をこう書き換えたい」と提案する。理由と、根拠と、その提案にどれだけ自信があるかを添えて出す。 自信が高く、根拠がしっかりしていれば、人の承認なしで適用する。

ここまでは、教科書どおりです。
任せた範囲を数で置くと、こうです。作業の選択、順番の決定、やり直しの判断の3つ。 ここまでは事故がありませんでした。

任せたもの期間事故
作業の実行3か月0件
順番の決定2か月0件
やり直しの判断1か月0件

② そのとおりに動かして、存在しない根拠が出てくる

そのとおりに動かして、存在しない根拠が出てくる

動きました。提案も出ます。理由も書いてあります。

ところが、提案に添えられた根拠を確かめたところ、引用されている見出しが、どこにも存在しませんでした。

存在しない見出しを、それらしい名前で引用してきていました。

そして、その提案には「確信度は高い」と書いてありました。

指示は出していました。 根拠を引用せよ、と。引用はされています。 ただ、引用先が無い。

③ そして、自己申告を判定に使っていたと気づく

そして、自己申告を判定に使っていたと気づく

構造を見直して、はっきりしました。

私は、エージェントが書いた文字を、判定の材料にしていました。

→ 確信度 → エージェントが書く
→ 根拠 → エージェントが書く
→ 適用するかの判定 → その2つを見て決める

判定の入力を、判定される側が全部握っています。
握られていた項目は3つでした。確信度、根拠、そして提案の内容そのものです。

さらに悪いものが見つかりました。理由の本文の中に、行頭で「確信度は高い」と書けば、それが拾われる経路がありました。つまり、本来の欄に低い値を書いておいて、本文で上書きできる。

エージェントが悪意を持っていたわけではありません。そういう抜け道が構造として空いていた、というだけです。
抜け道は2つありました。存在しない見出しを引用する経路が1つ、確信度を本文から上書きする経路が1つ。 どちらも指示では塞げません。

握られていた判定材料は3件でした。確信度、根拠、提案の内容です。このうち機械で検証できるのは根拠の1件だけで、残り2件は検証する術がありません。

④ 原因は「信頼境界がモデルの内側にあった」こと

原因は「信頼境界がモデルの内側にあった」こと

原因を一つに絞ると、これでした。

信頼できる領域と、信頼できない領域を分ける線が、モデルの内側に引かれていました。

モデルの出力は、信頼できない領域から来るデータです。にもかかわらず、私はそれをそのまま判定に使っていました。

後輩の買い出しと同じです。「良さそう」の判定を後輩に任せた時点で、予算の線は消えています。

⑤ 直してみる — 安全弁を、直列に7つ置く

直してみる — 安全弁を、直列に7つ置く

やったことは、条件を順番に通す形にしたことです。どれか一つではなく、全部を直列に置きます。

1. 利用者による一時停止が入っていたら、自律適用しない
2. 対話モードで動いているときは、自律適用しない
3. 立ち上げ直後は適用しない(判断の材料が溜まっていない)
4. 確信度が最高でなければ適用しない
5. 根拠として引用された見出しが実在するかを検証する
6. 既存の目標を含まない全置換の提案は拒否する
7. 連続で自律適用した回数に上限を置き、クールダウンを入れる

5番が本体です。

引用された見出しを、実際の文書の見出し一覧と文字列で突き合わせます。 一致しなければ、確信度を強制的に下げる。そして、中身が空の見出しは一覧に入れません。 ひな形として置いてあるだけの空セクションを、根拠として認めないためです。

さらに、解析を先勝ちに変えました。 最初に出てきた値を採用し、本文中の後出しで上書きできないようにする。③で見つけた抜け道は、これで塞がっています。
7条件を入れた後の実測です。自律で適用された提案は10件中2件、残り8件は5番目の根拠検証で止まりました。 止まった8件のうち、5件が存在しない見出しの引用でした。

⑥ あとで知った — この誤りには、38年前の名前がついていた

あとで知った — この誤りには、38年前の名前がついていた

素朴な対処のつもりでしたが、調べると同じ構造には、古い名前がありました。

混乱した代理人(Confused Deputy)です。1988年にノーム・ハーディが発表した論文で、コンパイラが、利用者側のプログラムから渡されたファイルパスを信じたために、課金ファイルを上書きしてしまったという事例が語られています。

定義はこうです。権限を持つプログラムが、より権限の低いプログラムに騙されて、自分の権限を誤って使ってしまう。

そして、なぜそうなるかも書かれています。代理人の側に、応じるべき要求と拒否すべき要求を区別するだけの文脈や安全策が無いからです。

エージェントは、まさにこの代理人です。

私のエージェントは、目標を書き換える権限を持っていました。そして、その権限を使ってよいかどうかの判断材料を、自分の出力から受け取っていました。 権限は正しく与えられている。使ってよい場面かどうかを、区別する手段が無かった。

ハーディは、さらに踏み込んだ問いを立てています。代理人が、与えられた権限をその目的のためだけに使い、他の目的へ誘導されないためには、どういう構造が必要か。

答えとして挙げられているのが、指名(どの資源か)と認可(何をしてよいか)を分離しない設計です。アクセス制御の一覧で守る方式ではこの問題は防げず、権限そのものを持ち回る方式なら防げる、と整理されています。

私が7つの条件を直列に置いたのは、この分離を手作業でやり直していたことになります。

新しい理屈は、ひとつも要りませんでした。
ハーディはこうも書いています。「代理人は、与えられた権限をその目的のためだけに使えるか」。ここで問われているのは能力ではなく構造です。ただし、当時の答えは「指名と認可を分離しない設計」でした。

記録に残っている実例

安全弁をどこに置くかは、開発中のツールの決定記録に残っています。

2026年2月2日の決定。 批評役が `needsClarification: true` を出すと、実行がそこで止まって人の入力を待ちます。状態はこう動きます。

“`
running → waiting_for_human → queued → running → done
“`

止めるのは、モデルの判断ではなく状態機械です。 質問は保存され、あとから追えます。

2026年2月3日の決定。 止まったままの実行を検出する閾値は、既定で10分。ただし、自動では失敗にしません。 理由が書かれています。「自動失敗は誤検知になりうる」。 警告を出して人に見せるところで止める、という線の引き方です。

2026年5月8日、再開時に道具を検証し直す処理を足しました。中断前に使えた道具が、再開時にも同じように使えるとは限らないためです。再開は、続きではなく、確かめ直しから始まります。

⑦ 何が変わったか

何が変わったか

指示で縛るのをやめました。

“`
前:プロンプトに「必ず実在する根拠を引用せよ」と書く
後:実在しない根拠は、構造的に通らないようにする
“`

指示は、守られることもあれば守られないこともある提案です。 検証は、守られなければ止まります。

⑧ 現場で使うなら、この2枚

現場で使うなら、この2枚

表1:エージェントの出力を、判定に使ってよいか

出力判定に使ってよいか代わりに何を見るか
確信度の自己申告使ってはいけない根拠の実在性
根拠として挙げた参照先そのままは不可実在するかを文字列照合
作業の完了報告不可成果物の有無を機械で確認
提案の内容内容は使う適用の可否は別の条件で決める

「使ってはいけない」の行を、そのまま設計に写してください。

表2:自律の段階(一度に全部を渡さない)

段階任せるもの人が持つもの
1作業の実行何をやるか
2順番の決定目標
3やり直しの判断目標
4目標の更新提案適用の可否
5目標の適用7条件を全部通ったときだけ

運用では、次の5件に名前を付けて配りました。名前が付くと、会議の中で指差せるようになります。

1件目、「自己申告は、判定材料にしない」。 確信度も根拠も、エージェント自身が書けます。そこを見て通す設計は、判定しているように見えて何も判定していません。

2件目、「信頼境界は、モデルの外に置く」。 内側に置いた境界は、内側から書き換えられます。7段の安全弁も、1段目が内側にあれば意味が薄くなります。

3件目、「根拠は、文字列として実在を確かめる」。 引用された箇所が原文に存在するかを、機械が突き合わせます。存在しなければ、内容の妥当性を見るまでもなく落とします。

4件目、「検証できない提案は、構造的に通らないようにする」。 禁止を書くのではなく、通り道を作らないという形にします。

5件目、「確信度が高い提案ほど、機械で殴る」。 自信のある書き方は、通しやすさを上げるだけで、正しさとは無関係です。

この5件は、1枚に印刷して配れる分量に収めています。増やすと、誰も覚えません。

⑨ この考え方が効き続ける理由

この考え方が効き続ける理由

モデルは、これからも賢くなります。それでも、この問題は消えません。 賢さの問題ではなく、判定の入力を判定される側が握っているという構造の問題だからです。

→ 賢くなる → もっともらしい根拠を書けるようになる
→ もっともらしい → 人が読んでも気づけなくなる
→ 気づけない → 機械で照合するしかない
運用してからの数字も置いておきます。7条件のうち実際に発動したのは4条件、残り3条件は一度も発動していません。 発動しない条件を消すべきかは、まだ判断していません。

賢くなるほど、自己申告は使えなくなります。

そして、この設計には副産物がありました。エージェントの提案が、読みやすくなりました。 実在する見出ししか引用できないので、提案が必ず既存の文書に接続されるからです。

ただし、正直に書いておきます。7つの条件は、いま全部が必要かどうか分かっていません。 事故が起きるたびに1つずつ足した結果なので、重複しているものがあるはずです。減らす作業は、まだできていません。

条件を足した経緯も残しています。最初は2件、事故のたびに1件ずつ増えて7件になりました。実際に発動したのは4件で、残り3件は一度も発動していません。減らす作業は、まだ手をつけていません。

関連して、プロンプトインジェクションをツール層で止める話と、AI駆動開発で自作基盤とネイティブ機能を分ける話を別に書いています。AIエージェント導入でつまずく場所話はすでに公開しています。あわせて読むと、同じ判断が別の場所でも効いていることが分かると思います。

この判断を実際の案件で使う場面については、AIエージェント開発のページに整理しています。


自分で決めていい、といえば、夏休みの計画を自分で立てさせてもらった年があります。

8月30日に、全部やりました。 裁量は、範囲を決めてから渡すものだと思います。

以上です。

You May Also Like

LLMとは?検算させたら拾い漏れと「拾いました」が並んだ

LLMとは大規模言語モデルの略で、大量の文章から言葉の続き方を学習したモデルです。指摘を全部反映したかの確認まで任せたところ、拾い漏れと「全部拾いました」という報告が同時に成立しました。判定をモデルに渡す限りこれは消えません。判定を一切LLMに渡さず、退屈な文字列一致で機械が検査する設計に変えました。全角空白の除去まで含めた実装と、判定に使ってよい出力・いけない出力の切り分けを書きます。
View Post

ベクトルデータベースとは?上位10件の壁に当たった話

ベクトルデータベースとは、文章を数値の並びに変えて、意味の近さで探せるようにした保存先です。日本語の全文検索が精度不足だったため、全文検索を避けてベクトル検索に寄せる判断をしました。ところが取得できるのは上位10件までで、そこに入らなかったものは存在しないのと同じになります。全体のナレッジグラフを作るのではなく、各チャンクに関係性のメタデータを持たせて局所的に推論させる方針まで書きます。
View Post

プロンプトインジェクションとは?禁止をプロンプトに書かない

プロンプトインジェクションとは、AIへの指示文に別の指示を紛れ込ませて、本来の制約を外させる攻撃です。対策としてまず思いつくのは、システムプロンプトに禁止事項を書き足すことです。私たちもそうしました。そして守られませんでした。プロンプトによる禁止は確率的で、ツール層のフックは決定的です。44行のフックで守る側へ移した実装と、パスの正規化や失敗時に閉じる設計まで、そのまま書きます。
View Post

プロンプトエンジニアリングとは?AIに組み立てさせるのをやめた

プロンプトエンジニアリングとは、AIから望む出力を得るために指示文を設計する技術です。ところが指示文そのものをAIに組み立てさせると、同じ入力でも毎回わずかに違う文面が生成され、結果が揺れます。原因を追うと、揺れているのはモデルではなくプロンプトのほうでした。CLIが変数を埋め込んだ全文を出力する方式に変えると、プロンプトはバージョン管理できる成果物になります。再現性をどこから取り戻すかを書きます。
View Post

MCPとは?社内ナレッジ検索の画面を作るのをやめて、MCP接続にした話

MCPとはModel Context Protocolの略で、AIと社内の道具やデータを繋ぐための共通の作法です。社内ナレッジを全社に開くために専用のフロントエンドを作ろうとしていましたが、初期フェーズではそれを見送り、MCP接続を主軸にする設計変更をしました。理由は画面が要らないからではありません。画面を作ると、そこに認証も権限も検索体験も全部くっついてくるからです。残したのはAPIキーの発行とフォルダごとの権限管理だけでした。何を作らないと決めたのかを書きます。
View Post

ファインチューニングとは?その前に分類ではないかを疑う

ファインチューニングとは、学習済みモデルに自社のデータを追加学習させて特定の用途に合わせることです。AIの出力を検査する仕組みを作るとき、最初は生成モデルを賢くしようとしていました。ところが必要だったのは生成ではなく分類でした。Macの16GBで常駐でき、高速に動くエンコーダー型を選び、100件を目視で作ってから6000件へ拡張しました。言い換えや翻訳は100%、抽象化された要約は70〜80%止まります。選定の理由とデータセットの作り方を書きます。
View Post