Docs⌘ K  Search
Docs/Getting started/Chatbot memory
Golden path

Chatbot memory

Give a chatbot long-term memory of each user. Save each conversation, search before you answer, and answer with what was found.

1
Save
After you reply, send the turn to Hebbrix. It keeps the facts, not the transcript.
2
Search
Before the next reply, search that user's memories with their message.
3
Answer
Give the memories to your model, or let Hebbrix chat do it for you.

01. Before you start

You need an API key from Dashboard → API Keys, kept on your server in HEBBRIX_API_KEY. Every call below sends it as Authorization: Bearer.

Two IDs decide whose memories you read and write. A collection holds your app's memories; create it once and store its ID. A user_id is your own stable ID for each end user. Send the same pair on every save, search and chat call. A memory saved for one user is only ever found for that user, so a mismatched ID means the fact is simply not found.

Connect and create a collection (once)
import os
import time

import httpx

BASE = os.environ.get("HEBBRIX_BASE_URL", "https://api.hebbrix.com/v1")
hebbrix = httpx.Client(
    base_url=BASE,
    headers={"Authorization": f"Bearer {os.environ['HEBBRIX_API_KEY']}"},
    timeout=60,
)

# Do this once and keep the ID, for example in your config.
collection_id = hebbrix.post("/collections", json={"name": "support-bot"}).json()["id"]
SCOPE = {"collection_id": collection_id, "user_id": "user-42"}

02. Save each conversation

After your bot has replied, send the turn to POST /v1/memories/process. It returns straight away with a job ID and extracts the facts in the background, so your user never waits for it. Hebbrix extracts short facts such as “The user is allergic to peanuts” rather than storing the whole transcript, and a newer fact replaces an older one it contradicts while the history is kept.

Save a turn
job = hebbrix.post("/memories/process", json={
    **SCOPE,
    "messages": [
        {"role": "user", "content": "I'm allergic to peanuts, and I'm moving to Austin next month."},
        {"role": "assistant", "content": "Thanks, I'll remember that."},
    ],
}).json()

In production you do not wait for the job. In a test or a demo, where the next line depends on the new memory, wait until the job has finished:

Wait for the job (tests and demos only)
while hebbrix.get(f"/memory-jobs/{job['job_id']}").json()["status"] not in ("completed", "failed"):
    time.sleep(1)

New memories are usually searchable within a few seconds; see measured latency. To store a fact you already have in final form, such as a setting from your own database, use POST /v1/memories/raw instead; it is stored word for word.

When the user writes again, search their memories with the message itself. Ask for a handful of results; view: "compact" keeps the response small (the SDKs use compact by default). include_profile: true also returns the user's standing facts and preferences, such as “keep answers short”, in a separate profile field, so they reach your prompt even when the message is about something else.

Find what the bot should know
question = "What food should I avoid?"
found = hebbrix.post("/search", json={
    **SCOPE,
    "query": question,
    "limit": 5,
    "view": "compact",
    "include_profile": True,
}).json()
memories = [hit["content"] for hit in found["results"]]
print(memories)

Results are ordered by relevance. The score on each result is for ordering, not a probability, so do not drop results with a fixed cut-off; keep the top few and let your model decide what is relevant. low_confidence marks only weak or unverified matches, so a result without it is a solid match. Add debug: true when you need the full ranking diagnostics.

04. Answer with memory

Option A: let Hebbrix chat do it. POST /v1/chat/completions is compatible with the OpenAI SDK. Point the SDK at Hebbrix, pass the same scope, and Hebbrix searches and adds the relevant memories to the prompt for you. Because you already save turns with /memories/process, turn chat's own learning off so nothing is saved twice.

Drop-in chat with the OpenAI SDK
from openai import OpenAI

llm = OpenAI(api_key=os.environ["HEBBRIX_API_KEY"], base_url=BASE)
reply = llm.chat.completions.create(
    model="gpt-5-nano",
    messages=[{"role": "user", "content": question}],
    extra_body={**SCOPE, "features": {"memory": True, "learning": False}},
)
print(reply.choices[0].message.content)

Personal questions are answered in plain language from the stored facts. A stored condition, restriction, preference or plan that bears on the message is used even when it does not answer it word for word: asked “What food should I avoid?”, the bot uses the peanut allergy. Two optional fields change the wording:

  • answer_style: "natural" (the default) composes a plain-language answer from the stored facts; "quote" returns the stored text word for word.
  • no_information_reply: what to say when nothing stored answers the question. The default is “I don't know that yet.”

The response carries memory_context: memories lists what was given to the model (facts used as background have the grounding reason relevant_user_context), and answer_composition says how the answer was put together. Log it while you test: it is the quickest way to see why the bot did or did not use a fact. With the Python SDK, MemoryChat.send() takes the same answer_style and no_information_reply arguments; in TypeScript, chatAnswerFields() builds them for any OpenAI-compatible client.

Option B: use your own model. Put the search results into your system prompt and call any model you like.

Bring your own model
known = "\n".join(f"- {fact}" for fact in memories) or "- nothing yet"
system_prompt = (
    "You are a helpful assistant. What you know about this user:\n" + known
)
print(system_prompt)  # send this with the user's message to your model

05. Checklist before you ship

  • The same collection_id and user_id go on every save, search and chat call for a user.
  • Saving happens after the reply is sent, never before it. Only the search (or the chat call that searches for you) runs while the user waits.
  • Tests wait for the save job before searching; production code does not.
  • If you let chat save turns instead (features.learning: true), read memory_learning in the response: readiness, searchable and estimated_ready_seconds tell you when the new facts can be found, usually in 4 to 5 seconds.
  • When a user asks you to forget them, call DELETE /v1/memories/all with their collection_id and user_id (see Memories).
Building an agent rather than a chatbot? The agent memory guide covers rules, tool errors and learning which actions work.
Ask the docs
reading · this page

Hi! I'm the Hebbrix docs assistant. Ask me anything about this page: setup, code examples, endpoints, pricing, or integrations.