Von der Quell‑AST bis zum Retriever – Zeilen‑Tracking‑Fluss
Erstellungsdatum: 27. Juni 2026
Zweck
Dieses Dokument fasst den am 27. Juni erneut überarbeiteten Stand des Abschnitts docs/roadmaps/2026-06-26-source-to-ast-input-flow.md zusammen, in dem zuvor Unstimmigkeiten auftraten.
Der Kern ist nicht, eine neue Designeinheit zu definieren. Die gesamte Architektur und die DB‑Design‑Richtung sind bereits separat dokumentiert. Hier wird nachverfolgt, welche Zeile welcher Datei bei tatsächlicher Eingabe in den AST‑Parser gelangt, welcher Ausschnitt für die Retriever‑Suche verwendet wird und welche Kandidaten‑Begründungen zurückkommen, um schließlich von einem LLM bewertet zu werden.
Das festzulegende Prinzip ist einfach.
Dateipfade werden angehängt, um den Standort zu verfolgen.
Im Retriever werden nicht Dateipfade, sondern Code-/Textausschnitte eingefügt.
.gd-Dateien werden vom AST-Parser in Funktions- und Deklarationseinheiten geschnitten.
Andere benötigte Textdateien werden direkt nach Zeilenbereich geschnitten.
Jedes Stück wird nacheinander vom Retriever und der LLM-Bewertung verarbeitet.Eingabeform
Wenn das Projekt geklont oder hochgeladen wird, wird es zunächst mit dem relativen Pfad entpackt.
Die Form sieht wie folgt aus.
# <Relative Pfad>
<Dateiinhalt>
# <Relative Pfad>
<Dateiinhalt>Diese Kennzeichnung dient dem Debuggen durch Menschen. Ein Header wie # player.gd ist lediglich ein Hinweis darauf, aus welcher Datei der nachfolgende Text stammt.
Retriever‑Suche enthält nicht # player.gd. Auch im AST‑Parser ist # player.gd nicht enthalten. Eingeschlossen wird nur der eigentliche Dateitext unterhalb der Überschrift.
Beispiel Eingabe
Unten ist ein kleines Godot-Projekt zu sehen. E001, E002 dienen nur zur Erläuterung und sind nicht Teil des eigentlichen Eingabetextes.
E001 # project.godot
E002 config_version=5
E003
E004 [application]
E005 config/name="Mini Dodge"
E006 run/main_scene="res://player.tscn"
E007
E008 # player.gd
E009 extends Area2D
E010
E011 signal hit
E012
E013 @export var speed = 400
E014 var screen_size
E015
E016 func _ready():
E017 screen_size = get_viewport_rect().size
E018 hide()
E019
E020 func _process(delta):
E021 var velocity = Vector2.ZERO
E022 if Input.is_action_pressed(&"move_right"):
E023 velocity.x += 1
E024 if Input.is_action_pressed(&"move_left"):
E025 velocity.x -= 1
E026
E027 if velocity.length() > 0:
E028 velocity = velocity.normalized() * speed
E029 $AnimatedSprite2D.play()
E030 else:
E031 $AnimatedSprite2D.stop()
E032
E033 position += velocity * delta
E034 position = position.clamp(Vector2.ZERO, screen_size)
E035
E036 func start(pos):
E037 position = pos
E038 show()
E039 $CollisionShape2D.disabled = false
E040
E041 # player.tscn
E042 [gd_scene load_steps=3 format=3 uid="uid://mini"]
E043
E044 [ext_resource type="Script" path="res://player.gd" id="1"]
E045
E046 [node name="Player" type="Area2D"]
E047 script = ExtResource("1")1. Schritt: Dateigrenzen aufteilen
Zuerst wird die Datei anhand der Überschrift # <relativer Pfad> in Abschnitte unterteilt.
project.godot beginnt bei E001. Der eigentliche Inhalt erstreckt sich von E002 bis E006. E001 ist ein Dateigrenz‑Marker und kein zu analysierender Text.
player.gd beginnt bei E008. Der eigentliche Inhalt erstreckt sich von E009 bis E039. E008 ist ein Dateigrenz‑Marker und wird nicht an den AST‑Parser übergeben.
player.tscn beginnt bei E041. Der eigentliche Inhalt erstreckt sich von E042 bis E047. E041 ist ein Dateigrenz‑Marker und kein Such‑Text für den Retriever.
In diesem Schritt kann die UI anzeigen, dass „derzeit player.gd von E009‑E039 verarbeitet wird“. Der Suchbegriff wird jedoch noch nicht erstellt.
2. Schritt: Vorgehensweise nach Dateityp festlegen
player.gd ist eine GDScript‑Datei. Deshalb werden die gesamten Zeilen E009‑E039 an den AST‑Parser übergeben.
project.godot ist eine Konfigurationsdatei. Sie wird nicht an den AST‑Parser gesendet, sondern in den benötigten Abschnittseinheiten direkt zerlegt.
player.tscn ist eine Szenendatei. Sie wird ebenfalls nicht an den AST‑Parser gesendet, sondern in Node/Resource‑Block‑Einheiten direkt zerlegt.
README‑ oder Markdown‑Dokumentationen werden im Quellcode‑Analyse‑Modus standardmäßig ausgeschlossen. Ausgeschlossene Dateien müssen trotzdem in der UI angezeigt werden, damit der Benutzer sehen kann, „was fehlt“.
Zum Beispiel, wenn es eine README.md gibt, wird sie von der Analyse ausgeschlossen und der Grund dafür muss angezeigt werden: „Im Quellcode‑Analyse‑Modus werden Dokumentationsdateien standardmäßig ausgeschlossen“. Diese Ausschluss‑Entscheidung ist jedoch nur der Standardwert des Analyse‑Modus; falls später ein Modus benötigt wird, der auch Dokumente liest, wird dies separat behandelt.
3. Schritt: .gd‑Dateien an den AST‑Parser übergeben
Der Input, der von player.gd an den AST‑Parser übergeben wird, sind die Zeilen E009‑E039.
Der eigentliche Text, den der AST‑Parser erhält, ist folgender:
extends Area2D
signal hit
@export var speed = 400
var screen_size
func _ready():
screen_size = get_viewport_rect().size
hide()
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)
func start(pos):
position = pos
show()
$CollisionShape2D.disabled = falseHier gibt es kein # player.gd.
Der AST-Parser liest diesen Text von oben nach unten und schneidet ihn in Deklarations- und Funktionsabschnitte.
Das erste Stück ist eine Zeile E009.
extends Area2DDer zweite Abschnitt ist eine Zeile E011.
signal hitDas dritte Stück ist E013‑E014.
@export var speed = 400
var screen_sizeDer vierte Abschnitt ist E016‑E018.
func _ready():
screen_size = get_viewport_rect().size
hide()Der fünfte Abschnitt ist E020‑E034.
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)Das sechste Stück ist E036‑E039.
func start(pos):
position = pos
show()
$CollisionShape2D.disabled = falseWichtig ist, dass das Fragment nach seiner Erstellung nicht seinen ursprünglichen Zeilenbereich verliert. Zum Beispiel wird das Fragment _process weiterhin als „Fragment aus player.gd Zeile E020‑E034“ nachverfolgt.
4. Schritt: Direktes Verarbeiten von Fragmenten
Auch Textdateien, die nicht Ziel des AST‑Parsers sind, werden bei Bedarf in Fragmente aufgeteilt.
In project.godot werden die Zeilen E004‑E006 zu einem Anwendungs‑Einstellungs‑Fragment.
[application]
config/name="Mini Dodge"
run/main_scene="res://player.tscn"Dieses Fragment kann verwendet werden, um die Start‑Scene des Projekts zu finden, weil run/main_scene="res://player.tscn" gesetzt ist. Wenn eine Retriever‑Suche durchgeführt wird, dienen Inhalte wie run/main_scene, res://player.tscn und application im Text als Suchmaterial. Der Dateipfad project.godot selbst wird nicht zum Suchbegriff.
In player.tscn wird eine Zeile E044 zum Skript‑Referenz‑Fragment.
[ext_resource type="Script" path="res://player.gd" id="1"]E046-E047 wird zu einem Node-Fragment.
[node name="Player" type="Area2D"]
script = ExtResource("1")Diese direkten Fragmente sind zwar keine AST‑Chunks, aber der nachfolgende Ablauf ist derselbe. Ein Teil des Textes wird an den Retriever übergeben, und die gefundenen Kandidaten werden vom LLM erneut verifiziert.
Schritt 5: Der eigentliche Inhalt, der in den Retriever gelangt
Im Retriever wird nicht „Dateipfad“, sondern „der aktuelle Abschnittstext und die daraus extrahierten Suchhinweise“ verwendet.
Zum Beispiel ist der zu durchsuchende Textabschnitt bei der Verarbeitung des _process‑Fragments E020‑E034.
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)In diesem Textabschnitt werden die Hinweise, die für die Suche verwendet werden können, wie folgt angezeigt.
Input.is_action_pressed
Vector2.ZERO
velocity.normalized
position.clamp
AnimatedSprite2D
_process
Godot 3
Godot 4
migrationUnter den obigen Hinweisen werden Godot 3, Godot 4 und migration angehängt, wenn die Benutzeranfrage etwa lautet: „Überprüfe, ob dieses Projekt Godot 3 oder Godot 4 ist, und finde bei Bedarf die Umwandlungsgrundlage“.
Die Retriever‑Suche verwendet den Text dieses Abschnitts und die Hinweise.
Bei der Vektorsuche werden der gesamte Inhalt der _process‑Funktion und die wichtigsten Symbole einbezogen.
Bei der Schlüsselwortsuche werden Symbolnamen wie Input.is_action_pressed, Vector2.ZERO, position.clamp verwendet.
Der Dateipfad player.gd wird nicht als Suchbegriff verwendet. Er wird jedoch später verwendet, um in Protokollen und der Benutzeroberfläche den Hinweis anzuhängen: „Diese Suche trat in player.gd bei E020‑E034 auf“.
6. Schritt: Was der Retriever sucht
Der Retriever durchsucht docs_chunks, api_mapping und label_prototypes auf dieselbe Weise mit demselben Fragment. Keine der drei Tabellen wird besonders behandelt.
In docs_chunks können Kandidaten für offizielle Dokumentationsbeschreibungen wie Input.is_action_pressed, Vector2.ZERO, position, Area2D erscheinen.
In api_mapping können Kandidaten für geänderte Funktionsnamen, Klassennamen und Eigenschaftsnamen von Godot 3 zu Godot 4 auftreten. Zum Beispiel können bei einem Code‑Fragment Hinweise wie KinematicBody2D, yield, Color8 zu entsprechenden Migrationskandidaten führen.
In label_prototypes können Kandidaten wie „ein Muster, bei dem die Art und Weise, wie eine Funktion verwendet wird, komplett geändert wird“ oder „Beispiele, bei denen die Argumentstruktur und Aufrufform geändert werden“ auftreten. Es ist von Bedeutung, wenn nicht nur der Name geändert wurde, sondern die Verwendungsweise selbst erklärt werden muss.
Zum Beispiel können im _process‑Abschnitt die folgenden Kandidaten zurückkommen.
docs_chunks Kandidaten:
Input.is_action_pressed offizielle Dokumentationsbeschreibung
Vector2.ZERO offizielle Dokumentationsbeschreibung
Node2D.position offizielle Dokumentationsbeschreibung
api_mapping Kandidat:
In diesem Abschnitt gibt es möglicherweise keine besonderen Godot 3 → 4‑Namensänderungsvorschläge.
label_prototypes Kandidaten:
Beispiel für Godot 4‑Bewegungscode mit `Input.is_action_pressed` und `Vector2.ZERO`Diese Kandidaten sind nicht die Lösung. Es handelt sich lediglich um „Begründungen, die möglicherweise mit diesem Code‑Fragment zusammenhängen“.
Schritt 7: Retriever‑Ergebnisse an das LLM übergeben
Im LLM werden der Benutzer‑Prompt, das aktuelle Code‑Fragment und die Retriever‑Kandidaten zusammengeführt.
Zum Beispiel wird im _process‑Fragment Folgendes übergeben:
Benutzeranfrage:
Überprüfe, ob dieses Projekt Godot 3 oder Godot 4 verwendet, und finde bei Bedarf die Umwandlungsgrundlage.
Aktueller Code‑Auszug:
player.gd Zeilen E020‑E034
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)
Retriever‑Kandidaten:
- docs_chunks → Input.is_action_pressed offizielle Dokumentation‑Kandidat
- docs_chunks → Vector2.ZERO offizielle Dokumentation‑Kandidat
- docs_chunks → Node2D.position offizielle Dokumentation‑Kandidat
- label_prototypes → Godot 4 Eingabeverarbeitungs‑Beispiel‑KandidatLLM beurteilt hier zwei Dinge.
Erstens, ob die gefundenen Kandidaten tatsächlich mit dem aktuellen Code‑Snippet zusammenhängen.
Zweitens, ob das aktuelle Code‑Snippet ein Signal aus Godot 3, ein Signal aus Godot 4 ist oder eine Migration erforderlich ist.
In diesem Beispiel können Input.is_action_pressed, Vector2.ZERO und position.clamp als Code‑Begründung interpretiert werden, die auch in Godot 4 verwendet werden kann. Daher ist es wahrscheinlich, dass dieses Snippet zu „Kann als Godot 4‑Code betrachtet werden, Migration nicht erforderlich“ tendiert.
Schritt 8: Ablauf des Godot 3‑Beispiel‑Snippets
Angenommen, in einer anderen Datei befindet sich das folgende Snippet.
G101 # enemy.gd
G102 extends KinematicBody2D
G103
G104 var velocity = Vector2.ZERO
G105
G106 func _physics_process(delta):
G107 velocity = move_and_slide(velocity)enemy.gd ist eine .gd-Datei, daher wird der G102‑G107‑Inhalt in den AST‑Parser eingefügt.
Das erste Fragment ist G102.
extends KinematicBody2DDer zweite Abschnitt ist G106‑G107.
func _physics_process(delta):
velocity = move_and_slide(velocity)extends KinematicBody2D-Fragment an den Retriever übergeben, wird das Suchhinweis wie folgt erfasst.
KinematicBody2D
Godot 3
Godot 4
migrationIn diesem Fall kann im api_mapping ein Kandidat erscheinen, bei dem KinematicBody2D in Godot 4 zu einer CharacterBody2D‑Klasse migriert wird.
In docs_chunks können Kandidaten für die offizielle Dokumentation zu CharacterBody2D oder physics body erscheinen.
label_prototypes kann ein Beispiel enthalten, bei dem der auf KinematicBody2D basierende Bewegungscode zu CharacterBody2D und velocity, move_and_slide() geändert wird.
In LLM wird es wie folgt eingefügt.
Benutzeranfrage:
Überprüfe, ob dieses Projekt Godot 3 oder Godot 4 ist, und finde bei Bedarf die Migrationsgrundlage.
Aktueller Codeabschnitt:
enemy.gd – G102
extends KinematicBody2D
Retriever‑Kandidaten:
- api_mapping: KinematicBody2D → CharacterBody2D Migrationskandidat
- docs_chunks: CharacterBody2D offizielle Dokumentationskandidat
- label_prototypes: Beispiel für KinematicBody2D‑Code‑UmwandlungskandidatDas LLM kann dieses Fragment als „Godot 3 Signal ist stark und Migration erforderlich“ beurteilen.
Anschließend wird das Fragment G106‑G107 ebenfalls separat verarbeitet.
func _physics_process(delta):
velocity = move_and_slide(velocity)In diesem Abschnitt wird der Aufruf move_and_slide(velocity) zum Suchhinweis. Es wird nicht nur der Funktionsname betrachtet, sondern auch die Aufrufform mit den übergebenen Argumenten.
Wenn nur der Funktionsname geändert wird, ist der api_mapping‑Kandidat wichtig; ändert sich die gesamte Aufrufweise, wird zusätzlich der label_prototypes‑Kandidat relevant.
9. Schritt: Ergebnis der Fragmente akkumulieren
Jedes Fragment wird einzeln beurteilt.
Die E020‑E034 in player.gd können als Signal für Godot 4 akkumuliert werden.
Der G102 in enemy.gd kann als Signal für Godot 3 akkumuliert werden.
Auch G106‑G107 in enemy.gd können als Godot 3‑Migrationssignal akkumuliert werden.
Die Gesamtbeurteilung des Projekts erfolgt nicht anhand des Dateinamens. Der Dateipfad dient nur zur Nachverfolgung. Die Gesamtbeurteilung des Projekts ergibt sich aus den akkumulierten Ergebnissen der einzelnen Code‑Fragmente.
Beispielsweise kann ein Projekt, in dem überwiegend Godot‑4‑Signale vorkommen, aber einige Godot‑3‑Migrationssignale enthält, zu einer Beurteilung führen, die eher mixed entspricht. Umgekehrt kann ein Projekt, in dem überwiegend Godot‑3‑Migrationssignale vorkommen, als Godot‑3‑Projekt klassifiziert werden.
Unterbrechung und Fortsetzung
RunPod oder ein lokaler Web‑Server können zwischendurch stoppen. Daher muss die Verarbeitung nicht dateibasiert, sondern fragmentbasiert fortgeführt werden können.
Beispiel: Wenn die Verarbeitung von player.gd bis E009, E011 und E013‑E014 abgeschlossen ist und bei E016‑E018 gestoppt wurde, muss nach einem Neustart die Verarbeitung wieder bei E016‑E018 beginnen.
Bereits abgeschlossene E009, E011, E013‑E014 dürfen nicht erneut verarbeitet werden.
Im Web‑UI muss Folgendes angezeigt werden.
player.gd E009 Verarbeitung abgeschlossen
player.gd E011 Verarbeitung abgeschlossen
player.gd E013-E014 Verarbeitung abgeschlossen
player.gd E016-E018 Verarbeitung unterbrochen
player.gd E020-E034 Warten
player.gd E036-E039 WartenSo kann man überprüfen, ob die vorherige Verarbeitung fortgesetzt wird oder von Anfang an neu gestartet wird.
Was auf dem Debug‑Bildschirm angezeigt werden muss
Der Debug‑Bildschirm ist für das Tracing erforderlich.
Mindestens muss Folgendes angezeigt werden.
Aktuelle Datei: player.gd
Aktueller Zeilenbereich: E020-E034
Aktueller Ausschnitt:
func _process(delta):
...
Suchhinweise, die in den Retriever eingegeben wurden:
- Input.is_action_pressed
- Vector2.ZERO
- position.clamp
Gefundene Kandidaten:
- docs_chunks: Input.is_action_pressed
- docs_chunks: Vector2.ZERO
- label_prototypes: Godot 4 input polling example
LLM-Bewertung:
- Godot 4 Signal
- Keine Migration erforderlichHier ist wichtig, dass „was in die Suche eingegangen ist“ und „was nur zum Tracking angehängt wurde“ getrennt sichtbar sind.
player.gd‑Pfad kann in der aktuellen Dateianzeige angezeigt werden. Aber er darf nicht in die Retriever‑Suchhinweisliste aufgenommen werden.
Zusammenfassung
Der feste Ablauf im Dokument vom 27. Tag ist wie folgt.
# <Relativer Pfad>
<Inhalt>
-> Nur die Dateigrenzen werden durch Header getrennt.
-> Der Inhalt der .gd-Datei wird an den AST-Parser übergeben.
-> Der AST-Parser schneidet Funktionen und Deklarationen nacheinander.
-> Der tatsächliche Inhalt jedes Abschnitts und das Symbolhinweis werden in die Retriever‑Suche eingespeist.
-> docs_chunks, api_mapping und label_prototypes werden auf dieselbe Weise durchsucht.
-> Suchkandidaten und der aktuelle Abschnitt werden gemeinsam an das LLM übergeben.
-> LLM‑Entscheidungen werden abschnittsweise gespeichert und projektweise akkumuliert.Der Zweck dieses Dokuments ist es nicht, eine neue Struktur festzulegen, sondern zu ermöglichen, zu erkennen, an welcher Zeile die tatsächliche Eingabe abgeschnitten wird und welcher Text in den nächsten Schritt übergeht. Auch bei der Implementierung muss diese Richtlinie befolgt werden, indem die Web‑UI gleichzeitig die aktuelle Datei, den aktuellen Zeilenbereich, den tatsächlich übermittelten Text, die Retriever‑Suchhinweise, die Suchkandidaten und die Bewertung durch das LLM anzeigt.