Hoppa till innehållet
AI-grafen
D· AI-utvecklareminnessystem· ca 45 min· grundläggande — ändras sällan· verifierad 2026-09-20

Ge din chatbot ett minne

Kunna spara och hämta tidigare samtal så att chatboten kan använda dem.

Förkunskaper

Intuition

En chatbot utan minne börjar om varje gång. Två sorters minne behövs, och de löser olika problem:

KortsiktigtLångsiktigt
Vadde senaste meddelandena i samtaletfakta och tidigare samtal
Vari prompteni en fil eller databas
Begränsningkontextfönstretdisk
Hämtasalltidvid behov, genom sökning

Kortsiktigt är enkelt: skicka med de senaste N meddelandena.

Långsiktigt kräver att man hittar rätt sak. Du kan inte skicka med tusen tidigare samtal — du måste välja ut de som är relevanta för just den här frågan. Och att söka i tidigare samtal är exakt samma problem som att söka i dokument.

Därför är sökmotorn förkunskapen: ett chatbotminne är en liten sökmotor över dina egna gamla samtal.

Kod

import json, math, re, time
from pathlib import Path
from collections import Counter

class Minne:
    def __init__(self, fil="minne.jsonl", behall_senaste=6):
        self.fil = Path(fil)
        self.behall = behall_senaste
        self.aktuellt = []                       # kortsiktigt
        self.gamla = [json.loads(r) for r in self.fil.read_text(encoding="utf-8").splitlines()] \
            if self.fil.exists() else []

    # --- kortsiktigt ---
    def lagg_till(self, roll, text):
        self.aktuellt.append({"roll": roll, "text": text})

    # --- långsiktigt ---
    def spara_samtal(self, sammanfattning):
        post = {"tid": time.strftime("%Y-%m-%d %H:%M"), "sammanfattning": sammanfattning,
                "meddelanden": self.aktuellt}
        with self.fil.open("a", encoding="utf-8") as f:
            f.write(json.dumps(post, ensure_ascii=False) + "\n")
        self.gamla.append(post)
        self.aktuellt = []

    def hitta(self, fraga, k=2):
        """Enkel ordöverlappning — samma idé som en liten sökmotor."""
        q = set(re.findall(r"\w+", fraga.lower()))
        traffar = []
        for post in self.gamla:
            ord_ = set(re.findall(r"\w+", post["sammanfattning"].lower()))
            gemensam = len(q & ord_)
            if gemensam:
                traffar.append((gemensam / math.sqrt(len(ord_) + 1), post))
        traffar.sort(key=lambda t: -t[0])
        return [p for _, p in traffar[:k]]

    def bygg_prompt(self, system, fraga):
        delar = [{"role": "system", "content": system}]
        relevanta = self.hitta(fraga)
        if relevanta:
            tidigare = "\n".join(f"- {p['tid']}: {p['sammanfattning']}" for p in relevanta)
            delar.append({"role": "system",
                          "content": f"Tidigare samtal som kan vara relevanta:\n{tidigare}"})
        delar += [{"role": m["roll"], "content": m["text"]}
                  for m in self.aktuellt[-self.behall:]]
        delar.append({"role": "user", "content": fraga})
        return delar

m = Minne("/tmp/minne.jsonl")
m.lagg_till("user", "Jag heter Ada och pluggar till prov i derivator.")
m.lagg_till("assistant", "Vi kan börja med kedjeregeln.")
m.spara_samtal("Ada pluggar derivator, började med kedjeregeln")

for d in m.bygg_prompt("Du är en handledare.", "Kan vi fortsätta med derivator?"):
    print(d["role"], "→", d["content"][:70])

Tre saker att tänka på från början:

FrågaVarför den måste besvaras
Vad sparas inte?personuppgifter, lösenord, känsliga uppgifter
Hur länge?sätt en gallringstid och håll den
Ser användaren minnet?hen ska kunna läsa, rätta och radera det

Den sista är både ett GDPR-krav och bra design: ett minne användaren inte kan se eller rätta blir obehagligt så fort det innehåller något fel.

Interaktivt

Bygg och testa på en kvart. Använd koden ovan och gör sedan fyra prov:

  1. Kortsiktigt fungerar? Säg ditt namn, ställ tre andra frågor, fråga sedan «vad heter jag?».
  2. Långsiktigt fungerar? Spara samtalet, starta om programmet, och fråga om något från förra gången.
  3. Hittar den rätt? Spara fem olika samtal om olika ämnen. Ställ en fråga om ett av dem. Kom rätt samtal med?
  4. Vad händer när minnet växer? Spara femtio samtal. Blir träffarna sämre?

Vad du troligen upptäcker i prov 3 och 4:

  • Ordöverlappning hittar rätt när frågan använder samma ord som sammanfattningen, och missar helt vid omskrivningar. «Hur går det med matten?» hittar inte «Ada pluggar derivator».
  • Ju fler samtal, desto fler irrelevanta träffar med något gemensamt ord.

Två förbättringar, i ordning:

  1. Bättre sammanfattningar. Låt modellen skriva dem, med instruktion att ta med ämne, namn och beslut. Det ger mer att matcha mot.
  2. Embeddingar i stället för ordmatchning. Då hittas omskrivningar. Det är exakt steget från den här noden till RAG.

Det är värt att känna på begränsningen själv innan man går vidare — den förklarar varför vektorsökning finns.

Behärskning innebär

  • Sparar samtal i en fil eller databas
  • Hämtar relevanta tidigare samtal
  • Skiljer på kortsiktigt och långsiktigt minne

Logga in för att göra övningarna och bygga upp din behärskning.

Källor

Alla källor och licenser