Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e7650d2281 | ||
|
|
d1033cee87 | ||
|
|
0810c8c536 | ||
|
|
d9f07b7ea0 | ||
|
|
22cb79c432 | ||
|
|
eeb7326261 | ||
|
|
327cf6f6c3 | ||
|
|
eca77d9e16 | ||
|
|
05a933306f | ||
|
|
9e58b1b7d3 |
@@ -235,6 +235,16 @@ const config: Config = {
|
||||
position: 'left',
|
||||
className: 'navbar-item-resources',
|
||||
items: [
|
||||
{
|
||||
to: '/best-practices',
|
||||
label: 'Best Practices',
|
||||
customProps: { icon: 'lu-star' },
|
||||
},
|
||||
{
|
||||
to: '/faq',
|
||||
label: 'FAQ',
|
||||
customProps: { icon: 'lu-circle-help' },
|
||||
},
|
||||
{
|
||||
to: '/cookbook',
|
||||
label: 'Cookbook',
|
||||
|
||||
@@ -283,6 +283,25 @@ const sidebars: SidebarsConfig = {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Resources',
|
||||
collapsible: false,
|
||||
items: [
|
||||
{
|
||||
type: 'link',
|
||||
href: '/best-practices',
|
||||
label: 'Best Practices',
|
||||
customProps: { icon: 'lu-star', iconAfter: 'lu-arrow-up-right' },
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/faq',
|
||||
label: 'FAQ',
|
||||
customProps: { icon: 'lu-circle-help', iconAfter: 'lu-arrow-up-right' },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'More',
|
||||
|
||||
@@ -0,0 +1,533 @@
|
||||
---
|
||||
title: Best Practices
|
||||
description: Practical guidance for agents and developers integrating Hindsight memory into production systems.
|
||||
hide_table_of_contents: true
|
||||
---
|
||||
|
||||
# Best Practices
|
||||
|
||||
Practical guidance for agents and developers integrating Hindsight memory into production systems.
|
||||
|
||||
**Contents**
|
||||
- [Core Concepts](#core-concepts) — Memory banks, taxonomy, memory types
|
||||
- [Bank Configuration](#bank-configuration) — Missions, dispositions, entity labels
|
||||
- [Retaining Data](#retaining-data) — Content format, context, document_id, [tags](#tags-naming-conventions), observation scopes
|
||||
- [Recalling Memories](#recalling-memories) — Budget, tag filtering, include options, query_timestamp
|
||||
- [Reflecting](#reflecting) — Recall vs reflect, response_schema, auditing
|
||||
- [Mental Models](#mental-models) — When to create, tag strategy, refresh
|
||||
- [Anti-patterns](#anti-patterns)
|
||||
|
||||
---
|
||||
|
||||
## Core Concepts
|
||||
|
||||
### Memory Banks
|
||||
|
||||
A **memory bank** is an isolated memory store — the unit of separation between users, agents, or contexts. All operations (retain, recall, reflect) target a single bank. Banks do not share data.
|
||||
|
||||
- One bank per user is the most common pattern for multi-user applications
|
||||
- One bank per agent is common for agent-specific long-term memory
|
||||
- A shared bank with tags can work for cross-user analysis (see [Tags](#tags-naming-conventions))
|
||||
|
||||
Banks are auto-created on first use. Configure them before ingesting data to steer behavior.
|
||||
|
||||
---
|
||||
|
||||
### Taxonomy
|
||||
|
||||
| Operation | What it does | When to call it |
|
||||
|-----------|-------------|-----------------|
|
||||
| **Retain** | Ingests raw content (conversations, documents, notes). The LLM extracts facts, entities, and relationships — raw content is never stored verbatim. | After each conversation turn or session ends |
|
||||
| **Recall** | Retrieves relevant memories using 4 parallel strategies: semantic search, BM25, graph traversal, and temporal ranking. Returns a ranked list of facts. | Before generating a response that benefits from past context |
|
||||
| **Reflect** | Autonomous reasoning loop: searches memory, synthesizes an answer, and returns it directly. Uses mental models and observations hierarchically. | When you want Hindsight to answer a question, not just retrieve facts |
|
||||
| **Observations** | Auto-synthesized knowledge patterns produced by the consolidation operation, which runs asynchronously after retain completes. Consolidate facts into durable insights (preferences, behavioral patterns, contradictions). | Triggered automatically after retain — not part of the retain call itself |
|
||||
| **Mental Models** | Pre-computed reflect responses stored for common queries. Return instantly and consistently. | Create for repeated high-traffic queries or slowly-changing user profiles |
|
||||
|
||||
---
|
||||
|
||||
### Memory Types
|
||||
|
||||
Facts extracted during retain are classified into three types:
|
||||
|
||||
| Type | Description | Example |
|
||||
|------|-------------|---------|
|
||||
| `world` | General knowledge, external facts | "The Eiffel Tower is in Paris" |
|
||||
| `experience` | Personal events, user-specific facts | "User moved to Berlin in 2024" |
|
||||
| `observation` | Consolidated patterns synthesized from facts | "User consistently prefers async communication" |
|
||||
|
||||
Use `types` filtering in recall to target specific memory types.
|
||||
|
||||
---
|
||||
|
||||
## Bank Configuration
|
||||
|
||||
Configure a bank before first use to steer memory behavior for your domain. Misconfigured missions are the single biggest cause of low-quality memories.
|
||||
|
||||
### Writing Effective Missions
|
||||
|
||||
All three missions accept plain language. Be specific about your domain — vague missions produce vague results.
|
||||
|
||||
#### `retain_mission`
|
||||
|
||||
Injected into the fact extraction prompt. Tells the LLM what to extract and what to ignore.
|
||||
|
||||
| Quality | Example |
|
||||
|---------|---------|
|
||||
| **Good** | `Always extract technical decisions, API design choices, architectural trade-offs, blockers, and error messages. Ignore greetings, small talk, and scheduling logistics.` |
|
||||
| **Good** | `Extract personal preferences, ongoing commitments, deadlines, health info, and relationship details. Ignore filler phrases and pleasantries.` |
|
||||
| **Bad** | `Extract all information` — too vague, extracts noise |
|
||||
| **Bad** | `Be helpful` — not an extraction directive |
|
||||
|
||||
**Tips:**
|
||||
- List the fact *types* you want (preferences, decisions, errors, commitments)
|
||||
- List what to *ignore* — this is as important as what to include
|
||||
- Match the mission to your actual data type (conversations vs documents vs tickets)
|
||||
|
||||
#### `observations_mission`
|
||||
|
||||
Steers what patterns are synthesized during consolidation. Runs after retain.
|
||||
|
||||
```
|
||||
Identify evolving preferences, recurring patterns, behavioral shifts, and contradictions
|
||||
with prior knowledge. Focus on durable patterns — not transient states. Highlight when
|
||||
user behavior contradicts previous observations.
|
||||
```
|
||||
|
||||
**Tips:**
|
||||
- Emphasize "durable patterns" to avoid ephemeral observation noise
|
||||
- Mention contradiction detection explicitly if you need historical tracking
|
||||
- Match scope to how often you expect patterns to change
|
||||
|
||||
#### `reflect_mission`
|
||||
|
||||
Sets the agent persona and reasoning frame for `reflect` operations.
|
||||
|
||||
| Use Case | Mission |
|
||||
|----------|---------|
|
||||
| Coding assistant | `You are a senior developer helping optimize the user's workflow. Always factor in past technical decisions, current project context, and stated preferences. Be direct and opinionated.` |
|
||||
| Customer support | `You are a support agent with full context of this customer's history. Reference past tickets and resolutions where relevant. Be concise and solution-focused.` |
|
||||
| Personal assistant | `You are a personal assistant who remembers everything important to the user. Personalize every response using what you know about their preferences, schedule, and ongoing projects.` |
|
||||
| Medical assistant | `You are a health assistant. Reference the user's history accurately. Always recommend consulting a professional for medical decisions. Do not speculate.` |
|
||||
|
||||
---
|
||||
|
||||
### Disposition Traits
|
||||
|
||||
Dispositions affect `reflect` only (not `recall`). Scale 1–5.
|
||||
|
||||
| Trait | 1 | 5 |
|
||||
|-------|---|---|
|
||||
| `skepticism` | Trusts all memories at face value | Questions contradictions, flags uncertain info |
|
||||
| `literalism` | Liberal interpretation, infers intent | Strict literal reading, no inference |
|
||||
| `empathy` | Clinical, neutral tone | Warm, personal, emotionally aware |
|
||||
|
||||
**Common profiles:**
|
||||
|
||||
| Agent type | Skepticism | Literalism | Empathy |
|
||||
|------------|------------|------------|---------|
|
||||
| Code review | 4 | 5 | 1 |
|
||||
| Customer support | 2 | 3 | 4 |
|
||||
| Personal assistant | 2 | 2 | 4 |
|
||||
| Medical assistant | 5 | 4 | 3 |
|
||||
| Research assistant | 4 | 4 | 2 |
|
||||
|
||||
---
|
||||
|
||||
### Entity Labels
|
||||
|
||||
Define a controlled vocabulary for classification. The LLM will extract and normalize values to your defined set.
|
||||
|
||||
```json
|
||||
{
|
||||
"entity_labels": [
|
||||
{
|
||||
"key": "tech_stack",
|
||||
"type": "multi-values",
|
||||
"values": [
|
||||
{"value": "python", "description": "Python programming language"},
|
||||
{"value": "typescript", "description": "TypeScript / Node.js"},
|
||||
{"value": "react", "description": "React frontend framework"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "priority",
|
||||
"type": "value",
|
||||
"tag": true,
|
||||
"values": [
|
||||
{"value": "high", "description": "Urgent or blocking"},
|
||||
{"value": "low", "description": "Nice to have"}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- **`type: "value"`** — single value per entity (last write wins)
|
||||
- **`type: "multi-values"`** — accumulates multiple values
|
||||
- **`tag: true`** — extracted label values are also added as tags (enables filtering by entity value)
|
||||
|
||||
Use entity labels when you need consistent classification — domain-specific terms, status values, priority levels, engagement types.
|
||||
|
||||
---
|
||||
|
||||
## Retaining Data
|
||||
|
||||
### Content Format
|
||||
|
||||
Pass the richest representation available. Never pre-summarize.
|
||||
|
||||
| Format | Recommendation |
|
||||
|--------|---------------|
|
||||
| JSON conversation array | **Preferred** for conversations — preserves structure, roles, and relationships |
|
||||
| Prefixed plain text | Acceptable — `[ISO-timestamp] role: text` per line |
|
||||
| Markdown / HTML / raw text | Works for documents and notes |
|
||||
| Pre-summarized text | **Avoid** — loses entity relationships, temporal markers, structural context |
|
||||
|
||||
**Conversation JSON (preferred):**
|
||||
|
||||
```json
|
||||
[
|
||||
{"role": "user", "content": "I'm using React for the frontend.", "timestamp": "2025-06-01T10:30:00Z"},
|
||||
{"role": "assistant", "content": "Got it. What state management are you using?"},
|
||||
{"role": "user", "content": "Zustand. We moved away from Redux last quarter."}
|
||||
]
|
||||
```
|
||||
|
||||
**Why not pre-summarize:** The LLM extracts facts, entities, and relationships from structure. A summary like "user uses React and Zustand" loses the temporal reference ("last quarter"), the entity relationship (React↔frontend, Redux↔migration), and the causal context (moved away from).
|
||||
|
||||
---
|
||||
|
||||
### The `context` Field
|
||||
|
||||
High-impact on extraction quality. Always set it. Describes the *nature and source* of the content.
|
||||
|
||||
```python
|
||||
# Good — specific, descriptive
|
||||
context="Customer support ticket #12345 from user Alice about a billing discrepancy"
|
||||
context="Developer's architecture review session for the payments service"
|
||||
context="User's onboarding form: stated goals, current tools, and team size"
|
||||
context="Weekly standup notes: blockers, progress, and upcoming tasks"
|
||||
|
||||
# Bad — generic, adds no signal
|
||||
context="some data"
|
||||
context="conversation"
|
||||
# Omitted entirely — extraction uses no context
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### The `document_id` Field
|
||||
|
||||
Use for upsert behavior. Same `document_id` = delete previous version and reprocess.
|
||||
|
||||
**Rules:**
|
||||
- Use stable, meaningful IDs (session ID, ticket ID, document UUID)
|
||||
- Always use the same ID for a growing conversation — retain the full conversation with each new message
|
||||
- Do NOT use random UUIDs per retain call — this creates duplicates
|
||||
|
||||
```python
|
||||
# Good — stable session ID
|
||||
client.retain(bank_id="user-alice", items=[{
|
||||
"content": full_conversation,
|
||||
"document_id": f"session-{session_id}",
|
||||
}])
|
||||
|
||||
# Bad — new random ID every call = duplicates
|
||||
client.retain(bank_id="user-alice", items=[{
|
||||
"content": full_conversation,
|
||||
"document_id": str(uuid.uuid4()), # ❌ creates a new document each time
|
||||
}])
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### The `timestamp` Field
|
||||
|
||||
Set whenever you have temporal context. Enables temporal retrieval strategies.
|
||||
|
||||
- ISO 8601 format: `"2025-06-01T10:32:00Z"`
|
||||
- For conversations: set to when the conversation *started*
|
||||
- Omitting it disables temporal ranking entirely
|
||||
|
||||
---
|
||||
|
||||
### Tags: Naming Conventions
|
||||
|
||||
Tags scope visibility. A memory tagged `user:alice` is only returned for recall/reflect calls that include `user:alice` in their `tags` filter (with strict matching).
|
||||
|
||||
**Standard naming conventions:**
|
||||
|
||||
| Pattern | Example | Use for |
|
||||
|---------|---------|---------|
|
||||
| `user:<id>` | `user:alice`, `user:u_123` | Per-user isolation |
|
||||
| `session:<id>` | `session:s_abc` | Session-scoped memories |
|
||||
| `team:<name>` | `team:engineering` | Shared team knowledge |
|
||||
| `topic:<name>` | `topic:billing`, `topic:technical` | Domain filtering |
|
||||
| `scope:<name>` | `scope:private`, `scope:public` | Visibility tiers |
|
||||
|
||||
**Multi-tenant minimum:** Every retain for user data must include at least `user:<id>`. Omitting it makes the memory globally visible.
|
||||
|
||||
```python
|
||||
# Multi-tenant retain — always tag with user ID
|
||||
items=[{
|
||||
"content": conversation,
|
||||
"tags": ["user:alice", "session:s_abc", "topic:billing"],
|
||||
"document_id": f"session-{session_id}",
|
||||
}]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Metadata Schema
|
||||
|
||||
Use for source tracking and downstream linking. **Not filterable** — use tags for filtering.
|
||||
|
||||
```python
|
||||
# Source tracking
|
||||
metadata={"source": "slack", "channel": "#engineering", "thread_id": "T123456"}
|
||||
|
||||
# Ticket linking
|
||||
metadata={"ticket_id": "JIRA-123", "priority": "high", "reporter": "alice"}
|
||||
|
||||
# Document provenance
|
||||
metadata={"url": "https://...", "section": "pricing-faq", "version": "2025-Q1"}
|
||||
```
|
||||
|
||||
Metadata is returned with every recalled memory — use it to link memories back to source systems for UI display, deep-linking, or audit trails.
|
||||
|
||||
---
|
||||
|
||||
### Observation Scopes
|
||||
|
||||
Controls which tag combinations get their own observation pass.
|
||||
|
||||
| Value | Behavior | When to use |
|
||||
|-------|----------|------------|
|
||||
| `"combined"` | One pass with all tags together | Default — single-user banks, general use |
|
||||
| `"per_tag"` | One pass per tag independently | Users should have isolated behavioral observations |
|
||||
| `"all_combinations"` | All possible subsets of tags | Complex multi-dimensional analysis (expensive) |
|
||||
| Custom list | Explicit scope list | Precise multi-tenant control |
|
||||
|
||||
**Custom scope example (recommended for multi-tenant):**
|
||||
|
||||
```python
|
||||
# Observations scoped to: user-level, team-level, and combined
|
||||
observation_scopes=[
|
||||
["user:alice"],
|
||||
["team:engineering"],
|
||||
["user:alice", "team:engineering"],
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Sync vs Async
|
||||
|
||||
| Mode | When to use |
|
||||
|------|-------------|
|
||||
| `async_=False` (default) | When you need confirmation before proceeding |
|
||||
| `async_=True` | End-of-turn or end-of-session retain; user-facing flows where latency matters |
|
||||
|
||||
Do not retain and recall in the same turn — retain is a write operation and the extracted memories will not be available immediately.
|
||||
|
||||
---
|
||||
|
||||
## Recalling Memories
|
||||
|
||||
### Budget Selection
|
||||
|
||||
| Budget | Latency | Use when |
|
||||
|--------|---------|----------|
|
||||
| `low` | 50–100ms | Simple fact lookups, single-hop questions |
|
||||
| `mid` | 100–300ms | Multi-hop reasoning, relationship queries *(default)* |
|
||||
| `high` | 300–500ms | Deep exploration, complex cross-domain patterns |
|
||||
|
||||
Default to `mid`. Use `low` for high-frequency agent loops. Reserve `high` for explicit "deep recall" user-triggered flows.
|
||||
|
||||
---
|
||||
|
||||
### Tag Filtering Modes
|
||||
|
||||
| Mode | Includes untagged? | Condition |
|
||||
|------|-------------------|-----------|
|
||||
| `any` *(default)* | Yes | At least one tag matches, OR untagged |
|
||||
| `all` | Yes | All specified tags present, OR untagged |
|
||||
| `any_strict` | No | At least one tag matches |
|
||||
| `all_strict` | No | All specified tags present |
|
||||
|
||||
**Decision guide:**
|
||||
- Shared global knowledge + per-user: `tags=["user:alice"], tags_match="any"` — returns Alice's memories and untagged global memories
|
||||
- Fully partitioned (no leakage): `tags=["user:alice"], tags_match="any_strict"` — Alice's memories only
|
||||
- Multi-condition AND: `tags=["user:alice", "topic:billing"], tags_match="all_strict"` — only where both tags present
|
||||
|
||||
**`tag_groups` for complex filters:**
|
||||
|
||||
Tag groups use a tree structure with `and`/`or`/`not` compound nodes and `{"tags": [...], "match": "..."}` leaf nodes.
|
||||
|
||||
```python
|
||||
# Alice's billing memories OR shared billing memories (no user tag)
|
||||
recall(
|
||||
query="...",
|
||||
tag_groups=[
|
||||
{"or": [
|
||||
{"tags": ["user:alice", "topic:billing"], "match": "all_strict"},
|
||||
{"and": [
|
||||
{"tags": ["topic:billing"], "match": "any_strict"},
|
||||
{"not": {"tags": ["user:alice"], "match": "any_strict"}},
|
||||
]},
|
||||
]}
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `include` Options
|
||||
|
||||
| Option | Default | Enable when |
|
||||
|--------|---------|-------------|
|
||||
| `include.entities` | Enabled | — (leave on; provides entity context for graph traversal) |
|
||||
| `include.chunks` | Disabled | Agent needs exact wording or source quotation |
|
||||
| `include.source_facts` | Disabled | Tracing observation provenance for auditing |
|
||||
|
||||
---
|
||||
|
||||
### `types` Filtering
|
||||
|
||||
| Value | Returns |
|
||||
|-------|---------|
|
||||
| *(not set)* | All types |
|
||||
| `["observation"]` | Consolidated patterns only — faster for high-level questions |
|
||||
| `["world", "experience"]` | Raw facts only — for ground-truth or citation-sensitive queries |
|
||||
|
||||
---
|
||||
|
||||
### `query_timestamp`
|
||||
|
||||
Set for time-sensitive queries. Anchors temporal ranking to a specific point in time.
|
||||
|
||||
```python
|
||||
# "What was the team working on in January?"
|
||||
recall(query="team priorities", query_timestamp="2025-01-31T23:59:59Z")
|
||||
|
||||
# Current context (most common)
|
||||
recall(query="user preferences", query_timestamp=datetime.utcnow().isoformat() + "Z")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Reflecting
|
||||
|
||||
### Recall vs Reflect
|
||||
|
||||
| Use `recall` when | Use `reflect` when |
|
||||
|-------------------|--------------------|
|
||||
| Agent will reason over facts itself | You want Hindsight to reason and return an answer |
|
||||
| You need raw citations | You need a synthesized response |
|
||||
| You're building a RAG pipeline | You want an autonomous multi-step search loop |
|
||||
| Latency is critical | Response quality matters more than latency |
|
||||
| You need precise fact counts | You need a contextual, nuanced answer |
|
||||
|
||||
---
|
||||
|
||||
### `response_schema`
|
||||
|
||||
Use when you need structured output for programmatic consumption.
|
||||
|
||||
```python
|
||||
reflect(
|
||||
query="What are the user's top 3 technical preferences?",
|
||||
response_schema={
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"preferences": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"maxItems": 3
|
||||
},
|
||||
"confidence": {"type": "number", "minimum": 0, "maximum": 1}
|
||||
},
|
||||
"required": ["preferences", "confidence"]
|
||||
}
|
||||
)
|
||||
# Returns: result.structured_output["preferences"], result.structured_output["confidence"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Auditing and Debugging
|
||||
|
||||
| Option | Purpose |
|
||||
|--------|---------|
|
||||
| `include.facts=True` | Exposes which memories and mental models were used (for transparency/auditing) |
|
||||
| `include.tool_calls=True` | Full execution trace of the internal search loop (for debugging) |
|
||||
|
||||
Enable `include.facts` in production for audit trails. Enable `include.tool_calls` only during development.
|
||||
|
||||
---
|
||||
|
||||
## Mental Models
|
||||
|
||||
Mental models are pre-computed `reflect` responses stored for common queries. They return instantly and consistently.
|
||||
|
||||
### When to Create
|
||||
|
||||
- Common repeated queries that should return consistent answers
|
||||
- High-traffic agents that need sub-100ms responses
|
||||
- User profiles or personas read on every request
|
||||
- Knowledge summaries reviewed or approved by humans
|
||||
- Cross-session state that changes slowly (preferences, skills, background)
|
||||
|
||||
### Tag Strategy
|
||||
|
||||
Tags on a mental model filter BOTH which memories are used to build it AND which recall/reflect calls can see it.
|
||||
|
||||
```python
|
||||
# Per-user mental model — uses Alice's memories (all_strict applied automatically during refresh)
|
||||
create_mental_model(
|
||||
bank_id="shared-bank",
|
||||
name="Alice's Technical Profile",
|
||||
source_query="Summarize Alice's technical background, preferred stack, and current projects",
|
||||
tags=["user:alice"],
|
||||
)
|
||||
|
||||
# Global mental model — uses all memories, visible to everyone
|
||||
create_mental_model(
|
||||
bank_id="shared-bank",
|
||||
name="Team Engineering Standards",
|
||||
source_query="What are the team's agreed engineering standards and conventions?",
|
||||
# No tags — reads all memories, visible to all
|
||||
)
|
||||
```
|
||||
|
||||
### Refresh Strategy
|
||||
|
||||
| Trigger | When to use |
|
||||
|---------|------------|
|
||||
| Manual via API | After significant data updates or review cycles |
|
||||
| `trigger={"refresh_after_consolidation": True}` | When observations update frequently and the model should stay current |
|
||||
|
||||
Create narrow, scoped models — one per knowledge dimension. A mental model titled "Everything about the user" is as useful as none.
|
||||
|
||||
**Model granularity examples for a personal assistant:**
|
||||
- "User Profile" — demographics, preferences, stated goals
|
||||
- "Current Projects" — active work, deadlines, blockers
|
||||
- "Technical Stack" — languages, tools, frameworks used
|
||||
- "Communication Style" — formality preferences, response length preferences
|
||||
|
||||
---
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
| Anti-pattern | Problem | Fix |
|
||||
|-------------|---------|-----|
|
||||
| Pre-summarizing before retain | Loses entity relationships, temporal markers, structural context | Retain raw content; Hindsight extracts facts |
|
||||
| Using random UUIDs as `document_id` | Creates duplicate documents on every retain | Use stable session/ticket/document IDs |
|
||||
| Omitting the `context` field | Reduces extraction quality significantly | Always describe what kind of data this is |
|
||||
| Using `metadata` for filtering | Metadata is not filterable | Use `tags` for anything you'll filter on |
|
||||
| Vague or generic missions | Generic extraction = noisy, low-value memories | Be specific about domain, data type, what to ignore |
|
||||
| `tags_match="any"` for multi-tenant banks | Leaks memories across users | Use `any_strict` or `all_strict` for user-partitioned data |
|
||||
| Retaining and recalling in the same request | Retained memories not yet indexed | Retain end-of-turn; recall at the start of next turn |
|
||||
| One mental model for everything | Low accuracy, slow refresh, hard to scope | Create one model per knowledge dimension |
|
||||
| `high` budget for every recall | Expensive, slow, usually unnecessary | Use `low` for simple lookups, `mid` default |
|
||||
| Missing `timestamp` on retain | Disables temporal retrieval strategies | Always set from actual content timestamps |
|
||||
@@ -1,13 +1,29 @@
|
||||
---
|
||||
title: Frequently Asked Questions
|
||||
description: Common questions and answers about Hindsight
|
||||
hide_table_of_contents: false
|
||||
hide_table_of_contents: true
|
||||
---
|
||||
|
||||
import {ClientsGrid, IntegrationsGrid, LLMProvidersGrid} from '@site/src/components/SupportedGrids';
|
||||
|
||||
# Frequently Asked Questions
|
||||
|
||||
**Contents**
|
||||
- [What is Hindsight and how does it differ from RAG?](#what-is-hindsight-and-how-does-it-differ-from-rag)
|
||||
- [Why use Hindsight instead of other solutions?](#why-use-hindsight-instead-of-other-solutions)
|
||||
- [Supported clients, integrations, and LLM providers](#which-clients-and-languages-are-supported)
|
||||
- [Which model should I use?](#which-model-should-i-use-with-hindsight)
|
||||
- [Hosting and system requirements](#do-i-need-to-host-my-own-infrastructure)
|
||||
- [How do I isolate user data?](#how-do-i-isolate-user-data)
|
||||
- [Retain, recall, and reflect — what's the difference?](#whats-the-difference-between-retain-recall-and-reflect)
|
||||
- [When should I use recall vs reflect?](#when-should-i-use-recall-vs-reflect)
|
||||
- [When should I use mental models?](#when-should-i-use-mental-models)
|
||||
- [Latency expectations](#whats-the-typical-latency-for-recall-operations)
|
||||
- [Tags, metadata, and entity labels](#does-hindsight-support-metadata-filtering)
|
||||
- [Recommended format for conversations](#what-is-the-recommended-format-for-retaining-conversations)
|
||||
|
||||
---
|
||||
|
||||
### What is Hindsight and how does it differ from RAG?
|
||||
|
||||
Hindsight is an agent memory system that provides long-term memory for AI agents using biomimetic data structures. Unlike traditional RAG (Retrieval-Augmented Generation), Hindsight:
|
||||
@@ -43,7 +59,6 @@ Unlike vector databases (just search) or RAG systems (document retrieval), Hinds
|
||||
|
||||
<ClientsGrid />
|
||||
|
||||
Any language can also use the [HTTP API](/developer/api/quickstart) directly.
|
||||
|
||||
---
|
||||
|
||||
@@ -59,22 +74,6 @@ Any language can also use the [HTTP API](/developer/api/quickstart) directly.
|
||||
|
||||
See [Models](/developer/models) for the full list of supported providers, recommended models, and configuration examples.
|
||||
|
||||
**Using local models with Ollama:**
|
||||
```bash
|
||||
HINDSIGHT_API_LLM_PROVIDER=ollama
|
||||
HINDSIGHT_API_LLM_MODEL=llama3.1
|
||||
HINDSIGHT_API_LLM_BASE_URL=http://localhost:11434
|
||||
```
|
||||
|
||||
**Using local models with LM Studio:**
|
||||
```bash
|
||||
HINDSIGHT_API_LLM_PROVIDER=lmstudio
|
||||
HINDSIGHT_API_LLM_MODEL=your-model-name
|
||||
HINDSIGHT_API_LLM_BASE_URL=http://localhost:1234/v1
|
||||
```
|
||||
|
||||
Configure your provider using the `HINDSIGHT_API_LLM_PROVIDER` environment variable. See [Configuration](/developer/configuration) and [Models](/developer/models) for details.
|
||||
|
||||
---
|
||||
|
||||
### Which model should I use with Hindsight?
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
LuActivity, LuPlug, LuShield, LuPackage, LuBook,
|
||||
LuNetwork, LuCode, LuLayers, LuCpu,
|
||||
LuArrowUpRight, LuBookOpen, LuRss, LuCloud, LuMessageCircle,
|
||||
LuChartBar, LuChartColumn,
|
||||
LuChartBar, LuChartColumn, LuStar, LuCircleHelp,
|
||||
} from 'react-icons/lu';
|
||||
import {SiGo, SiPython, SiGithub, SiSlack} from 'react-icons/si';
|
||||
|
||||
@@ -51,6 +51,9 @@ const ICON_MAP: Record<string, IconType> = {
|
||||
'lu-rss': LuRss,
|
||||
'lu-cloud': LuCloud,
|
||||
'lu-message-circle': LuMessageCircle,
|
||||
'lu-star': LuStar,
|
||||
'lu-circle-help': LuCircleHelp,
|
||||
'lu-file-text': LuFileText,
|
||||
};
|
||||
|
||||
type Props = WrapperProps<typeof LinkType>;
|
||||
|
||||
@@ -6,7 +6,7 @@ import type {IconType} from 'react-icons';
|
||||
import {
|
||||
LuArrowUpRight, LuCode, LuCircleHelp, LuScrollText,
|
||||
LuLayoutGrid, LuCloud, LuBook, LuRss, LuBookOpen,
|
||||
LuChartBar, LuCpu, LuFileText,
|
||||
LuChartBar, LuCpu, LuFileText, LuStar,
|
||||
} from 'react-icons/lu';
|
||||
import {SiGithub, SiSlack} from 'react-icons/si';
|
||||
|
||||
@@ -22,6 +22,7 @@ const ICON_MAP: Record<string, IconType> = {
|
||||
'lu-chart-bar': LuChartBar,
|
||||
'lu-cpu': LuCpu,
|
||||
'lu-file-text': LuFileText,
|
||||
'lu-star': LuStar,
|
||||
'si-github': SiGithub,
|
||||
'si-slack': SiSlack,
|
||||
};
|
||||
|
||||
@@ -5,78 +5,15 @@
|
||||
"label": "Architecture",
|
||||
"collapsible": false,
|
||||
"items": [
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/index",
|
||||
"label": "Overview",
|
||||
"customProps": {
|
||||
"icon": "lu-book"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/retain",
|
||||
"label": "Retain",
|
||||
"customProps": {
|
||||
"icon": "lu-brain"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/retrieval",
|
||||
"label": "Recall",
|
||||
"customProps": {
|
||||
"icon": "lu-search"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/reflect",
|
||||
"label": "Reflect",
|
||||
"customProps": {
|
||||
"icon": "lu-message"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/observations",
|
||||
"label": "Observations",
|
||||
"customProps": {
|
||||
"icon": "lu-activity"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/multilingual",
|
||||
"label": "Multilingual",
|
||||
"customProps": {
|
||||
"icon": "lu-languages"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/performance",
|
||||
"label": "Performance",
|
||||
"customProps": {
|
||||
"icon": "lu-zap"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/storage",
|
||||
"label": "Storage",
|
||||
"customProps": {
|
||||
"icon": "lu-database"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/rag-vs-hindsight",
|
||||
"label": "RAG vs Memory",
|
||||
"customProps": {
|
||||
"icon": "lu-compare"
|
||||
}
|
||||
}
|
||||
{ "type": "doc", "id": "developer/index", "label": "Overview", "customProps": { "icon": "lu-book" } },
|
||||
{ "type": "doc", "id": "developer/retain", "label": "Retain", "customProps": { "icon": "lu-brain" } },
|
||||
{ "type": "doc", "id": "developer/retrieval", "label": "Recall", "customProps": { "icon": "lu-search" } },
|
||||
{ "type": "doc", "id": "developer/reflect", "label": "Reflect", "customProps": { "icon": "lu-message" } },
|
||||
{ "type": "doc", "id": "developer/observations", "label": "Observations", "customProps": { "icon": "lu-activity" } },
|
||||
{ "type": "doc", "id": "developer/multilingual", "label": "Multilingual", "customProps": { "icon": "lu-languages" } },
|
||||
{ "type": "doc", "id": "developer/performance", "label": "Performance", "customProps": { "icon": "lu-zap" } },
|
||||
{ "type": "doc", "id": "developer/storage", "label": "Storage", "customProps": { "icon": "lu-database" } },
|
||||
{ "type": "doc", "id": "developer/rag-vs-hindsight", "label": "RAG vs Memory", "customProps": { "icon": "lu-compare" } }
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -84,87 +21,16 @@
|
||||
"label": "API",
|
||||
"collapsible": false,
|
||||
"items": [
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/api/quickstart",
|
||||
"label": "Quick Start",
|
||||
"customProps": {
|
||||
"icon": "lu-rocket"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/api/retain",
|
||||
"label": "Retain",
|
||||
"customProps": {
|
||||
"icon": "lu-brain"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/api/recall",
|
||||
"label": "Recall",
|
||||
"customProps": {
|
||||
"icon": "lu-search"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/api/reflect",
|
||||
"label": "Reflect",
|
||||
"customProps": {
|
||||
"icon": "lu-message"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/api/mental-models",
|
||||
"label": "Mental Models",
|
||||
"customProps": {
|
||||
"icon": "lu-layers"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/api/memory-banks",
|
||||
"label": "Memory Banks",
|
||||
"customProps": {
|
||||
"icon": "lu-memory"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/api/documents",
|
||||
"label": "Documents",
|
||||
"customProps": {
|
||||
"icon": "lu-file"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/api/operations",
|
||||
"label": "Operations",
|
||||
"customProps": {
|
||||
"icon": "lu-cpu"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/api/webhooks",
|
||||
"label": "Webhooks",
|
||||
"customProps": {
|
||||
"icon": "lu-webhook"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "link",
|
||||
"href": "/api-reference",
|
||||
"label": "API Reference",
|
||||
"customProps": {
|
||||
"icon": "lu-book-open",
|
||||
"iconAfter": "lu-arrow-up-right"
|
||||
}
|
||||
}
|
||||
{ "type": "doc", "id": "developer/api/quickstart", "label": "Quick Start", "customProps": { "icon": "lu-rocket" } },
|
||||
{ "type": "doc", "id": "developer/api/retain", "label": "Retain", "customProps": { "icon": "lu-brain" } },
|
||||
{ "type": "doc", "id": "developer/api/recall", "label": "Recall", "customProps": { "icon": "lu-search" } },
|
||||
{ "type": "doc", "id": "developer/api/reflect", "label": "Reflect", "customProps": { "icon": "lu-message" } },
|
||||
{ "type": "doc", "id": "developer/api/mental-models", "label": "Mental Models", "customProps": { "icon": "lu-layers" } },
|
||||
{ "type": "doc", "id": "developer/api/memory-banks", "label": "Memory Banks", "customProps": { "icon": "lu-memory" } },
|
||||
{ "type": "doc", "id": "developer/api/documents", "label": "Documents", "customProps": { "icon": "lu-file" } },
|
||||
{ "type": "doc", "id": "developer/api/operations", "label": "Operations", "customProps": { "icon": "lu-cpu" } },
|
||||
{ "type": "doc", "id": "developer/api/webhooks", "label": "Webhooks", "customProps": { "icon": "lu-webhook" } },
|
||||
{ "type": "link", "href": "/api-reference", "label": "API Reference", "customProps": { "icon": "lu-book-open", "iconAfter": "lu-arrow-up-right" } }
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -172,46 +38,11 @@
|
||||
"label": "Clients",
|
||||
"collapsible": false,
|
||||
"items": [
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/python",
|
||||
"label": "Python",
|
||||
"customProps": {
|
||||
"icon": "si-python"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/nodejs",
|
||||
"label": "TypeScript",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/typescript.png"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/go",
|
||||
"label": "Go",
|
||||
"customProps": {
|
||||
"icon": "si-go"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/cli",
|
||||
"label": "CLI",
|
||||
"customProps": {
|
||||
"icon": "lu-terminal"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/embed",
|
||||
"label": "Embedded Python",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/package.svg"
|
||||
}
|
||||
}
|
||||
{ "type": "doc", "id": "sdks/python", "label": "Python", "customProps": { "icon": "si-python" } },
|
||||
{ "type": "doc", "id": "sdks/nodejs", "label": "TypeScript", "customProps": { "icon": "/img/icons/typescript.png" } },
|
||||
{ "type": "doc", "id": "sdks/go", "label": "Go", "customProps": { "icon": "si-go" } },
|
||||
{ "type": "doc", "id": "sdks/cli", "label": "CLI", "customProps": { "icon": "lu-terminal" } },
|
||||
{ "type": "doc", "id": "sdks/embed", "label": "Embedded Python", "customProps": { "icon": "/img/icons/package.svg" } }
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -219,70 +50,14 @@
|
||||
"label": "Integrations",
|
||||
"collapsible": false,
|
||||
"items": [
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/integrations/local-mcp",
|
||||
"label": "Local MCP Server",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/mcp.png"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/integrations/litellm",
|
||||
"label": "LiteLLM",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/litellm.png"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/integrations/openclaw",
|
||||
"label": "OpenClaw",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/openclaw.png"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/integrations/ai-sdk",
|
||||
"label": "Vercel AI SDK",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/vercel.png"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/integrations/chat",
|
||||
"label": "Vercel Chat SDK",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/vercel.png"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/integrations/crewai",
|
||||
"label": "CrewAI",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/crewai.png"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/integrations/pydantic-ai",
|
||||
"label": "Pydantic AI",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/pydanticai.png"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "sdks/integrations/skills",
|
||||
"label": "Skills",
|
||||
"customProps": {
|
||||
"icon": "/img/icons/skills.png"
|
||||
}
|
||||
}
|
||||
{ "type": "doc", "id": "sdks/integrations/local-mcp", "label": "Local MCP Server", "customProps": { "icon": "/img/icons/mcp.png" } },
|
||||
{ "type": "doc", "id": "sdks/integrations/litellm", "label": "LiteLLM", "customProps": { "icon": "/img/icons/litellm.png" } },
|
||||
{ "type": "doc", "id": "sdks/integrations/openclaw", "label": "OpenClaw", "customProps": { "icon": "/img/icons/openclaw.png" } },
|
||||
{ "type": "doc", "id": "sdks/integrations/ai-sdk", "label": "Vercel AI SDK", "customProps": { "icon": "/img/icons/vercel.png" } },
|
||||
{ "type": "doc", "id": "sdks/integrations/chat", "label": "Vercel Chat SDK", "customProps": { "icon": "/img/icons/vercel.png" } },
|
||||
{ "type": "doc", "id": "sdks/integrations/crewai", "label": "CrewAI", "customProps": { "icon": "/img/icons/crewai.png" } },
|
||||
{ "type": "doc", "id": "sdks/integrations/pydantic-ai", "label": "Pydantic AI", "customProps": { "icon": "/img/icons/pydanticai.png" } },
|
||||
{ "type": "doc", "id": "sdks/integrations/skills", "label": "Skills", "customProps": { "icon": "/img/icons/skills.png" } }
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -290,79 +65,15 @@
|
||||
"label": "Hosting",
|
||||
"collapsible": false,
|
||||
"items": [
|
||||
{
|
||||
"type": "link",
|
||||
"href": "https://ui.hindsight.vectorize.io/signup",
|
||||
"label": "Cloud",
|
||||
"customProps": {
|
||||
"icon": "lu-cloud",
|
||||
"iconAfter": "lu-arrow-up-right"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/installation",
|
||||
"label": "Installation",
|
||||
"customProps": {
|
||||
"icon": "lu-package"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/services",
|
||||
"label": "Services",
|
||||
"customProps": {
|
||||
"icon": "lu-server"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/configuration",
|
||||
"label": "Configuration",
|
||||
"customProps": {
|
||||
"icon": "lu-settings"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/admin-cli",
|
||||
"label": "Admin CLI",
|
||||
"customProps": {
|
||||
"icon": "lu-terminal"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/extensions",
|
||||
"label": "Extensions",
|
||||
"customProps": {
|
||||
"icon": "lu-plug"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/models",
|
||||
"label": "Models",
|
||||
"customProps": {
|
||||
"icon": "lu-cpu"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/monitoring",
|
||||
"label": "Monitoring",
|
||||
"customProps": {
|
||||
"icon": "lu-activity"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "doc",
|
||||
"id": "developer/mcp-server",
|
||||
"label": "MCP Server",
|
||||
"customProps": {
|
||||
"icon": "lu-network"
|
||||
}
|
||||
}
|
||||
{ "type": "link", "href": "https://ui.hindsight.vectorize.io/signup", "label": "Cloud", "customProps": { "icon": "lu-cloud", "iconAfter": "lu-arrow-up-right" } },
|
||||
{ "type": "doc", "id": "developer/installation", "label": "Installation", "customProps": { "icon": "lu-package" } },
|
||||
{ "type": "doc", "id": "developer/services", "label": "Services", "customProps": { "icon": "lu-server" } },
|
||||
{ "type": "doc", "id": "developer/configuration", "label": "Configuration", "customProps": { "icon": "lu-settings" } },
|
||||
{ "type": "doc", "id": "developer/admin-cli", "label": "Admin CLI", "customProps": { "icon": "lu-terminal" } },
|
||||
{ "type": "doc", "id": "developer/extensions", "label": "Extensions", "customProps": { "icon": "lu-plug" } },
|
||||
{ "type": "doc", "id": "developer/models", "label": "Models", "customProps": { "icon": "lu-cpu" } },
|
||||
{ "type": "doc", "id": "developer/monitoring", "label": "Monitoring", "customProps": { "icon": "lu-activity" } },
|
||||
{ "type": "doc", "id": "developer/mcp-server", "label": "MCP Server", "customProps": { "icon": "lu-network" } }
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -370,69 +81,13 @@
|
||||
"label": "More",
|
||||
"collapsible": false,
|
||||
"items": [
|
||||
{
|
||||
"type": "link",
|
||||
"href": "/cookbook",
|
||||
"label": "Cookbook",
|
||||
"customProps": {
|
||||
"icon": "lu-book",
|
||||
"iconAfter": "lu-arrow-up-right"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "link",
|
||||
"href": "/blog",
|
||||
"label": "Blog",
|
||||
"customProps": {
|
||||
"icon": "lu-rss",
|
||||
"iconAfter": "lu-arrow-up-right"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "link",
|
||||
"href": "https://join.slack.com/t/hindsight-space/shared_invite/zt-3nhbm4w29-LeSJ5Ixi6j8PdiYOCPlOgg",
|
||||
"label": "Community",
|
||||
"customProps": {
|
||||
"icon": "si-slack",
|
||||
"iconAfter": "lu-arrow-up-right"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "link",
|
||||
"href": "https://github.com/vectorize-io/hindsight",
|
||||
"label": "GitHub",
|
||||
"customProps": {
|
||||
"icon": "si-github",
|
||||
"iconAfter": "lu-arrow-up-right"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "link",
|
||||
"href": "https://benchmarks.hindsight.vectorize.io/",
|
||||
"label": "Benchmarks",
|
||||
"customProps": {
|
||||
"icon": "lu-chart-bar",
|
||||
"iconAfter": "lu-arrow-up-right"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "link",
|
||||
"href": "https://benchmarks.hindsight.vectorize.io/",
|
||||
"label": "Which Model Should I Use?",
|
||||
"customProps": {
|
||||
"icon": "lu-cpu",
|
||||
"iconAfter": "lu-arrow-up-right"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "link",
|
||||
"href": "https://arxiv.org/abs/2512.12818",
|
||||
"label": "Paper",
|
||||
"customProps": {
|
||||
"icon": "lu-file-text",
|
||||
"iconAfter": "lu-arrow-up-right"
|
||||
}
|
||||
}
|
||||
{ "type": "link", "href": "/cookbook", "label": "Cookbook", "customProps": { "icon": "lu-book", "iconAfter": "lu-arrow-up-right" } },
|
||||
{ "type": "link", "href": "/blog", "label": "Blog", "customProps": { "icon": "lu-rss", "iconAfter": "lu-arrow-up-right" } },
|
||||
{ "type": "link", "href": "https://join.slack.com/t/hindsight-space/shared_invite/zt-3nhbm4w29-LeSJ5Ixi6j8PdiYOCPlOgg", "label": "Community", "customProps": { "icon": "si-slack", "iconAfter": "lu-arrow-up-right" } },
|
||||
{ "type": "link", "href": "https://github.com/vectorize-io/hindsight", "label": "GitHub", "customProps": { "icon": "si-github", "iconAfter": "lu-arrow-up-right" } },
|
||||
{ "type": "link", "href": "https://benchmarks.hindsight.vectorize.io/", "label": "Benchmarks", "customProps": { "icon": "lu-chart-bar", "iconAfter": "lu-arrow-up-right" } },
|
||||
{ "type": "link", "href": "https://benchmarks.hindsight.vectorize.io/", "label": "Which Model Should I Use?", "customProps": { "icon": "lu-cpu", "iconAfter": "lu-arrow-up-right" } },
|
||||
{ "type": "link", "href": "https://arxiv.org/abs/2512.12818", "label": "Paper", "customProps": { "icon": "lu-file-text", "iconAfter": "lu-arrow-up-right" } }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -7,6 +7,7 @@ set -e
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
DOCS_DIR="$ROOT_DIR/hindsight-docs/docs"
|
||||
PAGES_DIR="$ROOT_DIR/hindsight-docs/src/pages"
|
||||
EXAMPLES_DIR="$ROOT_DIR/hindsight-docs/examples"
|
||||
SKILL_DIR="$ROOT_DIR/skills/hindsight-docs"
|
||||
REFS_DIR="$SKILL_DIR/references"
|
||||
@@ -156,6 +157,24 @@ find "$DOCS_DIR" -type f \( -name "*.md" -o -name "*.mdx" \) | while read -r fil
|
||||
process_file "$file"
|
||||
done
|
||||
|
||||
# Process standalone pages (e.g. best-practices, faq) from src/pages/
|
||||
print_info "Processing standalone pages..."
|
||||
for page in best-practices faq; do
|
||||
for ext in md mdx; do
|
||||
src="$PAGES_DIR/$page.$ext"
|
||||
if [ -f "$src" ]; then
|
||||
dest="$REFS_DIR/$page.md"
|
||||
mkdir -p "$(dirname "$dest")"
|
||||
if [[ "$src" == *.mdx ]]; then
|
||||
convert_mdx_to_md "$src" "$dest"
|
||||
else
|
||||
cp "$src" "$dest"
|
||||
fi
|
||||
print_info "Included page: $page.$ext"
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
# Generate SKILL.md
|
||||
print_info "Generating SKILL.md..."
|
||||
cat > "$SKILL_DIR/SKILL.md" <<'EOF'
|
||||
@@ -187,6 +206,8 @@ All documentation is in `references/` organized by category:
|
||||
|
||||
```
|
||||
references/
|
||||
├── best-practices.md # START HERE — missions, tags, formats, anti-patterns
|
||||
├── faq.md # Common questions and decisions
|
||||
├── developer/
|
||||
│ ├── api/ # Core operations: retain, recall, reflect, memory banks
|
||||
│ └── *.md # Architecture, configuration, deployment, performance
|
||||
@@ -246,6 +267,14 @@ references/sdks/python.md
|
||||
references/cookbook/recipes/per-user-memory.md
|
||||
```
|
||||
|
||||
## Start Here: Best Practices
|
||||
|
||||
Before reading API docs, read the best practices guide. It covers practical rules for missions, tags, content format, observation scopes, and anti-patterns — the fastest way to integrate correctly.
|
||||
|
||||
```
|
||||
references/best-practices.md
|
||||
```
|
||||
|
||||
## Key Concepts
|
||||
|
||||
- **Memory Banks**: Isolated memory stores (one per user/agent)
|
||||
|
||||
@@ -26,6 +26,8 @@ All documentation is in `references/` organized by category:
|
||||
|
||||
```
|
||||
references/
|
||||
├── best-practices.md # START HERE — missions, tags, formats, anti-patterns
|
||||
├── faq.md # Common questions and decisions
|
||||
├── developer/
|
||||
│ ├── api/ # Core operations: retain, recall, reflect, memory banks
|
||||
│ └── *.md # Architecture, configuration, deployment, performance
|
||||
@@ -85,6 +87,14 @@ references/sdks/python.md
|
||||
references/cookbook/recipes/per-user-memory.md
|
||||
```
|
||||
|
||||
## Start Here: Best Practices
|
||||
|
||||
Before reading API docs, read the best practices guide. It covers practical rules for missions, tags, content format, observation scopes, and anti-patterns — the fastest way to integrate correctly.
|
||||
|
||||
```
|
||||
references/best-practices.md
|
||||
```
|
||||
|
||||
## Key Concepts
|
||||
|
||||
- **Memory Banks**: Isolated memory stores (one per user/agent)
|
||||
|
||||
@@ -0,0 +1,519 @@
|
||||
|
||||
# Best Practices
|
||||
|
||||
Practical guidance for agents and developers integrating Hindsight memory into production systems.
|
||||
|
||||
---
|
||||
|
||||
## Core Concepts
|
||||
|
||||
### Memory Banks
|
||||
|
||||
A **memory bank** is an isolated memory store — the unit of separation between users, agents, or contexts. All operations (retain, recall, reflect) target a single bank. Banks do not share data.
|
||||
|
||||
- One bank per user is the most common pattern for multi-user applications
|
||||
- One bank per agent is common for agent-specific long-term memory
|
||||
- A shared bank with tags can work for cross-user analysis (see [Tags](#tags--naming-conventions))
|
||||
|
||||
Banks are auto-created on first use. Configure them before ingesting data to steer behavior.
|
||||
|
||||
---
|
||||
|
||||
### Taxonomy
|
||||
|
||||
| Operation | What it does | When to call it |
|
||||
|-----------|-------------|-----------------|
|
||||
| **Retain** | Ingests raw content (conversations, documents, notes). The LLM extracts facts, entities, and relationships — raw content is never stored verbatim. | After each conversation turn or session ends |
|
||||
| **Recall** | Retrieves relevant memories using 4 parallel strategies: semantic search, BM25, graph traversal, and temporal ranking. Returns a ranked list of facts. | Before generating a response that benefits from past context |
|
||||
| **Reflect** | Autonomous reasoning loop: searches memory, synthesizes an answer, and returns it directly. Uses mental models and observations hierarchically. | When you want Hindsight to answer a question, not just retrieve facts |
|
||||
| **Observations** | Auto-synthesized knowledge patterns produced by the consolidation operation, which runs asynchronously after retain completes. Consolidate facts into durable insights (preferences, behavioral patterns, contradictions). | Triggered automatically after retain — not part of the retain call itself |
|
||||
| **Mental Models** | Pre-computed reflect responses stored for common queries. Return instantly and consistently. | Create for repeated high-traffic queries or slowly-changing user profiles |
|
||||
|
||||
---
|
||||
|
||||
### Memory Types
|
||||
|
||||
Facts extracted during retain are classified into three types:
|
||||
|
||||
| Type | Description | Example |
|
||||
|------|-------------|---------|
|
||||
| `world` | General knowledge, external facts | "The Eiffel Tower is in Paris" |
|
||||
| `experience` | Personal events, user-specific facts | "User moved to Berlin in 2024" |
|
||||
| `observation` | Consolidated patterns synthesized from facts | "User consistently prefers async communication" |
|
||||
|
||||
Use `types` filtering in recall to target specific memory types.
|
||||
|
||||
---
|
||||
|
||||
## Bank Configuration
|
||||
|
||||
Configure a bank before first use to steer memory behavior for your domain. Misconfigured missions are the single biggest cause of low-quality memories.
|
||||
|
||||
### Writing Effective Missions
|
||||
|
||||
All three missions accept plain language. Be specific about your domain — vague missions produce vague results.
|
||||
|
||||
#### `retain_mission`
|
||||
|
||||
Injected into the fact extraction prompt. Tells the LLM what to extract and what to ignore.
|
||||
|
||||
| Quality | Example |
|
||||
|---------|---------|
|
||||
| **Good** | `Always extract technical decisions, API design choices, architectural trade-offs, blockers, and error messages. Ignore greetings, small talk, and scheduling logistics.` |
|
||||
| **Good** | `Extract personal preferences, ongoing commitments, deadlines, health info, and relationship details. Ignore filler phrases and pleasantries.` |
|
||||
| **Bad** | `Extract all information` — too vague, extracts noise |
|
||||
| **Bad** | `Be helpful` — not an extraction directive |
|
||||
|
||||
**Tips:**
|
||||
- List the fact *types* you want (preferences, decisions, errors, commitments)
|
||||
- List what to *ignore* — this is as important as what to include
|
||||
- Match the mission to your actual data type (conversations vs documents vs tickets)
|
||||
|
||||
#### `observations_mission`
|
||||
|
||||
Steers what patterns are synthesized during consolidation. Runs after retain.
|
||||
|
||||
```
|
||||
Identify evolving preferences, recurring patterns, behavioral shifts, and contradictions
|
||||
with prior knowledge. Focus on durable patterns — not transient states. Highlight when
|
||||
user behavior contradicts previous observations.
|
||||
```
|
||||
|
||||
**Tips:**
|
||||
- Emphasize "durable patterns" to avoid ephemeral observation noise
|
||||
- Mention contradiction detection explicitly if you need historical tracking
|
||||
- Match scope to how often you expect patterns to change
|
||||
|
||||
#### `reflect_mission`
|
||||
|
||||
Sets the agent persona and reasoning frame for `reflect` operations.
|
||||
|
||||
| Use Case | Mission |
|
||||
|----------|---------|
|
||||
| Coding assistant | `You are a senior developer helping optimize the user's workflow. Always factor in past technical decisions, current project context, and stated preferences. Be direct and opinionated.` |
|
||||
| Customer support | `You are a support agent with full context of this customer's history. Reference past tickets and resolutions where relevant. Be concise and solution-focused.` |
|
||||
| Personal assistant | `You are a personal assistant who remembers everything important to the user. Personalize every response using what you know about their preferences, schedule, and ongoing projects.` |
|
||||
| Medical assistant | `You are a health assistant. Reference the user's history accurately. Always recommend consulting a professional for medical decisions. Do not speculate.` |
|
||||
|
||||
---
|
||||
|
||||
### Disposition Traits
|
||||
|
||||
Dispositions affect `reflect` only (not `recall`). Scale 1–5.
|
||||
|
||||
| Trait | 1 | 5 |
|
||||
|-------|---|---|
|
||||
| `skepticism` | Trusts all memories at face value | Questions contradictions, flags uncertain info |
|
||||
| `literalism` | Liberal interpretation, infers intent | Strict literal reading, no inference |
|
||||
| `empathy` | Clinical, neutral tone | Warm, personal, emotionally aware |
|
||||
|
||||
**Common profiles:**
|
||||
|
||||
| Agent type | Skepticism | Literalism | Empathy |
|
||||
|------------|------------|------------|---------|
|
||||
| Code review | 4 | 5 | 1 |
|
||||
| Customer support | 2 | 3 | 4 |
|
||||
| Personal assistant | 2 | 2 | 4 |
|
||||
| Medical assistant | 5 | 4 | 3 |
|
||||
| Research assistant | 4 | 4 | 2 |
|
||||
|
||||
---
|
||||
|
||||
### Entity Labels
|
||||
|
||||
Define a controlled vocabulary for classification. The LLM will extract and normalize values to your defined set.
|
||||
|
||||
```json
|
||||
{
|
||||
"entity_labels": [
|
||||
{
|
||||
"key": "tech_stack",
|
||||
"type": "multi-values",
|
||||
"values": [
|
||||
{"value": "python", "description": "Python programming language"},
|
||||
{"value": "typescript", "description": "TypeScript / Node.js"},
|
||||
{"value": "react", "description": "React frontend framework"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "priority",
|
||||
"type": "value",
|
||||
"tag": true,
|
||||
"values": [
|
||||
{"value": "high", "description": "Urgent or blocking"},
|
||||
{"value": "low", "description": "Nice to have"}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- **`type: "value"`** — single value per entity (last write wins)
|
||||
- **`type: "multi-values"`** — accumulates multiple values
|
||||
- **`tag: true`** — extracted label values are also added as tags (enables filtering by entity value)
|
||||
|
||||
Use entity labels when you need consistent classification — domain-specific terms, status values, priority levels, engagement types.
|
||||
|
||||
---
|
||||
|
||||
## Retaining Data
|
||||
|
||||
### Content Format
|
||||
|
||||
Pass the richest representation available. Never pre-summarize.
|
||||
|
||||
| Format | Recommendation |
|
||||
|--------|---------------|
|
||||
| JSON conversation array | **Preferred** for conversations — preserves structure, roles, and relationships |
|
||||
| Prefixed plain text | Acceptable — `[ISO-timestamp] role: text` per line |
|
||||
| Markdown / HTML / raw text | Works for documents and notes |
|
||||
| Pre-summarized text | **Avoid** — loses entity relationships, temporal markers, structural context |
|
||||
|
||||
**Conversation JSON (preferred):**
|
||||
|
||||
```json
|
||||
[
|
||||
{"role": "user", "content": "I'm using React for the frontend.", "timestamp": "2025-06-01T10:30:00Z"},
|
||||
{"role": "assistant", "content": "Got it. What state management are you using?"},
|
||||
{"role": "user", "content": "Zustand. We moved away from Redux last quarter."}
|
||||
]
|
||||
```
|
||||
|
||||
**Why not pre-summarize:** The LLM extracts facts, entities, and relationships from structure. A summary like "user uses React and Zustand" loses the temporal reference ("last quarter"), the entity relationship (React↔frontend, Redux↔migration), and the causal context (moved away from).
|
||||
|
||||
---
|
||||
|
||||
### The `context` Field
|
||||
|
||||
High-impact on extraction quality. Always set it. Describes the *nature and source* of the content.
|
||||
|
||||
```python
|
||||
# Good — specific, descriptive
|
||||
context="Customer support ticket #12345 from user Alice about a billing discrepancy"
|
||||
context="Developer's architecture review session for the payments service"
|
||||
context="User's onboarding form: stated goals, current tools, and team size"
|
||||
context="Weekly standup notes: blockers, progress, and upcoming tasks"
|
||||
|
||||
# Bad — generic, adds no signal
|
||||
context="some data"
|
||||
context="conversation"
|
||||
# Omitted entirely — extraction uses no context
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### The `document_id` Field
|
||||
|
||||
Use for upsert behavior. Same `document_id` = delete previous version and reprocess.
|
||||
|
||||
**Rules:**
|
||||
- Use stable, meaningful IDs (session ID, ticket ID, document UUID)
|
||||
- Always use the same ID for a growing conversation — retain the full conversation with each new message
|
||||
- Do NOT use random UUIDs per retain call — this creates duplicates
|
||||
|
||||
```python
|
||||
# Good — stable session ID
|
||||
client.retain(bank_id="user-alice", items=[{
|
||||
"content": full_conversation,
|
||||
"document_id": f"session-{session_id}",
|
||||
}])
|
||||
|
||||
# Bad — new random ID every call = duplicates
|
||||
client.retain(bank_id="user-alice", items=[{
|
||||
"content": full_conversation,
|
||||
"document_id": str(uuid.uuid4()), # ❌ creates a new document each time
|
||||
}])
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### The `timestamp` Field
|
||||
|
||||
Set whenever you have temporal context. Enables temporal retrieval strategies.
|
||||
|
||||
- ISO 8601 format: `"2025-06-01T10:32:00Z"`
|
||||
- For conversations: set to when the conversation *started*
|
||||
- Omitting it disables temporal ranking entirely
|
||||
|
||||
---
|
||||
|
||||
### Tags: Naming Conventions
|
||||
|
||||
Tags scope visibility. A memory tagged `user:alice` is only returned for recall/reflect calls that include `user:alice` in their `tags` filter (with strict matching).
|
||||
|
||||
**Standard naming conventions:**
|
||||
|
||||
| Pattern | Example | Use for |
|
||||
|---------|---------|---------|
|
||||
| `user:<id>` | `user:alice`, `user:u_123` | Per-user isolation |
|
||||
| `session:<id>` | `session:s_abc` | Session-scoped memories |
|
||||
| `team:<name>` | `team:engineering` | Shared team knowledge |
|
||||
| `topic:<name>` | `topic:billing`, `topic:technical` | Domain filtering |
|
||||
| `scope:<name>` | `scope:private`, `scope:public` | Visibility tiers |
|
||||
|
||||
**Multi-tenant minimum:** Every retain for user data must include at least `user:<id>`. Omitting it makes the memory globally visible.
|
||||
|
||||
```python
|
||||
# Multi-tenant retain — always tag with user ID
|
||||
items=[{
|
||||
"content": conversation,
|
||||
"tags": ["user:alice", "session:s_abc", "topic:billing"],
|
||||
"document_id": f"session-{session_id}",
|
||||
}]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Metadata Schema
|
||||
|
||||
Use for source tracking and downstream linking. **Not filterable** — use tags for filtering.
|
||||
|
||||
```python
|
||||
# Source tracking
|
||||
metadata={"source": "slack", "channel": "#engineering", "thread_id": "T123456"}
|
||||
|
||||
# Ticket linking
|
||||
metadata={"ticket_id": "JIRA-123", "priority": "high", "reporter": "alice"}
|
||||
|
||||
# Document provenance
|
||||
metadata={"url": "https://...", "section": "pricing-faq", "version": "2025-Q1"}
|
||||
```
|
||||
|
||||
Metadata is returned with every recalled memory — use it to link memories back to source systems for UI display, deep-linking, or audit trails.
|
||||
|
||||
---
|
||||
|
||||
### Observation Scopes
|
||||
|
||||
Controls which tag combinations get their own observation pass.
|
||||
|
||||
| Value | Behavior | When to use |
|
||||
|-------|----------|------------|
|
||||
| `"combined"` | One pass with all tags together | Default — single-user banks, general use |
|
||||
| `"per_tag"` | One pass per tag independently | Users should have isolated behavioral observations |
|
||||
| `"all_combinations"` | All possible subsets of tags | Complex multi-dimensional analysis (expensive) |
|
||||
| Custom list | Explicit scope list | Precise multi-tenant control |
|
||||
|
||||
**Custom scope example (recommended for multi-tenant):**
|
||||
|
||||
```python
|
||||
# Observations scoped to: user-level, team-level, and combined
|
||||
observation_scopes=[
|
||||
["user:alice"],
|
||||
["team:engineering"],
|
||||
["user:alice", "team:engineering"],
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Sync vs Async
|
||||
|
||||
| Mode | When to use |
|
||||
|------|-------------|
|
||||
| `async_=False` (default) | When you need confirmation before proceeding |
|
||||
| `async_=True` | End-of-turn or end-of-session retain; user-facing flows where latency matters |
|
||||
|
||||
Do not retain and recall in the same turn — retain is a write operation and the extracted memories will not be available immediately.
|
||||
|
||||
---
|
||||
|
||||
## Recalling Memories
|
||||
|
||||
### Budget Selection
|
||||
|
||||
| Budget | Latency | Use when |
|
||||
|--------|---------|----------|
|
||||
| `low` | 50–100ms | Simple fact lookups, single-hop questions |
|
||||
| `mid` | 100–300ms | Multi-hop reasoning, relationship queries *(default)* |
|
||||
| `high` | 300–500ms | Deep exploration, complex cross-domain patterns |
|
||||
|
||||
Default to `mid`. Use `low` for high-frequency agent loops. Reserve `high` for explicit "deep recall" user-triggered flows.
|
||||
|
||||
---
|
||||
|
||||
### Tag Filtering Modes
|
||||
|
||||
| Mode | Includes untagged? | Condition |
|
||||
|------|-------------------|-----------|
|
||||
| `any` *(default)* | Yes | At least one tag matches, OR untagged |
|
||||
| `all` | Yes | All specified tags present, OR untagged |
|
||||
| `any_strict` | No | At least one tag matches |
|
||||
| `all_strict` | No | All specified tags present |
|
||||
|
||||
**Decision guide:**
|
||||
- Shared global knowledge + per-user: `tags=["user:alice"], tags_match="any"` — returns Alice's memories and untagged global memories
|
||||
- Fully partitioned (no leakage): `tags=["user:alice"], tags_match="any_strict"` — Alice's memories only
|
||||
- Multi-condition AND: `tags=["user:alice", "topic:billing"], tags_match="all_strict"` — only where both tags present
|
||||
|
||||
**`tag_groups` for complex filters:**
|
||||
|
||||
Tag groups use a tree structure with `and`/`or`/`not` compound nodes and `{"tags": [...], "match": "..."}` leaf nodes.
|
||||
|
||||
```python
|
||||
# Alice's billing memories OR shared billing memories (no user tag)
|
||||
recall(
|
||||
query="...",
|
||||
tag_groups=[
|
||||
{"or": [
|
||||
{"tags": ["user:alice", "topic:billing"], "match": "all_strict"},
|
||||
{"and": [
|
||||
{"tags": ["topic:billing"], "match": "any_strict"},
|
||||
{"not": {"tags": ["user:alice"], "match": "any_strict"}},
|
||||
]},
|
||||
]}
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `include` Options
|
||||
|
||||
| Option | Default | Enable when |
|
||||
|--------|---------|-------------|
|
||||
| `include.entities` | Enabled | — (leave on; provides entity context for graph traversal) |
|
||||
| `include.chunks` | Disabled | Agent needs exact wording or source quotation |
|
||||
| `include.source_facts` | Disabled | Tracing observation provenance for auditing |
|
||||
|
||||
---
|
||||
|
||||
### `types` Filtering
|
||||
|
||||
| Value | Returns |
|
||||
|-------|---------|
|
||||
| *(not set)* | All types |
|
||||
| `["observation"]` | Consolidated patterns only — faster for high-level questions |
|
||||
| `["world", "experience"]` | Raw facts only — for ground-truth or citation-sensitive queries |
|
||||
|
||||
---
|
||||
|
||||
### `query_timestamp`
|
||||
|
||||
Set for time-sensitive queries. Anchors temporal ranking to a specific point in time.
|
||||
|
||||
```python
|
||||
# "What was the team working on in January?"
|
||||
recall(query="team priorities", query_timestamp="2025-01-31T23:59:59Z")
|
||||
|
||||
# Current context (most common)
|
||||
recall(query="user preferences", query_timestamp=datetime.utcnow().isoformat() + "Z")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Reflecting
|
||||
|
||||
### Recall vs Reflect
|
||||
|
||||
| Use `recall` when | Use `reflect` when |
|
||||
|-------------------|--------------------|
|
||||
| Agent will reason over facts itself | You want Hindsight to reason and return an answer |
|
||||
| You need raw citations | You need a synthesized response |
|
||||
| You're building a RAG pipeline | You want an autonomous multi-step search loop |
|
||||
| Latency is critical | Response quality matters more than latency |
|
||||
| You need precise fact counts | You need a contextual, nuanced answer |
|
||||
|
||||
---
|
||||
|
||||
### `response_schema`
|
||||
|
||||
Use when you need structured output for programmatic consumption.
|
||||
|
||||
```python
|
||||
reflect(
|
||||
query="What are the user's top 3 technical preferences?",
|
||||
response_schema={
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"preferences": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"maxItems": 3
|
||||
},
|
||||
"confidence": {"type": "number", "minimum": 0, "maximum": 1}
|
||||
},
|
||||
"required": ["preferences", "confidence"]
|
||||
}
|
||||
)
|
||||
# Returns: result.structured_output["preferences"], result.structured_output["confidence"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Auditing and Debugging
|
||||
|
||||
| Option | Purpose |
|
||||
|--------|---------|
|
||||
| `include.facts=True` | Exposes which memories and mental models were used (for transparency/auditing) |
|
||||
| `include.tool_calls=True` | Full execution trace of the internal search loop (for debugging) |
|
||||
|
||||
Enable `include.facts` in production for audit trails. Enable `include.tool_calls` only during development.
|
||||
|
||||
---
|
||||
|
||||
## Mental Models
|
||||
|
||||
Mental models are pre-computed `reflect` responses stored for common queries. They return instantly and consistently.
|
||||
|
||||
### When to Create
|
||||
|
||||
- Common repeated queries that should return consistent answers
|
||||
- High-traffic agents that need sub-100ms responses
|
||||
- User profiles or personas read on every request
|
||||
- Knowledge summaries reviewed or approved by humans
|
||||
- Cross-session state that changes slowly (preferences, skills, background)
|
||||
|
||||
### Tag Strategy
|
||||
|
||||
Tags on a mental model filter BOTH which memories are used to build it AND which recall/reflect calls can see it.
|
||||
|
||||
```python
|
||||
# Per-user mental model — uses Alice's memories (all_strict applied automatically during refresh)
|
||||
create_mental_model(
|
||||
bank_id="shared-bank",
|
||||
name="Alice's Technical Profile",
|
||||
source_query="Summarize Alice's technical background, preferred stack, and current projects",
|
||||
tags=["user:alice"],
|
||||
)
|
||||
|
||||
# Global mental model — uses all memories, visible to everyone
|
||||
create_mental_model(
|
||||
bank_id="shared-bank",
|
||||
name="Team Engineering Standards",
|
||||
source_query="What are the team's agreed engineering standards and conventions?",
|
||||
# No tags — reads all memories, visible to all
|
||||
)
|
||||
```
|
||||
|
||||
### Refresh Strategy
|
||||
|
||||
| Trigger | When to use |
|
||||
|---------|------------|
|
||||
| Manual via API | After significant data updates or review cycles |
|
||||
| `trigger={"refresh_after_consolidation": True}` | When observations update frequently and the model should stay current |
|
||||
|
||||
Create narrow, scoped models — one per knowledge dimension. A mental model titled "Everything about the user" is as useful as none.
|
||||
|
||||
**Model granularity examples for a personal assistant:**
|
||||
- "User Profile" — demographics, preferences, stated goals
|
||||
- "Current Projects" — active work, deadlines, blockers
|
||||
- "Technical Stack" — languages, tools, frameworks used
|
||||
- "Communication Style" — formality preferences, response length preferences
|
||||
|
||||
---
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
| Anti-pattern | Problem | Fix |
|
||||
|-------------|---------|-----|
|
||||
| Pre-summarizing before retain | Loses entity relationships, temporal markers, structural context | Retain raw content; Hindsight extracts facts |
|
||||
| Using random UUIDs as `document_id` | Creates duplicate documents on every retain | Use stable session/ticket/document IDs |
|
||||
| Omitting the `context` field | Reduces extraction quality significantly | Always describe what kind of data this is |
|
||||
| Using `metadata` for filtering | Metadata is not filterable | Use `tags` for anything you'll filter on |
|
||||
| Vague or generic missions | Generic extraction = noisy, low-value memories | Be specific about domain, data type, what to ignore |
|
||||
| `tags_match="any"` for multi-tenant banks | Leaks memories across users | Use `any_strict` or `all_strict` for user-partitioned data |
|
||||
| Retaining and recalling in the same request | Retained memories not yet indexed | Retain end-of-turn; recall at the start of next turn |
|
||||
| One mental model for everything | Low accuracy, slow refresh, hard to scope | Create one model per knowledge dimension |
|
||||
| `high` budget for every recall | Expensive, slow, usually unnecessary | Use `low` for simple lookups, `mid` default |
|
||||
| Missing `timestamp` on retain | Disables temporal retrieval strategies | Always set from actual content timestamps |
|
||||
@@ -414,6 +414,9 @@ Supported OpenAI embedding dimensions:
|
||||
| `HINDSIGHT_API_RERANKER_LOCAL_MODEL` | Model for local provider | `cross-encoder/ms-marco-MiniLM-L-6-v2` |
|
||||
| `HINDSIGHT_API_RERANKER_LOCAL_MAX_CONCURRENT` | Max concurrent local reranking (prevents CPU thrashing under load) | `4` |
|
||||
| `HINDSIGHT_API_RERANKER_LOCAL_TRUST_REMOTE_CODE` | Allow loading models with custom code (security risk, disabled by default) | `false` |
|
||||
| `HINDSIGHT_API_RERANKER_LOCAL_FP16` | Half-precision (FP16) inference for the local reranker. 27–36% faster on MPS; quality-identical. Disabled by default to avoid regressions on non-MPS deployments — some CPUs lack native FP16 support. | `false` |
|
||||
| `HINDSIGHT_API_RERANKER_LOCAL_BUCKET_BATCHING` | Sort pairs by token length before batching to reduce padding waste. 36–54% faster across models; quality-identical by construction. | `false` |
|
||||
| `HINDSIGHT_API_RERANKER_LOCAL_BATCH_SIZE` | Batch size for local reranker `predict()`. Optimal value varies by hardware and model (smaller batches can outperform larger ones on MPS). | `32` |
|
||||
| `HINDSIGHT_API_RERANKER_TEI_URL` | TEI server URL | - |
|
||||
| `HINDSIGHT_API_RERANKER_TEI_BATCH_SIZE` | Batch size for TEI reranking | `128` |
|
||||
| `HINDSIGHT_API_RERANKER_TEI_MAX_CONCURRENT` | Max concurrent TEI reranking requests | `8` |
|
||||
|
||||
@@ -0,0 +1,272 @@
|
||||
|
||||
|
||||
# Frequently Asked Questions
|
||||
|
||||
### What is Hindsight and how does it differ from RAG?
|
||||
|
||||
Hindsight is an agent memory system that provides long-term memory for AI agents using biomimetic data structures. Unlike traditional RAG (Retrieval-Augmented Generation), Hindsight:
|
||||
|
||||
- **Stores structured facts** instead of raw document chunks
|
||||
- **Builds mental models** that consolidate knowledge over time
|
||||
- **Uses graph-based relationships** between entities and concepts
|
||||
- **Supports temporal reasoning** with time-aware retrieval
|
||||
- **Enables disposition-aware reflection** for nuanced reasoning
|
||||
|
||||
For a detailed comparison, see [RAG vs Memory](/developer/rag-vs-hindsight).
|
||||
|
||||
---
|
||||
|
||||
### Why use Hindsight instead of other solutions?
|
||||
|
||||
Hindsight is purpose-built for agent memory with unique advantages:
|
||||
|
||||
- **State-of-the-art accuracy**: Ranked #1 LongMemEval benchmarks for agent memory (see [details](https://benchmarks.hindsight.vectorize.io/))
|
||||
- **Built on proven technology**: PostgreSQL - battle-tested, reliable, and widely understood
|
||||
- **Cloud-native architecture**: Designed for modern cloud deployments with horizontal scalability
|
||||
- **Flexible deployment**: Self-host or use Hindsight Cloud - works with any LLM provider
|
||||
- **True long-term memory**: Builds mental models that consolidate knowledge over time, not just retrieval
|
||||
- **Graph-based reasoning**: Understands relationships between entities and concepts for richer context
|
||||
- **Production-ready**: Scales to millions of memories with 50-500ms recall latency
|
||||
- **Developer-friendly**: Simple APIs (retain, recall, reflect), SDKs for Python/TypeScript/Go/Rust, integrations with LiteLLM/Vercel AI SDK
|
||||
|
||||
Unlike vector databases (just search) or RAG systems (document retrieval), Hindsight provides **living memory** that evolves with your users.
|
||||
|
||||
---
|
||||
|
||||
### Which clients and languages are supported?
|
||||
|
||||
<ClientsGrid />
|
||||
|
||||
---
|
||||
|
||||
### Which integrations are supported?
|
||||
|
||||
<IntegrationsGrid />
|
||||
|
||||
---
|
||||
|
||||
### Which LLM providers are supported?
|
||||
|
||||
<LLMProvidersGrid />
|
||||
|
||||
See [Models](/developer/models) for the full list of supported providers, recommended models, and configuration examples.
|
||||
|
||||
---
|
||||
|
||||
### Which model should I use with Hindsight?
|
||||
|
||||
The **[Model Leaderboard](https://benchmarks.hindsight.vectorize.io/)** benchmarks models across accuracy, speed, cost, and reliability for retain, reflect, and observation consolidation — it's the best place to find the right trade-off for your use case.
|
||||
|
||||
[](https://benchmarks.hindsight.vectorize.io/)
|
||||
|
||||
See [Models](/developer/models) for the full list of supported and tested models, provider defaults, and configuration examples.
|
||||
|
||||
---
|
||||
|
||||
### Do I need to host my own infrastructure?
|
||||
|
||||
No! You have two options:
|
||||
|
||||
1. **Hindsight Cloud** - Fully managed service at [ui.hindsight.vectorize.io](https://ui.hindsight.vectorize.io)
|
||||
2. **Self-hosted** - Deploy on your own infrastructure using Docker or direct installation
|
||||
|
||||
See [Installation](/developer/installation) for self-hosting instructions.
|
||||
|
||||
---
|
||||
|
||||
### What are the minimum system requirements for self-hosting?
|
||||
|
||||
For running the Hindsight API server locally:
|
||||
- Python 3.11+
|
||||
- 4GB RAM minimum (8GB recommended for production)
|
||||
- LLM API key (OpenAI, Anthropic, etc.) or local LLM setup
|
||||
|
||||
See [Installation](/developer/installation) for setup instructions.
|
||||
|
||||
---
|
||||
|
||||
### How do I isolate user data?
|
||||
|
||||
A **memory bank** is an isolated memory store (like a "brain") that contains its own memories, entities, relationships, and optional disposition traits (skepticism, literalism, empathy). Banks are completely isolated from each other with no data leakage.
|
||||
|
||||
There are two approaches for multi-user applications:
|
||||
|
||||
**1. Per-user memory banks** (recommended for most use cases)
|
||||
- Create one bank per user (e.g., `bank_id="user-123"`)
|
||||
- Easiest setup and strongest data isolation
|
||||
- Perfect for per-user queries and personalization
|
||||
- Each bank can have unique disposition traits and background context
|
||||
- **Limitation**: Cannot perform cross-user analysis (e.g., "What is the most mentioned topic across all users?")
|
||||
|
||||
**2. Single bank with tags** (for applications needing aggregated insights)
|
||||
- Use one bank for the entire application
|
||||
- Tag memories with user identifiers during retain (e.g., `tags={"user_id": "user-123"}`)
|
||||
- Filter by tags during recall/reflect for per-user queries
|
||||
- **Advantage**: Enables both per-user AND cross-user queries (e.g., analyze specific users or aggregate across all users)
|
||||
|
||||
Choose per-user banks for simplicity and privacy, or single bank with tags if you need holistic reasoning across users. See [Memory Banks](/developer/api/memory-banks) for management details.
|
||||
|
||||
---
|
||||
|
||||
### What's the difference between retain, recall, and reflect?
|
||||
|
||||
Hindsight has three core operations:
|
||||
|
||||
- **Retain**: Store data (facts, entities, relationships)
|
||||
- **Recall**: Search and retrieve raw memory data based on a query
|
||||
- **Reflect**: Use an AI agent to answer a query using retrieved memories
|
||||
|
||||
See [Operations](/developer/api/operations) for API details.
|
||||
|
||||
---
|
||||
|
||||
### When should I use recall vs reflect?
|
||||
|
||||
**Use recall when:**
|
||||
- You want raw facts to feed into your own reasoning or prompt
|
||||
- You need maximum control over how memories are interpreted
|
||||
- You're doing simple fact lookup (e.g., "What did Alice say about X?")
|
||||
- Latency is critical — recall is significantly faster (50-500ms vs 1-10s)
|
||||
- You want to build your own answer synthesis layer on top of retrieved memories
|
||||
|
||||
**Use reflect when:**
|
||||
- You want a ready-to-use answer generated from memories (no extra LLM call needed)
|
||||
- You need disposition-aware responses shaped by the bank's personality traits (skepticism, literalism, empathy)
|
||||
- The query requires multi-step reasoning across facts, observations, and mental models
|
||||
- You need structured output (via `response_schema`) from memory-grounded reasoning
|
||||
- You want citations — reflect returns which memories, mental models, and directives informed the answer
|
||||
|
||||
**Key difference**: Recall returns data; reflect returns an answer. Recall gives you raw materials, reflect does the reasoning for you using the bank's disposition and an autonomous search loop.
|
||||
|
||||
```
|
||||
recall("What food does Alice like?")
|
||||
→ ["Alice loves sushi", "Alice prefers vegetarian options"] # raw facts
|
||||
|
||||
reflect("What should I order for Alice?")
|
||||
→ "I'd recommend a vegetarian sushi platter — Alice loves sushi and prefers vegetarian options." # grounded answer
|
||||
```
|
||||
|
||||
See [Recall](/developer/api/recall) and [Reflect](/developer/reflect) for full API details.
|
||||
|
||||
---
|
||||
|
||||
### When should I use mental models?
|
||||
|
||||
**Mental models** are consolidated knowledge patterns synthesized from individual facts over time. Use them when you need:
|
||||
|
||||
- Higher-level understanding beyond raw facts (e.g., "User prefers functional programming patterns")
|
||||
- Long-term behavioral patterns (e.g., "Customer is price-sensitive but values quality")
|
||||
- Context for AI agent reasoning during **reflect** operations
|
||||
|
||||
Mental models are automatically built during retain and used by reflect to provide richer, more contextual responses. See [Mental Models](/developer/api/mental-models).
|
||||
|
||||
---
|
||||
|
||||
### What's the typical latency for recall operations?
|
||||
|
||||
Typical latencies:
|
||||
- **Without reranking**: 50-100ms
|
||||
- **With reranking**: 200-500ms (depends on reranker model and installation)
|
||||
|
||||
See [Performance](/developer/performance) for tuning options.
|
||||
|
||||
---
|
||||
|
||||
### Does Hindsight support metadata filtering?
|
||||
|
||||
Yes — through **Tags**. Tags are string labels attached to memories at retain time and used as a visibility filter at recall/reflect time. Only memories tagged with a matching value are returned.
|
||||
|
||||
```python
|
||||
# Tag memories at retain time
|
||||
client.retain(bank_id="my-bank", items=[{
|
||||
"content": "...",
|
||||
"tags": ["user:alice"],
|
||||
}])
|
||||
|
||||
# Filter by tag at recall time
|
||||
client.recall(bank_id="my-bank", query="...", tags=["user:alice"])
|
||||
```
|
||||
|
||||
See [Tags](/developer/api/retain#tags-and-document_tags) for full details including document-level tagging.
|
||||
|
||||
**What about filtering by entities?**
|
||||
|
||||
Entities (people, places, concepts) extracted from memories are stored in the knowledge graph and drive graph-based retrieval — so querying "tell me about Alice" will naturally surface Alice-related memories without any manual filtering.
|
||||
|
||||
If you need explicit tag-based filtering on entity-like values, use **entity labels** with `tag: true`. Entity labels let you define a controlled vocabulary of `key:value` classifiers (e.g. `user:alice`, `topic:algebra`) extracted at retain time. Setting `tag: true` on a label group automatically writes each extracted label as a tag on the memory unit, making them available for standard `tags`/`tags_match` filtering:
|
||||
|
||||
```python
|
||||
# Bank config: entity label group with tag: true
|
||||
{
|
||||
"entity_labels": [{
|
||||
"key": "user",
|
||||
"type": "text",
|
||||
"tag": True,
|
||||
"description": "The user this memory belongs to"
|
||||
}]
|
||||
}
|
||||
|
||||
# The label "user:alice" is extracted and also written as a tag
|
||||
# Filter at recall time using the standard tags parameter
|
||||
client.recall(bank_id="my-bank", query="...", tags=["user:alice"])
|
||||
```
|
||||
|
||||
See [Entity Labels](/developer/retain#entity-labels) for configuration details.
|
||||
|
||||
**What about document `metadata`?**
|
||||
|
||||
Document metadata (the `metadata` key-value pairs on a retain item) serves a different purpose. It is:
|
||||
- **Included in the fact extraction prompt**, so the LLM can use it as additional context when extracting facts — for example, knowing the document title or source can improve accuracy.
|
||||
- **Returned with every recalled memory** as-is, so your application can link memories back to source systems (e.g. a URL, thread ID, or ticket number) without extra lookups.
|
||||
|
||||
Metadata is not a filter — use tags when you need recall to be scoped to a subset of documents.
|
||||
|
||||
---
|
||||
|
||||
### What is the recommended format for retaining conversations?
|
||||
|
||||
Pass the **entire conversation as a single document** and upsert it as the conversation grows — Hindsight chunks it automatically, so you don't need to split it yourself.
|
||||
|
||||
**Preferred format: JSON array**
|
||||
|
||||
```json
|
||||
[
|
||||
{"role": "user", "content": "I moved to Berlin last month."},
|
||||
{"role": "assistant", "content": "How are you finding it?"},
|
||||
{"role": "user", "content": "Love it, especially the food scene."}
|
||||
]
|
||||
```
|
||||
|
||||
Hindsight has internal chunking optimizations for the JSON array format, since it's the most common conversation shape.
|
||||
|
||||
**Alternative: prefixed plain text**
|
||||
|
||||
```
|
||||
[2025-06-01T10:32:00Z] user: I moved to Berlin last month.
|
||||
[2025-06-01T10:32:05Z] assistant: How are you finding it?
|
||||
[2025-06-01T10:32:20Z] user: Love it, especially the food scene.
|
||||
```
|
||||
|
||||
Adding a username and timestamp prefix to each message improves extraction quality — the LLM uses those signals to attribute facts correctly and reason about timing.
|
||||
|
||||
**Use a stable document ID to upsert:**
|
||||
|
||||
```python
|
||||
await client.retain(
|
||||
bank_id="my-bank",
|
||||
documents=[{
|
||||
"id": "chat-session-abc123", # stable ID enables upsert
|
||||
"content": conversation, # full conversation so far
|
||||
}]
|
||||
)
|
||||
```
|
||||
|
||||
Re-retaining with the same `id` replaces the old document and its facts, so you won't accumulate duplicates as the conversation grows.
|
||||
|
||||
**Don't pre-summarize or pre-extract facts.** Hindsight does this automatically and needs the full conversation for context — a message like "yes, exactly" or "I'll go with option 2" is meaningless without the surrounding exchange.
|
||||
|
||||
---
|
||||
|
||||
## Still have questions?
|
||||
|
||||
Join our [Slack community](https://join.slack.com/t/hindsight-space/shared_invite/zt-3nhbm4w29-LeSJ5Ixi6j8PdiYOCPlOgg) or report issues on [GitHub](https://github.com/vectorize-io/hindsight/issues).
|
||||
Reference in New Issue
Block a user