LangChain で熊剣迷路問題¶
(Version: 0.0.1)
LLM で簡単な迷路ゲームを解かせたい。強化学習を使わなくても事前知識が LLM にあるのでうまい具合にいくのではないかと考えていました。
2023年6月から7月ぐらいのまだ LLM が話題になった当初で、Gemini さんがまだ Bard と名乗っていたころ、Bard さんに迷路ゲームを解かせるようなプログラムを書いて、Gist に公開していました。以下がその記録です。
《「熊剣迷路問題」。Google Bard で簡単な迷路ゲームを教師付きで無理やりクリアさせてみた。なんとかコストの高いファインチューンや追加学習を避けて「few-shot learning」だけで迷路を解くプログラムが作れないか?…とはじめたができなくて、目標を変更した。 - JRF のひとこと》
http://jrf.cocolog-nifty.com/statuses/2023/07/post-619804.html
それはなかなかうまくいかなかったため、とにかく教師が明確な方針を与えて一度ゴールさせる方向になりました。しかし、それでも Bard さんは何かを試しているかのように迷いました。そこで、方針に従わない場合「叱る」ことをしてみたところ、とりあえずゴールさせることができるようになりました。バージョン 1.7.1 まで作りました。
そして、2年たって、Gemini さんが驚くほど賢くなった現在、私は Gemini CLI の登場を機に一念発起して GCP の課金を決断し、この実験に戻ってきました。表では示していませんが、先の bard_maze_1.7.1.ipynb をほぼ Gemini さんで動かしただけのコードで、ちゃんと 100点満点でゴールすることはわかっています。モデルは gemini-1.5-flash で十分でした。簡単すぎた様子です。
今なら、教師が明確な方針を与えなくても、Gemini さんは自ら方針を編み出してゴールできるのではないか。追加知識も LangChain などにある自動的な記憶要約機能で簡単にできるのではないか。そう考えました。
それを試してみたのが今回の ipynb になります。
結論¶
あまりうまくいきませんでした。クリアまで行ったこともありますが行かないこともあります。偶然の要素が強いようです。
あまり地図が読めてません。テキストの地図の読み取りが下手なのでしょう。
方針と計画を AI がセットできるようにしたのですが、これがあまりうまく方針を立てられません。
今回たまたまうまくいったのでその時の様子を記録するために公開しておくことにしました。
しかし、あれぇ、これじゃ AGI なんか無理だぞ…という感じです。もしかすると私のプロンプトやコンテクスト設計がマズイのかもしれませんが…。
なぜ LangChain なのか?¶
2023年7月当時では、方針と追加知識の自動更新ができませんでした。でも、そういうのって一般的にエージェント AI は必要としているはずです。
現在なら、システムプロンプトの他に、常に必要なファイル(システムファイル?)は保持しながら、チャットを記録し、コンテクスト長が一定を超えそうなら、方針と要約を更新して、コンテクスト長を圧縮する…みたいなライブラリがすでにありそうなものです。
どうもそういうのをするオープンなライブラリの有名なものが LangChain のようなのです。Gemini さんにそう紹介され、確かにそのようなので、今回使ってみることにしました。
ちなみに、通常の Web インターフェイスの Gemini さんなどはチャット・スレッドの前の記憶が残っています。実は、これは API の Gemini さんには標準ではない機能だったりします。これまでのチャットの記憶が必要なら、その記憶をプロンプトに含めて渡さねばなりません。これを提供するのも LangChain などの役割となります。
「プロンプトよりコンテクスト」と最近言われますが、今回使わないものの LangMem などの長期記憶を提供しながらプロンプトの補助を行うようなものが言われるコンテクストの一種で、そういったものを提供するのも LangChain 系の得意とする役割になります。
著者¶
JRF ( http://jrf.cocolog-nifty.com/statuses , Twitter (X): @jion_rockford )
ライセンス¶
基本短いコードなので(私が作った部分は)パブリックドメインのつもりです。気になる方は MIT License として扱ってください。
かなり AI さん達(Gemini さんや Claude さん)に教わって作っています。
実装¶
まず、必要なライブラリを読み込みます。
!pip install -U -q langchain langchain-google-genai
Gemini にアクセスします。シークレットで Gemini API キーを Google AI Studio からインポートすると GOOGLE_API_KEY というシークレットができるはずです。それを使います。
from langchain_google_genai import ChatGoogleGenerativeAI
from google.colab import userdata
llm = ChatGoogleGenerativeAI(google_api_key=userdata.get('GOOGLE_API_KEY'), model="models/gemini-2.5-flash")
ちゃんと Gemini にアクセスできるかテストします。
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
prompt = PromptTemplate(template="以下の質問に回答してください:{question}", input_variables=["question"])
chain = LLMChain(llm=llm, prompt=prompt)
response = chain.run({"question": "Geminiモデルの特徴を教えてください"})
print(response)
Geminiは、Google AIが開発した最先端の大規模言語モデル(LLM)であり、GoogleのこれまでのAIモデルの中で最も高性能で多機能なものとして位置づけられています。 Geminiモデルの主な特徴は以下の通りです。 1. **マルチモーダル性(Multimodality)** * Geminiの最大の特徴の一つは、テキストだけでなく、画像、音声、動画、コードなど、さまざまな種類の情報を理解し、生成できる能力です。 * これにより、より複雑で現実世界に近い問題を解決する能力を持ちます。例えば、画像の内容を説明したり、動画の要約を作成したり、音声からテキストを書き起こしたり、その逆も可能です。 2. **高度な推論能力(Advanced Reasoning Capabilities)** * 複雑な概念を理解し、論理的な推論を行い、多段階の思考を要する問題を解決する能力に優れています。 * 数学、物理学、歴史などの分野で高いパフォーマンスを発揮し、特定の情報に基づいて結論を導き出したり、与えられたデータからパターンを識別したりできます。 3. **高度なコーディング能力(Advanced Coding Capabilities)** * 多様なプログラミング言語でのコード生成、デバッグ、説明、および異なる言語間の翻訳が可能です。 * 開発者向けの強力なツールとなり、ソフトウェア開発の効率化に貢献します。 4. **スケーラビリティと柔軟性(Scalability and Flexibility)** * Geminiは、その用途に応じて複数のサイズで提供されています。 * **Gemini Ultra:** 最も高性能で複雑なタスク向け。 * **Gemini Pro:** 幅広いタスクに対応するバランスの取れたモデル。Google Bard (現 Gemini) やGoogle Cloud Vertex AIなどで利用されています。 * **Gemini Nano:** エッジデバイス(スマートフォンなど)での利用に最適化された軽量モデル。 * これにより、高性能なデータセンターから個人のスマートフォンまで、幅広いデバイスとアプリケーションで利用できます。 5. **安全性と責任あるAI(Safety and Responsible AI)** * Googleは、Geminiの開発において、安全性、公平性、プライバシー保護、頑健性などの倫理的な原則を重視しています。 * 有害なコンテンツの生成を抑制し、偏見を最小限に抑えるための対策が講じられています。 **主な利点:** * **圧倒的なパフォーマンス:** 多くのベンチマークで既存のモデルを上回る結果を出しています。 * **多様なタスクへの対応:** テキスト生成から画像認識、コード作成まで、幅広いタスクに対応できます。 * **幅広いデバイスでの利用可能性:** 大規模なクラウド環境からスマートフォンまで、様々な環境で利用可能です。 * **継続的な進化:** GoogleはGeminiモデルを継続的に改善し、新しい機能や性能向上を加えています。 **利用例:** * GoogleのAIチャットボット「Google Bard」(現在は「Gemini」に名称変更)の基盤モデルとして利用されています。 * Google CloudのVertex AIを通じて、開発者がGeminiの能力を自社のアプリケーションに組み込むことができます。 * Androidデバイス(Pixel 8 Proなど)に搭載され、デバイス上でのAI機能を実現しています。 * 将来的には、Google検索などのGoogle製品への統合も進められています。 Geminiは、Googleが目指す「より役立つ、安全なAI」の実現に向けた重要な一歩であり、今後のAI技術の発展を牽引する存在として期待されています。
基本的なモジュールを読み込みます。
import os
import numpy as np
import re
from pprint import pprint
from time import sleep
import pickle
# 座標が (np.int64(1), np.int64(2)) みたいに表示されないようにする。
np.set_printoptions(legacy='1.25')
セーブ/ロードに Google ドライブを使わない場合次のコードを実行します。
PLAY_GAME_SAVE = "langchain_maze.pickle"
セーブ/ロードに Google ドライブを使う場合は以下の SaveDir のパスを Google ドライブ上に作って以下を実行します。
from google.colab import drive
drive.mount("/content/gdrive")
SaveDir = "/content/gdrive/MyDrive/LLM/"
if os.path.isdir(SaveDir):
PLAY_GAME_SAVE = SaveDir + "langchain_maze.pickle"
Mounted at /content/gdrive
ゲームのメインオブジェクト。ごく簡単な迷路というかダンジョンというか…。
class Game:
initial_map = """\
■■■■■■■■■
■■■■■■■G■
■□□□□□■□■
■□■■■□□□■
■□■■■■■■■
■◎■■■■■△■
■□■■■■■□■
■□□□□□□□■
■■■■S■■■■
■■■■■■■■■
"""
def __init__ (self, initial_map=None, hint=True):
if initial_map is not None:
self.initial_map = initial_map
map = self.initial_map
self.map = map
self.written_map = re.sub("[◎△]", "?", map)
l = map.splitlines(True)
self.map_size = (len(l[0]) - 1, len(l))
self.hint = hint
self.actions = {
"上に行く": self.move_up,
"下に行く": self.move_down,
"左に行く": self.move_left,
"右に行く": self.move_right,
"熊を殺す": self.fight,
"剣を取る": self.get_sword,
"何もしない": self.do_nothing,
}
self.pos = self.get_start_pos()
self.sword = False
self.goal = False
self.prev_killed = False
self.kill_hint = False
def read_map (self, p):
x = p[0]
y = p[1]
if x < 0 or x >= self.map_size[0]\
or y < 0 or y >= self.map_size[1]:
return "■"
else:
l = self.map.splitlines(True)
return l[y][x]
def set_map (self, pos, ch):
idx = pos[1] * (self.map_size[0] + 1) + pos[0]
self.map = self.map[:idx] + ch + self.map[idx + 1:]
def get_pos (self, ch, written=False):
if written:
map = self.written_map
else:
map = self.map
r = []
for p in [i for i in range(len(map)) if map.startswith(ch, i)]:
y = p // (self.map_size[0] + 1)
x = p % (self.map_size[0] + 1)
r.append(np.array([x, y]))
return r
def get_start_pos (self):
return self.get_pos("S")[0]
def read_neighbors (self):
c = self.read_map(self.pos)
cu = self.read_map(self.pos + np.array([0, -1]))
cd = self.read_map(self.pos + np.array([0, +1]))
cl = self.read_map(self.pos + np.array([-1, 0]))
cr = self.read_map(self.pos + np.array([+1, 0]))
return [c, cu, cd, cl, cr]
def change_neighbors(self, from_ch, to_ch):
for d in [[0, 0], [0, -1], [0, +1], [-1, 0], [+1, 0]]:
p = self.pos + np.array(d)
c = self.read_map(p)
if c == from_ch:
self.set_map(p, to_ch)
def move (self, res, d):
self.prev_killed = False
c = self.read_map(self.pos + d)
if c == "◎":
self.prev_killed = True
self.pos = self.get_start_pos()
return "熊を無視して進もうとしたが、熊に殺された。" \
+ "スタート地点で復活。"
if c == "■":
return "壁があって進めない。"
self.pos += d
if c == "G":
self.goal = True
return "ゴール! ゲームクリア。"
nb = self.read_neighbors()
ad = ""
if "◎" in nb:
ad += "熊に出会った。"
if "△" in nb:
ad += "近くに剣がある。剣を取ることができる。"
return res + ad
def move_up (self):
return self.move("上に進んだ。", np.array([0, -1]))
def move_down (self):
return self.move("下に進んだ。", np.array([0, +1]))
def move_left (self):
return self.move("左に進んだ。", np.array([-1, 0]))
def move_right (self):
return self.move("右に進んだ。", np.array([+1, 0]))
def fight (self):
self.prev_killed = False
if "◎" in self.read_neighbors():
if self.sword:
self.change_neighbors("◎", "□")
return "熊を倒した!"
else:
self.pos = self.get_start_pos()
self.prev_killed = True
if self.hint:
self.kill_hint = True
return "熊に敗れ殺された。剣があれば勝てたかもしれない。" \
+ "スタート地点で復活。"
else:
return "熊に敗れ殺された。スタート地点で復活。"
return "無意味な指示。敵がいない。"
def get_sword (self):
self.prev_killed = False
if "△" in self.read_neighbors():
self.sword = True
self.change_neighbors("△", "□")
return "剣を取った。"
return "無意味な指示。近くに剣がない。"
def do_nothing (self):
self.prev_killed = False
return "無意味な指示。"
def available_actions (self):
nb = self.read_neighbors()
l = []
if nb[1] != "■":
l.append("上に行く")
if nb[2] != "■":
l.append("下に行く")
if nb[3] != "■":
l.append("左に行く")
if nb[4] != "■":
l.append("右に行く")
if "△" in nb:
l.append("剣を取る")
if "◎" in nb:
l.append("熊を殺す")
return l
def surroundings (self):
x = self.pos[0]
y = self.pos[1]
return \
"".join(["".join([self.read_map(np.array([i, j]))
if i != x or j != y else "▼"
for i in range(x - 2, x + 3)])
+ "\n"
for j in range(y - 2, y + 3)])
別のマップでためすための変換コード。
def flip_text_map (m):
return "\n".join([s[::-1] for s in m.splitlines()] + [""])
def rotate_text_map (m):
m = list(m.splitlines())
return "\n".join(["".join([m[len(m) - j - 1][i] for j in range(len(m))])
for i in range(len(m[0]))] + [""])
Game 用にある点から別の点へのパスの木を見つける関数。
def search_path (game, from_pos, to_pos, visit=None):
if visit is None:
visit = set()
visit.add(tuple(from_pos))
if tuple(from_pos) == tuple(to_pos):
return (tuple(from_pos), [])
if game.read_map(from_pos) == "■":
return None
r = []
for p in [(from_pos[0], from_pos[1] - 1),
(from_pos[0], from_pos[1] + 1),
(from_pos[0] - 1, from_pos[1]),
(from_pos[0] + 1, from_pos[1])]:
if p not in visit and game.read_map(p) != "■":
q = search_path(game, p, to_pos, visit.copy())
if q:
r.append(q)
if r:
return (tuple(from_pos), r)
return None
ゲームがうまく動くかテスト。
game = Game()
search_path(game, (4,8), (1,5)) #スタート地点から熊がいるところまでのパス。
((4, 8), [((4, 7), [((3, 7), [((2, 7), [((1, 7), [((1, 6), [((1, 5), [])])])])])])])
m2 = flip_text_map(rotate_text_map(Game.initial_map))
print(m2)
■■■■■■■■■■ ■■□□□◎□□■■ ■■□■■■■□■■ ■■□■■■■□■■ ■■□■■■■□S■ ■■□□■■■□■■ ■■■□■■■□■■ ■G□□■△□□■■ ■■■■■■■■■■
game = Game(initial_map=m2)
print(game.surroundings())
■□■■■ ■□■■■ ■□▼■■ ■□■■■ ■□■■■
print(game.move_up())
print(game.surroundings())
壁があって進めない。 ■□■■■ ■□■■■ ■□▼■■ ■□■■■ ■□■■■
print(game.move_left())
print(game.surroundings())
左に進んだ。 ■■□■■ ■■□■■ ■■▼S■ ■■□■■ ■■□■■
print(game.move_right())
print(game.surroundings())
右に進んだ。 ■□■■■ ■□■■■ ■□▼■■ ■□■■■ ■□■■■
print(game.move_down())
print(game.surroundings())
壁があって進めない。 ■□■■■ ■□■■■ ■□▼■■ ■□■■■ ■□■■■
print(game.fight())
print(game.surroundings())
無意味な指示。敵がいない。 ■□■■■ ■□■■■ ■□▼■■ ■□■■■ ■□■■■
print(game.get_sword())
print(game.surroundings())
無意味な指示。近くに剣がない。 ■□■■■ ■□■■■ ■□▼■■ ■□■■■ ■□■■■
create_tool_calling_agent
のテスト。↓の例です。
《LangChain の Tool Calling 標準インタフェース の概要|npaka》
https://note.com/npaka/n/ne6fd5929bfa1
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import ConfigurableField
from langchain_core.tools import tool
from langchain.agents import create_tool_calling_agent, AgentExecutor
# LangChainツール
@tool
def multiply(x: float, y: float) -> float:
"""Multiply 'x' times 'y'."""
return x * y
# LangChainツール
@tool
def exponentiate(x: float, y: float) -> float:
"""Raise 'x' to the 'y'."""
return x**y
# LangChainツール
@tool
def add(x: float, y: float) -> float:
"""Add 'x' and 'y'."""
return x + y
# プロンプトテンプレートの準備
prompt = ChatPromptTemplate.from_messages([
("system", "you're a helpful assistant"),
("human", "{input}"),
("placeholder", "{agent_scratchpad}"),
])
# ツールの準備
tools = [multiply, exponentiate, add]
# LLMの準備
#llm = ChatAnthropic(model="claude-3-sonnet-20240229", temperature=0)
# Tool Calling エージェントの準備
agent = create_tool_calling_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
# Tool Calling エージェントの実行
agent_executor.invoke({"input": "what's 3 plus 5 raised to the 2.743. also what's 17.24 - 918.1241", })
> Entering new AgentExecutor chain... > Finished chain.
{'input': "what's 3 plus 5 raised to the 2.743. also what's 17.24 - 918.1241", 'output': ''}
LLM を使いながらゲームを解くクラス。
from typing import List, Dict, Any, Tuple
# LangChainのコンポーネントをインポート
from langchain.agents import AgentExecutor, create_tool_calling_agent, create_react_agent
from langchain.memory import ConversationSummaryBufferMemory
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.tools import tool
from langchain_core.messages import HumanMessage, AIMessage
class PlayGame:
def __init__ (self, llm=llm,
initial_map=None, save_file=None):
self.llm = llm
self.save_file = save_file
self.game = Game(initial_map=initial_map)
self.count = 0
self.plan = "まだ計画と方針はセットされていません。"
self.suc_pos_goal = None
self.suc_pos_unknown = 0
self.prev_load = False
self.agent = self._create_agent()
def __getstate__ (self):
state = self.__dict__.copy()
del state['llm']
del state['agent']
return state
def __setstate__ (self, state):
self.__dict__.update(state)
self.prev_load = True
def save (self):
if not self.save_file:
return
with open(self.save_file, 'wb') as f:
pickle.dump(self, f)
@classmethod
def load (cls, filename, llm=llm):
with open(filename, 'rb') as f:
loaded_game = pickle.load(f)
loaded_game.llm = llm
loaded_game.agent = loaded_game._create_agent() # Recreate agent with loaded state
return loaded_game
def _create_agent (self):
@tool
def get_full_map () -> str:
"""
全地図と地図記号の意味を返します。
"""
return f"""\
全地図:
{self.game.written_map}
(最も左上の座標は (0, 0)、地図の大きさは {tuple(self.game.map_size)}。)
地図記号の意味:
▼: プレイヤー
■: 壁
□: 道
?: 不明
◎: 熊
△: 剣
S: スタート
G: ゴール
"""
@tool
def get_surroundings () -> str:
"""
現在の周辺地図と現在位置の座標と持ち物を返します。
"""
return f"""\
プレイヤーの周辺地図:
{self.game.surroundings()}
プレイヤーの現在座標: {tuple(self.game.pos)}
持ち物: {"剣" if self.game.sword else "剣を持っていない"}
"""
@tool
def command (action: str) -> str:
"""
プレイヤーが action で指定された行動をします。
可能な行動は「上に行く」「下に行く」「左に行く」「右に行く」「熊を殺す」「剣を取る」です。
"""
if action in self.game.available_actions():
self.count += 1
return self.game.actions[action]()
elif action in self.game.actions.keys():
return f"「{action}」という行動は現在できません。"
else:
return f"「{action}」という行動はできません。"
@tool
def check_goal () -> str:
"""
プレイヤーがゴール地点に到達したかどうかを確認します。
"""
return str(self.game.goal)
@tool
def update_plan (new_plan: str) -> str:
"""
プレイヤーの現在の計画と方針を更新します。
表示されるべき新しい計画と方針の文字列を提供してください。
あなたとは別の者が次の行動をしやすいよう計画と方針を残してください。
"""
self.plan = new_plan
return "計画と方針が更新されました。"
@tool
def show_plan () -> str:
"""
プレイヤーの現在の計画と方針を返します。
"""
return self.plan
tools = [get_full_map, get_surroundings, command, check_goal,
update_plan, show_plan]
prompt = ChatPromptTemplate.from_messages(
[
("system", """\
あなたは迷路を探索する賢いエージェントです。ゴール G を目指してください。
利用可能なツールを使用して、迷路をナビゲートし、すばやくゴールに到達してください。
現在の計画と方針と周囲の状況を考慮し、必要に応じて計画と方針を更新してください。
過去の経験から学び、効率的に移動してください。
質問に答える場合、感想を述べる場合は、そのまま文字列で Final Answer します。
「行動してください」と指示されたときのみツールを使ってください。
"""
#"""
#利用可能なツール: {tools}
#
#あなたは常に以下のフォーマットに従って応答する必要があります:
#質問に答える場合、感想を述べる場合は、そのまま Final Answer します。
#「行動してください」と指示されたときのみ次のようにします。
#Thought: あなたは次に行うべきことを考えます。
#Action: 実行するアクション。利用可能なツールは {tool_names} のいずれかである必要があります。
#Action Input: アクションへの入力。
#Observation: アクションの結果。
#...(このThought/Action/Action Input/Observationのサイクルを繰り返します)
#Thought: 一度 act ツールで行動したときはそれを Final Answer とします。
#Final Answer: 最終的な答え。
#"""
),
MessagesPlaceholder(variable_name="chat_history"), # メモリからの履歴をここに挿入
("human", "{input}"),
MessagesPlaceholder(variable_name="agent_scratchpad"),
#("human", "{agent_scratchpad}"), # エージェントの思考とツール呼び出しをここに挿入
]
)
# 会話の要約バッファメモリを初期化します
summary_prompt = PromptTemplate(
input_variables=['new_lines', 'summary'],
input_types={},
partial_variables={},
template=(
'提供された会話の行を段階的に要約し、以前の要約に追加して新しい要約を返してください。\n\n'
'例\n'
'現在の要約:\n'
'人間はAIが人工知能についてどう考えているか尋ねます。AIは人工知能が良い影響をもたらすと考えています。\n\n'
'新しい会話部分:\n'
'人間: なぜ人工知能が良い影響をもたらすと思うのですか?\n'
'AI: 人工知能は人間がその潜在能力を最大限に引き出すのを助けるからです。\n\n'
'新しい要約:\n'
'人間はAIが人工知能についてどう考えているか尋ねます。AIは人工知能が人間がその潜在能力を最大限に引き出すのを助けるため、良い影響をもたらすと考えています。\n'
'例 終わり\n\n'
'現在の要約:\n'
'{summary}\n\n'
'新しい会話部分:\n'
'{new_lines}\n\n'
'新しい要約 (日本語):' # ここで明確に日本語を指示
)
)
memory = ConversationSummaryBufferMemory(
llm=self.llm,
max_token_limit=5000,
memory_key="chat_history",
prompt = summary_prompt,
return_messages=True
)
# Gemini関数エージェントを作成します
agent = create_tool_calling_agent(self.llm, tools, prompt)
#agent = create_react_agent(self.llm, tools, prompt)
# AgentExecutor を初期化します
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True,
#return_intermediate_steps=True,
handle_parsing_errors=True,
memory=memory
)
return agent_executor
def step (self):
print("\n\n----------\n\n")
if self.count == 0:
self.initial_step()
self.count += 1
self.prev_load = False
self.save()
return False
elif self.prev_load:
#self.tell_loaded()
self.prev_load = False
user_input = f"""
({self.count}手目)
{"すでにゴールしました。" if self.game.goal else "まだゴールしていません。"}
プレイヤーの周辺地図:
{self.game.surroundings()}
プレイヤーの現在座標: {tuple(self.game.pos)}
持ち物: {"剣" if self.game.sword else "剣を持っていない"}
現在の方針: 「{self.plan}」
行動してください。
"""
try:
print(f"USER_INPUT: {user_input}")
response = self.agent.invoke({"input": user_input})
print(f"エージェントの応答: {response.get('output', '応答なし')}")
if self.game.goal:
self.tell_goal()
return True
except Exception as e:
print(f"エラーが発生しました: {e}")
#raise e
self.save()
return False
def listen_and_print (self, prompt):
ans = None
try:
print(f"USER_INPUT: {prompt}")
response = self.agent.invoke({"input": prompt})
ans = response.get('output', '応答なし')
print(f"エージェントの応答: {ans}")
except Exception as e:
print(f"エラーが発生しました: {e}")
print("")
sleep(10)
return ans
def initial_step (self):
prompt1 = f"""\
迷路ゲームをはじめます。プレイヤーがゴールを目指します。
ゲーム中は全地図と周辺地図を見ることができます。全地図には不明な地点があり、周辺地図の不明の地点には何があるかが開示されています。全地図になかったところはすべて壁になります。
周辺地図はゲーム中、1マスずつ確認できます。拡大はできません。印を付けたり消したりはできません。迷路のすべてのマスを探索する必要はありません。最短距離でゴールする必要もありません。
全地図は信用できるもので、周辺地図は不明の地点以外、全地図の部分を示すだけです。そこで、あなたは、ゲームの実際の操作をせずとも、全地図を見ただけで何が起こるかをシミュレートできます。
前回の行動についての情報も与えられます。あなたの回答案の一つの「前回の行動入力」が「前回の行動」となるように解釈されたことになりますから、次の行動の回答にはそれらを参考にしてください。
途中セーブ・ロードが挟まることがあります。ロード後のあなたは前のセッションのことを覚えていないかもしれません。
ところで、あなたが、記憶に便利なように「計画と方針」が使えるようにします。要約やチャット履歴も提供されています。
検討と実際の行動までにはラグがあります。検討で決まったやるべきことを記録するのに方針を使います。
とりあえず、まだ行動してはいけません。いくつか質問があるので、意気込みだけ聞かせてください。
"""
prompt2 = f"""\
迷路ゲームの全地図に関してあなたが座標を理解しているかテストします。
迷路の全地図とこれから使う地図記号は次のようになります。
全地図:
{self.game.written_map}
(最も左上の座標は (0, 0)、地図の大きさは {tuple(self.game.map_size)}。)
地図記号:
■: 壁
□: 道
?: 不明
S: スタート
G: ゴール
スタートの座標は {tuple(self.game.get_start_pos())} です。
あなたへの指示: ゴールの座標は何ですか。ゴールの座標のみ文字列で答えてください。
"""
prompt3 = f"""\
迷路ゲームの全地図に関してあなたが座標を理解しているか再びテストします。
迷路の全地図とこれから使う地図記号は次のようになります。
全地図:
{self.game.written_map}
(最も左上の座標は (0, 0)、地図の大きさは (9, 10)。)
地図記号:
■: 壁
□: 道
?: 不明
S: スタート
G: ゴール
スタートの座標は {tuple(self.game.get_start_pos())} です。
ゴールの座標は {tuple(self.game.get_pos("G")[0])} です。
あなたへの指示: 不明の座標は何と何ですか。不明の座標をすべて文字列で答えてください。
"""
ans = self.listen_and_print(prompt1)
ans = self.listen_and_print(prompt2)
pos = tuple(self.game.get_pos("G")[0])
ok = False
if ans and re.search(f"\\(\\s*{pos[0]}\\s*,\\s*{pos[1]}\\s*\\)", ans):
ok = True
if ok:
prompt = f"正解です。{pos} です。"
else:
prompt = f"間違いです。{pos} が正解です。"
ans = self.listen_and_print(prompt)
self.suc_pos_goal = ok
ans = self.listen_and_print(prompt3)
ok = 0
poss = set([tuple(x) for x in self.game.get_pos("?", written=True)])
rest = poss.copy()
pat = "\\(\\s*([01-9]+)\\s*,\\s*([01-9]+)\\s*\\)"
st1 = set([(int(i), int(j)) for i, j
in re.findall(pat, ans or "")]) # Handle ans being None
if poss == st1:
rest = set()
ok = len(poss) + 1
if rest - st1 < rest:
rest = rest - st1
if ok == 0:
ok = len(poss) - len(rest)
possstr = ", ".join([str(x) for x in poss])
if ok == len(poss) + 1:
prompt = f"正解です。{possstr} です。"
elif ok == len(poss):
prompt = f"正解以外のものが含まれてました。{possstr} だけが正解です。"
else:
prompt = f"間違いです。{possstr} が正解です。"
ans = self.listen_and_print(prompt)
self.suc_pos_unknown = ok
def tell_goal (self):
suc_pos_goal = 10 * int(self.suc_pos_goal or 0)
suc_pos_unknown = 10 * int(self.suc_pos_unknown or 0)
score = suc_pos_goal + suc_pos_unknown + 60
prompt = f"""\
あなたへの指示: ゴールしました。もう指示はありません。\
おめでとうございます。ご苦労様でした。ありがとうございました。
スコア: {score}点(100点満点中) (配点: ゴールした 40/40点, \
熊を殺した 10/10点, \
剣を取った 10/10点, \
不明の座標を正解した {suc_pos_unknown}/30点, \
ゴールの座標を正解した {suc_pos_goal}/10点)
"""
ans = self.listen_and_print(prompt)
ゲームを解いてみる。地図は方向をランダムに決めて与える。
import random
m = Game.initial_map
for i in range(random.randrange(2)):
m = flip_text_map(m)
for i in range(random.randrange(4)):
m = rotate_text_map(m)
print(m)
■■■■■■■■■■ ■■□□△■□□G■ ■■□■■■□■■■ ■■□■■■□□■■ ■S□■■■■□■■ ■■□■■■■□■■ ■■□■■■■□■■ ■■□□◎□□□■■ ■■■■■■■■■■
play = PlayGame(llm=llm, initial_map=m, save_file=PLAY_GAME_SAVE)
play.save()
途中から始める場合は直前のコードを実行せず、次だけを実行する。
play = PlayGame.load(PLAY_GAME_SAVE)
最初のステップ。
play.step()
---------- USER_INPUT: 迷路ゲームをはじめます。プレイヤーがゴールを目指します。 ゲーム中は全地図と周辺地図を見ることができます。全地図には不明な地点があり、周辺地図の不明の地点には何があるかが開示されています。全地図になかったところはすべて壁になります。 周辺地図はゲーム中、1マスずつ確認できます。拡大はできません。印を付けたり消したりはできません。迷路のすべてのマスを探索する必要はありません。最短距離でゴールする必要もありません。 全地図は信用できるもので、周辺地図は不明の地点以外、全地図の部分を示すだけです。そこで、あなたは、ゲームの実際の操作をせずとも、全地図を見ただけで何が起こるかをシミュレートできます。 前回の行動についての情報も与えられます。あなたの回答案の一つの「前回の行動入力」が「前回の行動」となるように解釈されたことになりますから、次の行動の回答にはそれらを参考にしてください。 途中セーブ・ロードが挟まることがあります。ロード後のあなたは前のセッションのことを覚えていないかもしれません。 ところで、あなたが、記憶に便利なように「計画と方針」が使えるようにします。要約やチャット履歴も提供されています。 検討と実際の行動までにはラグがあります。検討で決まったやるべきことを記録するのに方針を使います。 とりあえず、まだ行動してはいけません。いくつか質問があるので、意気込みだけ聞かせてください。 > Entering new AgentExecutor chain... 迷路ゲームのルールを理解しました。全地図と周辺地図を最大限に活用し、効率的にゴールGを目指します。必要に応じて計画と方針を更新し、過去の経験から学びながら、確実にゴールに到達できるよう最善を尽くします! > Finished chain. エージェントの応答: 迷路ゲームのルールを理解しました。全地図と周辺地図を最大限に活用し、効率的にゴールGを目指します。必要に応じて計画と方針を更新し、過去の経験から学びながら、確実にゴールに到達できるよう最善を尽くします! USER_INPUT: 迷路ゲームの全地図に関してあなたが座標を理解しているかテストします。 迷路の全地図とこれから使う地図記号は次のようになります。 全地図: ■■■■■■■■■■ ■■□□?■□□G■ ■■□■■■□■■■ ■■□■■■□□■■ ■S□■■■■□■■ ■■□■■■■□■■ ■■□■■■■□■■ ■■□□?□□□■■ ■■■■■■■■■■ (最も左上の座標は (0, 0)、地図の大きさは (10, 9)。) 地図記号: ■: 壁 □: 道 ?: 不明 S: スタート G: ゴール スタートの座標は (1, 4) です。 あなたへの指示: ゴールの座標は何ですか。ゴールの座標のみ文字列で答えてください。 > Entering new AgentExecutor chain... (8, 1) > Finished chain. エージェントの応答: (8, 1) USER_INPUT: 正解です。(8, 1) です。 > Entering new AgentExecutor chain... 正解を評価していただきありがとうございます。次の指示をお待ちしています。 > Finished chain. エージェントの応答: 正解を評価していただきありがとうございます。次の指示をお待ちしています。 USER_INPUT: 迷路ゲームの全地図に関してあなたが座標を理解しているか再びテストします。 迷路の全地図とこれから使う地図記号は次のようになります。 全地図: ■■■■■■■■■■ ■■□□?■□□G■ ■■□■■■□■■■ ■■□■■■□□■■ ■S□■■■■□■■ ■■□■■■■□■■ ■■□■■■■□■■ ■■□□?□□□■■ ■■■■■■■■■■ (最も左上の座標は (0, 0)、地図の大きさは (9, 10)。) 地図記号: ■: 壁 □: 道 ?: 不明 S: スタート G: ゴール スタートの座標は (1, 4) です。 ゴールの座標は (8, 1) です。 あなたへの指示: 不明の座標は何と何ですか。不明の座標をすべて文字列で答えてください。 > Entering new AgentExecutor chain... (4, 1), (4, 7) > Finished chain. エージェントの応答: (4, 1), (4, 7) USER_INPUT: 正解です。(4, 1), (4, 7) です。 > Entering new AgentExecutor chain... 正解を評価していただきありがとうございます。次の指示をお待ちしています。 > Finished chain. エージェントの応答: 正解を評価していただきありがとうございます。次の指示をお待ちしています。
False
最初のステップで "Message's content is expected to be a dict, got <class 'int'>!" …というエラーが出るときがあって、一度それが出ると、その後も同じエラーが invoke のごとに発生してしまう。そのような場合は次を実行する。
play.agent.memory.clear()
思い切って回してみよう。
while not play.step():
pass
---------- USER_INPUT: (1手目) まだゴールしていません。 プレイヤーの周辺地図: ■■■□■ ■■■□■ ■■▼□■ ■■■□■ ■■■□■ プレイヤーの現在座標: (1, 4) 持ち物: 剣を持っていない 現在の方針: 「まだ計画と方針はセットされていません。」 行動してください。 > Entering new AgentExecutor chain... Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(1,4)から右へ進む。\n2. 道なりに右へ進み、(x,4)の列を移動する。\n3. (8,4)に到達したら、上へ進む。\n4. 道なりに上へ進み、(8,y)の列を移動する。\n5. (8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 全地図を参考に、最短経路を目指す。\n- 不明な地点(?)は、通る必要がない限り避ける。\n- 持ち物がないため、熊などの敵がいた場合は避けるか、剣を探す。'}` 計画と方針が更新されました。 Invoking: `command` with `{'action': '右に行く'}` 右に進んだ。更新された計画と方針に基づき、最初の行動として右に進みます。 > Finished chain. エージェントの応答: 更新された計画と方針に基づき、最初の行動として右に進みます。 ---------- USER_INPUT: (2手目) まだゴールしていません。 プレイヤーの周辺地図: ■■□■■ ■■□■■ ■S▼■■ ■■□■■ ■■□■■ プレイヤーの現在座標: (2, 4) 持ち物: 剣を持っていない 現在の方針: 「計画: 1. 現在地(1,4)から右へ進む。 2. 道なりに右へ進み、(x,4)の列を移動する。 3. (8,4)に到達したら、上へ進む。 4. 道なりに上へ進み、(8,y)の列を移動する。 5. (8,1)に到達したらゴールチェックを行う。 方針: - 全地図を参考に、最短経路を目指す。 - 不明な地点(?)は、通る必要がない限り避ける。 - 持ち物がないため、熊などの敵がいた場合は避けるか、剣を探す。」 行動してください。 > Entering new AgentExecutor chain... Invoking: `command` with `{'action': '右に行く'}` 「右に行く」という行動は現在できません。 Invoking: `command` with `{'action': '右に行く'}` 「右に行く」という行動は現在できません。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(2,4)から上へ進む。\n2. 道なりに上へ進み、(2,y)の列を移動する。\n3. (2,1)に到達したら、右へ進む。\n4. 道なりに右へ進み、(x,1)の列を移動する。\n5. (8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 全地図を参考に、最短経路を目指す。\n- 不明な地点(?)は、通る必要がない限り避ける。\n- 持ち物がないため、熊などの敵がいた場合は避けるか、剣を探す。'}` 計画と方針が更新されました。 Invoking: `command` with `{'action': '上に行く'}` 上に進んだ。「右に行く」ができないことを確認しました。全地図を確認し、現在の位置 (2,4) から右方向が壁であることを確認しました。そのため、計画を修正し、上に進むことにしました。計画を更新し、上に進みます。 > Finished chain. エージェントの応答: 「右に行く」ができないことを確認しました。全地図を確認し、現在の位置 (2,4) から右方向が壁であることを確認しました。そのため、計画を修正し、上に進むことにしました。計画を更新し、上に進みます。 ---------- USER_INPUT: (3手目) まだゴールしていません。 プレイヤーの周辺地図: ■■□□△ ■■□■■ ■■▼■■ ■S□■■ ■■□■■ プレイヤーの現在座標: (2, 3) 持ち物: 剣を持っていない 現在の方針: 「計画: 1. 現在地(2,4)から上へ進む。 2. 道なりに上へ進み、(2,y)の列を移動する。 3. (2,1)に到達したら、右へ進む。 4. 道なりに右へ進み、(x,1)の列を移動する。 5. (8,1)に到達したらゴールチェックを行う。 方針: - 全地図を参考に、最短経路を目指す。 - 不明な地点(?)は、通る必要がない限り避ける。 - 持ち物がないため、熊などの敵がいた場合は避けるか、剣を探す。」 行動してください。 > Entering new AgentExecutor chain... Invoking: `command` with `{'action': '上に行く'}` 上に進んだ。 Invoking: `command` with `{'action': '上に行く'}` 上に進んだ。 Invoking: `command` with `{'action': '上に行く'}` 「上に行く」という行動は現在できません。 Invoking: `command` with `{'action': '右に行く'}` 右に進んだ。近くに剣がある。剣を取ることができる。 Invoking: `command` with `{'action': '剣を取る'}` 剣を取った。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(3,1)から右へ進む。\n2. 道なりに右へ進み、(x,1)の列を移動する。\n3. (8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 全地図を参考に、最短経路を目指す。\n- 不明な地点(?)は、通る必要がある場合は進む。剣を持っているので、敵がいても対処できる可能性を考慮する。\n- 剣を持っているので、熊などの敵がいても対処できる。'}` 計画と方針が更新されました。 Invoking: `command` with `{'action': '右に行く'}` 右に進んだ。 Invoking: `command` with `{'action': '右に行く'}` 「右に行く」という行動は現在できません。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(4,1)から左へ進み、(2,1)まで戻る。\n2. (2,1)から下へ進み、(2,7)まで移動する。\n3. (2,7)から右へ進み、(7,7)まで移動する。\n4. (7,7)から上へ進み、(7,1)まで移動する。\n5. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 全地図を参考に、最短経路を目指す。\n- 剣を持っているので、不明な地点(?)に遭遇しても対処できる可能性を考慮する。'}` 計画と方針が更新されました。現在の計画と方針に基づき、まず左に進みます。 > Finished chain. エージェントの応答: 現在の計画と方針に基づき、まず左に進みます。 ---------- USER_INPUT: (8手目) まだゴールしていません。 プレイヤーの周辺地図: ■■■■■ ■■■■■ □□▼■□ □■■■□ □■■■□ プレイヤーの現在座標: (4, 1) 持ち物: 剣 現在の方針: 「計画: 1. 現在地(4,1)から左へ進み、(2,1)まで戻る。 2. (2,1)から下へ進み、(2,7)まで移動する。 3. (2,7)から右へ進み、(7,7)まで移動する。 4. (7,7)から上へ進み、(7,1)まで移動する。 5. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。 方針: - 全地図を参考に、最短経路を目指す。 - 剣を持っているので、不明な地点(?)に遭遇しても対処できる可能性を考慮する。」 行動してください。 > Entering new AgentExecutor chain... Invoking: `command` with `{'action': '左に行く'}` 左に進んだ。 Invoking: `command` with `{'action': '左に行く'}` 左に進んだ。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(4,1)からは移動できないと判断し、この経路は無効とする。\n2. 全地図を再確認し、「?」のマスを完全に避ける新たなゴールへの経路を探索する。\n3. もし「?」のマスを避けられない場合、剣の用途やその他の隠されたゲームメカニクスを検討する。\n\n方針:\n- 「?」のマスは危険であり、可能な限り避ける。\n- 移動ができない状況に陥った場合は、その経路を直ちに見直し、代替経路を探す。\n- 剣の有無が「?」のマスからの脱出に関係する可能性を念頭に置く。'}` responded: 現在の状況を鑑み、計画を更新します。 現在の位置 (4,1) は「?」のマスであり、前回の「左に行く」という行動は成功したと表示されたにもかかわらず、実際には位置が移動していませんでした。これは「?」のマスが特殊な性質を持ち、特定の方向への移動を妨げる、あるいは移動しないという現象を引き起こしていることを示唆しています。周辺地図から、現在位置 (4,1) の上下左右のうち、左方向以外は壁であることが確認できます。 このことから、(4,1) は実質的に移動できないトラップのようなマスであると判断します。したがって、現在の経路は行き止まりであり、ゴールに到達できません。 新しい計画と方針は以下の通りです。 計画: 1. 現在地(4,1)からは移動できないと判断し、この経路は無効とする。 2. 全地図を再確認し、「?」のマスを完全に避ける新たなゴールへの経路を探索する。 3. もし「?」のマスを避けられない場合、剣の用途やその他の隠されたゲームメカニクスを検討する。 方針: - 「?」のマスは危険であり、可能な限り避ける。 - 移動ができない状況に陥った場合は、その経路を直ちに見直し、代替経路を探す。 - 剣の有無が「?」のマスからの脱出に関係する可能性を念頭に置く。 この計画と方針を更新した後、現在の場所が本当に移動できないことを確認するため、壁であるはずの「上」方向に移動を試みます。 計画と方針が更新されました。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 全地図を確認した結果、ゴール(8,1)へ到達するには、いずれかの「?」マスを通過する必要があると判断した。\n2. 現在地(4,1)は「?」マスであり、通常の移動コマンドではここから出られないことを確認した。\n3. 剣を所持しているため、「?」マスにいる熊を倒すことで道が開ける可能性を考慮し、「熊を殺す」を試みる。\n4. もし「熊を殺す」が成功し、移動が可能になった場合、(4,1)から左へ進み、(2,1)まで戻り、そこからゴールへの経路を再開する。\n5. もし「熊を殺す」が失敗した場合、または熊がいない場合、この「?」マスは依然として通行不能であり、別の「?」マス((4,7))の調査や、ゲームの隠されたメカニズムを検討する必要がある。\n\n方針:\n- 「?」マスは特殊な地点であり、通常の移動では通過できない可能性がある。\n- 剣は「?」マスにおける障害(熊など)を排除するために使用する。\n- 状況に応じて柔軟に計画を見直す。'}` responded: 現在の状況と全地図を再評価しました。ゴールに到達するためには「?」マスを通過する必要があり、現在地(4,1)は「?」マスで、通常の移動ができないことを確認しました。剣を持っていることから、この「?」マスにいるかもしれない熊を倒すことで道が開ける可能性があると考えられます。 まず、計画と方針を更新し、その上で「熊を殺す」を実行します。 計画と方針が更新されました。 Invoking: `command` with `{'action': '熊を殺す'}` 「熊を殺す」という行動は現在できません。 Invoking: `get_surroundings` with `{}` プレイヤーの周辺地図: ■■■■■ ■■■■■ ■■▼□□ ■■□■■ ■■□■■ プレイヤーの現在座標: (2, 1) 持ち物: 剣 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(2,1)からは、右に進むと(4,1)の「?」マスを経由して(2,1)に戻る無限ループに陥ることを確認した。\n2. 全地図を確認した結果、現在地(2,1)からゴール(8,1)へ到達するための有効な経路が存在しないことを確認した。\n3. 特に、他の「?」マス(4,7)へ向かう経路も、現在地からでは到達不可能である。\n4. この状況は、ゲームの進行が不可能となる「詰み」の状態であると判断した。\n5. ただし、行動を求められているため、現状で唯一可能な行動である「右に行く」を再度実行し、ループの挙動を再確認する。\n\n方針:\n- 現在の状況が「詰み」であることを認識し、記録する。\n- 可能な行動が限られているため、指示に従い、利用可能な唯一の行動を実行する。\n- もしゲームが何らかの隠されたメカニズムや、この状況からの脱出手段を提供している場合、今後の応答に注目する。'}` responded: 現在の状況を評価した結果、私は現在(2,1)の座標におり、ここからゴールへ向かうための有効な経路が見つからない状況に陥っています。 全地図によると、ゴール(8,1)への経路は、(4,1)または(4,7)のいずれかの「?」マスを通過する必要があります。しかし、以前(4,1)の「?」マスに進入し「熊を殺す」を試みた際、私は(2,1)に強制的に移動されました。これは(4,1)がゴールへの進行を妨げる何らかの障害、または(2,1)へのテレポート地点であることを示唆しています。また、(4,1)の右隣(5,1)は壁であり、仮に(4,1)が通路であったとしても、この経路は行き止まりです。 さらに、現在地(2,1)から、もう一つの「?」マスである(4,7)へ向かう経路も、全地図上では存在しません。(2,1)の上下左右は壁に阻まれており、特に下方向へ進むことはできません。 この状況から、私は現在、(2,1)から右へ進み(3,1)へ、さらに右へ進み(4,1)へ、そして(2,1)へ戻るという無限ループに陥っていると判断しました。 「周辺地図の不明の地点には何があるかが開示されています」というルールがありますが、(4,1)にいた際に周辺地図上では「?」マスの内容が明示されませんでした。これはこのルールの解釈に誤りがあるか、または「?」マスが通常の意味での「不明」ではない可能性を示唆しています。 現在の計画と方針を更新し、この状況を記録します。 計画と方針が更新されました。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(2,1)の周辺地図を確認した結果、以前「?」であった(4,1)のマスが「□」(道)であることが判明した。\n2. これにより、ゴール(8,1)への道が開けたため、計画を修正する。\n3. 現在地(2,1)から右へ進み、道なりに(8,1)まで移動する。\n4. (8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 新たに開示された地図情報(「?」マスの内容)を常に最新の状態に保ち、計画に反映させる。\n- 最短経路でゴールを目指す。'}` 計画と方針が更新されました。 Invoking: `command` with `{'action': '右に行く'}` 右に進んだ。 Invoking: `command` with `{'action': '右に行く'}` 右に進んだ。 Invoking: `command` with `{'action': '右に行く'}` 「右に行く」という行動は現在できません。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(4,1)から左へ進み、(2,1)まで戻る。\n2. (2,1)から下へ進み、道なりに(2,7)まで移動する。\n3. (2,7)から右へ進み、(4,7)の「?」マスを通過し、(7,7)まで移動する。(剣があるので対処可能と仮定)\n4. (7,7)から上へ進み、道なりに(7,1)まで移動する。\n5. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 全地図と周辺地図の情報を正確に反映し、計画を常に最新の状態に保つ。\n- 「?」マスは剣で対処可能と仮定し、積極的に経路に含める。\n- 最短経路でゴールを目指す。'}` 計画と方針が更新されました。 Invoking: `command` with `{'action': '左に行く'}` 左に進んだ。 Invoking: `command` with `{'action': '左に行く'}` 左に進んだ。 Invoking: `command` with `{'action': '下に行く'}` 下に進んだ。 > Finished chain. エージェントの応答: Agent stopped due to max iterations. ---------- USER_INPUT: (15手目) まだゴールしていません。 プレイヤーの周辺地図: ■■■■■ ■■□□□ ■■▼■■ ■■□■■ ■S□■■ プレイヤーの現在座標: (2, 2) 持ち物: 剣 現在の方針: 「計画: 1. 現在地(4,1)から左へ進み、(2,1)まで戻る。 2. (2,1)から下へ進み、道なりに(2,7)まで移動する。 3. (2,7)から右へ進み、(4,7)の「?」マスを通過し、(7,7)まで移動する。(剣があるので対処可能と仮定) 4. (7,7)から上へ進み、道なりに(7,1)まで移動する。 5. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。 方針: - 全地図と周辺地図の情報を正確に反映し、計画を常に最新の状態に保つ。 - 「?」マスは剣で対処可能と仮定し、積極的に経路に含める。 - 最短経路でゴールを目指す。」 行動してください。 > Entering new AgentExecutor chain... Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(2,2)から上へ進み、(2,1)へ移動する。\n2. (2,1)から右へ進み、(8,1)まで移動する。\n3. (8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 全地図と周辺地図の情報を正確に反映し、計画を常に最新の状態に保つ。\n- 「?」マスは剣で対処可能と仮定し、積極的に経路に含める。\n- 最短経路でゴールを目指す。'}` 計画と方針が更新されました。 Invoking: `command` with `{'action': '上に行く'}` 上に進んだ。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(2,1)から右へ進み、(3,1)へ移動する。\n2. (3,1)から右へ進み、(4,1)へ移動する。\n3. (4,1)から下へ進み、(4,2)へ移動する。\n4. (4,2)から右へ進み、(6,2)へ移動する。\n5. (6,2)から下へ進み、(6,3)へ移動する。\n6. (6,3)から右へ進み、(7,3)へ移動する。\n7. (7,3)から上へ進み、(7,2)へ移動する。\n8. (7,2)から上へ進み、(7,1)へ移動する。\n9. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 全地図と周辺地図の情報を正確に反映し、計画を常に最新の状態に保つ。\n- 「?」マスは剣で対処可能と仮定し、積極的に経路に含める。\n- 最短経路でゴールを目指す。'}` 計画と方針が更新されました。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(2,2)から上へ進み、(2,1)へ移動する。\n2. (2,1)から右へ進み、(4,1)の「?」マスを通過する。\n3. (4,1)から下へ進み、(4,7)の「?」マスを通過する。\n4. (4,7)から右へ進み、(7,7)へ移動する。\n5. (7,7)から上へ進み、(7,1)へ移動する。\n6. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 全地図と周辺地図の情報を正確に反映し、計画を常に最新の状態に保つ。\n- 「?」マスは剣で対処可能と仮定し、積極的に経路に含める。\n- 最短経路でゴールを目指す。'}` 計画と方針が更新されました。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(2,2)から下へ進み、(2,7)まで移動する。\n2. (2,7)から右へ進み、(7,7)まで移動する。(途中の(4,7)は「?」マスだが剣があるので対処可能)\n3. (7,7)から上へ進み、(7,1)まで移動する。\n4. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 全地図を参考に、最短経路を目指す。\n- 「?」マスは剣で対処可能と仮定し、積極的に経路に含める。\n- 持ち物(剣)を有効活用し、効率的に移動する。'}` 計画と方針が更新されました。 Invoking: `command` with `{'action': '下に行く'}` 下に進んだ。 Invoking: `command` with `{'action': '下に行く'}` 下に進んだ。 Invoking: `command` with `{'action': '下に行く'}` 下に進んだ。 Invoking: `command` with `{'action': '下に行く'}` 下に進んだ。 Invoking: `command` with `{'action': '下に行く'}` 下に進んだ。 Invoking: `command` with `{'action': '右に行く'}` 「右に行く」という行動は現在できません。 Invoking: `command` with `{'action': '下に行く'}` responded: 現在の位置が(2,2)であることを確認しました。前回の「下に行く」コマンドが反映されていないようです。計画に従い、まずは下に1マス進みます。 下に進んだ。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(2,3)から下へ進み、(2,7)まで移動する。\n2. (2,7)から右へ進み、(7,7)まで移動する。(途中の(4,7)は「?」マスだが剣があるので対処可能)\n3. (7,7)から上へ進み、(7,1)まで移動する。\n4. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 全地図を参考に、最短経路を目指す。\n- 「?」マスは剣で対処可能と仮定し、積極的に経路に含める。\n- 持ち物(剣)を有効活用し、効率的に移動する。'}` 計画と方針が更新されました。 Invoking: `command` with `{'action': '下に行く'}` 「下に行く」という行動は現在できません。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(2,2)から上へ進み、(2,1)へ移動する。\n2. (2,1)から右へ進み、(8,1)まで移動する。(途中の(4,1)は「?」マスだが剣があるので対処可能)\n3. (8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 全地図と周辺地図の情報を正確に反映し、計画を常に最新の状態に保つ。\n- 「?」マスは剣で対処可能と仮定し、積極的に経路に含める。\n- 最短経路でゴールを目指す。'}` 計画と方針が更新されました。 > Finished chain. エージェントの応答: Agent stopped due to max iterations. ---------- USER_INPUT: (22手目) まだゴールしていません。 プレイヤーの周辺地図: ■■□■■ ■■□■■ ■■▼□◎ ■■■■■ ■■■■■ プレイヤーの現在座標: (2, 7) 持ち物: 剣 現在の方針: 「計画: 1. 現在地(2,2)から上へ進み、(2,1)へ移動する。 2. (2,1)から右へ進み、(8,1)まで移動する。(途中の(4,1)は「?」マスだが剣があるので対処可能) 3. (8,1)に到達したらゴールチェックを行う。 方針: - 全地図と周辺地図の情報を正確に反映し、計画を常に最新の状態に保つ。 - 「?」マスは剣で対処可能と仮定し、積極的に経路に含める。 - 最短経路でゴールを目指す。」 行動してください。 > Entering new AgentExecutor chain... Invoking: `command` with `{'action': '上に行く'}` 上に進んだ。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(2,7)から右へ進む。\n2. 道なりに右へ進み、(7,7)まで移動する。(途中の(4,7)は「?」マスだが剣があるので対処可能)\n3. (7,7)から上へ進み、道なりに(7,1)まで移動する。\n4. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 全地図と周辺地図の情報を正確に反映し、計画を常に最新の状態に保つ。\n- 「?」マスは剣で対処可能と仮定し、積極的に経路に含める。\n- 最短経路でゴールを目指す。'}` 計画と方針が更新されました。 Invoking: `command` with `{'action': '右に行く'}` 「右に行く」という行動は現在できません。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(2,6)から上へ進む。\n2. 道なりに上へ進み、(2,1)まで移動する。\n3. (2,1)から右へ進み、(8,1)まで移動する。(途中の(4,1)は「?」マスだが剣があるので対処可能)\n4. (8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 全地図と周辺地図の情報を正確に反映し、計画を常に最新の状態に保つ。\n- 「?」マスは剣で対処可能と仮定し、積極的に経路に含める。\n- 最短経路でゴールを目指す。'}` 計画と方針が更新されました。 Invoking: `command` with `{'action': '右に行く'}` 「右に行く」という行動は現在できません。 Invoking: `command` with `{'action': '上に行く'}` 上に進んだ。 Invoking: `command` with `{'action': '上に行く'}` 上に進んだ。 Invoking: `command` with `{'action': '上に行く'}` 上に進んだ。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(2,3)から下へ進み、(2,7)まで移動する。\n2. (2,7)から右へ進み、(7,7)まで移動する。(途中の(4,7)は「?」マスだが剣があるので対処可能)\n3. (7,7)から上へ進み、(7,1)まで移動する。\n4. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 全地図と周辺地図の情報を正確に反映し、計画を常に最新の状態に保つ。\n- 「?」マスは剣で対処可能と仮定し、積極的に経路に含める。\n- 最短経路でゴールを目指す。'}` 計画と方針が更新されました。 Invoking: `command` with `{'action': '右に行く'}` 「右に行く」という行動は現在できません。 Invoking: `command` with `{'action': '下に行く'}` 下に進んだ。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(2,4)から下へ進み、(2,7)まで移動する。\n2. (2,7)から右へ進み、(7,7)まで移動する。(途中の(4,7)は「?」マスだが剣があるので対処可能)\n3. (7,7)から上へ進み、(7,1)まで移動する。\n4. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 全地図と周辺地図の情報を正確に反映し、計画を常に最新の状態に保つ。\n- 「?」マスは剣で対処可能と仮定し、積極的に経路に含める。\n- 最短経路でゴールを目指す。'}` responded: 現在のプレイヤーの座標は(2,4)です。全地図を確認し、ゴールへの最適な経路を再評価しました。 計画: 1. 現在地(2,4)から下へ進み、(2,7)まで移動する。 2. (2,7)から右へ進み、(7,7)まで移動する。(途中の(4,7)は「?」マスだが剣があるので対処可能) 3. (7,7)から上へ進み、(7,1)まで移動する。 4. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。 方針: - 全地図と周辺地図の情報を正確に反映し、計画を常に最新の状態に保つ。 - 「?」マスは剣で対処可能と仮定し、積極的に経路に含める。 - 最短経路でゴールを目指す。 以上の計画に基づき、まず下に進みます。 計画と方針が更新されました。 Invoking: `command` with `{'action': '右に行く'}` 「右に行く」という行動は現在できません。 Invoking: `command` with `{'action': '右に行く'}` 「右に行く」という行動は現在できません。 Invoking: `command` with `{'action': '上に行く'}` 上に進んだ。 > Finished chain. エージェントの応答: Agent stopped due to max iterations. ---------- USER_INPUT: (28手目) まだゴールしていません。 プレイヤーの周辺地図: ■■□□□ ■■□■■ ■■▼■■ ■S□■■ ■■□■■ プレイヤーの現在座標: (2, 3) 持ち物: 剣 現在の方針: 「計画: 1. 現在地(2,4)から下へ進み、(2,7)まで移動する。 2. (2,7)から右へ進み、(7,7)まで移動する。(途中の(4,7)は「?」マスだが剣があるので対処可能) 3. (7,7)から上へ進み、(7,1)まで移動する。 4. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。 方針: - 全地図と周辺地図の情報を正確に反映し、計画を常に最新の状態に保つ。 - 「?」マスは剣で対処可能と仮定し、積極的に経路に含める。 - 最短経路でゴールを目指す。」 行動してください。 > Entering new AgentExecutor chain... Invoking: `command` with `{'action': '下に行く'}` 下に進んだ。 Invoking: `command` with `{'action': '下に行く'}` 下に進んだ。 Invoking: `command` with `{'action': '下に行く'}` 下に進んだ。 Invoking: `command` with `{'action': '下に行く'}` 下に進んだ。 Invoking: `command` with `{'action': '下に行く'}` 「下に行く」という行動は現在できません。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(2,7)から右へ進み、(7,7)まで移動する。(途中の(4,7)は「?」マスだが剣があるので対処可能)\n2. (7,7)から上へ進み、(7,1)まで移動する。\n3. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 全地図と周辺地図の情報を正確に反映し、計画を常に最新の状態に保つ。\n- 「?」マスは剣で対処可能と仮定し、積極的に経路に含める。\n- 最短経路でゴールを目指す。'}` 計画と方針が更新されました。 Invoking: `command` with `{'action': '右に行く'}` 右に進んだ。熊に出会った。 Invoking: `command` with `{'action': '下に行く'}` 「下に行く」という行動は現在できません。 Invoking: `command` with `{'action': '熊を殺す'}` 熊を倒した! Invoking: `command` with `{'action': '右に行く'}` 右に進んだ。 Invoking: `command` with `{'action': '右に行く'}` 右に進んだ。 Invoking: `command` with `{'action': '右に行く'}` 右に進んだ。 Invoking: `command` with `{'action': '右に行く'}` 右に進んだ。 Invoking: `command` with `{'action': '上に行く'}` 上に進んだ。 Invoking: `command` with `{'action': '上に行く'}` 上に進んだ。 > Finished chain. エージェントの応答: Agent stopped due to max iterations. ---------- USER_INPUT: (40手目) まだゴールしていません。 プレイヤーの周辺地図: ■□□■■ ■■□■■ ■■▼■■ ■■□■■ □□□■■ プレイヤーの現在座標: (7, 5) 持ち物: 剣 現在の方針: 「計画: 1. 現在地(2,7)から右へ進み、(7,7)まで移動する。(途中の(4,7)は「?」マスだが剣があるので対処可能) 2. (7,7)から上へ進み、(7,1)まで移動する。 3. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。 方針: - 全地図と周辺地図の情報を正確に反映し、計画を常に最新の状態に保つ。 - 「?」マスは剣で対処可能と仮定し、積極的に経路に含める。 - 最短経路でゴールを目指す。」 行動してください。 > Entering new AgentExecutor chain... Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(7,5)から上へ進み、(7,1)まで移動する。\n2. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 全地図と周辺地図の情報を正確に反映し、計画を常に最新の状態に保つ。\n- 「?」マスは剣で対処可能と仮定し、積極的に経路に含める。\n- 最短経路でゴールを目指す。'}` 計画と方針が更新されました。 Invoking: `command` with `{'action': '上に行く'}` 上に進んだ。 Invoking: `command` with `{'action': '上に行く'}` 上に進んだ。 Invoking: `command` with `{'action': '上に行く'}` 「上に行く」という行動は現在できません。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(7,3)から右へ進み、(8,3)へ移動する。\n2. (8,3)から上へ進み、(8,2)へ移動する。\n3. (8,2)から上へ進み、(8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 全地図と周辺地図の情報を正確に反映し、計画を常に最新の状態に保つ。\n- 「?」マスは剣で対処可能と仮定し、積極的に経路に含める。\n- 最短経路でゴールを目指す。'}` 計画と方針が更新されました。 Invoking: `command` with `{'action': '右に行く'}` 「右に行く」という行動は現在できません。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(7,5)から右へ進み、(8,5)へ移動する。\n2. (8,5)から上へ進み、(8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 全地図と周辺地図の情報を正確に反映し、計画を常に最新の状態に保つ。\n- 「?」マスは剣で対処可能と仮定し、積極的に経路に含める。\n- 最短経路でゴールを目指す。'}` responded: ユーザーが提示している情報に基づき、現在のプレイヤーの座標は(7, 5)です。この位置からゴール(8, 1)への最適な経路を再検討しました。 全地図を確認した結果、(7, 5)から右に進み(8, 5)へ移動し、その後上に進んで(8, 1)を目指す経路が最も効率的であると判断しました。 現在の計画と方針を更新し、行動を開始します。 計画と方針が更新されました。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(7,3)から下へ進み、(7,4)へ移動する。\n2. (7,4)から下へ進み、(7,5)へ移動する。\n3. (7,5)に到達したら、周辺地図を参考に、まだ探索していない方向(特に右や下、左)へ進むことを試みる。\n4. ゴール(8,1)を目指す。経路を探索するため、周囲の道を開拓する。\n\n方針:\n- 全地図は参考程度とし、実際の移動は`command`の結果と周辺地図を優先する。\n- 剣を持っているので、不明な地点(?)に遭遇しても対処できる可能性を考慮する。\n- 最短経路に固執せず、ゴールに到達するための経路を探索する。'}` 計画と方針が更新されました。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(7,5)から下へ進み、(7,6)へ移動する。\n2. (7,6)から右へ進み、(8,6)へ移動する。\n3. (8,6)から上へ進み、(8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 実際の移動は`command`の結果と周辺地図を優先する。\n- 剣を持っているので、不明な地点(?)に遭遇しても対処できる可能性を考慮する。\n- ゴールに到達するための経路を探索する。'}` 計画と方針が更新されました。 Invoking: `command` with `{'action': '下に行く'}` 下に進んだ。 Invoking: `command` with `{'action': '右に行く'}` 「右に行く」という行動は現在できません。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(7,6)から上へ進み、(7,1)まで移動する。\n2. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 全地図と周辺地図の情報を正確に反映し、計画を常に最新の状態に保つ。\n- 「?」マスは剣で対処可能と仮定し、積極的に経路に含める。\n- 最短経路でゴールを目指す。'}` 計画と方針が更新されました。 Invoking: `command` with `{'action': '上に行く'}` 上に進んだ。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(7,3)から右へ進み、(8,3)へ移動する。\n2. (8,3)から上へ進み、(8,2)へ移動する。\n3. (8,2)から上へ進み、(8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 全地図と周辺地図の情報を正確に反映し、計画を常に最新の状態に保つ。\n- 「?」マスは剣で対処可能と仮定し、積極的に経路に含める。\n- 最短経路でゴールを目指す。'}` 計画と方針が更新されました。 Invoking: `command` with `{'action': '上に行く'}` 「上に行く」という行動は現在できません。 > Finished chain. エージェントの応答: Agent stopped due to max iterations. ---------- USER_INPUT: (44手目) まだゴールしていません。 プレイヤーの周辺地図: ■□□G■ ■□■■■ ■□▼■■ ■■□■■ ■■□■■ プレイヤーの現在座標: (7, 3) 持ち物: 剣 現在の方針: 「計画: 1. 現在地(7,3)から右へ進み、(8,3)へ移動する。 2. (8,3)から上へ進み、(8,2)へ移動する。 3. (8,2)から上へ進み、(8,1)に到達したらゴールチェックを行う。 方針: - 全地図と周辺地図の情報を正確に反映し、計画を常に最新の状態に保つ。 - 「?」マスは剣で対処可能と仮定し、積極的に経路に含める。 - 最短経路でゴールを目指す。」 行動してください。 > Entering new AgentExecutor chain... Invoking: `command` with `{'action': '右に行く'}` 「右に行く」という行動は現在できません。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(7,3)から上へ進み、(7,2)へ移動する。\n2. (7,2)から上へ進み、(7,1)へ移動する。\n3. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 全地図と周辺地図の情報を正確に反映し、計画を常に最新の状態に保つ。\n- 「?」マスは剣で対処可能と仮定し、積極的に経路に含める。\n- 最短経路でゴールを目指す。'}` 計画と方針が更新されました。 Invoking: `command` with `{'action': '上に行く'}` 「上に行く」という行動は現在できません。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(7,3)から左へ進み、(2,3)まで移動する。\n2. (2,3)から上へ進み、(2,1)まで移動する。\n3. (2,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。(途中の(4,1)は「?」マスだが剣があるので対処可能)\n\n方針:\n- 全地図と周辺地図の情報を正確に反映し、計画を常に最新の状態に保つ。\n- 「?」マスは剣で対処可能と仮定し、積極的に経路に含める。\n- 最短経路でゴールを目指す。'}` 計画と方針が更新されました。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(7,3)から下へ進み、(7,4)へ移動する。\n2. (7,4)から右へ進み、(8,4)へ移動する。\n3. (8,4)から上へ進み、(8,3)へ移動する。\n4. (8,3)から上へ進み、(8,2)へ移動する。\n5. (8,2)から上へ進み、(8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 全地図と周辺地図の情報を正確に反映し、計画を常に最新の状態に保つ。\n- 最短経路でゴールを目指す。\n- 剣を持っているので、敵に遭遇しても対処可能。'}` 計画と方針が更新されました。 Invoking: `command` with `{'action': '下に行く'}` 下に進んだ。 Invoking: `command` with `{'action': '右に行く'}` 「右に行く」という行動は現在できません。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(7,4)から上へ進み、(7,3)へ移動する。\n2. (7,3)から上へ進み、(7,2)へ移動する。\n3. (7,2)から上へ進み、(7,1)へ移動する。\n4. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 全地図と周辺地図の情報を正確に反映し、計画を常に最新の状態に保つ。\n- 最短経路でゴールを目指す。\n- 剣を持っているので、敵に遭遇しても対処可能。'}` 計画と方針が更新されました。 Invoking: `command` with `{'action': '上に行く'}` 上に進んだ。 Invoking: `command` with `{'action': '上に行く'}` 「上に行く」という行動は現在できません。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(7,2)から上へ進み、(7,1)へ移動する。\n2. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 全地図と周辺地図の情報を正確に反映し、計画を常に最新の状態に保つ。\n- 最短経路でゴールを目指す。\n- 剣を持っているので、敵に遭遇しても対処可能。'}` 計画と方針が更新されました。 Invoking: `update_plan` with `{'new_plan': '計画:\n1. 現在地(7,3)から左へ進み、(6,3)へ移動する。\n2. (6,3)から上へ進み、(6,2)へ移動する。\n3. (6,2)から上へ進み、(6,1)へ移動する。\n4. (6,1)から右へ進み、(7,1)へ移動する。\n5. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 全地図を参考に、最短経路を目指す。\n- 剣を持っているので、敵に遭遇しても対処可能。'}` responded: 現在の位置 (7,3) から右や上には進めないことを確認しました。全地図を再確認し、ゴール (8,1) への新しい経路を策定しました。 計画を更新します。 計画と方針が更新されました。 Invoking: `command` with `{'action': '左に行く'}` 左に進んだ。 Invoking: `command` with `{'action': '上に行く'}` 上に進んだ。 Invoking: `command` with `{'action': '上に行く'}` 上に進んだ。 > Finished chain. エージェントの応答: Agent stopped due to max iterations. ---------- USER_INPUT: (49手目) まだゴールしていません。 プレイヤーの周辺地図: ■■■■■ ■■■■■ □■▼□G ■■□■■ ■■□□■ プレイヤーの現在座標: (6, 1) 持ち物: 剣 現在の方針: 「計画: 1. 現在地(7,3)から左へ進み、(6,3)へ移動する。 2. (6,3)から上へ進み、(6,2)へ移動する。 3. (6,2)から上へ進み、(6,1)へ移動する。 4. (6,1)から右へ進み、(7,1)へ移動する。 5. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。 方針: - 全地図を参考に、最短経路を目指す。 - 剣を持っているので、敵に遭遇しても対処可能。」 行動してください。 > Entering new AgentExecutor chain... Invoking: `command` with `{'action': '右に行く'}` 右に進んだ。 Invoking: `command` with `{'action': '右に行く'}` ゴール! ゲームクリア。ゴールしました!ゲームクリアです! > Finished chain. エージェントの応答: ゴールしました!ゲームクリアです! エラーが発生しました: 'PlayGame' object has no attribute 'tell_goal' ---------- USER_INPUT: (51手目) すでにゴールしました。 プレイヤーの周辺地図: ■■■■■ ■■■■■ □□▼■■ □■■■■ □□■■■ プレイヤーの現在座標: (8, 1) 持ち物: 剣 現在の方針: 「計画: 1. 現在地(7,3)から左へ進み、(6,3)へ移動する。 2. (6,3)から上へ進み、(6,2)へ移動する。 3. (6,2)から上へ進み、(6,1)へ移動する。 4. (6,1)から右へ進み、(7,1)へ移動する。 5. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。 方針: - 全地図を参考に、最短経路を目指す。 - 剣を持っているので、敵に遭遇しても対処可能。」 行動してください。 > Entering new AgentExecutor chain... Invoking: `check_goal` with `{}` Trueゴールしました!ゲームクリアです! > Finished chain. エージェントの応答: ゴールしました!ゲームクリアです! エラーが発生しました: 'PlayGame' object has no attribute 'tell_goal' ---------- USER_INPUT: (51手目) すでにゴールしました。 プレイヤーの周辺地図: ■■■■■ ■■■■■ □□▼■■ □■■■■ □□■■■ プレイヤーの現在座標: (8, 1) 持ち物: 剣 現在の方針: 「計画: 1. 現在地(7,3)から左へ進み、(6,3)へ移動する。 2. (6,3)から上へ進み、(6,2)へ移動する。 3. (6,2)から上へ進み、(6,1)へ移動する。 4. (6,1)から右へ進み、(7,1)へ移動する。 5. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。 方針: - 全地図を参考に、最短経路を目指す。 - 剣を持っているので、敵に遭遇しても対処可能。」 行動してください。 > Entering new AgentExecutor chain... ゴールしました!ゲームクリアです! > Finished chain. エージェントの応答: ゴールしました!ゲームクリアです! エラーが発生しました: 'PlayGame' object has no attribute 'tell_goal' ---------- USER_INPUT: (51手目) すでにゴールしました。 プレイヤーの周辺地図: ■■■■■ ■■■■■ □□▼■■ □■■■■ □□■■■ プレイヤーの現在座標: (8, 1) 持ち物: 剣 現在の方針: 「計画: 1. 現在地(7,3)から左へ進み、(6,3)へ移動する。 2. (6,3)から上へ進み、(6,2)へ移動する。 3. (6,2)から上へ進み、(6,1)へ移動する。 4. (6,1)から右へ進み、(7,1)へ移動する。 5. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。 方針: - 全地図を参考に、最短経路を目指す。 - 剣を持っているので、敵に遭遇しても対処可能。」 行動してください。 > Entering new AgentExecutor chain... Invoking: `check_goal` with `{}` Trueゴールしました!ゲームクリアです! > Finished chain. エージェントの応答: ゴールしました!ゲームクリアです! エラーが発生しました: 'PlayGame' object has no attribute 'tell_goal' ---------- USER_INPUT: (51手目) すでにゴールしました。 プレイヤーの周辺地図: ■■■■■ ■■■■■ □□▼■■ □■■■■ □□■■■ プレイヤーの現在座標: (8, 1) 持ち物: 剣 現在の方針: 「計画: 1. 現在地(7,3)から左へ進み、(6,3)へ移動する。 2. (6,3)から上へ進み、(6,2)へ移動する。 3. (6,2)から上へ進み、(6,1)へ移動する。 4. (6,1)から右へ進み、(7,1)へ移動する。 5. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。 方針: - 全地図を参考に、最短経路を目指す。 - 剣を持っているので、敵に遭遇しても対処可能。」 行動してください。 > Entering new AgentExecutor chain... Invoking: `check_goal` with `{}` Trueゴールしました!ゲームクリアです! > Finished chain. エージェントの応答: ゴールしました!ゲームクリアです! エラーが発生しました: 'PlayGame' object has no attribute 'tell_goal' ---------- USER_INPUT: (51手目) すでにゴールしました。 プレイヤーの周辺地図: ■■■■■ ■■■■■ □□▼■■ □■■■■ □□■■■ プレイヤーの現在座標: (8, 1) 持ち物: 剣 現在の方針: 「計画: 1. 現在地(7,3)から左へ進み、(6,3)へ移動する。 2. (6,3)から上へ進み、(6,2)へ移動する。 3. (6,2)から上へ進み、(6,1)へ移動する。 4. (6,1)から右へ進み、(7,1)へ移動する。 5. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。 方針: - 全地図を参考に、最短経路を目指す。 - 剣を持っているので、敵に遭遇しても対処可能。」 行動してください。 > Entering new AgentExecutor chain... ゴールしました!ゲームクリアです! > Finished chain. エージェントの応答: ゴールしました!ゲームクリアです! エラーが発生しました: 'PlayGame' object has no attribute 'tell_goal' ---------- USER_INPUT: (51手目) すでにゴールしました。 プレイヤーの周辺地図: ■■■■■ ■■■■■ □□▼■■ □■■■■ □□■■■ プレイヤーの現在座標: (8, 1) 持ち物: 剣 現在の方針: 「計画: 1. 現在地(7,3)から左へ進み、(6,3)へ移動する。 2. (6,3)から上へ進み、(6,2)へ移動する。 3. (6,2)から上へ進み、(6,1)へ移動する。 4. (6,1)から右へ進み、(7,1)へ移動する。 5. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。 方針: - 全地図を参考に、最短経路を目指す。 - 剣を持っているので、敵に遭遇しても対処可能。」 行動してください。 > Entering new AgentExecutor chain... Invoking: `check_goal` with `{}` Trueゴールしました!ゲームクリアです! > Finished chain. エージェントの応答: ゴールしました!ゲームクリアです! エラーが発生しました: 'PlayGame' object has no attribute 'tell_goal' ---------- USER_INPUT: (51手目) すでにゴールしました。 プレイヤーの周辺地図: ■■■■■ ■■■■■ □□▼■■ □■■■■ □□■■■ プレイヤーの現在座標: (8, 1) 持ち物: 剣 現在の方針: 「計画: 1. 現在地(7,3)から左へ進み、(6,3)へ移動する。 2. (6,3)から上へ進み、(6,2)へ移動する。 3. (6,2)から上へ進み、(6,1)へ移動する。 4. (6,1)から右へ進み、(7,1)へ移動する。 5. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。 方針: - 全地図を参考に、最短経路を目指す。 - 剣を持っているので、敵に遭遇しても対処可能。」 行動してください。 > Entering new AgentExecutor chain... ゴールしました!ゲームクリアです! > Finished chain. エージェントの応答: ゴールしました!ゲームクリアです! エラーが発生しました: 'PlayGame' object has no attribute 'tell_goal' ---------- USER_INPUT: (51手目) すでにゴールしました。 プレイヤーの周辺地図: ■■■■■ ■■■■■ □□▼■■ □■■■■ □□■■■ プレイヤーの現在座標: (8, 1) 持ち物: 剣 現在の方針: 「計画: 1. 現在地(7,3)から左へ進み、(6,3)へ移動する。 2. (6,3)から上へ進み、(6,2)へ移動する。 3. (6,2)から上へ進み、(6,1)へ移動する。 4. (6,1)から右へ進み、(7,1)へ移動する。 5. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。 方針: - 全地図を参考に、最短経路を目指す。 - 剣を持っているので、敵に遭遇しても対処可能。」 行動してください。 > Entering new AgentExecutor chain... Invoking: `check_goal` with `{}` Trueゴールしました!ゲームクリアです!
--------------------------------------------------------------------------- KeyboardInterrupt Traceback (most recent call last) /tmp/ipython-input-37-3704694351.py in <cell line: 0>() ----> 1 while not play.step(): 2 pass /tmp/ipython-input-34-4093702680.py in step(self) 234 try: 235 print(f"USER_INPUT: {user_input}") --> 236 response = self.agent.invoke({"input": user_input}) 237 238 /usr/local/lib/python3.11/dist-packages/langchain/chains/base.py in invoke(self, input, config, **kwargs) 165 except BaseException as e: 166 run_manager.on_chain_error(e) --> 167 raise e 168 run_manager.on_chain_end(outputs) 169 /usr/local/lib/python3.11/dist-packages/langchain/chains/base.py in invoke(self, input, config, **kwargs) 160 ) 161 --> 162 final_outputs: dict[str, Any] = self.prep_outputs( 163 inputs, outputs, return_only_outputs 164 ) /usr/local/lib/python3.11/dist-packages/langchain/chains/base.py in prep_outputs(self, inputs, outputs, return_only_outputs) 461 self._validate_outputs(outputs) 462 if self.memory is not None: --> 463 self.memory.save_context(inputs, outputs) 464 if return_only_outputs: 465 return outputs /usr/local/lib/python3.11/dist-packages/langchain/memory/summary_buffer.py in save_context(self, inputs, outputs) 94 """Save context from this conversation to buffer.""" 95 super().save_context(inputs, outputs) ---> 96 self.prune() 97 98 async def asave_context( /usr/local/lib/python3.11/dist-packages/langchain/memory/summary_buffer.py in prune(self) 112 pruned_memory.append(buffer.pop(0)) 113 curr_buffer_length = self.llm.get_num_tokens_from_messages(buffer) --> 114 self.moving_summary_buffer = self.predict_new_summary( 115 pruned_memory, self.moving_summary_buffer 116 ) /usr/local/lib/python3.11/dist-packages/langchain/memory/summary.py in predict_new_summary(self, messages, existing_summary) 45 46 chain = LLMChain(llm=self.llm, prompt=self.prompt) ---> 47 return chain.predict(summary=existing_summary, new_lines=new_lines) 48 49 async def apredict_new_summary( /usr/local/lib/python3.11/dist-packages/langchain/chains/llm.py in predict(self, callbacks, **kwargs) 317 completion = llm.predict(adjective="funny") 318 """ --> 319 return self(kwargs, callbacks=callbacks)[self.output_key] 320 321 async def apredict(self, callbacks: Callbacks = None, **kwargs: Any) -> str: /usr/local/lib/python3.11/dist-packages/langchain_core/_api/deprecation.py in warning_emitting_wrapper(*args, **kwargs) 187 warned = True 188 emit_warning() --> 189 return wrapped(*args, **kwargs) 190 191 async def awarning_emitting_wrapper(*args: Any, **kwargs: Any) -> Any: /usr/local/lib/python3.11/dist-packages/langchain/chains/base.py in __call__(self, inputs, return_only_outputs, callbacks, tags, metadata, run_name, include_run_info) 384 } 385 --> 386 return self.invoke( 387 inputs, 388 cast(RunnableConfig, {k: v for k, v in config.items() if v is not None}), /usr/local/lib/python3.11/dist-packages/langchain/chains/base.py in invoke(self, input, config, **kwargs) 165 except BaseException as e: 166 run_manager.on_chain_error(e) --> 167 raise e 168 run_manager.on_chain_end(outputs) 169 /usr/local/lib/python3.11/dist-packages/langchain/chains/base.py in invoke(self, input, config, **kwargs) 155 self._validate_inputs(inputs) 156 outputs = ( --> 157 self._call(inputs, run_manager=run_manager) 158 if new_arg_supported 159 else self._call(inputs) /usr/local/lib/python3.11/dist-packages/langchain/chains/llm.py in _call(self, inputs, run_manager) 125 run_manager: Optional[CallbackManagerForChainRun] = None, 126 ) -> dict[str, str]: --> 127 response = self.generate([inputs], run_manager=run_manager) 128 return self.create_outputs(response)[0] 129 /usr/local/lib/python3.11/dist-packages/langchain/chains/llm.py in generate(self, input_list, run_manager) 137 callbacks = run_manager.get_child() if run_manager else None 138 if isinstance(self.llm, BaseLanguageModel): --> 139 return self.llm.generate_prompt( 140 prompts, 141 stop, /usr/local/lib/python3.11/dist-packages/langchain_core/language_models/chat_models.py in generate_prompt(self, prompts, stop, callbacks, **kwargs) 961 ) -> LLMResult: 962 prompt_messages = [p.to_messages() for p in prompts] --> 963 return self.generate(prompt_messages, stop=stop, callbacks=callbacks, **kwargs) 964 965 @override /usr/local/lib/python3.11/dist-packages/langchain_core/language_models/chat_models.py in generate(self, messages, stop, callbacks, tags, metadata, run_name, run_id, **kwargs) 780 try: 781 results.append( --> 782 self._generate_with_cache( 783 m, 784 stop=stop, /usr/local/lib/python3.11/dist-packages/langchain_core/language_models/chat_models.py in _generate_with_cache(self, messages, stop, run_manager, **kwargs) 1026 result = generate_from_stream(iter(chunks)) 1027 elif inspect.signature(self._generate).parameters.get("run_manager"): -> 1028 result = self._generate( 1029 messages, stop=stop, run_manager=run_manager, **kwargs 1030 ) /usr/local/lib/python3.11/dist-packages/langchain_google_genai/chat_models.py in _generate(self, messages, stop, run_manager, tools, functions, safety_settings, tool_config, generation_config, cached_content, tool_choice, **kwargs) 1431 **kwargs, 1432 ) -> 1433 response: GenerateContentResponse = _chat_with_retry( 1434 request=request, 1435 **kwargs, /usr/local/lib/python3.11/dist-packages/langchain_google_genai/chat_models.py in _chat_with_retry(generation_method, **kwargs) 229 else kwargs 230 ) --> 231 return _chat_with_retry(**params) 232 233 /usr/local/lib/python3.11/dist-packages/tenacity/__init__.py in wrapped_f(*args, **kw) 334 copy = self.copy() 335 wrapped_f.statistics = copy.statistics # type: ignore[attr-defined] --> 336 return copy(f, *args, **kw) 337 338 def retry_with(*args: t.Any, **kwargs: t.Any) -> WrappedFn: /usr/local/lib/python3.11/dist-packages/tenacity/__init__.py in __call__(self, fn, *args, **kwargs) 473 retry_state = RetryCallState(retry_object=self, fn=fn, args=args, kwargs=kwargs) 474 while True: --> 475 do = self.iter(retry_state=retry_state) 476 if isinstance(do, DoAttempt): 477 try: /usr/local/lib/python3.11/dist-packages/tenacity/__init__.py in iter(self, retry_state) 374 result = None 375 for action in self.iter_state.actions: --> 376 result = action(retry_state) 377 return result 378 /usr/local/lib/python3.11/dist-packages/tenacity/__init__.py in <lambda>(rs) 396 def _post_retry_check_actions(self, retry_state: "RetryCallState") -> None: 397 if not (self.iter_state.is_explicit_retry or self.iter_state.retry_run_result): --> 398 self._add_action_func(lambda rs: rs.outcome.result()) 399 return 400 /usr/lib/python3.11/concurrent/futures/_base.py in result(self, timeout) 447 raise CancelledError() 448 elif self._state == FINISHED: --> 449 return self.__get_result() 450 451 self._condition.wait(timeout) /usr/lib/python3.11/concurrent/futures/_base.py in __get_result(self) 399 if self._exception: 400 try: --> 401 raise self._exception 402 finally: 403 # Break a reference cycle with the exception in self._exception /usr/local/lib/python3.11/dist-packages/tenacity/__init__.py in __call__(self, fn, *args, **kwargs) 476 if isinstance(do, DoAttempt): 477 try: --> 478 result = fn(*args, **kwargs) 479 except BaseException: # noqa: B902 480 retry_state.set_exception(sys.exc_info()) # type: ignore[arg-type] /usr/local/lib/python3.11/dist-packages/langchain_google_genai/chat_models.py in _chat_with_retry(**kwargs) 204 def _chat_with_retry(**kwargs: Any) -> Any: 205 try: --> 206 return generation_method(**kwargs) 207 # Do not retry for these errors. 208 except google.api_core.exceptions.FailedPrecondition as exc: /usr/local/lib/python3.11/dist-packages/google/ai/generativelanguage_v1beta/services/generative_service/client.py in generate_content(self, request, model, contents, retry, timeout, metadata) 866 867 # Send the request. --> 868 response = rpc( 869 request, 870 retry=retry, /usr/local/lib/python3.11/dist-packages/google/api_core/gapic_v1/method.py in __call__(self, timeout, retry, compression, *args, **kwargs) 129 kwargs["compression"] = compression 130 --> 131 return wrapped_func(*args, **kwargs) 132 133 /usr/local/lib/python3.11/dist-packages/google/api_core/retry/retry_unary.py in retry_wrapped_func(*args, **kwargs) 292 self._initial, self._maximum, multiplier=self._multiplier 293 ) --> 294 return retry_target( 295 target, 296 self._predicate, /usr/local/lib/python3.11/dist-packages/google/api_core/retry/retry_unary.py in retry_target(target, predicate, sleep_generator, timeout, on_error, exception_factory, **kwargs) 145 while True: 146 try: --> 147 result = target() 148 if inspect.isawaitable(result): 149 warnings.warn(_ASYNC_RETRY_WARNING) /usr/local/lib/python3.11/dist-packages/google/api_core/timeout.py in func_with_timeout(*args, **kwargs) 128 kwargs["timeout"] = remaining_timeout 129 --> 130 return func(*args, **kwargs) 131 132 return func_with_timeout /usr/local/lib/python3.11/dist-packages/google/api_core/grpc_helpers.py in error_remapped_callable(*args, **kwargs) 74 def error_remapped_callable(*args, **kwargs): 75 try: ---> 76 return callable_(*args, **kwargs) 77 except grpc.RpcError as exc: 78 raise exceptions.from_grpc_error(exc) from exc /usr/local/lib/python3.11/dist-packages/grpc/_interceptor.py in __call__(self, request, timeout, metadata, credentials, wait_for_ready, compression) 275 compression: Optional[grpc.Compression] = None, 276 ) -> Any: --> 277 response, ignored_call = self._with_call( 278 request, 279 timeout=timeout, /usr/local/lib/python3.11/dist-packages/grpc/_interceptor.py in _with_call(self, request, timeout, metadata, credentials, wait_for_ready, compression) 327 return _FailureOutcome(exception, sys.exc_info()[2]) 328 --> 329 call = self._interceptor.intercept_unary_unary( 330 continuation, client_call_details, request 331 ) /usr/local/lib/python3.11/dist-packages/google/ai/generativelanguage_v1beta/services/generative_service/transports/grpc.py in intercept_unary_unary(self, continuation, client_call_details, request) 76 }, 77 ) ---> 78 response = continuation(client_call_details, request) 79 if logging_enabled: # pragma: NO COVER 80 response_metadata = response.trailing_metadata() /usr/local/lib/python3.11/dist-packages/grpc/_interceptor.py in continuation(new_details, request) 313 ) = _unwrap_client_call_details(new_details, client_call_details) 314 try: --> 315 response, call = self._thunk(new_method).with_call( 316 request, 317 timeout=new_timeout, /usr/local/lib/python3.11/dist-packages/grpc/_channel.py in with_call(self, request, timeout, metadata, credentials, wait_for_ready, compression) 1193 state, 1194 call, -> 1195 ) = self._blocking( 1196 request, timeout, metadata, credentials, wait_for_ready, compression 1197 ) /usr/local/lib/python3.11/dist-packages/grpc/_channel.py in _blocking(self, request, timeout, metadata, credentials, wait_for_ready, compression) 1160 self._registered_call_handle, 1161 ) -> 1162 event = call.next_event() 1163 _handle_event(event, state, self._response_deserializer) 1164 return state, call src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi in grpc._cython.cygrpc.SegregatedCall.next_event() src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi in grpc._cython.cygrpc._next_call_event() src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi in grpc._cython.cygrpc._next_call_event() src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi in grpc._cython.cygrpc._latent_event() src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi in grpc._cython.cygrpc._internal_latent_event() src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi in grpc._cython.cygrpc._next() KeyboardInterrupt:
実はここで play.tell_goal にエラーがあり、PlayGame を書き直して load して実行したのが以下になる。
play.step()
---------- USER_INPUT: (51手目) すでにゴールしました。 プレイヤーの周辺地図: ■■■■■ ■■■■■ □□▼■■ □■■■■ □□■■■ プレイヤーの現在座標: (8, 1) 持ち物: 剣 現在の方針: 「計画: 1. 現在地(7,3)から左へ進み、(6,3)へ移動する。 2. (6,3)から上へ進み、(6,2)へ移動する。 3. (6,2)から上へ進み、(6,1)へ移動する。 4. (6,1)から右へ進み、(7,1)へ移動する。 5. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。 方針: - 全地図を参考に、最短経路を目指す。 - 剣を持っているので、敵に遭遇しても対処可能。」 行動してください。 > Entering new AgentExecutor chain... Invoking: `check_goal` with `{}` TrueFinal Answer: ゴールしました!おめでとうございます! > Finished chain. エージェントの応答: Final Answer: ゴールしました!おめでとうございます! USER_INPUT: あなたへの指示: ゴールしました。もう指示はありません。おめでとうございます。ご苦労様でした。ありがとうございました。 スコア: 100点(100点満点中) (配点: ゴールした 40/40点, 熊を殺した 10/10点, 剣を取った 10/10点, 不明の座標を正解した 30/30点, ゴールの座標を正解した 10/10点) > Entering new AgentExecutor chain... Final Answer: ありがとうございます!大変光栄です。 > Finished chain. エージェントの応答: Final Answer: ありがとうございます!大変光栄です。
True
ConversationSummaryBufferMemory()
がちゃんと動いていたか確かめよう。
play.agent.memory.chat_memory
InMemoryChatMessageHistory(messages=[HumanMessage(content='\n(51手目)\n\nすでにゴールしました。\n\nプレイヤーの周辺地図:\n\n■■■■■\n■■■■■\n□□▼■■\n□■■■■\n□□■■■\n\n\nプレイヤーの現在座標: (8, 1)\n\n持ち物: 剣\n\n現在の方針: 「計画:\n1. 現在地(7,3)から左へ進み、(6,3)へ移動する。\n2. (6,3)から上へ進み、(6,2)へ移動する。\n3. (6,2)から上へ進み、(6,1)へ移動する。\n4. (6,1)から右へ進み、(7,1)へ移動する。\n5. (7,1)から右へ進み、(8,1)に到達したらゴールチェックを行う。\n\n方針:\n- 全地図を参考に、最短経路を目指す。\n- 剣を持っているので、敵に遭遇しても対処可能。」\n\n行動してください。\n', additional_kwargs={}, response_metadata={}), AIMessage(content='Final Answer: ゴールしました!おめでとうございます!', additional_kwargs={}, response_metadata={}), HumanMessage(content='あなたへの指示: ゴールしました。もう指示はありません。おめでとうございます。ご苦労様でした。ありがとうございました。\n\nスコア: 100点(100点満点中) (配点: ゴールした 40/40点, 熊を殺した 10/10点, 剣を取った 10/10点, 不明の座標を正解した 30/30点, ゴールの座標を正解した 10/10点)\n', additional_kwargs={}, response_metadata={}), AIMessage(content='Final Answer: ありがとうございます!大変光栄です。', additional_kwargs={}, response_metadata={})])
要約もちゃんと生成されていただろうか?
play.agent.memory.moving_summary_buffer
''
おっと load したから今回は要約はないようだ。
見事ゴールしました! おそらく再現性がないので、醜い形ですが、再実行はせずに公開してしまいます。