Skip to main content

agent-memory-systems

Implements memory systems for LLM agents including conversation buffers, windowed context, bounded model context management, and vector store-backed long-term memory retrieval with embeddings.

Ir para a instalação

Informações da origem

Repositório
paulpas/agent-skill-router
Última atividade na origem
9 de junho de 2026 às 16:28
Idioma detectado do SKILL.md
inglês
Estrelas
4
Forks
1

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
agent-memory-systems
description
Implements memory systems for LLM agents including conversation buffers, windowed context, bounded model context management, and vector store-backed long-term memory retrieval with embeddings.
license
MIT
compatibility
opencode
metadata
{"version":"1.0.0","domain":"coding","role":"implementation","scope":"implementation","output-format":"code","archetypes":["tactical"],"anti_triggers":["brainstorming","vague ideation","long-form architecture"],"response_profile":{"verbosity":"low","directive_strength":"high","abstraction_level":"operational"},"triggers":"memory systems, conversation buffer, windowed memory, long-term memory, vector store embeddings, context management, conversation history, how do i manage agent memory","related-skills":"agent-tool-calling-architecture,agent-planning-reasoning,langchain"}
# Agent Memory Systems Implements the three-layer memory architecture for LLM agents — short-term conversation buffering, bounded windowed context management, and long-term vector store retrieval with embeddings. When loaded, this skill makes the model produce production-grade memory system code extracted from LangChain, AutoGen, and LlamaIndex patterns. ## TL;DR Checklist - [ ] Short-term memory uses `ChatMemory` backend with configurable human/AI prefixes - [ ] Windowed memory enforces bounded size after each `save_context()` call via `k * 2` message cap - [ ] Model context objects are passed explicitly to agents — never pass full conversation history on each call - [ ] Long-term memory store uses embedding-based semantic similarity with configurable relevance threshold - [ ] Vector store queries return only results above `relevance_threshold` (default 0.7) - [ ] Max tool iterations bounded in assistant agent context to prevent infinite loops --- ## When to Use Use this skill when: - Implementing conversation history management for an LLM agent - Needing bounded context windows to stay within model token limits - Designing long-term memory with vector store-backed semantic retrieval - Building multi-turn agents that need both recent context and factual recall - Integrating AutoGen-style `ChatCompletionContext` objects into agent workflows ## When NOT to Use Avoid this skill for: - Single-turn LLM calls with no conversation history needed - Simple prompt templates without stateful memory management - Implementing tool calling architecture (use `agent-tool-calling-architecture` instead) - Planning and reasoning patterns (use `agent-planning-reasoning` instead) --- ## Core Workflow 1. **Initialize Short-Term Memory with Conversation Buffer** — Create a memory backend (in-memory or database-backed `BaseChatMemory`) and wrap it in `ConversationBufferMemory`. Set `human_prefix`, `ai_prefix`, `memory_key` for prompt injection, and `return_messages=True` for raw message objects. **Checkpoint:** Verify `load_memory_variables()` returns the full conversation under the configured key. 2. **Enforce Bounded Context with Windowed Memory** — Use `ConversationBufferWindowMemory` with parameter `k` (number of turns to retain). After each `save_context()`, check if message count exceeds `k * 2`. If so, clear and re-add only the most recent messages. This provides bounded memory usage with recency bias. **Checkpoint:** Verify that buffer property always returns at most `k * 2` messages regardless of total conversation length. 3. **Configure Model Context Objects (AutoGen Pattern)** — Create an `AssistantAgent` with explicit `model_context` parameter. Use `UnboundedChatCompletionContext()` for unlimited history or subclass for bounded behavior. Set `max_tool_iterations` to prevent infinite tool-call loops. Only pass NEW messages to `on_messages()`, not the full conversation. **Checkpoint:** Verify `_execute_tool_loop()` respects `max_tool_iterations` and falls back with a message when limit is reached. 4. **Set Up Long-Term Memory with Vector Store Embeddings** — Initialize `LongTermMemoryStore` with an embedding model, vector store backend (Pinecone, Weaviate, Qdrant, pgvector), and similarity threshold. Call `add_memory()` to store factual information. Retrieve via `retrieve_memories(query, relevance_threshold)` which performs semantic similarity search. **Checkpoint:** Verify that only results with `score >= relevance_threshold` are returned. 5. **Integrate Memory into Agent Execution** — Inject conversation buffer and retrieved long-term memories into the prompt before each LLM call. The pattern: load recent context (windowed memory) → retrieve relevant long-term facts → combine into single system prompt or message sequence. **Checkpoint:** Verify total token count stays within model limits after combining short-term + long-term memory. --- ## Implementation Patterns ### Pattern 1: Short-Term Memory — Conversation Buffer The simplest form of memory — keeps every message in a list and injects them into future prompts. Use for short conversations only; for long conversations, use windowed or summary memory to manage context limits. ```python # Source: langchain-ai/langchain — libs/langchain/langchain_classic/memory/buffer.py """Conversation buffer memory - stores entire conversation history.""" from typing import Any from langchain_core.messages import BaseMessage, get_buffer_string class ConversationBufferMemory: """Basic memory that stores the entire conversation history. This is the simplest form of memory — it keeps every message in a list and injects them into future prompts. Use this for short conversations. For long conversations, use ConversationBufferWindowMemory or ConversationSummaryMemory instead to manage context window limits. """ def __init__( self, chat_memory: "BaseChatMemory", *, human_prefix: str = "Human", ai_prefix: str = "AI", memory_key: str = "history", return_messages: bool = False, ) -> None: """Initialize the conversation buffer memory. Args: chat_memory: Storage backend for messages (in-memory, database, etc.) human_prefix: Label for human messages in formatted string. ai_prefix: Label for AI messages in formatted string. memory_key: Key to use when injecting into chain inputs. return_messages: If True, return raw message objects; else format as string. """ self.chat_memory = chat_memory self.human_prefix = human_prefix self.ai_prefix = ai_prefix self.memory_key = memory_key self.return_messages = return_messages @property def buffer(self) -> str | list[BaseMessage]: """Current conversation buffer, as string or message list.""" messages = self.chat_memory.messages if self.return_messages: return messages return get_buffer_string( messages, human_prefix=self.human_prefix, ai_prefix=self.ai_prefix, ) def load_memory_variables(self, inputs: dict[str, Any]) -> dict[str, Any]: """Return the current conversation history as a memory variable.""" return {self.memory_key: self.buffer} def save_context( self, inputs: dict[str, Any], outputs: dict[str, str] ) -> None: """Add new interaction to the conversation history. Args: inputs: User input dict (typically has 'input' key). outputs: AI output dict (typically has 'output' or 'response' key). """ human_msg = HumanMessage(content=inputs["input"]) ai_msg = AIMessage(content=outputs["output"]) self.chat_memory.add_messages([human_msg, ai_msg]) def clear(self) -> None: """Clear all stored conversation history.""" self.chat_memory.clear() ``` ### Pattern 2: Windowed Memory — Bounded Context Keeps only the last k turns of a conversation. If the number of messages exceeds `k * 2`, oldest messages are dropped. This provides bounded memory usage with recency bias — recent context is more relevant than older context in most dialogues. ```python # Source: langchain-ai/langchain — libs/langchain/langchain_classic/memory/buffer_window.py """Windowed conversation memory - keeps only the last K turns.""" from typing import Any from langchain_core.messages import BaseMessage, get_buffer_string class ConversationBufferWindowMemory: """Keeps only the last k turns of a conversation. If the number of messages exceeds k * 2, oldest messages are dropped. This provides bounded memory usage with recency bias — recent context is more relevant than older context in most dialogues. Args: k: Number of turns to retain. Each turn = 1 human + 1 AI message. Total messages kept = k * 2. """ def __init__( self, chat_memory: "BaseChatMemory", *, k: int = 5, human_prefix: str = "Human", ai_prefix: str = "AI", memory_key: str = "history", ) -> None: """Initialize windowed memory. Args: chat_memory: Underlying message storage backend. k: Number of conversation turns to retain. Default 5 (10 messages). human_prefix: Label for human messages in formatted output. ai_prefix: Label for AI messages in formatted output. memory_key: Key name when injecting into chain inputs. """ self.chat_memory = chat_memory self.k = k self.human_prefix = human_prefix self.ai_prefix = ai_prefix self.memory_key = memory_key @property def buffer(self) -> str | list[BaseMessage]: """Last k turns of conversation history.""" messages = self.chat_memory.messages # Keep last k * 2 messages (k human + k AI exchanges) recent = messages[-self.k * 2:] if self.k > 0 else [] return get_buffer_string( recent, human_prefix=self.human_prefix, ai_prefix=self.ai_prefix, ) def save_context( self, inputs: dict[str, Any], outputs: dict[str, str] ) -> None: """Add new interaction and enforce window bounds.""" human_msg = HumanMessage(content=inputs["input"]) ai_msg = AIMessage(content=outputs["output"]) self.chat_memory.add_messages([human_msg, ai_msg]) # Enforce window after each save — drop oldest if over limit messages = self.chat_memory.messages if len(messages) > self.k * 2: self.chat_memory.clear() self.chat_memory.add_messages(messages[-self.k * 2:]) ``` ### Pattern 3: AutoGen Model Context Management Modern agents use explicit model context objects that track conversation history and provide bounded window management. The `AssistantAgent` maintains its own internal context — never pass the full conversation history on each call. ```python # Source: microsoft/autogen — python/packages/autogen-agentchat/src/autogen_agentchat/agents/_assistant_agent.py from __future__ import annotations import asyncio import logging import uuid from typing import ( Any, AsyncGenerator, Awaitable, Callable, Dict, List, Optional, Sequence, TypeVar, ) from autogen_core import CancellationToken, Component, FunctionCall from autogen_core.memory import Memory from autogen_core.model_context import ( ChatCompletionContext, UnboundedChatCompletionContext, ) from autogen_core.models import ( AssistantMessage, ChatCompletionClient, CreateResult, FunctionExecutionResult, FunctionExecutionResultMessage, LLMMessage, SystemMessage, ) from autogen_core.tools import BaseTool, FunctionTool, ToolResult from pydantic import BaseModel, Field class AssistantAgentConfig(BaseModel): """Declarative configuration for the assistant agent.""" name: str model_client: ComponentModel tools: List[ComponentModel] | None = None handoffs: List[HandoffBase | str] | None = None model_context: ComponentModel | None = None memory: List[ComponentModel] | None = None description: str system_message: str | None = None reflect_on_tool_use: bool tool_call_summary_format: str max_tool_iterations: int = Field(default=1, ge=1) class AssistantAgent(BaseChatAgent, Component[AssistantAgentConfig]): """An agent that provides assistance with tool use. State Management: - The agent maintains its own conversation history via model_context - Do NOT pass entire conversation history on each call — only new messages - max_tool_iterations controls how many sequential tool-call loops run Tool Call Behavior: - If model returns no tool calls → response returned as TextMessage - When reflect_on_tool_use=True → another inference after tool results - Multiple parallel tool calls are executed concurrently when supported """ def __init__( self, name: str, model_client: ChatCompletionClient, *, tools: Sequence[BaseTool] = (), handoffs: Sequence[HandoffBase | str] = (), model_context: ChatCompletionContext | None = None, memory: Sequence[Memory] = (), description: str = "An agent", system_message: str | None = "You are a helpful AI assistant.", reflect_on_tool_use: bool = True, tool_call_summary_format: str = "{response}", max_tool_iterations: int = 1, ) -> None: """Initialize assistant agent. Args: name: Unique identifier for this agent in a multi-agent team. model_client: LLM client for chat completion calls. tools: Tools available for the model to invoke via function calling. handoffs: Other agents this agent can transfer control to. model_context: Conversation history store. Defaults to unbounded. memory: External memory systems (vector stores, knowledge bases). description: Shown to other agents when selecting speakers. system_message: Initial system prompt for the conversation. reflect_on_tool_use: If True, make another LLM call after tool results. tool_call_summary_format: How to summarize tool call results. max_tool_iterations: Max sequential tool-call loops (prevents infinite loops). """ self._name = name self._model_client = model_client self._tools = list(tools) self._handoffs = list(handoffs) self._model_context = model_context or UnboundedChatCompletionContext() self._memory = list(memory) self._description = description self._system_message = system_message self._reflect_on_tool_use = reflect_on_tool_use self._max_tool_iterations = max_tool_iterations async def on_messages( self, messages: Sequence[BaseChatMessage], cancellation_token: CancellationToken | None = None, ) -> Response: """Handle a sequence of messages. Only NEW messages should be passed. The agent maintains its own internal context. Do not pass the full conversation history on each call. Args: messages: New messages since last invocation. cancellation_token: Optional token for aborting long operations. Returns: Response with final chat_message as the agent's reply. """ # Add new messages to internal context for msg in messages: await self._model_context.add_message(msg) # Execute tool call iteration loop response = await self._execute_tool_loop(cancellation_token) return Response( chat_message=response.chat_message, inner_messages=response.inner_messages or [], ) async def _execute_tool_loop( self, cancellation_token: CancellationToken | None ) -> Response: """Run the tool call loop up to max_tool_iterations. Loop pattern: 1. Build conversation from context + system message 2. Call LLM with tools bound 3. If tool calls returned → execute them, add results to context 4. Repeat until text response or max iterations reached """ inner_messages: list[BaseAgentEvent] = [] for _iteration in range(self._max_tool_iterations): # Build full conversation for the LLM call conversation = await self._model_context.get_messages() all_messages: list[LLMMessage] = [SystemMessage(content=self._system_message)] all_messages.extend(conversation) # Call the model with tools result = await self._model_client.create( all_messages, tools=self._tools, cancellation_token=cancellation_token, ) if result.content: # Text response — done text_msg = TextMessage( content=result.content[0].text or "", source=self._name, ) await self._model_context.add_message(text_msg) return Response(chat_message=text_msg, inner_messages=inner_messages) # Tool calls returned — execute them if result.call_events: tool_results = [] for call in result.call_events: if isinstance(call, FunctionCall): execution = await self._execute_single_tool_call(call) tool_results.append(execution) # Add results to context for next iteration execution_msg = FunctionExecutionResultMessage( contents=tool_results ) await self._model_context.add_message(execution_msg) inner_messages.extend(tool_results) # Max iterations reached without text response fallback_msg = TextMessage( content=f"Reached maximum tool iterations ({self._max_tool_iterations}).", source=self._name, ) return Response(chat_message=fallback_msg, inner_messages=inner_messages) async def _execute_single_tool_call(self, call: FunctionCall) -> ToolCallExecutionEvent: """Execute a single function/tool call by name and arguments.""" tool = next((t for t in self._tools if isinstance(t, FunctionTool) and t.name == call.name), None) if tool is None: return ToolCallExecutionEvent( contents=[ToolResult(content=f"Unknown tool: {call.name}", tool_name=call.name)], id=call.id or str(uuid.uuid4()), ) try: result = await tool.run_json(call.args, cancellation_token=None) return ToolCallExecutionEvent( contents=[ToolResult(content=str(result), tool_name=call.name)], id=call.id or str(uuid.uuid4()), ) except Exception as e: return ToolCallExecutionEvent( contents=[ToolResult(content=f"Error: {e}", tool_name=call.name)],
Ver no GitHub
Este SKILL.md e muito grande, entao o SkillsMP mostra aqui apenas a primeira secao. Ver no GitHub