Budowa chatbota CLI

5. Budowa lokalnego indeksu

Lokalne chatboty, agenci i systemy RAG z własną bazą wiedzy

Instrukcja krok po kroku · materiał uzupełniający

Budujemy chatbota w konsoli

dane/index.json

Odniesienie: M3 R2, R3, R5   |   Czas: 20 min + obliczenia

Zamień każdy fragment na wektor i zapisz wektory razem z informacją, jak powstały. Indeks zbudujesz raz dla danej wersji bazy i modelu.

Zależności, które muszą pozostać zgodne

Pytanie i dokumenty muszą być osadzane tym samym modelem embeddingowym. Sama zgodność liczby wymiarów nie wystarcza. Dlatego zapiszemy tag i digest modelu, skrót pliku fragmentów oraz kolejność identyfikatorów.

Utwórz indeks.py: pierwsza część

Skopiuj poniższy blok do nowego pliku indeks.py. Następny podrozdział zawiera dalszą część tego samego pliku. Uruchomisz go dopiero po złożeniu obu części.

"""Mały indeks JSON; pełny przegląd wektorów, bez zewnętrznych bibliotek."""
import argparse
import hashlib
import json
import math
from datetime import datetime, timezone
from lokalny import ROOT, CONFIG, api, embed, require_models, unit
from baza import CHUNKS, read_chunks

INDEX = ROOT / "dane" / "index.json"


def file_hash(path):
    return hashlib.sha256(path.read_bytes()).hexdigest()


def build():
    if INDEX.exists():
        raise FileExistsError("index.json już istnieje. Zachowaj go pod inną nazwą przed nową budową.")
    records = read_chunks()
    model = CONFIG["embedding_model"]
    before = require_models([model])[model]
    vectors = []
    for i, record in enumerate(records, 1):
        vectors.append(embed(record["text"]))
        print(f"Embedding {i}/{len(records)}", flush=True)
    if len({len(v) for v in vectors}) != 1:
        raise ValueError("Niezgodne wymiary embeddingów.")
    if require_models([model])[model] != before:
        raise ValueError("Model zmienił się podczas budowania indeksu. Powtórz budowę.")
    result = {"format": "poradnik-json-v1", "created_at": datetime.now(timezone.utc).isoformat(),
              "embedding_model": model, "embedding_digest": before,
              "ollama_version": api("/api/version")["version"],
              "chunks_sha256": file_hash(CHUNKS), "dimension": len(vectors[0]),
              "chunk_ids": [r["chunk_id"] for r in records], "vectors": vectors}
    with INDEX.open("x", encoding="utf-8") as output:
        json.dump(result, output, ensure_ascii=False)
    print("Indeks gotowy:", INDEX)

Co zapisujemy

PolePo co
vectorsWektory w kolejności odpowiadającej fragmentom.
chunk_idsKontrola przypisania wiersza wektora do treści.
embedding_digestWykrycie zmiany modelu pod tym samym tagiem.
chunks_sha256Wykrycie zmiany treści, kolejności lub metadanych bazy.
dimensionKontrola zgodności rozmiaru wszystkich wektorów.

Funkcja unit() normalizuje wektor. Dla dwóch wektorów o długości jeden iloczyn skalarny jest podobieństwem kosinusowym. Wynik służy do porządkowania fragmentów, nie do określania prawdopodobieństwa prawdziwości odpowiedzi.

Punkt kontrolny

  • Rozumiesz, dlaczego zmiana dokumentu wymaga nowego indeksu.
  • Masz zapisaną pierwszą część indeks.py.

Instrukcja uczestnika · Python i Ollama · wydanie 29.09.2026