自分の学びのために、小さなブログを書くことにしました。Open AI Agents SDK を理解してみようと思います。
初回は、Memory の機能に関して、書いてみます。今回はデフォルトの短期記憶の Session について記載しますが、次回は、長期記憶のサンプルを書いてみたいと思います。
Memory のフィーチャー
Agent で使えるメモリのフィーチャーは基本的に、長期記憶用ではなくて、短期のヒストリ用です。セッション履歴を保持します。一応公式ドキュメントはあるのですが、どっちかというと、公式のリポジトリのサンプルや、本体のコードから理解するほうがよさげです。(AIも古いサンプルを返しました)
他にも、ここで示した、インメモリの実装の他にも sqliteの実装がありますが、インターフェイスは単純なので、自分で実装できそうです。Sessionsを観ると定義が分かります。
class SessionABC(ABC):
"""Abstract base class for session implementations.
Session stores conversation history for a specific session, allowing
agents to maintain context without requiring explicit manual memory management.
This ABC is intended for internal use and as a base class for concrete implementations.
Third-party libraries should implement the Session protocol instead.
"""
session_id: str
@abstractmethod
async def get_items(self, limit: int | None = None) -> list[TResponseInputItem]:
"""Retrieve the conversation history for this session.
Args:
limit: Maximum number of items to retrieve. If None, retrieves all items.
When specified, returns the latest N items in chronological order.
Returns:
List of input items representing the conversation history
"""
...
@abstractmethod
async def add_items(self, items: list[TResponseInputItem]) -> None:
"""Add new items to the conversation history.
Args:
items: List of input items to add to the history
"""
...
@abstractmethod
async def pop_item(self) -> TResponseInputItem | None:
"""Remove and return the most recent item from the session.
Returns:
The most recent item if it exists, None if the session is empty
"""
...
@abstractmethod
async def clear_session(self) -> None:
"""Clear all items for this session."""
...
この実装をどのように使うかというと、とても単純で
session = OpenAIConversationsSession()
agent = Agent(
name="Assistant",
instructions="Reply very concisely."
)
result = await Runner.run(
agent,
user_input,
session=session
)
サンプル
もちろん先ほど示したメソッドを示すこともできます。一つ単純なサンプルを書いてみます。
import asyncio
from dotenv import load_dotenv
from agents import Agent, OpenAIConversationsSession, Runner
load_dotenv()
session = OpenAIConversationsSession()
agent = Agent(
name="Assistant",
instructions="Reply very concisely."
)
async def main():
print("=== Simple ChatBot with Agent SDK Memory ===")
print("type 'exit' to quit\n")
while True:
user_input=input("You: ")
if user_input.lower() in ["exit", "quit"]:
break
if user_input.lower() in ["clear"]:
session.clear_session()
print("Chat history cleared.")
continue
result = await Runner.run(
agent,
user_input,
session=session
)
print("Bot:", result.final_output)
# Display session contents with color
print("\n\033[36m" + "="*50) # Cyan color
print("Session Contents:")
print("="*50)
for idx, message in enumerate(await session.get_items(), 1):
role = message.get('role', 'unknown')
content = message.get('content', '')
print(f"{idx}. [{role.upper()}]: {content}")
print("="*50 + "\033[0m\n") # Reset color
if __name__ == "__main__":
asyncio.run(main())
実行したらヒストリが蓄積されているのが分かります。
You: リトルウォルターはいつ生まれたのかと、代表曲を教えてください。
Bot: リトル・ウォルター(Little Walter)は、1930年5月1日生まれです。
代表曲:
- "Juke"
- "My Babe"
- "Mean Old World"
- "Blues with a Feeling"
==================================================
Session Contents:
==================================================
1. [USER]: [{'text': 'Deep Blues のアーティストを教えてください', 'type': 'input_text'}]
2. [ASSISTANT]: [{'annotations': [], 'text': 'Deep Blues のアーティストは、Cornelius(小山田圭吾)です。', 'type': 'output_text', 'logprobs': []}]
3. [USER]: [{'text': 'それではなくDelta blues や Deep な Chicago Blues のアーティストです', 'type': 'input_text'}]
4. [ASSISTANT]: [{'annotations': [], 'text': '代表的なDelta bluesアーティスト:\n- ロバート・ジョンソン (Robert Johnson)\n- サン・ハウス (Son House)\n- チャーリー・パットン (Charley Patton)\n- ミシシッピ・ジョン・ハート (Mississippi John Hurt)\n\n代表的なDeepなChicago Bluesアーティスト:\n- マディ・ウォーターズ (Muddy Waters)\n- ハウリン・ウルフ (Howlin’ Wolf)\n- オーティス・ラッシュ (Otis Rush)\n- バディ・ガイ (Buddy Guy)', 'type': 'output_text', 'logprobs': []}]
5. [USER]: [{'text': '代表的なハーププレイヤーを教えてください。', 'type': 'input_text'}]
6. [ASSISTANT]: [{'annotations': [], 'text': '代表的なブルース・ハープ(ハーモニカ)プレイヤー:\n\n- リトル・ウォルター (Little Walter)\n- ソニー・ボーイ・ウィリアムソン II (Sonny Boy Williamson II)\n- ジュニア・ウェルズ (Junior Wells)\n- ジェイムズ・コットン (James Cotton)\n- ビッグ・ウォルター・ホートン (Big Walter Horton)\n- ソニー・テリー (Sonny Terry)', 'type': 'output_text', 'logprobs': []}]
7. [USER]: [{'text': 'リトルウォルターはいつ生まれたのかと、代表曲を教えてください。', 'type': 'input_text'}]
8. [ASSISTANT]: [{'annotations': [], 'text': 'リトル・ウォルター(Little Walter)は、1930年5月1日生まれです。\n\n代表曲:\n- "Juke"\n- "My Babe"\n- "Mean Old World"\n- "Blues with a Feeling"', 'type': 'output_text', 'logprobs': []}]
==================================================
ヒストリの制限
簡単な例として、ヒストリを制限できないでしょうか?永遠とヒストリをキープしていると、LLMが混乱しますので、例えば、ラスト10のヒストリを有効にするとか、きっとオプションで…できなそう。
このようなケースでは、自分で実装すれば良さげです。
from __future__ import annotations
from typing import Any, Dict, List
from agents import OpenAIConversationsSession
MAX_HISTORY_ITEMS = 10
class LimitedOpenAIConversationsSession(OpenAIConversationsSession):
"""Session wrapper that scopes retrieved history to the latest N items."""
def __init__(self, *, max_history_items: int = MAX_HISTORY_ITEMS, **kwargs: Any) -> None:
super().__init__(**kwargs)
if max_history_items <= 0:
raise ValueError("max_history_items must be a positive integer")
self._max_history_items = max_history_items
@property
def max_history_items(self) -> int:
return self._max_history_items
async def get_items(self, limit: int | None = None) -> List[Dict[str, Any]]:
"""Return at most `max_history_items` conversation items in chronological order."""
effective_limit = self._max_history_items if limit is None else min(limit, self._max_history_items)
return await super().get_items(limit=effective_limit)
先ほどのサンプルを変更して、ヒストリの保持を3にしています。
import asyncio
from dotenv import load_dotenv
from agents import Agent, Runner
from limited_session import (
LimitedOpenAIConversationsSession,
)
load_dotenv()
session = LimitedOpenAIConversationsSession(max_history_items=3)
agent = Agent(
name="Assistant",
instructions="Reply very concisely."
)
async def main():
print("=== Simple ChatBot with Agent SDK Memory ===")
print("type 'exit' to quit\n")
while True:
user_input=input("You: ")
if user_input.lower() in ["exit", "quit"]:
break
if user_input.lower() in ["clear"]:
session.clear_session()
print("Chat history cleared.")
continue
result = await Runner.run(
agent,
user_input,
session=session
)
print("Bot:", result.final_output)
# Display session contents with color
print("\n\033[36m" + "="*50) # Cyan color
print("Session Contents:")
print("="*50)
for idx, message in enumerate(await session.get_items(), 1):
role = message.get('role', 'unknown')
content = message.get('content', '')
print(f"{idx}. [{role.upper()}]: {content}")
print("="*50 + "\033[0m\n") # Reset color
if __name__ == "__main__":
asyncio.run(main())
実行したらしっかり鳥のように忘れていますね。
(simple-chatbot) PS C:\repo\learning\memory\scoped-history-simple-chatbot> python app.py
=== Simple ChatBot with Agent SDK Memory ===
type 'exit' to quit
You: Deep Blues のアーティストについて教えてください。
Bot: 「Deep Blues」は、複数のアーティストやバンドによるアルバム・プロジェクト名や曲名として使われていますが、有名な例としては「Deep Blues: Original Motion Picture Soundtrack」があります。これは1991年の同名ドキュメンタリー映画のサウンドトラックで、Junior Kimbrough、R.L. Burnside、Big Jack Johnson、Roosevelt Barnes など、ミシシッピ・ブルースの名アーティストが参加しています。詳しいアーティスト名を指定していただければ、より深くお調べします。
==================================================
Session Contents:
==================================================
1. [USER]: [{'text': 'Deep Blues のアーティストについて教えてください。', 'type': 'input_text'}]
2. [ASSISTANT]: [{'annotations': [], 'text': '「Deep Blues」は、複数のアーティストやバンドによるアルバム・プロジェクト名や曲名として使われていますが、有名な例としては「Deep Blues: Original Motion Picture Soundtrack」があります。これは1991年の同名ドキュメンタリー映画のサウンドトラックで、Junior Kimbrough、R.L. Burnside、Big Jack Johnson、Roosevelt Barnes など、ミシシッピ・ブルースの名アーティストが参加しています。詳しいアーティスト名を指定していただければ、より深くお調べします。', 'type': 'output_text', 'logprobs': []}]
==================================================
You: R.L. Burnside について詳しく教えてください
Bot: R.L. Burnside(Rural L. Burnside、1926年11月23日 - 2005年9月1日)は、アメリカ合衆国ミシシッピ州出身のブルース・ミュージシャンです。ノース・ミシシッピ・ヒル・カントリー・ブルースの代表的存在で、粗削りなギターとディープなグルーヴが特徴です。1990年代にFat Possum Recordsからのアルバムリリースで再評価され、「It's Bad You Know」や「Let My Baby Ride」などが人気。ロック・ヒップホップともコラボし、ブルース・リバイバルの立役者となりました。
==================================================
Session Contents:
==================================================
1. [ASSISTANT]: [{'annotations': [], 'text': '「Deep Blues」は、複数のアーティストやバンドによるアルバム・プロジェクト名や曲名として使われていますが、有名な例としては「Deep Blues: Original Motion Picture Soundtrack」があります。これは1991年の同名ドキュメンタリー映画のサウンドトラックで、Junior Kimbrough、R.L. Burnside、Big Jack Johnson、Roosevelt Barnes など、ミシシッピ・ブルースの名アーティストが参加しています。詳しいアーティスト名を指定していただければ、より深くお調べします。', 'type': 'output_text', 'logprobs': []}]
2. [USER]: [{'text': 'R.L. Burnside について詳しく教えてください', 'type': 'input_text'}]
3. [ASSISTANT]: [{'annotations': [], 'text': "R.L. Burnside(Rural L. Burnside、1926年11月23日 - 2005年9月1日)は、アメリカ合衆国ミシシッピ州出身のブルース・ミュージシャンです。ノース・ミシシッピ・ヒル・カントリー・ブルースの代表的存在で、粗削りなギターとディープなグルーヴが特徴です。1990年代にFat Possum Recordsからのアルバムリリースで再評価され、「It's Bad You Know」や「Let My Baby Ride」などが人気。ロック・ヒップホップともコラボし、ブルース・リバイバルの立役者となりました。", 'type': 'output_text', 'logprobs': []}]
==================================================
You: 子供はいますか?
Bot: はい、R.L. Burnsideには複数の子供がいます。なかでも息子のCedric Burnside(セドリック・バーンサイド)はドラマーおよびブルース・ミュージシャンとして有名です。CedricはR.L.と一緒に演奏し、現在も活躍しています。
==================================================
Session Contents:
==================================================
1. [ASSISTANT]: [{'annotations': [], 'text': "R.L. Burnside(Rural L. Burnside、1926年11月23日 - 2005年9月1日)は、アメリカ合衆国ミシシッピ州出身のブルース・ミュージシャンです。ノース・ミシシッピ・ヒル・カントリー・ブルースの代表的存在で、粗削りなギターとディープなグルーヴが特徴です。1990年代にFat Possum Recordsからのアルバムリリースで再評価され、「It's Bad You Know」や「Let My Baby Ride」などが人気。ロック・ヒップホップともコラボし、ブルース・リバイバルの立役者となりました。", 'type': 'output_text', 'logprobs': []}]
2. [USER]: [{'text': '子供はいますか?', 'type': 'input_text'}]
3. [ASSISTANT]: [{'annotations': [], 'text': 'はい、R.L. Burnsideには複数の子供がいます。なかでも息子のCedric Burnside(セドリック・バーンサイド)はドラマーおよびブルース・ミュージシャンとして有名です。CedricはR.L.と一緒に演奏し、現在も活躍しています。', 'type': 'output_text', 'logprobs': []}]
==================================================
You: Cedric について教えてください
Bot: Cedric Burnside(セドリック・バーンサイド、1978年8月26日生まれ)は、アメリカ・ミシシッピ州出身のブルース・ドラマー、ギタリスト、シンガーです。祖父R.L. Burnsideのバンドで10代からドラムを担当し、ノース・ミシシッピ・ヒル・カントリー・ブルースの重要な継承者とされています。
ソロ活動でも評価が高く、グラミー賞を受賞(2022年「I Be Trying」)しました。タフなビートと魂のこもった歌声が特徴です。
==================================================
Session Contents:
==================================================
1. [ASSISTANT]: [{'annotations': [], 'text': 'はい、R.L. Burnsideには複数の子供がいます。なかでも息子のCedric Burnside(セドリック・バーンサイド)はドラマーおよびブルース・ミュージシャンとして有名です。CedricはR.L.と一緒に演奏し、現在も活躍しています。', 'type': 'output_text', 'logprobs': []}]
2. [USER]: [{'text': 'Cedric について教えてください', 'type': 'input_text'}]
3. [ASSISTANT]: [{'annotations': [], 'text': 'Cedric Burnside(セドリック・バーンサイド、1978年8月26日生まれ)は、アメリカ・ミシシッピ州出身のブルース・ドラマー、ギタリスト、シンガーです。祖父R.L. Burnsideのバンドで10代からドラムを担当し、ノース・ミシシッピ・ヒル・カントリー・ブルースの重要な継承者とされています。\n\nソロ活動でも評価が高く、グラミー賞を受賞(2022年「I Be Trying」)しました。タフなビートと魂のこもった歌声が特徴です。', 'type': 'output_text', 'logprobs': []}]
==================================================
You: 私が最初にした質問は何ですか?
Bot: あなたが最初にした質問は「R.L. Burnsideの子供は?」です。
==================================================
Session Contents:
==================================================
1. [ASSISTANT]: [{'annotations': [], 'text': 'Cedric Burnside(セドリック・バーンサイド、1978年8月26日生まれ)は、アメリカ・ミシシッピ州出身のブルース・ドラマー、ギタリスト、シンガーです。祖父R.L. Burnsideのバンドで10代からドラムを担当し、ノース・ミシシッピ・ヒル・カントリー・ブルースの重要な継承者とされています。\n\nソロ活動でも評価が高く、グラミー賞を受賞(2022年「I Be Trying」)しました。タフなビートと魂のこもった歌声が特徴です。', 'type': 'output_text', 'logprobs': []}]
2. [USER]: [{'text': '私が最初にした質問は何ですか?', 'type': 'input_text'}]
3. [ASSISTANT]: [{'annotations': [], 'text': 'あなたが最初にした質問は「R.L. Burnsideの子供は?」です。', 'type': 'output_text', 'logprobs': []}]
==================================================
次回
次回以降は、mem0 や、CosmosDB + Vector Search を使って、長期記憶の実装を試してみます。