idea_world_labDEV JOURNAL
Sonntag, 28. Juni 2026

Fazit

Das stimmt. Ich habe die Absicht falsch erfasst.

Genau genommen, ist es das hier.

1. Im ZIP befinden sich das ursprüngliche Markdown, das Schema, der Debugger und die Designdokumentation.  
2. In deinem lokalen System ist bereits die konvertierte Version markdown → JSONL → DB vorhanden.  
3. Was ich sehen kann, ist das „Markdown vor der Konvertierung und das DB‑Schema/Suchablauf“.  
4. Daher muss der PoC das Markdown im ZIP in JSONL‑Chunks aufteilen und die Suchziele simulieren, die in deiner lokalen DB vorhanden sein könnten.  
5. Was du möchtest, ist nicht das Codegerüst, sondern das Verfolgen des Ablaufs, wie jede Suchmethode Punkte erzeugt und warum sie erfolgreich bzw. fehlschlägt, wenn ein Chunk eingefügt wird.

Und eine wichtige Änderung.

Der /api/retrieve des aktuellen Projekts ist nicht BM25.
Der aktuelle Code lautet:

chunkText
-> plainto_tsquery('simple', chunkText)
-> search_tsv @@ query
-> ts_rank_cd(...)

Das ist. PostgreSQLs ts_rank_cd ist ein Full‑Text‑Ranking und kein reines BM25. Auch die PostgreSQL‑Dokumentation beschreibt ts_rank/ts_rank_cd als Ranking‑Funktionen, die eine Normalisierungsoption für die Dokumentlänge erhalten. plainto_tsquery tokenisiert den Eingabesatz, ignoriert Satzzeichen und erstellt aus Nicht‑Stop‑Wörtern eine Abfrage. (PostgreSQL)


Fazit

Die beste Lösung, die Ihre Bedingungen erfüllt, ist dies.

Eingabe:
raw chunkText unverändert

Retriever intern:
  1. raw chunk unverändert BM25‑Kandidaten suchen
  2. raw chunk unverändert Code‑Embedding‑Kandidaten suchen
  3. Kandidaten vereinigen
  4. mit Reranker neu ordnen
  5. Qwen oder Validator prüft JSONL direkte Begründung

Dies ist die Version, bei der das Extrahieren von Godot‑API‑Signalen nicht zwingend erforderlich ist.

Das heißt, der von mir zuvor erwähnte „Godot API signal extractor“ darf nicht als zwingend erforderlich betrachtet werden. Wie du sagst, wirkt das nach Hardcoding. Es ist zwar nutzbar, aber wenn man es zum Kern des Grunddesigns macht, verschlechtert sich die Wartbarkeit.

Die endgültige Empfehlung ist:

Erster Kandidat: BM25
Zweiter Kandidat: code embedding
Endgültige Sortierung: reranker
Validierung: Qwen direct-evidence validator

Projektverständnis‑Verifizierung

Die tatsächliche Struktur, die im Zip‑Archiv zu sehen ist, sieht folgendermaßen aus.

JSONL‑Entwurf

Im Dokument sind die Ergebnisse wie folgt definiert.

work/godot_rag/jsonl/docs_chunks.jsonl
work/godot_rag/jsonl/api_mapping.jsonl
work/godot_rag/jsonl/label_prototypes.jsonl
work/godot_rag/jsonl/ingest_report.jsonl

Das DB‑Schema ist nicht so aufgebaut, dass eine gesamte JSONL‑Zeile in payload jsonb eingefügt wird.
Die JSONL‑Felder werden als Tabellenspalten ausgeweitet.

docs_chunks:
  chunk_id
  doc_version
  source_url
  source_file
  source_sha256
  doc_type
  symbol
  section_path
  heading
  content
  code_blocks
  language_tags
  godot_version_tags
  api_symbols
  token_count
  metadata
  embedding
  search_tsv

api_mapping:
  mapping_id
  source_api
  target_api
  change_type
  godot_from
  godot_to
  confidence
  evidence_chunk_ids
  match_terms
  notes
  negative_patterns

label_prototypes:
  prototype_id
  label
  task_type
  input_pattern
  expected_finding
  recommended_action
  evidence_mapping_ids
  evidence_chunk_ids
  severity
  validator_rules
  embedding
  search_tsv

Das heißt, in deiner lokalen Datenbank wird es in etwa so aussehen.

