跳转到内容

记忆:通过MemoryService实现长期知识存储

我们已经了解了Session如何跟踪单个持续对话的历史记录(events)和临时数据(state)。但如果智能体需要回忆过去对话的信息或访问外部知识库呢?这正是长期知识MemoryService概念发挥作用的地方。

可以这样理解:

  • Session / State: 就像你在某次特定聊天中的短期记忆。
  • 长期知识(MemoryService:就像一个可搜索的档案库或知识库,智能体可以随时查阅,可能包含来自过去多次对话或其他来源的信息。

MemoryService 角色

BaseMemoryService 定义了管理这个可搜索的长期知识存储的接口。其主要职责包括:

  1. 信息摄取 (add_session_to_memory): 获取一个(通常已完成的)Session的内容,并将相关信息添加到长期知识存储中。
  2. 信息搜索 (search_memory): 允许智能体(通常通过Tool)查询知识库,并根据搜索查询检索相关片段或上下文。

MemoryService 实现

ADK提供了实现这种长期知识存储的不同方法:

  1. InMemoryMemoryService

    • 工作原理: 将会话信息存储在应用程序内存中,并为搜索执行基本的关键词匹配。
    • 持久性: 无。如果应用程序重启,所有存储的知识都将丢失。
    • 要求:无需额外条件。
    • 最佳适用场景:原型设计、简单测试、仅需基础关键词召回且无需持久化的场景。
    from google.adk.memory import InMemoryMemoryService
    memory_service = InMemoryMemoryService()
    
  2. VertexAiRagMemoryService

    • 工作原理: 利用Google Cloud的Vertex AI RAG(检索增强生成)服务。它将会话数据摄取到指定的RAG语料库中,并利用强大的语义搜索能力进行检索。
    • 持久性: 是的。知识会持久存储在配置的Vertex AI RAG Corpus中。
    • 要求: 一个Google Cloud项目、适当的权限、必要的SDK(pip install google-adk[vertexai])以及预先配置好的Vertex AI RAG Corpus资源名称/ID。
    • 最佳适用场景:需要可扩展、持久且语义相关知识检索的生产应用程序,特别是部署在Google Cloud上的情况。
    # Requires: pip install google-adk[vertexai]
    # Plus GCP setup, RAG Corpus, and authentication
    from google.adk.memory import VertexAiRagMemoryService
    
    # The RAG Corpus name or ID
    RAG_CORPUS_RESOURCE_NAME = "projects/your-gcp-project-id/locations/us-central1/ragCorpora/your-corpus-id"
    # Optional configuration for retrieval
    SIMILARITY_TOP_K = 5
    VECTOR_DISTANCE_THRESHOLD = 0.7
    
    memory_service = VertexAiRagMemoryService(
        rag_corpus=RAG_CORPUS_RESOURCE_NAME,
        similarity_top_k=SIMILARITY_TOP_K,
        vector_distance_threshold=VECTOR_DISTANCE_THRESHOLD
    )
    

内存在实际中的工作原理

典型的工作流程包括以下步骤:

  1. 会话交互:用户通过Session与智能体进行交互,该会话由SessionService管理。可以添加事件,并可能更新状态。
  2. 存入记忆:在某个时刻(通常是当会话被认为已完成或产生了重要信息时),您的应用程序会调用memory_service.add_session_to_memory(session)。这将从会话事件中提取相关信息,并将其添加到长期知识存储(内存字典或RAG语料库)中。
  3. 后续查询:不同(或相同)的会话中,用户可能会提出需要历史上下文的问题(例如:"上周我们关于项目X讨论了什么?")。
  4. 智能体使用记忆工具: 配备记忆检索工具(如内置的load_memory工具)的智能体会识别出需要过去上下文的情况。它会调用该工具,提供一个搜索查询(例如"上周讨论项目X")。
  5. 搜索执行: 该工具内部调用 memory_service.search_memory(app_name, user_id, query)
  6. 返回结果: MemoryService 搜索其存储(使用关键词匹配或语义搜索)并返回相关片段作为 SearchMemoryResponse,其中包含一个 MemoryResult 对象列表(每个对象可能包含来自相关过去会话的事件)。
  7. 智能体使用结果: 该工具将这些结果返回给智能体,通常作为上下文或函数响应的一部分。智能体随后可以利用检索到的信息来构建最终给用户的答案。

示例:添加和搜索记忆

此示例演示了使用InMemory服务的基本流程,以简化操作。

Full Code
import asyncio
from google.adk.agents import LlmAgent
from google.adk.sessions import InMemorySessionService, Session
from google.adk.memory import InMemoryMemoryService # Import MemoryService
from google.adk.runners import Runner
from google.adk.tools import load_memory # Tool to query memory
from google.genai.types import Content, Part

# --- Constants ---
APP_NAME = "memory_example_app"
USER_ID = "mem_user"
MODEL = "gemini-2.0-flash" # Use a valid model

# --- Agent Definitions ---
# Agent 1: Simple agent to capture information
info_capture_agent = LlmAgent(
    model=MODEL,
    name="InfoCaptureAgent",
    instruction="Acknowledge the user's statement.",
    # output_key="captured_info" # Could optionally save to state too
)

# Agent 2: Agent that can use memory
memory_recall_agent = LlmAgent(
    model=MODEL,
    name="MemoryRecallAgent",
    instruction="Answer the user's question. Use the 'load_memory' tool "
                "if the answer might be in past conversations.",
    tools=[load_memory] # Give the agent the tool
)

# --- Services and Runner ---
session_service = InMemorySessionService()
memory_service = InMemoryMemoryService() # Use in-memory for demo

runner = Runner(
    # Start with the info capture agent
    agent=info_capture_agent,
    app_name=APP_NAME,
    session_service=session_service,
    memory_service=memory_service # Provide the memory service to the Runner
)

# --- Scenario ---

# Turn 1: Capture some information in a session
print("--- Turn 1: Capturing Information ---")
session1_id = "session_info"
session1 = session_service.create_session(APP_NAME, USER_ID, session1_id)
user_input1 = Content(parts=[Part(text="My favorite project is Project Alpha.")])

# Run the agent
final_response_text = "(No final response)"
for event in runner.run(USER_ID, session1_id, user_input1):
    if event.is_final_response() and event.content and event.content.parts:
        final_response_text = event.content.parts[0].text
print(f"Agent 1 Response: {final_response_text}")

# Get the completed session
completed_session1 = session_service.get_session(APP_NAME, USER_ID, session1_id)

# Add this session's content to the Memory Service
print("\n--- Adding Session 1 to Memory ---")
memory_service.add_session_to_memory(completed_session1)
print("Session added to memory.")

# Turn 2: In a *new* (or same) session, ask a question requiring memory
print("\n--- Turn 2: Recalling Information ---")
session2_id = "session_recall" # Can be same or different session ID
session2 = session_service.create_session(APP_NAME, USER_ID, session2_id)

# Switch runner to the recall agent
runner.agent = memory_recall_agent
user_input2 = Content(parts=[Part(text="What is my favorite project?")])

# Run the recall agent
print("Running MemoryRecallAgent...")
final_response_text_2 = "(No final response)"
for event in runner.run(USER_ID, session2_id, user_input2):
    print(f"  Event: {event.author} - Type: {'Text' if event.content and event.content.parts and event.content.parts[0].text else ''}"
        f"{'FuncCall' if event.get_function_calls() else ''}"
        f"{'FuncResp' if event.get_function_responses() else ''}")
    if event.is_final_response() and event.content and event.content.parts:
        final_response_text_2 = event.content.parts[0].text
        print(f"Agent 2 Final Response: {final_response_text_2}")
        break # Stop after final response

# Expected Event Sequence for Turn 2:
# 1. User sends "What is my favorite project?"
# 2. Agent (LLM) decides to call `load_memory` tool with a query like "favorite project".
# 3. Runner executes the `load_memory` tool, which calls `memory_service.search_memory`.
# 4. `InMemoryMemoryService` finds the relevant text ("My favorite project is Project Alpha.") from session1.
# 5. Tool returns this text in a FunctionResponse event.
# 6. Agent (LLM) receives the function response, processes the retrieved text.
# 7. Agent generates the final answer (e.g., "Your favorite project is Project Alpha.").