はじめに
「現場で活用するためのAIエージェント実践入門」の第2章で私がつまずいたことのメモです。
(このメモのほかの章へ:1章 / 2章 / 3章 / 4章)
第2章 AIエージェントの構成
この章ではAIエージェントの構成を学びます。
2.1 AIエージェントの内部構成
AIエージェントって人間みたいですよね。個性(プロフィール)があり、過去の経験や知見を覚えていて(メモリ)、それらに基づいて行動し(計画、行動、環境への作用)、その結果によって(知覚)次の行動を考えたり見直したり(自己修正)します。AIエージェントとしてこれらをどう組み立てるかは「エンジニアの腕の見せ所」とのことです。
また、LLMに与える環境の質も大切です。複雑すぎたりノイズが混ざっているとLLMが混乱してしまうので、いかに複雑さを抑えるかも「エンジニアの腕の見せ所」とのことです。
腕の見せ所がたくさんあって、エンジニアの仕事はまだまだなくならなさそうです。
2.2 プロフィール
赤い鳥の本1でLLMにペルソナを作らせましたが、この本では実際のアンケート結果をもとに作るアプローチなども紹介されています。
2.3 ツール呼び出し
ツールを使う理由の例として「計算」が説明されていますが、LLMは暗算でツールは電卓というたとえ話はすごくいいですね!私は職業柄、AIに詳しくない方へLLMの特性を説明することが多いので、次から使わせてもらいます![]()
また、ツールをLLMに理解させるための方法として、人間の認知プロセスを参考にするというアプローチが有効であるという話が興味深かったです。手続き記憶(道具の使い方の説明)と宣言的記憶(事実や出来事の説明)の両側面が必要とのこと。言われてみれば当たり前なのですが、この辺を意識するとツール選択の精度を上げられそうです。
2.4 計画(Planning)
少し脱線しますが、AI業界ではMinecraftの話がよく出てきますよね。この本でも「ビデオゲームのMinecraftでのキャラクターの行動計画」や「希少なダイヤモンドを採掘する場合」といった感じで例が出てきます。ただ、残念ながら私は遊んだことがないので例がピンときません(あ、ドラゴンクエストビルダーズは遊んでいたので、なんとなくの想像はできるのですが)。
Minecraftといえば、2023年春にGPT-4(当時は最先端LLM)を使ってゲーム内で試行錯誤しながら成長していく、OpenAIのVoyagerというAIエージェントが話題になりました。
MinecraftはAI研究においてちょうどよい実験環境になっているようなので、AIエージェントを勉強するなら必修科目(?)なのかもしれません。遊んでみたいところですが、時間が溶けそうで怖い……
話を戻します。LLMにとって計画立案はまだまだ難しいタスクで、本でもいろいろなアプローチが紹介されています。その中で興味深かったのは、LLMにPDDL(Planning Domain Definition Language)を書かせて、それを外部のソルバーに解かせて計画を作るというLLM+Pです。私はこの辺りの知識がまったくなかったので軽く調べてみました。
LLM+Pとは
本で紹介されている論文はこちらです。
ざっくりの概要ですが、まず、ユーザーの自然文による入力をLLMに渡してPDDLを出力させます。本で例に挙げられているブロックワールド問題の場合、「AをBの上に、BをCの上に積みたい」みたいな入力からPDDLを生成させる流れになります。
PDDLは1998年に作られたAIプランニングのための言語で、「世界の状態」、「行動の定義」、「初期状態」、「目標状態」を定義するものです。
今回のブロックワールド問題の場合、世界の状態と行動の定義として次のような内容を記述します。
(define (domain blocksworld)
;; ブロックワールド領域の定義
(:requirements :strips)
;; --- 世界の状態を表す述語(Predicates) ---
(:predicates
(on ?x ?y) ;; ブロックxがブロックyの上にある
(ontable ?x) ;; ブロックxがテーブルの上にある
(clear ?x) ;; ブロックxの上に何も乗っていない
(handempty) ;; 手が空である
(holding ?x) ;; 手がブロックxを持っている
)
;; --- 行動(アクション)の定義 ---
;; ① pick-up(ブロックをテーブルから持ち上げる)
;; 前提条件: そのブロックがテーブル上にあり、上が空で、手が空である
;; 結果: そのブロックを手に持ち、テーブルから消え、手が空でなくなる
(:action pick-up
:parameters (?x)
:precondition (and (ontable ?x) (clear ?x) (handempty))
:effect (and (holding ?x)
(not (ontable ?x))
(not (handempty))))
;; ② put-down(持っているブロックをテーブルに置く)
;; 前提条件: 手がそのブロックを持っている
;; 結果: ブロックがテーブル上に戻り、手が空になる
(:action put-down
:parameters (?x)
:precondition (holding ?x)
:effect (and (ontable ?x)
(handempty)
(not (holding ?x))))
;; ③ stack(持っているブロックを別のブロックの上に積む)
;; 前提条件: 手がブロックxを持っていて、ブロックyの上が空である
;; 結果: xがyの上に乗り、xの上は空、手は空、yの上は空でなくなる
(:action stack
:parameters (?x ?y)
:precondition (and (holding ?x) (clear ?y))
:effect (and (on ?x ?y)
(clear ?x)
(handempty)
(not (holding ?x))
(not (clear ?y))))
;; ④ unstack(ブロックを別のブロックの上から取り上げる)
;; 前提条件: xがyの上にあり、xの上が空で、手が空である
;; 結果: xを手に持ち、yの上は空になる
(:action unstack
:parameters (?x ?y)
:precondition (and (on ?x ?y) (clear ?x) (handempty))
:effect (and (holding ?x)
(clear ?y)
(not (on ?x ?y))
(not (handempty))))
)
また、初期状態と目標状態の定義はこんな感じです。
(define (problem stacking-problem)
;; --- 問題ファイルの名前(任意の識別名) ---
;; この問題は「ブロックを積み上げるタスク」です
(:domain blocksworld) ;; 使用するドメイン(=ruleset)は "blocksworld"
;; --- 登場するオブジェクトの定義 ---
;; ここでは3つのブロック A, B, C を使用します
(:objects A B C)
;; --- 初期状態(init)---
;; 世界のスタート時点の状態をすべて列挙します
(:init
(ontable A) ;; A はテーブルの上にある
(ontable B) ;; B もテーブルの上にある
(ontable C) ;; C もテーブルの上にある
(clear A) ;; A の上には何もない
(clear B) ;; B の上にも何もない
(clear C) ;; C の上にも何もない
(handempty) ;; 手は空である
)
;; --- 目標状態(goal)---
;; 達成したい最終状態を論理式で表現します
(:goal
(and
(on A B) ;; A が B の上にある
(on B C) ;; B が C の上にある
)
)
)
このPDDLの生成をLLMに任せたら、Fast Downwardなどのソルバーに渡して計画を得ます。
たとえば次のような計画が得られます。
1. pick-up B
2. stack B C
3. pick-up A
4. stack A B
Bを手に取り、Cの上に置き、Aを手に取り、Bの上に置けば目標状態になるというわけですね。最後にこれを再びLLMに入力して、実際の処理を進める形になります。
LLMに任せるのはPDDLの生成部分や計画ができあがった後の部分で、計画そのものを考えるのは従来からある非LLMのソルバーです。なんでもLLMに任せてしまうと制御や維持が大変になるので、LLM+Pは"餅は餅屋"的な分担がいいですね!
PDDL-Instructとは
調べている途中で興味深い論文を見つけました。こちらはLLMをファインチューニングすることでソルバーも任せようという方向性の、PDDL-Instructという手法です。
この論文についてはらみさんの解説がすごくわかりやすかったので、ご興味のある方はぜひこちらをご参照ください。
本の話に戻りますが、本に書かれているようにo1-previewのような大規模推論モデル(Large Reasoning Model、LRM)では、計画の精度が大きく向上したという検証結果もあります。計画立案については、まだまだいろいろなアプローチが考案されそうです。
2.5 自己修正(Self-Correction)
自己修正のうちの内省(Reflection)については赤い鳥の本1で実際に動かしましたが、他にもいろいろなアプローチが解説されています。
その中の自己一貫性(Self-Consistency)の説明だけ、「もっとも一貫した回答を評価する」という部分の意味が最初はよくわからなかったのですが、これはモデルや温度などを変えて複数の回答を生成させて、そこから多数決で回答を選ぶことで誤りを除外し、結果として修正と同じような効果を得るアプローチということですね。
実装上で気をつけることに書かれている「いつ自己修正するといいのか」については、基準が用意できるポイントや責務を超えないポイントでの実施がお勧めとのことです。昔ながらの単体テストで品質を作り込んでいくという話と近い要素がありますね。
2.6 メモリ(Memory)
少し脱線しますが、対話履歴のところでWebブラウザ版ChatGPTのメモリ機能の話がでてきたので、手元のWebブラウザ版ChatGPTで何が記憶されているのか試してみました。「私について何を覚えている?」と質問すれば答えてくれます。なお、私はProプランの契約ですが、プランによって少し違うかもしれません。
多少間違っている部分もありますが、ざっくり合っていました。
ただ、保存されたメモリを表示(パーソナライズ > メモリ > 管理する)しても中は空っぽです。
ここには自動的に記録されていくのですが、私は不要な内容が記録されていた時に手動で削除していて、現時点では特に記憶して欲しいものがない状態です。そのため、「私について何を覚えている?」で答えてくれている内容は、このメモリ機能の部分ではなく別の見えないところにあります。
この見えない記憶はプロジェクト2内の対話履歴の内容が基本なのですが、対話履歴に残したまま記憶からの削除を指示することができます。「私について何を覚えている?」の最後に尋ねられるので、そこで指定すれば見えない記憶から削除できます。
できれば以前のようにメモリ管理の機能を使って人間側で要・不要をきっちり制御したいところなのですが、LLMとの連携が密になってきて、記憶の内容を人間が見てわかる形で列挙することが難しくなっているのかもしれません。
ChatGPTから本の話へ戻りますが、実装上で気をつけることに書かれている、経験を抽象化する話がとても興味深いです。経験が具体的すぎると再利用性が下がるので抽象化しないといけないのですが、そのさじ加減が難しいですよね。これについては第9章に出てくるとのことで楽しみです。
2.7 シングルエージェントワークフロー
「エージェントワークフロー」の言葉の定義がややこしいのですが、columnにあるように「AIワークフロー」は事前に決まったフローを処理していくもので、そこに環境との相互作用や計画・自己修正などの要素が加わってくると「エージェントワークフロー」と呼ばれることが多いそうです。
そもそもの「AI」や「DX」もそうなのですが、明確な定義のない言葉がバズってしまうと詳しくない方が混乱してしまうので、なんとかして欲しいものです。
2.8 マルチエージェントワークフロー
シングルエージェントとマルチエージェントの用語の境界もややこしいですね。人間に置き換えてみたときに、きっちり段取り組んで進めれば1人でできそうな課題がシングルエージェントワークフロー向き、複数人で分担しないと無理そうなことがマルチエージェントワークフロー向き、くらいの判断が良さそうでしょうか。
なお、実装上で気をつけることに書かれている、どれだけ相手を思いやれるのか、の部分は具体的なイメージが湧きませんでした。これは、システムプロンプトの調整やどこまでコンテキストを共有すべきか、みたいなお話になるのでしょうか。詳細はこの後に出てくるかもしれません。
2.9 まとめ
この第2章はとにかく情報量が多くて、なんと60本近くもの論文が紹介されていました。もう少し個々の論文の概要があるとうれしかったのですが、そんなことしたら何ページあっても足りないでしょうし、ChatGPTに聞けば概要はすぐにわかるので、時代に合った書籍のスタイルなのかもしれません。
ただ、論文のURLを手入力するのが面倒なんですよね。本のGitHubリポジトリに脚注のURL一覧があるかも!と思って見に行ったのですが、残念ながらありませんでした。この点はKindle版のほうがよいかもしれません。
次回はいよいよAIエージェントの実装です。
(このメモのほかの章へ:1章 / 2章 / 3章 / 4章)
-
有料プランでは、「プロジェクト」を作ることで対話履歴や見えない記憶を分離できます。たとえば業務に関する質問とプライベートに関する質問は、プロジェクトを分けておいた方が見えない記憶を有効活用できそうです。 ↩