{"chunk_id":"...","source_file":"outputs/godot_docs_full/pages/getting_started__first_2d_game__03.coding_the_player__161d377b.md","doc_type":"tutorial","heading":"Coding the player","content":"...","code_blocks":["func _process(delta): ..."],"api_symbols":["Input.is_action_pressed","Vector2.ZERO","AnimatedSprite2D","position.clamp"]}

Vier Chunk Eingabe

Wir gehen davon aus, dass die Eingabe immer genau so ist.

func _process(delta):
	var velocity = Vector2.ZERO
	if Input.is_action_pressed(&"move_right"):
		velocity.x += 1
	if Input.is_action_pressed(&"move_left"):
		velocity.x -= 1

	if velocity.length() > 0:
		velocity = velocity.normalized() * speed
		$AnimatedSprite2D.play()
	else:
		$AnimatedSprite2D.stop()

	position += velocity * delta
	position = position.clamp(Vector2.ZERO, screen_size)

Wenn man dieses Chunk mit einem Code‑Tokenizer betrachtet, sieht man die eindeutigen Token wie folgt.

_process
animatedsprite2d
clamp
delta
else
func
if
input
is_action_pressed
length
move_left
move_right
normalized
play
position
screen_size
speed
stop
var
vector2
velocity
x
zero
0
1

Insgesamt 43 Token, davon 25 eindeutig.

Der wichtige Token hier ist dieser.

Starke Token:
  animatedsprite2d
  is_action_pressed
  move_left
  move_right
  normalized
  clamp
  screen_size
  vector2
  zero

Schwache Token:
  func
  var
  if
  else
  velocity
  position
  delta
  x
  0
  1

BM25 gibt starken Tokens eine hohe Punktzahl.
Denn je seltener ein Wort im gesamten Dokument vorkommt, desto größer wird der IDF.


Wie BM25 funktioniert und Ergebnisse liefert

BM25 berechnet grob „wie gut das Abfrage‑Wort im Dokument verankert ist“.

Formell gibt es drei Kernpunkte.

TF: Wie oft ein Wort in diesem Dokument vorkommt  
IDF: Wie selten dieses Wort im gesamten Korpus ist  
Length normalization: Korrektur, damit lange Dokumente nicht automatisch im Vorteil sind

Elasticsearch verwendet ebenfalls BM25 als Standard‑Relevanzalgorithmus und erklärt term frequency, inverse document frequency und field‑length normalization als Schlüsselelemente. (Elastic)

Die Formel sieht ungefähr so aus.

score(query, doc)
= Σ over query terms [
    IDF(term)
    *
    TF_boost(term frequency in doc, doc length)
  ]

Das heißt, wenn ein seltenes Wort wie animatedsprite2d mehrfach im Dokument vorkommt, steigt die Punktzahl erheblich.


Ergebnis der Simulation wie in der Realität

Originales Godot-Markdown im Zip:

outputs/godot_docs_full/pages/

Ich habe dies in etwa 1800 Zeichen große Chunks wie JSONL docs_chunks aufgeteilt und die rohen Chunks unverändert als Abfrage in BM25 eingegeben.

Kandidat 1

Input.is_action_pressed("move_right")
Input.is_action_pressed("move_left")
velocity.length()
velocity.normalized() * speed
$AnimatedSprite2D.play()
$AnimatedSprite2D.stop()

Warum es Platz 1 ist, diese Tokens haben direkt gepasst.

animatedsprite2d
is_action_pressed
move_left
move_right
normalized
play
stop
input
speed
length
velocity
vector2
zero

Die Top‑Beitragstoken, die die Punktzahl stark erhöht haben, sind folgende.

animatedsprite2d   df=18   tf=7   contribution=11.975
is_action_pressed  df=27   tf=2   contribution=8.609
move_left          df=13   tf=1   contribution=7.479
velocity           df=180  tf=18  contribution=7.467
move_right         df=15   tf=1   contribution=7.299
normalized         df=67   tf=2   contribution=7.069
stop               df=133  tf=2   contribution=5.900
play               df=144  tf=2   contribution=5.764
input              df=323  tf=7   contribution=5.650
speed              df=219  tf=3   contribution=5.637

Hier ist df die Anzahl der Chunks, die das betreffende Wort enthalten, von insgesamt 4165 Chunks.

Das heißt:

animatedsprite2d erscheint nur in 18 von insgesamt 4165 Chunks  
move_left erscheint nur in 13 Chunks  
move_right erscheint nur in 15 Chunks  
is_action_pressed erscheint nur in 27 Chunks

Deshalb werden Dokumente, die diese Wörter enthalten, stark angezeigt.

Das ist der Prozess, wie BM25 den ersten Platz erreicht hat.


