Nivå 3 — Viderekommende

Bygge chatbots

Lær å bygge en fullverdig chatbot med samtalehistorikk, system prompt og streaming — i PHP og Python.
📅 21.05.2026 👁 53 visninger 🇬🇧 Read in English

Hva skiller en chatbot fra et enkelt API-kall?

Et enkelt API-kall er statsløst — Claude husker ingenting mellom kallene. En chatbot må selv holde styr på samtalehistorikken og sende den med i hvert API-kall. Dette er det viktigste konseptet å forstå for chatbot-utvikling.

💡 Slik fungerer samtalehistorikk:
Runde 1: Send [bruker: "Hei"] → få svar
Runde 2: Send [bruker: "Hei", assistent: "Hei!", bruker: "Hva heter du?"] → få svar
Runde 3: Send alle tidligere meldinger + ny melding → få svar

Claude "husker" fordi du sender hele historikken hver gang.

Grunnleggende chatbot-arkitektur

💾
Lagre historikk — i session, database eller localStorage. Hver melding lagres som {role, content}.
📤
Send historikk — hele samtalehistorikken sendes med i hvert API-kall i messages-arrayet.
📥
Legg til svar — Claudes svar legges til historikken som {role: "assistant", content: "..."}.
✂️
Trim historikk — behold de siste N turene for å holde token-kostnadene nede.

Komplett chatbot — PHP

💡 chat.php — backend:
session_start();
header("Content-Type: application/json");

$api_key    = getenv("ANTHROPIC_API_KEY");
$handling   = $_POST["handling"] ?? "send";

if ($handling === "nullstill") {
    $_SESSION["historikk"] = [];
    echo json_encode(["ok" => true]);
    exit;
}

$melding = trim($_POST["melding"] ?? "");
if (!$melding) { echo json_encode(["feil" => "Tom melding"]); exit; }

if (!isset($_SESSION["historikk"])) $_SESSION["historikk"] = [];

$_SESSION["historikk"][] = ["role" => "user", "content" => $melding];

$historikk = array_slice($_SESSION["historikk"], -20);

$data = [
    "model"      => "claude-sonnet-4-20250514",
    "max_tokens" => 1024,
    "system"     => "Du er en hjelpsom assistent for Kvisvik Nettutvikling. Svar alltid på norsk.",
    "messages"   => $historikk
];

$ch = curl_init("https://api.anthropic.com/v1/messages");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => json_encode($data),
    CURLOPT_HTTPHEADER     => [
        "x-api-key: $api_key",
        "anthropic-version: 2023-06-01",
        "content-type: application/json"
    ]
]);

$respons = json_decode(curl_exec($ch), true);
$svar    = $respons["content"][0]["text"] ?? "Feil i API-kall";

$_SESSION["historikk"][] = ["role" => "assistant", "content" => $svar];

echo json_encode(["svar" => $svar, "ant_meldinger" => count($_SESSION["historikk"])]);

Frontend — HTML + JavaScript

💡 chat.html — frontend:
<div id="chat-vindu"></div>
<input id="melding-felt" placeholder="Skriv melding...">
<button onclick="sendMelding()">Send</button>
<button onclick="nullstill()">Ny samtale</button>

<script>
async function sendMelding() {
    var melding = document.getElementById("melding-felt").value.trim();
    if (!melding) return;
    leggTilMelding("Du", melding);
    document.getElementById("melding-felt").value = "";

    var fd = new FormData();
    fd.append("melding", melding);

    var res  = await fetch("chat.php", { method: "POST", body: fd });
    var data = await res.json();
    leggTilMelding("Claude", data.svar);
}

function leggTilMelding(avsender, tekst) {
    var div = document.createElement("div");
    div.innerHTML = "<strong>" + avsender + ":</strong> " + tekst;
    document.getElementById("chat-vindu").appendChild(div);
}

async function nullstill() {
    var fd = new FormData();
    fd.append("handling", "nullstill");
    await fetch("chat.php", { method: "POST", body: fd });
    document.getElementById("chat-vindu").innerHTML = "";
}

document.getElementById("melding-felt").addEventListener("keydown", function(e) {
    if (e.key === "Enter") sendMelding();
});
</script>

Lagre historikk i MySQL

For produksjon bør samtalehistorikk lagres i database — ikke session:

✅ MySQL-tabell for chathistorikk:
CREATE TABLE chat_historikk (
    id          INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    sesjon_id   VARCHAR(64) NOT NULL,
    rolle       ENUM("user","assistant") NOT NULL,
    innhold     TEXT NOT NULL,
    opprettet   DATETIME DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_sesjon (sesjon_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

Viktige designvalg

📏
Historikk-lengde — behold de siste 10–20 turene. Eldre kontekst er sjelden nødvendig og koster tokens.
🔄
Nullstill-knapp — alltid gi brukeren mulighet til å starte ny samtale. Ryddig UX og nullstiller token-kostnadene.
Loading-indikator — vis alltid at noe skjer mens Claude svarer. Brukere forlater sider som virker hengte.
🛡️
Rate limiting — begrens antall API-kall per bruker per minutt for å unngå misbruk og uventede kostnader.
⚠️ Aldri send API-nøkkelen til frontend!
All kommunikasjon med Anthropic API skal skje server-side. Frontenden snakker med din backend, backenden snakker med Anthropic.
"En god chatbot husker nok til å være nyttig — og glemmer nok til å holde kostnadene nede." — Om balansen i samtalehistorikk
Alt godt er nå på vei til meg, og jeg tar det imot med takknemlighet.
— Florence Scovel Shinn

🎯 Test deg selv

Test deg selv — helt valgfritt, men morsomt! 🎯

Spørsmål 1 av 3

Spørsmål 1 av 3

Hvorfor må en chatbot sende hele samtalehistorikken i hvert API-kall?

Claude API er statsløst — Claude husker ingenting mellom kall. Historikken må sendes med for at Claude skal ha kontekst.

Spørsmål 2 av 3

Spørsmål 2 av 3

Hvor skal kommunikasjonen med Anthropic API alltid skje?

Alltid server-side — aldri fra frontend. API-nøkkelen må aldri eksponeres i JavaScript eller HTML som brukeren kan se.

Spørsmål 3 av 3

Spørsmål 3 av 3

Hvor mange meldingsrunder bør du typisk beholde i historikken?

De siste 10–20 turene er vanligvis nok — eldre kontekst er sjelden nødvendig og øker token-kostnadene unødvendig.
Del:

Les også