Skip to main content 首页 创作者 adu2021 skillxiv agentfly-memory-augmented-agents
agentfly-memory-augmented-agents Enable agent learning through episodic memory and neural case selection without fine-tuning the underlying LLM, achieving efficient continual adaptation via policy updates in memory space.
跳到安装 Skills Marketplace 发现并探索由社区构建的 Agent Skills
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/ADu2021/skillXiv --skill agentfly-memory-augmented-agents命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
下载 Zip 下载中... name agentfly-memory-augmented-agents title AgentFly: Memory-Augmented Learning Without LLM Fine-tuning version 0.0.2 engine skillxiv-v0.0.2-claude-opus-4.6 license MIT url https://arxiv.org/abs/2508.16153 keywords ["memory-augmented-learning","agent-adaptation","episodic-memory","reinforcement-learning","in-context-learning"] description Enable agent learning through episodic memory and neural case selection without fine-tuning the underlying LLM, achieving efficient continual adaptation via policy updates in memory space.
AgentFly: Memory-Augmented Learning Without LLM Fine-tuning
Core Concept
AgentFly (Memento) enables language model agents to learn and adapt without fine-tuning the base LLM. Instead, it uses memory-augmented online reinforcement learning with episodic memory storage and a learned case-selection policy. Past experiences are stored in differentiable or non-parametric memory, and a neural policy selects relevant experiences to guide decision-making. This approach achieves rapid adaptation on research-oriented tasks while maintaining the benefits of frozen, pre-trained models.
Architecture Overview
Episodic Memory System : Stores experience tuples (state, action, outcome)
Neural Case-Selection Policy : Learns which memories are relevant for decisions
Memory-Augmented MDP (M-MDP) : Markov decision process with memory state
Continual Adaptation : Policy updates through memory rewriting
Frozen LLM Base : No gradient updates to base model parameters
Implementation Steps
1. Design Episodic Memory Structure
Create abstraction for experience storage:
from dataclasses import dataclass
from typing import Dict , List , Any , Optional
import numpy as np
from collections import deque
@dataclass
class Experience :
"""Single experience stored in memory."""
state: str
action: str
observation: str
reward: float
success: bool
timestamp: float
metadata: [ , ] =
:
experiences: [Experience]
task_id:
success_rate:
last_accessed:
:
( ):
.experiences: deque = deque(maxlen=max_size)
.max_size = max_size
.similarity_metric = similarity_metric
.task_groups: [ , [Experience]] = {}
( ):
.experiences.append(experience)
task_id = experience.metadata.get( , )
task_id .task_groups:
.task_groups[task_id] = []
.task_groups[task_id].append(experience)
( ) -> [ [Experience, ]]:
candidates = .task_groups.get(filter_task) filter_task ( .experiences)
candidates:
[]
similarities = []
exp candidates:
similarity = ._compute_similarity(query_state, exp.state)
similarities.append((exp, similarity))
similarities.sort(key= x: x[ ], reverse= )
similarities[:k]
( ) -> :
.similarity_metric == :
emb1 = ._encode(state1)
emb2 = ._encode(state2)
np.dot(emb1, emb2) / (np.linalg.norm(emb1) * np.linalg.norm(emb2) + )
.similarity_metric == :
set1 = (state1.split())
set2 = (state2.split())
intersection = (set1 & set2)
union = (set1 | set2)
intersection / (union + )
( ) -> np.ndarray:
( ) -> [ , ]:
{
: ( .experiences),
: ( .task_groups),
: ( .experiences) / ( ( .task_groups), ),
: ( .experiences) / .max_size
}
Dict
str
Any
None
@dataclass
class
MemoryTrace
"""Linked traces of related experiences."""
List
str
float
float
class
EpisodicMemory
"""Storage for agent experiences."""
def
__init__
self,
max_size: int = 10000 ,
similarity_metric: str = "embedding"
self
self
self
self
Dict
str
List
def
store_experience
self, experience: Experience
"""Add experience to memory."""
self
"task_id"
"default"
if
not
in
self
self
self
def
retrieve_similar
self,
query_state: str ,
k: int = 5 ,
filter_task: Optional [str ] = None
List
Tuple
float
"""Retrieve k most similar experiences to query."""
self
if
else
list
self
if
not
return
for
in
self
lambda
1
True
return
def
_compute_similarity
self, state1: str , state2: str
float
"""Compute similarity between two states."""
if
self
"embedding"
self
self
return
1e-8
elif
self
"string"
set
set
len
len
return
1e-8
return
0.0
def
_encode
self, text: str
"""Encode text to embedding."""
pass
def
get_memory_statistics
self
Dict
str
Any
"""Compute memory health metrics."""
return
"total_experiences"
len
self
"unique_tasks"
len
self
"avg_task_size"
len
self
max
len
self
1
"memory_utilization"
len
self
self
2. Implement Neural Case-Selection Policy Learn which memories to retrieve for decisions:
import torch
import torch.nn as nn
class CaseSelectionPolicy (nn.Module):
"""Policy for selecting relevant cases from memory."""
def __init__ (
self,
embedding_dim: int = 768 ,
hidden_dim: int = 512 ,
max_cases: int = 5
):
super ().__init__()
self .embedding_dim = embedding_dim
self .max_cases = max_cases
self .state_encoder = nn.Sequential(
nn.Linear(embedding_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, embedding_dim)
)
self .relevance_scorer = nn.Sequential(
nn.Linear(embedding_dim * 2 , hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, 1 )
)
self .use_memory_gate = nn.Sequential(
nn.Linear(embedding_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, 1 ),
nn.Sigmoid()
)
def forward (
self,
current_state: torch.Tensor,
candidate_cases: List [torch.Tensor],
return_scores: bool = False
) -> torch.Tensor:
"""
Select top cases and return their indices/scores.
"""
state_encoded = self .state_encoder(current_state)
relevance_scores = []
for case in candidate_cases:
combined = torch.cat([state_encoded, case ])
score = self .relevance_scorer(combined)
relevance_scores.append(score)
relevance_scores = torch.stack(relevance_scores).squeeze(-1 )
memory_use_prob = self .use_memory_gate(state_encoded)
topk_scores, topk_indices = torch.topk(
relevance_scores,
k=min (self .max_cases, len (candidate_cases))
)
if return_scores:
return topk_indices, topk_scores
return topk_indices
def train_on_trajectory (
self,
states: List [torch.Tensor],
selected_cases: List [int ],
outcomes: List [float ],
gamma: float = 0.99
):
"""Train policy on trajectory data."""
returns = []
G = 0
for outcome in reversed (outcomes):
G = outcome + gamma * G
returns.insert(0 , G)
returns = torch.tensor(returns, dtype=torch.float32)
returns = (returns - returns.mean()) / (returns.std() + 1e-8 )
total_loss = 0.0
for state, case_idx, ret in zip (states, selected_cases, returns):
with torch.no_grad():
logits = self .relevance_scorer(state)
log_prob = torch.log_softmax(logits, dim=-1 )[case_idx]
loss = -log_prob * ret
total_loss += loss
return total_loss / len (states)
3. Implement Memory-Augmented MDP Integrate memory into decision process:
class MemoryAugmentedMDP :
"""Markov decision process with episodic memory."""
def __init__ (
self,
base_model: "LLM" ,
memory: EpisodicMemory,
selection_policy: CaseSelectionPolicy,
max_memory_context_length: int = 2000
):
self .base_model = base_model
self .memory = memory
self .selection_policy = selection_policy
self .max_context_length = max_memory_context_length
def get_action (
self,
task_description: str ,
current_observation: str ,
use_memory: bool = True
) -> Tuple [str , Dict [str , Any ]]:
"""
Select action considering memory context.
"""
relevant_experiences = []
if use_memory and len (self .memory.experiences) > 0 :
relevant_experiences = self .memory.retrieve_similar(
current_observation,
k=5 ,
filter_task=task_description
)
context = self ._build_context(
task_description,
current_observation,
relevant_experiences
)
prompt = f"{context} \n\nNext action:"
action = self .base_model.generate(prompt, max_tokens=100 )
return action, {"context_length" : len (context), "memories_used" : len (relevant_experiences)}
def _build_context (
self,
task: str ,
observation: str ,
experiences: List [Tuple [Experience, float ]]
) -> str :
"""Build LLM context including relevant memories."""
context = f"Task: {task} \n\nCurrent Observation: {observation} \n"
if experiences:
context += "\nRelevant Past Experiences:\n"
for i, (exp, score) in enumerate (experiences[:3 ]):
context += f"{i+1 } . Previous: {exp.state} \n"
context += f" Action: {exp.action} \n"
context += f" Result: {exp.observation} \n"
context += f" Success: {exp.success} \n"
return context
def collect_rollout (
self,
task_description: str ,
max_steps: int = 20
) -> List [Experience]:
"""Collect trajectory using memory-augmented decisions."""
trajectory = []
observation = "Initial state"
for step in range (max_steps):
action, metadata = self .get_action(task_description, observation)
new_observation, reward, done = self ._execute_action(
task_description,
action
)
experience = Experience(
state=observation,
action=action,
observation=new_observation,
reward=reward,
success=(reward > 0.5 ),
timestamp=0 ,
metadata={"task_id" : task_description, **metadata}
)
trajectory.append(experience)
if done:
break
observation = new_observation
return trajectory
def _execute_action (
self,
task: str ,
action: str
) -> Tuple [str , float , bool ]:
"""Execute action and get feedback."""
pass
4. Implement Continual Adaptation Update memory and policy without LLM fine-tuning:
class ContinualAdapter :
"""Handles continual learning without LLM updates."""
def __init__ (
self,
mdp: MemoryAugmentedMDP,
selection_policy: CaseSelectionPolicy,
learning_rate: float = 1e-4
):
self .mdp = mdp
self .selection_policy = selection_policy
self .optimizer = torch.optim.Adam(
selection_policy.parameters(),
lr=learning_rate
)
def adapt_to_trajectory (self, trajectory: List [Experience] ):
"""Update memory and policy based on new trajectory."""
for exp in trajectory:
self .mdp.memory.store_experience(exp)
successful_trajectory = [e for e in trajectory if e.success]
if successful_trajectory:
self ._train_selection_policy(successful_trajectory)
if len (self .mdp.memory.experiences) > self .mdp.memory.max_size * 0.9 :
self ._prune_memory()
def _train_selection_policy (self, trajectory: List [Experience] ):
"""Train policy on successful trajectory."""
states = [self ._encode_state(e.state) for e in trajectory]
outcomes = [e.reward for e in trajectory]
selected_cases = []
for state in states:
candidates = self ._get_candidate_embeddings(state)
indices = self .selection_policy(
state, candidates, return_scores=False
)
selected_cases.append(indices[0 ].item())
loss = self .selection_policy.train_on_trajectory(
states, selected_cases, outcomes
)
self .optimizer.zero_grad()
loss.backward()
torch.nn.utils.clip_grad_norm_(self .selection_policy.parameters(), 1.0 )
self .optimizer.step()
return loss.item()
def _prune_memory (self ):
"""Remove least useful experiences."""
pass
def _encode_state (self, state: str ) -> torch.Tensor:
"""Encode state to embedding."""
pass
def _get_candidate_embeddings (self, state_embedding ) -> List [torch.Tensor]:
"""Get embeddings of candidate memory cases."""
pass
5. Evaluate Agent Learning Measure adaptation efficiency without LLM fine-tuning:
def evaluate_agentfly_learning (
mdp: MemoryAugmentedMDP,
test_tasks: List [Dict ],
num_rollouts_per_task: int = 3
) -> Dict [str , float ]:
"""
Evaluate memory-augmented agent performance.
"""
task_successes = []
memory_hit_rates = []
trajectory_lengths = []
for task in test_tasks:
task_desc = task["description" ]
expected_solution = task["expected" ]
for _ in range (num_rollouts_per_task):
trajectory = mdp.collect_rollout(task_desc, max_steps=50 )
final_obs = trajectory[-1 ].observation if trajectory else ""
success = evaluate_task_success(final_obs, expected_solution)
task_successes.append(success)
memory_hits = sum (
1 for exp in trajectory
if exp.metadata.get("memories_used" , 0 ) > 0
)
memory_hit_rates.append(memory_hits / len (trajectory))
trajectory_lengths.append(len (trajectory))
mdp_adapter = ContinualAdapter(mdp, mdp.selection_policy)
mdp_adapter.adapt_to_trajectory(trajectory)
return {
"avg_success_rate" : sum (task_successes) / len (task_successes),
"avg_memory_hit_rate" : sum (memory_hit_rates) / len (memory_hit_rates),
"avg_trajectory_length" : sum (trajectory_lengths) / len (trajectory_lengths),
"memory_size" : len (mdp.memory.experiences)
}
Practical Guidance
When to Use AgentFly
Research tasks requiring rapid adaptation (GAIA, DeepResearcher)
Scenarios where LLM fine-tuning is expensive/prohibited
Agents needing to learn from few examples
Continual learning systems with non-stationary tasks
Open-source or proprietary model deployment
When NOT to Use
Tasks where base model knowledge is insufficient
Extremely low-latency inference requirements
Scenarios with no clear episodic structure
Tasks requiring fundamental capability changes
Key Hyperparameters
max_memory_size : 5000-20000 experiences
memory_context_length : 1000-3000 tokens
learning_rate : 1e-4 to 1e-3
k (top cases retrieved) : 3-5 usually sufficient
gamma (discount factor) : 0.99
Performance Expectations
GAIA Benchmark: 87.88% Pass@3
Adaptation Speed: 2-5 examples sufficient for new task class
Memory Efficiency: Sub-linear growth with task diversity
No LLM Fine-tuning: Entire approach requires 0 LLM updates
Reference Researchers. (2024). AgentFly: Fine-tuning LLM Agents without Fine-tuning LLMs. arXiv preprint arXiv:2508.16153.