Zweiter Platz

AnimatedSprite2D Beschreibung
$AnimatedSprite2D.play()
get_node("AnimatedSprite2D").play()
position += velocity * delta
position = position.clamp(Vector2.ZERO, screen_size)

Übereinstimmendes Token:

animatedsprite2d
clamp
screen_size
play
delta
_process
velocity
position
stop
vector2
zero

Dieser Abschnitt belegt den zweiten Platz, weil zwar kein Eingabeverarbeitungs‑Teil vorhanden ist, aber clamp, screen_size und AnimatedSprite2D stark passen.

Insbesondere:

screen_size df=3
clamp df=32
animatedsprite2d df=18

screen_size ist ein fast nie vorkommendes Wort, daher hat es selbst bei einmaligem Auftreten eine hohe Punktzahl.


Kandidat 3. Platz: Fehlkandidat

3D player movement
Input.is_action_pressed("move_right")
Input.is_action_pressed("move_left")
Vector3.ZERO
direction.normalized()
Chunk Inhalt:

Übereinstimmendes Token:

is_action_pressed
move_left
move_right
normalized
speed
velocity
delta
input
x
var
func
zero

Das scheint relevant zu sein, ist aber nicht die genaue Antwort.

Warum es gepostet wurde:

Input.is_action_pressed
move_right
move_left
normalized
speed

Dies liegt daran, dass solche gemeinsamen Tokens des Bewegungscodes stark überlappen.

Aber dieses Dokument ist 3D. Ihr Chunk ist 2D, und AnimatedSprite2D, Vector2, position.clamp, screen_size sind zentral.

Das heißt, wenn man nur BM25 verwendet, entstehen solche Fehlalarme.


Der Grund, warum die aktuelle Methode fehlschlägt

Der Ansatz, der /api/retrieve nahe kommt, ist plainto_tsquery(raw_chunk).

Dieser Ansatz führt ungefähr zu einer solchen Abfrage.

func & process & delta & var & velocity & vector2 & zero
& input & is_action_pressed & move_right & move_left
& length & normalized & speed & animatedsprite2d
& play & stop & position & clamp & screen_size

Auf diese Weise verlangt ein JSONL‑Chunk zu viele Tokens.

In meiner Simulation:

strict raw AND hits: 0

Das heißt, wenn ein Chunk nicht gleichzeitig alle eindeutigen Token erfüllt, ist das Ergebnis 0.

Denn auch die offizielle Dokumentation ist so aufgeteilt.

chunk A:
  Input.is_action_pressed
  velocity.normalized
  AnimatedSprite2D.play/stop

chunk B:
  AnimatedSprite2D Beschreibung
  position.clamp
  screen_size

Beide sind relevant, aber nicht alles ist in einer einzigen Zeile enthalten.

Deshalb ist es richtig, die aktuelle Vorgehensweise zu überarbeiten.


Methodenbezogene Alternativen

Alternative A. Aktuelle Methode: raw chunk + PostgreSQL plainto_tsquery

Ablauf:

raw chunkText
-> plainto_tsquery
-> search_tsv @@ query
-> ts_rank_cd

Ja Chunk Ergebnis:

Fehlerrate hoch  
Selbst bei einer kleinen Änderung der Chunk‑Aufteilung gibt es 0 Fälle.

Vorteile:

Implementierung ist bereits vorhanden  
Nur mit PostgreSQL möglich  
Einfache Infrastruktur

Nachteile:

Schwach bei langen Code‑Chunks  
AND‑Bedingungen sind zu häufig  
Viele Code‑Token‑Rauschen  
Kein BM25  
Semantische Suche nicht möglich

Bewertung:

Entsorgung

Alternative B. Rohabschnitt + BM25 nur

Ablauf:

raw chunkText
-> tokenizer
-> BM25
-> top JSONL zurückgeben

Ja Chunk Ergebnis:

1. Platz: first_2d_game / coding_the_player
2. Platz: first_2d_game / coding_the_player / clamp Teil
3. Platz: first_3d_game / player_movement_code

Warum hat es funktioniert?

AnimatedSprite2D
move_right
move_left
is_action_pressed
screen_size
clamp

Diese Wörter sind in der gesamten Godot‑Dokumentation selten, sodass sie hohe Punkte erhalten haben.

Vorteile:

Prinzipien transparent  
Einfach zu debuggen  
Keine Modellkosten  
Roh‑Chunk kann unverändert verwendet werden  
Code/API ist stark bei genauen Zeichenketten

Nachteile:

