Video Memory for AI Agents
Agents that forget what they've seen can't answer questions about long videos or compare across multiple recordings. Video memory gives agents persistent, searchable access to video content — without reprocessing the video for every query.
The Memory Problem
Without memory, agents face limitations:
- Context limits: Can't process hour-long videos in one prompt
- Repeated work: Re-analyze video for each question
- No cross-video reasoning: Can't compare incidents across recordings
- No history: Can't remember what was discussed before
Video memory solves this by extracting and storing video content in queryable form.
Memory Architecture
┌─────────────────────────────────────────────────┐
│ Agent Query │
│ "What time did the car arrive?" │
└───────────────────────┬─────────────────────────┘
↓
┌─────────────────────────────────────────────────┐
│ Memory Retrieval │
│ Search vector store + temporal index │
└───────────────────────┬─────────────────────────┘
↓
┌─────────────────────────────────────────────────┐
│ Relevant Context │
│ Frame 847 (10:32:15): "Blue sedan enters lot" │
│ Frame 923 (10:33:42): "Sedan parks in spot 12" │
└───────────────────────┬─────────────────────────┘
↓
┌─────────────────────────────────────────────────┐
│ Agent Response │
│ "The car arrived at 10:32:15 AM" │
└─────────────────────────────────────────────────┘
Building Video Memory
Step 1: Extract Content
from typing import List, Dict
def extract_video_content(video_url: str) -> List[Dict]:
"""Extract searchable content from video."""
# Enhance first for better extraction
enhanced = bettervideo.enhance(video_url)
# Extract frames at key intervals
frames = extract_keyframes(enhanced)
content = []
for frame in frames:
# Describe frame with vision model
description = vision_model.describe(frame.image)
# Extract structured data
objects = detector.detect(frame.image)
text = ocr.extract(frame.image)
faces = face_detector.detect(frame.image)
content.append({
"timestamp": frame.timestamp,
"description": description,
"objects": objects,
"text": text,
"faces": len(faces),
"embedding": embed_model.embed(description)
})
return content
Step 2: Store in Vector Database
import chromadb
def store_video_memory(video_id: str, content: List[Dict]):
"""Store extracted content in vector database."""
client = chromadb.Client()
collection = client.get_or_create_collection("video_memory")
for item in content:
collection.add(
ids=[f"{video_id}_{item['timestamp']}"],
embeddings=[item['embedding']],
metadatas=[{
"video_id": video_id,
"timestamp": item['timestamp'],
"objects": str(item['objects']),
"text": item['text'],
"faces": item['faces']
}],
documents=[item['description']]
)
Step 3: Query Memory
def query_video_memory(question: str, video_id: str = None) -> List[Dict]:
"""Retrieve relevant video content for a question."""
collection = client.get_collection("video_memory")
# Embed the question
query_embedding = embed_model.embed(question)
# Search
where_filter = {"video_id": video_id} if video_id else None
results = collection.query(
query_embeddings=[query_embedding],
n_results=10,
where=where_filter
)
return results
Temporal Indexing
Video is temporal — time matters. Add temporal indexing to your memory:
# Store with temporal metadata
{
"timestamp": "10:32:15",
"frame_number": 847,
"relative_time": 632.5, # Seconds from start
"events_before": ["Person A entered"],
"events_after": ["Vehicle stopped"]
}
# Query with temporal constraints
def query_timerange(start_time: float, end_time: float):
return collection.query(
where={
"$and": [
{"relative_time": {"$gte": start_time}},
{"relative_time": {"$lte": end_time}}
]
}
)
Memory-Augmented Agent
class VideoMemoryAgent:
def __init__(self, video_ids: List[str]):
self.video_ids = video_ids
self.memory = VideoMemory()
def answer(self, question: str) -> str:
# 1. Retrieve relevant memory
context = self.memory.query(question, self.video_ids)
# 2. Build prompt with retrieved context
prompt = f"""
You are analyzing video recordings. Use the following retrieved content to answer.
Retrieved Video Content:
{self.format_context(context)}
Question: {question}
Answer based only on the retrieved content. If the answer isn't in the content, say so.
"""
# 3. Generate answer
return llm.complete(prompt)
def format_context(self, context):
return "\n".join([
f"[{c['timestamp']}] {c['description']}"
for c in context
])
Frequently Asked Questions
Much less than the video itself. You're storing text descriptions and embeddings, not frames. A 1-hour video might produce 10-50MB of memory data.
Yes — that's the point. Store all videos in the same collection, use video_id to filter when needed, or search across all videos at once.
Stream frames through extraction, add to memory in real-time. Use a sliding window to limit memory size if needed.
Ready to get started?
Try BetterVideo's privacy-first video enhancement API — free sandbox, no credit card required.