Concepts
Opinions & Observations
Part of the expertise layer. Read the overview →
SmartMemory synthesizes opinions and observations from raw memories, enabling agents to form beliefs and entity summaries that evolve over time.
Overview
| Type | Description | Example |
|---|---|---|
| Opinion | Belief with confidence score | "User prefers functional programming (85% confident)" |
| Observation | Entity summary | "Alice: Works at Google since 2020, promoted in 2023" |
Opinions
Opinions are beliefs formed from patterns in episodic memories. They have confidence scores that can be reinforced or contradicted.
Formation
The OpinionSynthesisEvolver detects patterns:
graph LR
E1[Episodic: User chose map()] --> P[Pattern Detector]
E2[Episodic: User chose filter()] --> P
E3[Episodic: User avoided loops] --> P
P --> O[Opinion: Prefers functional style]
Confidence Scoring
from smartmemory.models.opinion import OpinionMetadata
meta = OpinionMetadata(
confidence=0.75,
subject="functional programming",
subject_type="preference"
)
# When supporting evidence arrives
meta.reinforce("evidence_123")
# confidence: 0.75 → 0.775 (diminishing returns)
# When contradicting evidence arrives
meta.contradict("evidence_456")
# confidence: 0.775 → 0.659 (15% penalty)Disposition
Opinions are influenced by configurable disposition traits:
from smartmemory.models.opinion import Disposition
disposition = Disposition(
skepticism=0.7, # Requires more evidence before forming opinions
literalism=0.5, # Balance literal vs inferred meaning
empathy=0.8 # Weight emotional/preference signals highly
)Reinforcement Evolver
The OpinionReinforcementEvolver runs as a background job:
- Scans new episodic memories for evidence
- Matches against existing opinions
- Reinforces or contradicts based on similarity
- Decays stale opinions over time
- Archives opinions below confidence threshold
Observations
Observations are synthesized entity summaries built from scattered facts.
Synthesis
The ObservationSynthesisEvolver combines facts:
graph TD
F1["Alice works at Google"] --> S[Synthesis]
F2["Alice started in 2020"] --> S
F3["Alice was promoted in 2023"] --> S
S --> O["Observation: Alice's career at Google<br/>Started 2020, promoted 2023"]
Aspect Coverage
Observations track which aspects of an entity are covered:
from smartmemory.models.opinion import ObservationMetadata
meta = ObservationMetadata(
entity_id="alice_123",
entity_name="Alice",
entity_type="person",
aspects_covered=["career", "location", "skills"],
completeness=0.6 # 60% complete
)Available aspects:
career- Work, job, company, roleeducation- School, degree, studylocation- City, country, addresspreferences- Likes, favoritesrelationships- Family, colleaguesskills- Expertise, proficiencyinterests- Hobbies, passions
The Reflect API
Trigger synthesis on-demand:
# Run synthesis evolvers and get results
result = memory.reflect(top_k=5)This:
- Runs
OpinionSynthesisEvolver - Runs
ObservationSynthesisEvolver - Returns newly formed opinions/observations
Evolution Configuration
Opinion Synthesis
from smartmemory.plugins.evolvers.opinion_synthesis import OpinionSynthesisConfig
config = OpinionSynthesisConfig(
min_pattern_occurrences=3, # Pattern must appear 3+ times
min_confidence=0.5, # Minimum confidence to create
lookback_days=30, # Analyze last 30 days
skepticism=0.5 # Disposition skepticism
)Opinion Reinforcement
from smartmemory.plugins.evolvers.opinion_reinforcement import OpinionReinforcementConfig
config = OpinionReinforcementConfig(
min_confidence_threshold=0.2, # Archive below this
lookback_days=7, # Check last 7 days for evidence
enable_decay=True, # Enable staleness decay
decay_after_days=30, # Start decaying after 30 days
decay_rate=0.05 # 5% decay per cycle
)Observation Synthesis
from smartmemory.plugins.evolvers.observation_synthesis import ObservationSynthesisConfig
config = ObservationSynthesisConfig(
min_facts_per_entity=2, # Need 2+ facts to synthesize
lookback_days=90, # Look back 90 days
max_observations_per_run=20 # Limit per evolution cycle
)Memory Types
# Opinion and observation are extended *string* memory types — pass them as
# strings (they are not members of the `MemoryType` enum).
# Store opinion
memory.add(
content="User prefers functional programming",
memory_type="opinion",
metadata={
"confidence": 0.85,
"subject": "functional programming",
"subject_type": "preference"
}
)
# Store observation
memory.add(
content="Alice: Senior engineer at Google since 2020",
memory_type="observation",
metadata={
"entity_id": "alice_123",
"entity_name": "Alice",
"aspects_covered": ["career"]
}
)