Schwach bei Synonymen/Beschreibungen  
Wenn der API-Name nicht direkt erscheint, kann er nicht gefunden werden  
Ähnlicher Code wird gemischt, wie bei 3D movement  
Wird die Dokumentation anders ausgedrückt, wird es übersehen

Bewertung:

Muss unbedingt geschrieben werden  
Aber allein ist es nicht ausreichend

Alternative C. Roh-Chunk + Nur-Einbettung

Ablauf:

raw chunkText
-> embedding vector
-> docs_chunks/api_mapping/label_prototypes Embedding und Cosine‑Suche
-> top JSONL zurückgeben

Warum das Modell verwendet wird:

Um Dokumente zu finden, deren Bedeutung nahe beieinander liegt, auch wenn die Zeichenketten nicht exakt übereinstimmen.

Zum Beispiel enthält die Abfrage:

position.clamp(Vector2.ZERO, screen_size)

Es gibt, und im Dokument:

prevent the player from leaving the screen
clamping a value means restricting it to a given range

Wenn es so erklärt wird, kann BM25 schwächer sein. Embedding erfasst solche semantischen Verbindungen.

Vorteile:

Auch bei unterschiedlicher Ausdrucksweise gefunden  
Stark bei dokumentationsbeschreibendem Inhalt  
Einfach, rohe Chunks unverändert einzufügen  
Lange Chunks können ebenfalls verarbeitet werden

Nachteile:

**Genaues API‑Urteil ist schwach**  
3D/2D, Godot 3/Godot 4 – solche feinen Unterschiede können vermischt werden  
Es ist schwer zu erklären, warum dieses Ergebnis entstanden ist  
Im api_mapping besteht ein hohes Risiko für Fehlalarme (false positives)

Ja, Chunk‑Vorhersage:

Erfolg:
first_2d_game / coding_the_player Hohe Wahrscheinlichkeit, dass es gefunden wird

Fehlschlag:
first_3d_game movement könnte ebenfalls mit hoher Wahrscheinlichkeit auftreten
weil die Bedeutung von “player movement” ähnlich ist

Bewertung:

Einzelverwendung verboten  
Zur Ergänzung von BM25‑Kandidaten verwenden

Alternative D. raw chunk + BM25 + Einbettung parallel

Ablauf:

raw chunkText
-> BM25 top 50
-> embedding top 50
-> Zusammenführen
-> Punkte mischen
-> top JSONL zurückgeben

Dieser Ansatz ist ziemlich gut.

Der Chunk-Fluss:

Was BM25 erfasst:
  Input.is_action_pressed
  AnimatedSprite2D
  position.clamp
  screen_size

Was embedding erfasst:
  player movement
  2D movement tutorial
  moving inside screen
  animation based on movement

Vorteile:

Die Schwächen der Zeichenkettensuche und der semantischen Suche ergänzen sich gegenseitig  
Auch ohne Qwen verbessert sich die erste Qualitätsstufe  
Beibehaltung der raw‑chunk‑Bedingung

Nachteile:

Score‑Kombinationstuning ist erforderlich  
BM25‑Score und Vektor‑Score haben unterschiedliche Skalen  
False Positives können nicht vollständig verhindert werden

Bewertung:

Praktische Mindestempfehlung

Alternative E. Rohdaten‑Chunk + Qwen‑Abfrage‑JSON‑Erstellung + Suche

Um Hard‑Coding zu vermeiden, ist diese Vorgehensweise ebenfalls möglich.

Ablauf:

raw chunkText
-> Anfrage zur Erstellung von JSON für die Suche an Qwen
-> BM25/Vector-Suche mit dem erstellten JSON
-> Rückgabe von JSONL-Kandidaten

Zum Beispiel Qwen‑Ausgabe:

{
  "search_intent": "Godot 4 2D player movement tutorial",
  "important_literals": [
    "Input.is_action_pressed",
    "Vector2.ZERO",
    "AnimatedSprite2D",
    "position.clamp",
    "screen_size"
  ],
  "likely_doc_topics": [
    "first 2D game",
    "coding the player",
    "player movement",
    "clamp position to screen",
    "play and stop AnimatedSprite2D"
  ],
  "migration_signals": []
}

Dies ist eine Methode, bei der der Godot‑API‑Signal‑Extraktor nicht direkt hardcodiert wird. Stattdessen erstellt Qwen das Abfrageprofil.

Vorteile:

Wenig Hardcoding  
Zusammenfassung der Absicht in komplexen Chunks möglich  
Suchbegriffe können für Menschen lesbarer gemacht werden  
Spezialisierte Godot‑Entscheidungen können Qwen überlassen werden

