Skip to content
Docs

Long-Term Patient History Tracker

A physician treating a patient for chest pain needs to know about the patient’s cardiac history, current medications, allergies, and recent lab results — information that may be scattered across an EHR system, specialist referral notes, pharmacy records, and previous hospital visits. Searching through these systems manually takes 10-15 minutes per patient, and critical context is still missed because keyword search cannot find semantically related information (searching “heart problems” won’t surface a note about “mitral valve prolapse”). Studies show that 60-70% of relevant patient history is not surfaced during clinical encounters, contributing to an estimated 12 million diagnostic errors annually in the US.

The challenge is not just storage but retrieval: a patient’s 20-year medical history might contain thousands of entries, but only a handful are relevant to any given clinical question. Traditional database queries require knowing exactly what to search for, but clinical reasoning often starts with vague queries like “any previous respiratory issues” that require semantic understanding.

Beluga AI’s memory package combined with vector stores enables semantic retrieval of patient history. The architecture uses the MemGPT-inspired memory model: interactions are stored persistently in a vector store (archival memory) and indexed using embeddings for semantic search, while recent context stays in working memory for active conversations. This design means a query like “cardiac history” retrieves relevant entries even if the original notes used terms like “MI”, “STEMI”, or “troponin elevation”. Access control integrates at the retrieval layer to enforce HIPAA requirements — every query is filtered by patient-provider authorization before results are returned.

┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Patient │───▶│ History │───▶│ Memory │
│ Interaction │ │ Tracker │ │ Store │
└──────────────┘ └──────────────┘ └──────┬───────┘
┌──────────────┐ ┌──────────────┐ ┌─────▼────────┐
│ Patient │◀───│ Semantic │◀───│ Persistent │
│ History │ │ Search │ │ Storage │
└──────────────┘ └──────────────┘ └──────────────┘
┌──────┴───────┐
│ Provider │
│ Query │
└──────────────┘

The tracker maintains long-term patient history with semantic indexing:

package main
import (
"context"
"fmt"
"time"
"github.com/lookatitude/beluga-ai/memory"
"github.com/lookatitude/beluga-ai/rag/embedding"
"github.com/lookatitude/beluga-ai/rag/vectorstore"
"github.com/lookatitude/beluga-ai/schema"
_ "github.com/lookatitude/beluga-ai/rag/embedding/providers/openai"
_ "github.com/lookatitude/beluga-ai/rag/vectorstore/providers/pgvector"
)
type PatientHistoryTracker struct {
memory memory.Memory
embedder embedding.Embedder
store vectorstore.VectorStore
}
func NewPatientHistoryTracker(ctx context.Context) (*PatientHistoryTracker, error) {
embedder, err := embedding.New("openai", embedding.ProviderConfig{
Model: "text-embedding-3-large",
})
if err != nil {
return nil, fmt.Errorf("create embedder: %w", err)
}
store, err := vectorstore.New("pgvector", vectorstore.ProviderConfig{
ConnectionString: "postgresql://localhost/patient_history",
})
if err != nil {
return nil, fmt.Errorf("create vector store: %w", err)
}
// Use vector-backed memory for persistent, searchable history
mem := memory.NewVectorMemory(store,
memory.WithEmbedder(embedder),
memory.WithNamespace("patient_history"),
)
return &PatientHistoryTracker{
memory: mem,
embedder: embedder,
store: store,
}, nil
}

Each interaction is stored with both an embedding (for semantic search) and structured metadata (for exact filtering by patient ID, type, and provider). This dual indexing is important because clinical queries combine semantic intent (“cardiac history”) with exact constraints (“for patient P-12345 only”):

type PatientInteraction struct {
PatientID string
Type string // "visit", "diagnosis", "prescription", etc.
Details string
ProviderID string
Timestamp time.Time
}
func (t *PatientHistoryTracker) RecordInteraction(ctx context.Context, interaction PatientInteraction) error {
// Create history entry
historyText := fmt.Sprintf("%s - %s: %s",
interaction.Type,
interaction.Timestamp.Format("2006-01-02"),
interaction.Details,
)
// Generate embedding
embeddings, err := t.embedder.Embed(ctx, []string{historyText})
if err != nil {
return fmt.Errorf("embed interaction: %w", err)
}
// Store with metadata
doc := schema.Document{
Content: historyText,
Metadata: map[string]interface{}{
"patient_id": interaction.PatientID,
"type": interaction.Type,
"provider_id": interaction.ProviderID,
"timestamp": interaction.Timestamp,
},
}
if err := t.store.Add(ctx, []schema.Document{doc}, [][]float64{embeddings[0]}); err != nil {
return fmt.Errorf("store interaction: %w", err)
}
// Also save to memory for conversation context
if err := t.memory.Save(ctx, []schema.Message{
&schema.HumanMessage{Parts: []schema.ContentPart{
schema.TextPart{Text: historyText},
}},
}); err != nil {
return fmt.Errorf("save to memory: %w", err)
}
return nil
}

Retrieve patient history using semantic search:

type HistoryEntry struct {
Content string
Metadata map[string]interface{}
Score float64
Timestamp time.Time
}
func (t *PatientHistoryTracker) GetHistory(ctx context.Context, patientID, query string, topK int) ([]HistoryEntry, error) {
var results []schema.Document
var err error
if query != "" {
// Semantic search for specific query
queryEmbeddings, err := t.embedder.Embed(ctx, []string{query})
if err != nil {
return nil, fmt.Errorf("embed query: %w", err)
}
results, err = t.store.SimilaritySearch(ctx, queryEmbeddings[0],
vectorstore.WithTopK(topK),
vectorstore.WithMetadataFilter(map[string]interface{}{
"patient_id": patientID,
}),
)
if err != nil {
return nil, fmt.Errorf("similarity search: %w", err)
}
} else {
// Get all history for patient (chronological)
results, err = t.store.Filter(ctx,
vectorstore.WithMetadataFilter(map[string]interface{}{
"patient_id": patientID,
}),
)
if err != nil {
return nil, fmt.Errorf("filter by patient: %w", err)
}
}
// Convert to history entries
entries := make([]HistoryEntry, len(results))
for i, result := range results {
entries[i] = HistoryEntry{
Content: result.Content,
Metadata: result.Metadata,
Score: result.Score,
Timestamp: result.Metadata["timestamp"].(time.Time),
}
}
// Sort by timestamp descending (most recent first)
sort.Slice(entries, func(i, j int) bool {
return entries[i].Timestamp.After(entries[j].Timestamp)
})
return entries, nil
}

Implement HIPAA-compliant access control:

type AccessControl struct {
permissions map[string][]string // providerID -> patientIDs
}
func (t *PatientHistoryTracker) GetHistoryWithAccessControl(ctx context.Context, patientID, providerID, query string) ([]HistoryEntry, error) {
// Verify provider has access to patient
if !t.hasAccess(ctx, providerID, patientID) {
return nil, fmt.Errorf("access denied: provider %s does not have access to patient %s", providerID, patientID)
}
// Audit log access
t.auditLog(ctx, "history_access", providerID, patientID)
// Retrieve history
history, err := t.GetHistory(ctx, patientID, query, 20)
if err != nil {
return nil, fmt.Errorf("get history: %w", err)
}
return history, nil
}
func (t *PatientHistoryTracker) hasAccess(ctx context.Context, providerID, patientID string) bool {
// Check access control system
// Implementation depends on your access control mechanism
return true
}
func (t *PatientHistoryTracker) auditLog(ctx context.Context, action, providerID, patientID string) {
// Log access for HIPAA compliance
// Implementation depends on your audit logging system
}

Encrypt patient data at rest and in transit for HIPAA compliance:

import "github.com/lookatitude/beluga-ai/guard"
func NewSecurePatientHistoryTracker(ctx context.Context, encryptionKey []byte) (*PatientHistoryTracker, error) {
embedder, err := embedding.New("openai", embedding.ProviderConfig{
Model: "text-embedding-3-large",
})
if err != nil {
return nil, fmt.Errorf("create embedder: %w", err)
}
// Use encrypted vector store
store, err := vectorstore.New("pgvector", vectorstore.ProviderConfig{
ConnectionString: "postgresql://localhost/patient_history",
Encryption: true,
EncryptionKey: encryptionKey,
})
if err != nil {
return nil, fmt.Errorf("create vector store: %w", err)
}
mem := memory.NewVectorMemory(store,
memory.WithEmbedder(embedder),
memory.WithNamespace("patient_history"),
)
return &PatientHistoryTracker{
memory: mem,
embedder: embedder,
store: store,
}, nil
}

Implement retention policies for regulatory compliance:

func (t *PatientHistoryTracker) PurgeOldRecords(ctx context.Context, retentionYears int) error {
cutoff := time.Now().AddDate(-retentionYears, 0, 0)
// Delete records older than retention period
err := t.store.Delete(ctx,
vectorstore.WithMetadataFilter(map[string]interface{}{
"timestamp": map[string]interface{}{
"$lt": cutoff,
},
}),
)
if err != nil {
return fmt.Errorf("purge old records: %w", err)
}
return nil
}

Track history access and performance for compliance and optimization:

import (
"github.com/lookatitude/beluga-ai/o11y"
"go.opentelemetry.io/otel/attribute"
)
func (t *PatientHistoryTracker) RecordInteractionWithTracing(ctx context.Context, interaction PatientInteraction) error {
ctx, span := o11y.StartSpan(ctx, "patient_history.record")
defer span.End()
span.SetAttributes(
attribute.String("patient_id", interaction.PatientID),
attribute.String("interaction_type", interaction.Type),
attribute.String("provider_id", interaction.ProviderID),
)
err := t.RecordInteraction(ctx, interaction)
if err != nil {
span.RecordError(err)
return err
}
return nil
}
  • Indexing strategy: Create indexes on patient_id, timestamp, and type for fast filtering
  • Partitioning: Partition by patient_id or time range for large datasets
  • Caching: Cache frequently accessed patient histories
  • Batch operations: Batch record insertions for efficiency

After implementing the patient history tracker, the provider achieved:

MetricBeforeAfterImprovement
Information Retention60-70%96%37-60% improvement
Duplicate Test Rate15-20%4%73-80% reduction
Care Coordination Score6.0/109.2/1053% improvement
Provider Access Time10-15 min1.5 min85-90% reduction
Patient Satisfaction7.0/109.1/1030% improvement
Care Quality Score7.5/109.0/1020% improvement