Skip to main content

Building Chatbots

Learn how to build chatbots with persistent memory using Trix.

Architecture

A memory-enabled chatbot typically follows this flow:

  1. User sends a message
  2. Recall relevant memories for context
  3. Generate response with memory context
  4. Extract and store new memories
  5. Return response to user

Basic Implementation

import { Trix } from '@trixdb/client';
import OpenAI from 'openai';

const trix = new Trix({ apiKey: process.env.TRIX_API_KEY });
const openai = new OpenAI();

async function handleMessage(userId: string, message: string) {
  // 1. Recall relevant context
  const results = await trix.memories.list({
    q: message,
    spaceId: userId,
    limit: 10
  });

  // 2. Build system prompt with memories
  const systemPrompt = `You are a helpful assistant.

What you know about this user:
${results.data.map(m => `- ${m.content}`).join('\n') || 'Nothing yet'}

Remember to be personalized based on what you know.`;

  // 3. Generate response
  const response = await openai.chat.completions.create({
    model: 'gpt-4',
    messages: [
      { role: 'system', content: systemPrompt },
      { role: 'user', content: message }
    ]
  });

  return response.choices[0].message.content;
}

Automatic Memory Extraction

Use the AI to decide what's worth remembering:

async function extractMemories(userId: string, conversation: Message[]) {
  const extraction = await openai.chat.completions.create({
    model: 'gpt-4',
    messages: [
      {
        role: 'system',
        content: `Extract key facts about the user from this conversation.
Return a JSON array of strings, each being a distinct fact.
Only include meaningful, personal information.`
      },
      { role: 'user', content: JSON.stringify(conversation) }
    ],
    response_format: { type: 'json_object' }
  });

  const { facts } = JSON.parse(extraction.choices[0].message.content);

  // Store each extracted fact
  for (const fact of facts) {
    await trix.memories.create({ content: fact, spaceId: userId });
  }
}

Run memory extraction asynchronously after each conversation to avoid adding latency.

Best Practices

  • Use a similarity threshold (0.6-0.8) to avoid irrelevant memories
  • Limit recalled memories to prevent context overflow
  • Extract memories asynchronously for better response times
  • Deduplicate similar memories periodically
  • Use contexts to separate different types of information