Nachteile:

Langsam  
Kosten entstehen  
Kann Hinweise ohne Qwen erzeugen  
Halluzination bereits ab der Vor‑Suchphase möglich  
Eine direkte Evidenzprüfung des Rohchunks ist unbedingt erforderlich

Ja Chunk Erfolg:

Wenn Qwen AnimatedSprite2D / Input.is_action_pressed / position.clamp herausnimmt, ist es erfolgreich.

Ja Chunk-Fehler:

Qwen erzeugt eine nicht vorhandene Absicht wie „Migration von Godot 3 zu 4“ und führt dadurch zu einer falschen api_mapping.

Bewertung:

Gut für Suchqualitäts‑Experimente  
Vorsichtig als primäre Produktionssuche

Alternative F. raw chunk + BM25 + embedding + reranker

Das ist am besten.

Ablauf:

- BM25 top 80  
- embedding top 80  
- Kandidaten‑Union  
- Der Reranker vergleicht den Roh‑Chunk und jede JSONL‑Kandidatur direkt  
- Gibt das beste JSONL zurück  
- Der Qwen‑Validator prüft die direkte Begründung

reranker liest die Abfrage und das Kandidatendokument gemeinsam und bewertet die Relevanz erneut. Das Voyage‑Dokument wird ebenfalls als ein Modell beschrieben, das den reranker verwendet, um die Kandidaten der ersten Suche wie embedding/BM25 nach einem Relevanz‑Score neu zu ordnen. rerank-2.5 ist ein qualitätsoptimierter reranker mit 32 K Kontext. (Voyage AI)

Die Aufgaben des rerankers im Chunk:

**Kandidat 1:**  
  first_2d_game / coding_the_player  
Der raw chunk ist fast gleich dem direkten Codefluss.
  => **Sehr hoch**

**Kandidat 2:**  
  same page / clamp section  
Es gibt eine Erklärung zu `position.clamp` und `AnimatedSprite2D`.
  => **Hoch**

**Kandidat 3:**  
  first_3d_game / player_movement  
Input.is_action_pressed ist gleich, aber im Vector3/3D‑Kontext
AnimatedSprite2D keine
screen_size clamp fehlt
  => **Niedrig**

Vorteile:

Beste Qualität  
BM25‑Falschpositive stark reduziert  
Embedding‑Falschpositive ebenfalls reduziert  
Roh‑Chunk‑Bedingungen beibehalten  
Hardcoding‑Abhängigkeit gering

Nachteile:

Kosten vorhanden  
Latenz vorhanden  
Wenn zu viele Kandidaten eingefügt werden, wird es langsam  
Der Reranker ist ebenfalls kein Beweisprüfer, daher wird ein letzter Validator benötigt

Bewertung:

## Endgültige Empfehlung

Warum man das Modell verwendet und warum nicht

BM25 hat kein Modell

BM25 ist eine statistische Suche.

Dieses Wort ist in der Abfrage.  
Dieses Wort ist auch im Dokument.  
Dieses Wort ist im Korpus selten.  
Dann wird die Punktzahl erhöht.

Deshalb ist die Code‑Suche wie bei deinem Chunk stark.

AnimatedSprite2D
Input.is_action_pressed
Vector2.ZERO
position.clamp

In solchen Fällen ist die Zeichenkette wichtiger als die Bedeutung.

Aber BM25 hat eine schwache Bedeutungs­verknüpfung zu Ausdrücken wie „clamp darf nicht aus dem Bildschirm herausgehen“.


Warum ein Embedding‑Modell verwenden

Embedding wandelt Sätze in Vektoren um.

raw chunk
-> [0.12, -0.03, ...]
docs_chunk
-> [0.11, -0.02, ...]
cosine similarity

Deshalb wird auch dann nach nahegelegenem Inhalt gesucht, wenn die Zeichenketten nicht exakt übereinstimmen.

Falls in diesem Projekt Einbettungen benötigt werden:

1. Wenn das Dokument beschreibend ist und Code und Wörter unterschiedlich sind  
2. Wenn die API-Namen nicht kollidieren, aber das gleiche Konzept darstellen  
3. Wenn das Tutorial‑Chunk in mehreren Ausdrücken verteilt ist  
4. Wenn BM25 0 Treffer liefert und ein Fallback benötigt wird

Falls das Einbetten ausgeschlossen werden muss:

