【Claude.app】AIエージェントは
条件を厳しく考えて失敗する
(Keynote)

  • 配る資料にページ番号を入れたくて、説明用のスライドをKeynoteのスキップ機能で外すと、スライドショーでもそのスライドが飛ばされてしまいます。
  • AIエージェントに「今の番号をそのまま固定して」と頼んだところ、番号欄そのものを書き換える道を選び、12枚のラベルを消しました。
  • 「番号欄は消して、別のテキストボックスを置けばいい」と条件を緩めたら、一度で通りました。
  • エージェントは目的を知らないので、こちらが出した条件のほうを目的として扱います。失敗が続くときは、指示を強めるより先に、自分が足した条件を疑ったほうが早い。

関連記事

1. 印刷用にスキップすると、スライドショーまで飛んでしまう

スライドを作っていたら、こういう場面になりました。
配る資料にはページ番号を入れたい。
ただ、話すときだけ出す説明用のスライドがあって、そこには番号がいりません。

1. 印刷用にスキップすると、スライドショーまで飛んでしまう

Keynoteには「スライドをスキップ」があります。
これを使うと、そのスライドは印刷に出ず1、番号の数え上げからも外れます。
残ったページに1から順に番号が振られる2。
配る資料としては、これで正しい形になります。

困るのは再生のほうです。
スキップしたスライドは、スライドショーでも飛ばされます3。
話すために作ったスライドが、話す場面で出てこない。

では、今フッターに出ている番号を、そのまま固定できないか。
そう思って、AIエージェントに頼みました。

2. エージェントは番号欄そのものを書き換えようとした

2. エージェントは番号欄そのものを書き換えようとした

2.1. プレースホルダに数字を流し込む筋

Keynoteのページ番号は、スライドレイアウトに置かれたプレースホルダ(placeholder:場所取り)が表示しています4。
中身は自動で計算される値で、手で書き換える設定はありません。

ところが、AppleScriptから覗くと、この番号欄がただのテキスト項目として見えていました。
入っている文字はU+FFFCという、ここに何かが入ることを表す一文字5。
試しに文字列を代入したら、通ってしまった。

tell application "Keynote"
  tell front document
    tell slide 21
      set object text of text item 1 to "4"
    end tell
  end tell
end tellCode language: AppleScript (applescript)

PDFに書き出して確かめると、座標もフォントも色も元と完全に一致していました。
前にスライドを1枚足しても、番号は4のまま動かない。
狙いどおりです。

そこで、これを70枚に流しました。
スキップしないスライドには通し番号を、スキップしたスライドには空文字を入れる。

repeat with i from 1 to (count of slides)
  tell slide i
    if skipped is false then
      set n to n + 1
      set object text of text item 1 to (n as string)
    else
      set object text of text item 1 to ""
    end if
  end tell
end repeatCode language: AppleScript (applescript)

2.2. テキスト項目の並び順はスライドごとに違った

書き出して検証すると、28枚中26枚は正しく番号が入っていました。
残り2枚がおかしい。
調べたら、そこだけの話ではありませんでした。

text item 1 が番号欄だとは限らなかったんです。
アピアランスの「スライド番号」がオフになっているスライドには、番号欄の項目がそもそも存在しません6。
そういうスライドでは、左上に置いた「説明」「補足」といったラベルが1番目でした。

12枚で、ラベルの文字がページ番号や空文字に置き換わっていました。
「Q3」と書いてあったラベルが「20」になっている。
70枚のうち58枚では当たっていたので、検証の網を通り抜けてしまったわけです。

2.3. バックアップと全文照合で被害を確定させる

幸い、作業前にファイルごと複製してありました。
Keynoteは数分おきに自動保存するので、書類を保存しないで閉じても元には戻りません。
実際、壊したあとにディスク上のファイルを見たら、作業中の版で上書きされていました。

ただ、いきなり複製に戻すのも怖い。
複製を取ったのは作業開始の時点なので、それ以降に私が手を入れていたら、その分が消えます。

そこで、バックアップと現物の両方を開いて、全スライドのテキストを吸い出して突き合わせました7。

tell slide i
  set txts to object text of every text item
  set poss to position of every text item
end tellCode language: AppleScript (applescript)

一項目ずつ問い合わせると70枚で数千回のやり取りになって終わらないので、every text item でまとめて取っています。
最初はこれをやらずに走らせて、2分待っても返ってこずに諦めました。

差分は12枚のラベルだけ。
それ以外の本文はバックアップと完全に一致していました。
戻しても失うものが無いと分かったので、そこで復元しています。

3. 番号欄を捨てたら、ただの文字を置くだけの作業になった

ここで私が出したのが、こういう案です。
全スライドの番号欄をオフにして、スキップしないスライドにだけ、フッターの位置に数字のテキストボックスを置けばいいのではないか。

これが一度で通りました。

3.1. 並び順を仮定せずに番号欄を見つける

やることは二つだけになります。
番号欄を探して消す。
新しいテキストボックスを作って置く8。

番号欄は、中身がU+FFFCかどうかで見分けられます。
位置でも並び順でもなく、中身で探す。

set phChar to character id 65532
set idx to 0
set txts to object text of every text item
repeat with k from 1 to (count of txts)
  if ((item k of txts) as string) is phChar then set idx to k
