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 さん)に教わって作っています。

実装¶

まず、必要なライブラリを読み込みます。

In [ ]:
!pip install -U -q langchain langchain-google-genai

Gemini にアクセスします。シークレットで Gemini API キーを Google AI Studio からインポートすると GOOGLE_API_KEY というシークレットができるはずです。それを使います。

In [ ]:
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 にアクセスできるかテストします。

In [ ]:
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技術の発展を牽引する存在として期待されています。

基本的なモジュールを読み込みます。

In [ ]:
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 ドライブを使わない場合次のコードを実行します。

In [ ]:
PLAY_GAME_SAVE = "langchain_maze.pickle"

セーブ/ロードに Google ドライブを使う場合は以下の SaveDir のパスを Google ドライブ上に作って以下を実行します。

In [ ]:
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

ゲームのメインオブジェクト。ごく簡単な迷路というかダンジョンというか…。

In [ ]:
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)])

別のマップでためすための変換コード。

In [ ]:
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 用にある点から別の点へのパスの木を見つける関数。

In [ ]:
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

ゲームがうまく動くかテスト。

In [ ]:
game = Game()
In [ ]:
search_path(game, (4,8), (1,5)) #スタート地点から熊がいるところまでのパス。
Out[ ]:
((4, 8),
 [((4, 7), [((3, 7), [((2, 7), [((1, 7), [((1, 6), [((1, 5), [])])])])])])])
In [ ]:
m2 = flip_text_map(rotate_text_map(Game.initial_map))
print(m2)
■■■■■■■■■■
■■□□□◎□□■■
■■□■■■■□■■
■■□■■■■□■■
■■□■■■■□S■
■■□□■■■□■■
■■■□■■■□■■
■G□□■△□□■■
■■■■■■■■■■

In [ ]:
game = Game(initial_map=m2)
In [ ]:
print(game.surroundings())
■□■■■
■□■■■
■□▼■■
■□■■■
■□■■■

In [ ]:
print(game.move_up())
print(game.surroundings())
壁があって進めない。
■□■■■
■□■■■
■□▼■■
■□■■■
■□■■■

In [ ]:
print(game.move_left())
print(game.surroundings())
左に進んだ。
■■□■■
■■□■■
■■▼S■
■■□■■
■■□■■

In [ ]:
print(game.move_right())
print(game.surroundings())
右に進んだ。
■□■■■
■□■■■
■□▼■■
■□■■■
■□■■■

In [ ]:
print(game.move_down())
print(game.surroundings())
壁があって進めない。
■□■■■
■□■■■
■□▼■■
■□■■■
■□■■■

In [ ]:
print(game.fight())
print(game.surroundings())
無意味な指示。敵がいない。
■□■■■
■□■■■
■□▼■■
■□■■■
■□■■■

In [ ]:
print(game.get_sword())
print(game.surroundings())
無意味な指示。近くに剣がない。
■□■■■
■□■■■
■□▼■■
■□■■■
■□■■■

create_tool_calling_agent のテスト。↓の例です。

《LangChain の Tool Calling 標準インタフェース の概要|npaka》
https://note.com/npaka/n/ne6fd5929bfa1

In [ ]:
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.
Out[ ]:
{'input': "what's 3 plus 5 raised to the 2.743. also what's 17.24 - 918.1241",
 'output': ''}

LLM を使いながらゲームを解くクラス。

In [ ]:
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
In [ ]:
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)

ゲームを解いてみる。地図は方向をランダムに決めて与える。

In [ ]:
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□■■■■□■■
■■□■■■■□■■
■■□■■■■□■■
■■□□◎□□□■■
■■■■■■■■■■

In [ ]:
play = PlayGame(llm=llm, initial_map=m, save_file=PLAY_GAME_SAVE)
play.save()

途中から始める場合は直前のコードを実行せず、次だけを実行する。

In [ ]:
play = PlayGame.load(PLAY_GAME_SAVE)

最初のステップ。

In [ ]:
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.
エージェントの応答: 正解を評価していただきありがとうございます。次の指示をお待ちしています。

Out[ ]:
False

最初のステップで "Message's content is expected to be a dict, got <class 'int'>!" …というエラーが出るときがあって、一度それが出ると、その後も同じエラーが invoke のごとに発生してしまう。そのような場合は次を実行する。

In [ ]:
play.agent.memory.clear()

思い切って回してみよう。

In [ ]:
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 して実行したのが以下になる。

In [ ]:
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: ありがとうございます!大変光栄です。

Out[ ]:
True

ConversationSummaryBufferMemory() がちゃんと動いていたか確かめよう。

In [ ]:
play.agent.memory.chat_memory
Out[ ]:
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={})])

要約もちゃんと生成されていただろうか?

In [ ]:
play.agent.memory.moving_summary_buffer
Out[ ]:
''

おっと load したから今回は要約はないようだ。

見事ゴールしました! おそらく再現性がないので、醜い形ですが、再実行はせずに公開してしまいます。