1. api_mapping source_api genaue Übereinstimmung
2. Godot3/Godot4 Versionsbestimmung
3. Entfernen von false positives, die nur target_api entsprechen
4. Bestätigung der Migrationsregel

Das heißt:

embedding = recall Erweiterung
BM25/exact = direkter Beweis
reranker/Qwen validator = Kandidatenbereinigung und -validierung

Modelleigenschaften

voyage-code-3

Passt am besten zu diesem Projekt.

Grund:

query ist kein natürlicher Sprachfrage, sondern ein GDScript‑Code‑Chunk.  
Die zu durchsuchenden JSONL‑Einträge enthalten ebenfalls Code‑Blöcke, API‑Namen und Dokumentationsbeschreibungen.

Nach den offiziellen Dokumenten von Voyage voyage-code-3 ist ein für Code‑Retrieval optimiertes Modell, unterstützt 32 K Kontext, standardmäßig 1024 Dimensionen und 256/512/1024/2048 Dimensionen. In der Voyage‑Präsentation wird außerdem erklärt, dass es auf 32 Code‑Retrieval‑Datensätzen im Vergleich zu OpenAI text-embedding-3-large und CodeSage-large eine höhere durchschnittliche Leistung erzielt hat. (Voyage AI)

Eigenschaften:

Vorteile:
code query ist stark
Lange Chunk-Verarbeitung möglich
1024/2048 auswählbar
code -> docs für die Suche geeignet

Nachteile:
Externe API‑Abhängigkeit
Kosten entstehen
Kein Godot-spezifisches Modell

Empfohlene Verwendung:

voyage-code-3 1024 float

Wenn man nur die Qualität betrachtet, ist 2048 auch möglich, aber 1024 + Reranker ist realistischer.


OpenAI text-embedding-3-large

Dies ist ein universelles hochwertiges Embedding.

Laut der offiziellen OpenAI‑Dokumentation hat text-embedding-3-large standardmäßig 3072 Dimensionen, und text-embedding-3-small hat standardmäßig 1536 Dimensionen. (OpenAI Entwickler)

Eigenschaften:

Vorteile:
  Universelle semantische Suche ist stark
  Stabil bei der Suche nach Dokumentenbeschreibungen
  OpenAI-Ökosystem ist gut

Nachteile:
  Nicht ausschließlich für Code‑Suche gedacht
  3072 Dimensionen führen zu hohen Speicher‑/Indexierungskosten
  Das „GDScript chunk → JSONL“ dieses Projekts ist weniger direkt als voyage‑code‑3

Empfehlungsgrad:

Zweite Priorität

Gemini Embedding

Google Gemini Embedding ist standardmäßig 3072‑dimensional, und mit output_dimensionality können Größen wie 768/1536/3072 gewählt werden. Google‑Dokumentation erklärt, dass bei Verwendung einer kleineren Dimension Speicherplatz und Rechenaufwand reduziert werden können, während der Qualitätsverlust gering bleibt. (Google AI for Developers)

Merkmale:

Vorteile:
  Allgemeine/mehrsprachige semantische Suche ist stark
  Gut für dokumentenbasierte beschreibende Suche
  Dimensionsreduktion möglich

Nachteile:
  Keine reine Code‑Retrieval‑Option
  Fokussiert mehr auf Bedeutungsähnlichkeit als auf API‑Code‑Genauigkeit
  Alleinige Verwendung bei genauer Beurteilung der Godot‑Migration ist riskant

Empfehlungsgrad:

Dokument‑QA‑zentriert wäre gut  
Wenn der Fokus auf der Suche nach Code‑Chunks liegt, unter voyage-code-3

Jina‑Einbettungen v4

Jina‑Einbettungen v4 ist ein Modell, das sich besonders für die Suche in komplexen Dokumenten, mehrsprachige, multimodale sowie visuell reiche Dokumente wie Tabellen, Diagramme und Bilder eignet. Nach den Angaben von Jina wird dabei besonders langer Input und die Retrieval‑Aufgabe für multimodale Dokumente hervorgehoben. (jina.ai)

Merkmale:

Vorteile:
Der Suchbereich des Dokuments ist breit.
multimodal/stark bei zusammengesetzten Dokumenten
code adapter ist ebenfalls vorhanden

Nachteile:
Dein Projekt ist derzeit markdown/code‑zentriert.
Bild-/Tabellenabruf ist nicht das Kernstück
könnte eine übermäßige Wahl sein

Empfehlungsgrad:

Im Moment ist die Priorität niedrig.

Wenn Qwen für die Suche verwendet wird