end repeat
if idx > 0 then delete text item idxCode language: AppleScript (applescript)

これなら、番号欄が無い12枚は素通りします。
実際、70枚のうち削除されたのは58枚でした。
最初の失敗で壊したのは、まさにこの差の12枚だったわけです。

3.2. 色と座標は、元の番号欄から測って写す

書式は、数値で指定するとずれました。
グレーの#535353を16ビットの値に直して渡したのに、書き出すと#666666になる。
Generic RGBからsRGBへのガンマ変換が挟まっていました9。

元の番号欄から読み取った値をそのまま代入したら、一致しました。
フォントとサイズも同じように写しています。

set stdColor to color of object text of text item idx
set t to make new text item with properties {object text:(n as string)}
set color of object text of t to stdColor
set position of t to {(360.65 - ((width of t) / 2)), 504.57}Code language: AppleScript (applescript)

360.65という半端な数字は実測から出ています。
テキストボックスの左上と、実際に描かれる文字の左端は3.6ポイントずれる10。
書き出したPDFから文字の外接矩形を読んで、その分を引いた位置に置いています11。

全部を数値で測ったので、元データのばらつきも見つかりました。
28枚のうち1枚だけ番号がCalibriの12ポイント黒で、もう1枚は他より12ポイント下にありました。
何年か前に自分でいじった跡だと思います。
自動で振られているつもりのものが、実は1枚ずつ動かせる部品だった。

最後の確認は、70枚すべてのスキップを一時的に解除してPDFにしました。
自動採番なら1から70に振り直されるところ、番号は1から28のまま動かない。
説明用の42枚には何も出ない。

これで、スキップは印刷に出すかどうかを決めるだけの役目になりました。
何度切り替えても番号は動かないので、印刷のときだけ説明用を外して、再生のときは全部出す。
最初にやりたかったのは、これだけです。

4. エージェントは指示の内側しか探さない

振り返ると、遠回りを作ったのは私の「そのまま固定したい」という一言でした。

私としては、見た目を変えずに、という意味で言いました。
エージェントはこれを、今そこにある番号欄をそのまま残して固定する、と読んだ。
番号欄に触らずに済ませる道は、最初から探索の外にあったわけです。

人は目的を知っているので、条件は目的に近づくための手段として出します。
エージェントは目的を知らないので、条件のほうを目的として扱う12。
この差が、失敗が続くときの原因になっていることがあります。

だから、二回三回と同じところで転んだら、指示を強めるより先に指示を疑ったほうが早い。
どこが本当の要件で、どこが自分の思い込みか。
代わりの手段を一つ挙げるだけで、探索の形が変わります。

AIは万能ではありません。
というより、こちらが引いた線の内側でしか動けない。
線を引いたのが自分だということを、忘れやすいだけかもしれません。

  1. 印刷や書き出しでスキップしたスライドがどう扱われるかは、Appleのスキップの説明ページには書かれていない。ここは手元でPDFに書き出すと70枚が28ページになった、という観察から書いている。 – Skip or unskip a slide in Keynote on Mac
  2. Appleのヘルプに「Skipped slides aren’t numbered.」とある。番号はスライドの順序を変えると更新される。 – Show or hide slide numbers in Keynote on Mac
  3. Appleは「プレゼンテーション中に再生したくないスライドはスキップできる」と説明している。スキップしたスライドはナビゲータで横線として表示される。 – Skip or unskip a slide in Keynote on Mac
  4. 番号の位置と書式は、スライドレイアウトを編集して変えるとAppleが説明している。 – Show or hide slide numbers in Keynote on Mac
  5. U+FFFC OBJECT REPLACEMENT CHARACTER は、複合文書などで別のオブジェクトの場所取りに使う文字。Unicode 2.1 で追加された。 – U+FFFC OBJECT REPLACEMENT CHARACTER
  6. スライド番号は、ナビゲータでスライドを選んでフォーマットサイドバーのチェックを外せば、そのスライドだけ消せる。 – Show or hide slide numbers in Keynote on Mac
  7. Keynote の slide には skipped というブール値のプロパティがあり、AppleScript から読み書きできる。どのスライドが印刷に出るかを、この値から数え直せる。 – AppleScript and Keynote: Skipping Slides
  8. テキスト項目は、height、width、position といった iWork 共通のプロパティを持つ。作ってから位置と大きさを指定できる。 – AppleScript and Keynote: Text Items
  9. Apple の Generic RGB プロファイルは P22 蛍光体、D65 白色点、ガンマ1.8で作られている。sRGB とはトーンカーブが違う。 – Technical Q&A QA1430: Apple RGB and Generic RGB profiles explained
  10. テキスト項目には文字の配置(alignment)のプロパティがまだ実装されていないので、中央揃えを指定できない。幅を読んでから中央に来る位置を計算しているのはこのため。 – AppleScript and Keynote: Text Items
  11. PyMuPDF は文字のまとまりごとに、外接矩形・フォント名・サイズ・色を返す。色は sRGB の整数で得られるので、元の番号と数値で突き合わせられる。 – TextPage – PyMuPDF documentation
  12. Anthropic は、指示の背景や動機まで伝えると狙いが正しく伝わる、と案内している。前提を知らない新しい同僚に頼むつもりで書け、という説明もある。 – Prompting best practices