Qwen ist, wie du sagst, derzeit im Bereich JSONL-Erstellung/Validierung.
Es kann auch für die Suche verwendet werden.

Es gibt zwei Arten der Verwendung.

1. Qwen query profile Generator
2. Qwen validator / reranker

Qwen‑Abfrageprofil‑Generator

raw chunk
-> Qwen erstellt JSON für die Suche
-> BM25/Vector‑Suche

Vorteile:

Reduzierung von Hardcoding  
Godot‑Kontextinferenz möglich  
Komplexe Code‑Chunks zusammenfassen möglich

Nachteile:

hallucination möglich
Vor dem Suchschritt kann eine falsche Absichtseinspeisung möglich sein
Langsam
Kosten vorhanden

Qwen‑Validator

raw chunk
+ retrieved JSONL
-> Bewerten, ob dieses JSONL direkte Evidenz ist

Das ist stark. Im Projektbeobachtungsdokument ist bereits die Richtlinie festgelegt, dass nicht die breite Themenähnlichkeit, sondern das JSONL‑Feld und der Chunk‑String direkt übereinstimmen müssen.

Empfehlung:

Qwen ist sicherer, wenn es nach der Suche als direkter Evidenzvalidator verwendet wird, anstatt vor der Suche eine Abfrage zu erzeugen.

Netzwerk‑Chunk‑basierter Erfolgs‑/Fehlablauf

Erfolgsablauf: BM25 + Einbettung + Reranker

Eingabe:

roher Chunk unverändert

Erster BM25 ist Rauschen:

first_2d_game / coding_the_player

Begründung:
  Input.is_action_pressed
  move_right
  move_left
  velocity.normalized
  AnimatedSprite2D.play
  AnimatedSprite2D.stop

Der zweite BM25 ist Rauschen:

same page / clamp section

Begründung:
  AnimatedSprite2D
  position.clamp
  Vector2.ZERO
  screen_size

Embedding ist verbessert:

player movement
2D movement
animation based on movement
screen bounds

Reranker Zusammenfassung:

1. Platz:
  first_2d_game / coding_the_player

2. Platz:
  same page / clamp and AnimatedSprite2D explanation

Niedrigere:
  first_3d_game / player_movement_code

Endgültiges JSONL:

{"table":"docs_chunks","payload":{"source_file":"outputs/godot_docs_full/pages/getting_started__first_2d_game__03.coding_the_player__161d377b.md","doc_type":"tutorial","heading":"Coding the player","content":"...Input.is_action_pressed...velocity.normalized...$AnimatedSprite2D.play()...$AnimatedSprite2D.stop()...","api_symbols":["Input.is_action_pressed","Vector2.ZERO","AnimatedSprite2D"]}}
{"table":"docs_chunks","payload":{"source_file":"outputs/godot_docs_full/pages/getting_started__first_2d_game__03.coding_the_player__161d377b.md","doc_type":"tutorial","heading":"Coding the player","content":"...position += velocity * delta...position = position.clamp(Vector2.ZERO, screen_size)...","api_symbols":["Vector2.ZERO","position.clamp","AnimatedSprite2D"]}}

Das ist ein Erfolg.


Fehlerablauf 1: aktueller raw tsquery

Eingabe:

roher Chunk unverändert

Interne Abfrage:

func & process & delta & var & velocity & vector2 & zero
& input & is_action_pressed & move_right & move_left
& length & normalized & speed & animatedsprite2d
& play & stop & position & clamp & screen_size

Ergebnis:

0 Einträge möglich

Fehlergrund:

Fehlschlag, wenn nicht alle Wörter in einem JSONL‑Chunk enthalten sind.

Das muss umgearbeitet werden.


Fehlablauf 2: BM25 only

Ergebnis:

1. Platz first_2d_game / coding_the_player  
2. Platz same page / clamp section  
3. Platz first_3d_game / player_movement_code

Fehlergrund:

first_3d_game teilt ebenfalls Input.is_action_pressed, move_left, move_right, normalized.

BM25 versteht nicht vollständig, ob es sich um „2D“ oder „3D“ handelt.
Es berechnet einfach nur die Wortpunkte.

Deshalb ist BM25 allein nicht ausreichend.


Fehlermeldungsablauf 3: Nur Einbettung

Erwartetes Ergebnis:

2D player movement
3D player movement
scripting player input
vector math
animation player docs

Fehlergrund:

Bedeutungs­mäßig alles Spielerbewegung, also Nähe

embedding findet gut Dinge, die inhaltlich nah beieinander liegen, aber die API‑Genauigkeit ist schwach.


Fehlablauf 4: Qwen‑Abfrageprofil nur

Wenn Qwen so gut auswählt, ist es erfolgreich.

{"important_terms":["Input.is_action_pressed","AnimatedSprite2D","position.clamp","Vector2.ZERO"]}

Aber wenn man es so auswählt, schlägt es fehl.

{"migration_intent":"Godot 3 to Godot 4 migration","important_terms":["AnimatedSprite","AnimatedSprite2D"]}

Fehlergrund:

In raw chunk gibt es kein AnimatedSprite, nur AnimatedSprite2D.  
Es ist gültiger Godot 4‑Code, jedoch kann das Migrations‑Mapping mitgebracht werden.

Deshalb ist es gefährlich, Qwen nur als Query‑Generator vor der Suche zu verwenden. Nach der Suche ist der Validator sicherer.


Endgültige 3 Empfehlungen

Variante 1: geringste Komplexität

raw chunk
-> BM25
-> top JSONL

Verwendung:

PoC 1. Phase
Schnelle visuelle Überprüfung der Suchqualität

Vorteile:

Einfachheit
Schnell
Transparenz
Keine Modellkosten

Nachteile:

false positive vorhanden  
Bedeutungssuche nicht möglich  
Wenn die Dokumentdarstellung unterschiedlich ist, wird es übersehen

Im Chunk:

Erfolg ist  
Aber 3D movement ist gemischt

Option 2: Ausgewogene Form

-> BM25 top 50
-> embedding top 50
-> union
-> weighted score
-> JSONL Rückgabe
-> Qwen Direct‑Evidence Überprüfung

Verwendung:

Der realistisch beste Zwischenschritt im aktuellen Projekt

Vorteile:

BM25 und Embedding ergänzen  
JSONL entfernen, die nicht mit Qwen zusammenhängen  
Wenig Hardcoding

Nachteile:

Punktzahl‑Anpassung erforderlich  
Wenn kein Re‑Ranker vorhanden ist, ist das Ranking etwas instabil

Im Chunk:

first_2d_game ist stabil und liegt an der Spitze  
3D movement ist bei der Qwen‑Verifizierung gesunken

Variante 3: Qualität an erster Stelle

-> BM25 top 80
-> voyage-code-3 embedding top 80
-> union
-> rerank-2.5
-> Qwen direct-evidence validator
-> Endgültige JSONL

Verwendung:

## Endgültige Empfehlung

Vorteile:

Beste Qualität  
Minimierung von Hardcoding  
Beibehaltung der Roh‑Chunk‑Bedingungen  
Der Reranker reduziert BM25/Embedding‑Fehlalarme  
Der Qwen‑Validator entfernt JSONL ohne direkte Begründung

Nachteile:

Kosten  
latency  
Viele Implementierungsstufen

Im Chunk:

**Endgültige Annahme:**  
  docs_chunks / first_2d_game / coding_the_player  

**Endgültige Ablehnung oder niedrigeres Ranking:**  
  first_3d_game / player_movement_code  
  unrelated api_mapping  
  migration label_prototypes

Endgültiges Urteil

Wenn ich dieses Projekt jetzt umkremple, gehe ich so vor.

Der Input behält immer nur einen chunkText bei.

Die erste Suche erfolgt mit BM25.  
  Grund: Es ist am transparentesten und stärkste für die Suche nach Code/API‑Strings.

Die zweite Suche erfolgt mit voyage-code-3 Embedding.  
  Grund: Da die Abfrage ein Code‑Chunk ist, passt ein Code‑Retrieval‑Modell.

Die dritte Sortierung erfolgt mit rerank-2.5.  
  Grund: Um das echte Chunk und das passende JSONL unter den ähnlichen Kandidaten, die von BM25 und Embedding geliefert wurden, nach oben zu bringen.

Die abschließende Validierung erfolgt mit dem Qwen direct‑evidence validator.  
  Grund: Wenn es im JSONL keinen direkten String/Pattern‑Beweis gibt, der zum Chunk passt, muss er verworfen werden.

Einzeilig zusammengefasst:

raw chunk 그대로 입력 → BM25 + code embedding 병렬 후보 생성 → reranker 재정렬 → Qwen 직접근거 검증 ist die richtige Antwort.

Es ist richtig, den Godot‑API‑Signal‑Extractor nicht zwingend einzufügen. Selbst wenn du es hinzufügst, solltest du es nur als „Punktbonus“ verwenden. Die Grundsuche sollte über raw‑Chunk‑basiertes BM25/Vector laufen, was deiner Absicht entspricht.