Conclusion dès le départ
Exactement. J'ai mal compris l'intention.
Si je le reformule correctement, c’est cela.
1. Dans le zip, il y a le markdown original, le schéma, le débogueur et le document de conception.
2. Sur votre machine locale, il y a déjà la version convertie markdown → JSONL → DB.
3. Ce que je peux voir, c’est le « markdown avant conversion et le schéma DB / flux de recherche ».
4. Ainsi, le PoC doit découper le markdown du zip en morceaux similaires à des chunks JSONL, afin de simuler les cibles de recherche qui auraient pu être insérées dans votre base de données locale.
5. Ce que vous voulez, ce n’est pas le squelette du code, mais suivre le flux montrant comment chaque méthode de recherche génère un score et pourquoi elle réussit ou échoue lorsqu’un chunk est inséré.Et une modification importante.
Dans le projet actuel, /api/retrieve n'est pas BM25.
Le code actuel est :
chunkText
-> plainto_tsquery('simple', chunkText)
-> search_tsv @@ query
-> ts_rank_cd(...)Ceci est. Le ts_rank_cd de PostgreSQL est un classement de texte intégral, et ce n’est pas le BM25 lui‑même. La documentation de PostgreSQL indique également que ts_rank/ts_rank_cd sont des fonctions de classement qui acceptent une option de normalisation de la longueur du document. plainto_tsquery tokenise la phrase d’entrée, ignore la ponctuation et crée une requête à partir des mots qui ne sont pas des stop‑words. (PostgreSQL)
Conclusion dès le départ
La meilleure solution qui satisfait vos conditions est celle‑ci.
Entrée:
raw chunkText tel quel
À l'intérieur du Retriever:
1. Recherche de candidats BM25 avec le raw chunk tel quel
2. Recherche de candidats d'embedding de code avec le raw chunk tel quel
3. Union des candidats
4. Réordonnancement avec le reranker
5. Vérification directe des preuves JSONL par Qwen ou le validateurVersion où l'extraction du signal API de Godot n'est pas obligatoire.
En d'autres termes, le « extracteur de signal API de Godot » que j'ai mentionné précédemment ne doit pas être rendu obligatoire. Comme vous le dites, cela donne une impression de codage en dur. On peut l'utiliser, mais le placer au cœur de la conception de base rend la maintenance plus difficile.
Recommandation finale :
Premier candidat : BM25
Deuxième candidat : code embedding
Tri final : reranker
Validation : Qwen direct-evidence validatorVérification de la compréhension du projet
Le véritable structure observée dans le zip est la suivante.
Conception JSONL
Le document définit les livrables comme suit.
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.jsonlLe schéma de la base de données n’est pas structuré de façon à insérer une ligne complète de JSONL dans une colonne payload jsonb.
Le champ JSONL est déployé en tant que colonnes de la table.
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_tsvEn d’autres termes, votre base de données locale contiendra cela.
{"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"]}Entrée de quatre morceaux
Supposons que l'entrée soit toujours exactement ceci.
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)Si l’on regarde ce chunk avec le tokenizer de code, les tokens uniques apparaissent ainsi.
_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
1Il y a un total de 43 jetons, dont 25 uniques.
Le jeton important ici est celui-ci.
Tokens forts:
animatedsprite2d
is_action_pressed
move_left
move_right
normalized
clamp
screen_size
vector2
zero
Tokens faibles:
func
var
if
else
velocity
position
delta
x
0
1BM25 accorde un score élevé aux tokens forts.
C’est parce que plus un mot apparaît rarement dans l’ensemble du document, plus son IDF est grand.
Comment BM25 fonctionne et produit des résultats
BM25 calcule grossièrement « dans quelle mesure le mot de requête est bien présent dans le document ».
Officiellement, trois éléments sont essentiels.
TF: combien de fois le mot apparaît dans ce document
IDF: à quel point le mot est rare dans l'ensemble du corpus
Length normalization: correction pour que les documents longs ne soient pas automatiquement avantagésElasticsearch utilise également BM25 comme algorithme de pertinence par défaut, en expliquant la fréquence des termes, la fréquence inverse des documents et la normalisation de la longueur du champ comme éléments clés. (Elastic)
La formule ressemble à ceci.
score(query, doc)
= Σ over query terms [
IDF(term)
*
TF_boost(term frequency in doc, doc length)
]En d'autres termes, si un mot rare comme animatedsprite2d apparaît plusieurs fois dans le document, le score augmente considérablement.
Résultat de la simulation réaliste
Le markdown original Godot réel dans le zip :
outputs/godot_docs_full/pages/Nous l'avons découpé en morceaux d'environ 1800 caractères comme le JSONL docs_chunks, puis nous avons inséré les morceaux bruts tels quels dans la requête et exécuté BM25.
Candidat n°1
Input.is_action_pressed("move_right")
Input.is_action_pressed("move_left")
velocity.length()
velocity.normalized() * speed
$AnimatedSprite2D.play()
$AnimatedSprite2D.stop()Pourquoi c’est la première place ? Parce que ces jetons ont été directement corrects.
animatedsprite2d
is_action_pressed
move_left
move_right
normalized
play
stop
input
speed
length
velocity
vector2
zeroLes principaux jetons contributeurs qui ont fortement augmenté le score sont les suivants.
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.637Ici, df représente le nombre de chunks contenant le mot parmi les 4165 chunks au total.
C’est‑à‑dire :
animatedsprite2d n'apparaît que dans 18 des 4165 chunks au total
move_left n'apparaît que dans 13
move_right n'apparaît que dans 15
is_action_pressed n'apparaît que dans 27Ainsi, les documents contenant ces mots remontent fortement.
C’est le processus par lequel BM25 a créé la première place.
Candidat 2e place
Description d'AnimatedSprite2D
$AnimatedSprite2D.play()
get_node("AnimatedSprite2D").play()
position += velocity * delta
position = position.clamp(Vector2.ZERO, screen_size)Jeton correspondant :
animatedsprite2d
clamp
screen_size
play
delta
_process
velocity
position
stop
vector2
zeroLa raison pour laquelle ce chunk est en deuxième position est qu'il n'y a pas de partie de traitement d'entrée, mais que clamp, screen_size et AnimatedSprite2D correspondent fortement.
En particulier :
screen_size df=3
clamp df=32
animatedsprite2d df=18screen_size est un mot qui apparaît rarement, donc même s'il n'apparaît qu'une fois, le score est élevé.
3e candidat : candidat échoué
3D player movement
Input.is_action_pressed("move_right")
Input.is_action_pressed("move_left")
Vector3.ZERO
direction.normalized()
contenu du fragment:Jeton correspondant :
is_action_pressed
move_left
move_right
normalized
speed
velocity
delta
input
x
var
func
zeroCela semble lié, mais ce n’est pas la réponse exacte.
Pourquoi cela a‑t‑il été publié :
Input.is_action_pressed
move_right
move_left
normalized
speedCette raison provient du fait que les jetons communs du code de déplacement se chevauchent fortement.
Cependant, ce document concerne la 3D. Le chunk est en 2D et AnimatedSprite2D, Vector2, position.clamp, screen_size sont essentiels.
En d’autres termes, l’utilisation exclusive de BM25 entraîne ce type de faux positif.
Pourquoi la méthode actuelle échoue
La méthode proche de /api/retrieve actuelle est plainto_tsquery(raw_chunk).
Cette méthode se traduit approximativement par la requête suivante.
func & process & delta & var & velocity & vector2 & zero
& input & is_action_pressed & move_right & move_left
& length & normalized & speed & animatedsprite2d
& play & stop & position & clamp & screen_sizeDans ce cas, un seul morceau JSONL exige trop de jetons.
Dans ma simulation :
strict raw AND hits: 0En d’autres termes, si un chunk ne satisfait pas simultanément tous les tokens uniques, il n’y a aucun résultat.
En effet, la documentation officielle est également structurée de cette manière.
chunk A:
Input.is_action_pressed
velocity.normalized
AnimatedSprite2D.play/stop
chunk B:
Description d'AnimatedSprite2D
position.clamp
screen_sizeLes deux sont liés, mais tout n'est pas contenu dans une seule ligne.
Donc, il est approprié de réviser complètement la méthode actuelle.
Alternatives par méthode
Alternative A. Méthode actuelle : raw chunk + PostgreSQL plainto_tsquery
Flux:
raw chunkText
-> plainto_tsquery
-> search_tsv @@ query
-> ts_rank_cdVoici le résultat du chunk :
Probabilité d'échec élevée
Même un léger changement dans la division du chunk donne 0 casAvantages:
L'implémentation est déjà faite
Possible uniquement avec PostgreSQL
Infrastructure simpleInconvénients:
Faible avec les gros morceaux de code
Les conditions AND sont excessives
Il y a beaucoup de bruit de jetons de code
Ce n'est pas BM25
Recherche sémantique impossibleJugement:
ÉliminationAlternative B. raw chunk + BM25 only
Flux :
raw chunkText
-> tokenizer
-> BM25
-> top JSONL retourVoici le résultat du chunk :
1er: first_2d_game / coding_the_player
2e: first_2d_game / coding_the_player / clamp section
3e: first_3d_game / player_movement_codePourquoi a-t-il réussi ?
AnimatedSprite2D
move_right
move_left
is_action_pressed
screen_size
clampCes mots sont rares dans l’ensemble de la documentation Godot, ce qui leur a valu un score élevé.
Avantages :
Principe transparent
Débogage facile
Aucun coût de modèle
Utilisation directe du raw chunk possible
Code/API robuste aux chaînes exactesInconvénients:
Faible avec les synonymes/phrases explicatives
Impossible de le trouver si le nom de l'API n'apparaît pas directement
Du code similaire se mélange, comme 3D movement
Manqué si le document est exprimé différemmentJugement:
Il faut absolument l'écrire
Mais seul, ce n'est pas suffisantAlternative C. raw chunk + embedding only
Flux:
raw chunkText
-> embedding vector
-> docs_chunks/api_mapping/label_prototypes embedding et recherche cosinus
-> retour du top JSONLRaison d’utiliser le modèle :
Pour trouver des documents dont le sens est proche même si les chaînes ne se chevauchent pas exactement.Par exemple, la requête contient :
position.clamp(Vector2.ZERO, screen_size)Il y a, et le document contient :
prevent the player from leaving the screen
clamping a value means restricting it to a given rangeSi cela est expliqué ainsi, BM25 peut être affaibli. L'embedding capture ce type de connexion sémantique.
Avantages:
Même si l'expression diffère, il trouve
Fort avec le contenu de type description de document
Facile à insérer le chunk brut tel quel
Capable de traiter même les gros chunksInconvénients:
Le jugement précis de l'API est faible
Il peut mélanger des différences subtiles comme 3D/2D, Godot3/Godot4
Il est difficile d'expliquer pourquoi ce résultat est apparu
Il y a un grand risque de faux positifs dans api_mappingVotre prévision de chunk :
Succès:
first_2d_game / coding_the_player probabilité élevée de le trouver
Échec:
first_3d_game movement aussi susceptible d’apparaître avec une probabilité élevée
parce que le sens de « player movement » est similaireJugement:
**Interdiction d’utilisation exclusive**
Utilisé pour compléter les candidats BM25Alternative D. raw chunk + BM25 + embedding parallèle
Flux :
raw chunkText
-> BM25 top 50
-> embedding top 50
-> Combiner
-> Mélanger les scores
-> Retourner le top JSONLCette méthode est assez bonne.
Votre flux de chunk :
BM25 qui capture :
Input.is_action_pressed
AnimatedSprite2D
position.clamp
screen_size
embedding qui capture :
player movement
2D movement tutorial
moving inside screen
animation based on movementAvantages:
Complémenter mutuellement les faiblesses de la recherche de chaînes et de la recherche sémantique
La qualité initiale s'améliore même sans Qwen
Conserver les conditions du raw chunkInconvénients:
Score combiné nécessite un réglage
Le score BM25 et l'échelle du score vectoriel sont différents
Impossible de bloquer complètement les faux positifsJugement:
Ligne minimale recommandée en pratiqueAlternative E. génération de raw chunk + requête JSON Qwen + recherche
Pour éviter le codage en dur, cette méthode est également possible.
Flux :
-> Demander à Qwen de créer un JSON pour la recherche
-> Recherche BM25/vector avec le JSON généré
-> Retourner les candidats JSONLPar exemple, sortie Qwen :
{
"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": []
}Ceci est une méthode qui n'implique pas le codage en dur de l'extracteur de signaux de l'API Godot.
À la place, Qwen crée un profil de requête.
Avantages :
Peu de codage en dur
Possibilité de résumer l'intention dans des chunks complexes
Il est possible de rendre les mots-clés plus lisibles pour les humains
On peut confier le jugement spécialisé pour Godot à QwenInconvénients:
Lenteur
Coût engendré
Qwen peut créer des indices inexistants
Hallucination possible dès la phase de recherche
Il est indispensable de vérifier directement les preuves brutes du fragmentOui chunk succès:
Qwen obtient le succès lorsqu'il extrait AnimatedSprite2D / Input.is_action_pressed / position.clamp.Oui échec du chunk:
Si Qwen crée une intention inexistante comme « migration de Godot 3 vers 4 », il entraîne une mauvaise manipulation d'api_mapping.Jugement:
Bon pour les expériences de qualité de recherche
À utiliser avec prudence comme moteur de recherche principal en productionAlternative F. raw chunk + BM25 + embedding + reranker
C’est le meilleur.
Flux :
-> BM25 top 80
-> embedding top 80
-> union des candidats
-> le reranker compare directement le raw chunk avec chaque candidat JSONL
-> retourne le JSONL top
-> le validateur Qwen vérifie les preuves directesreranker lit la requête et le document candidat ensemble et réévalue leur pertinence. Le document Voyage est également décrit comme un modèle de réordonnancement qui reçoit les candidats du résultat de recherche de premier niveau tels que embedding/BM25 et les réarrange selon un score de pertinence. rerank-2.5 est un réordonnanceur optimisé pour la qualité avec un contexte de 32 K. (Voyage AI)
Ce que fait le réordonnanceur dans chaque chunk :
**Candidat 1**
- `first_2d_game / coding_the_player`
- Le flux de code brut est presque identique au *raw chunk*
- => **Très élevé**
**Candidat 2**
- `same page / clamp section`
- Contient une explication de `position.clamp` et d'`AnimatedSprite2D`
- => **Élevé**
**Candidat 3**
- `first_3d_game / player_movement`
- `Input.is_action_pressed` est le même, mais le contexte est Vector3/3D
- Aucun `AnimatedSprite2D`
- Aucun clamp de `screen_size`
- => **Réduit**Avantages:
Meilleure qualité
Réduit considérablement les faux positifs BM25
Réduit également les faux positifs d'embedding
Maintient les conditions du chunk brut
Faible dépendance au codage en durInconvénients:
Coût présent
Latence présente
Si vous mettez trop de candidats, c’est lent
Le reranker n’est pas non plus un vérificateur de preuves, donc un validateur final est nécessaireJugement:
Recommandation finalePourquoi utiliser le modèle et pourquoi ne pas l'utiliser
BM25 n'a pas de modèle
BM25 est une recherche statistique.
Ce mot est dans la requête.
Ce mot est aussi dans le document.
Ce mot est rare dans le corpus.
Alors on augmente le score.Ainsi, il est performant pour la recherche de code comme votre chunk.
AnimatedSprite2D
Input.is_action_pressed
Vector2.ZERO
position.clampCette chose accorde plus d'importance à la chaîne de caractères qu'au sens.
Cependant, BM25 a une connexion sémantique faible, comme « empêcher le clamp de sortir de l'écran ».
Pourquoi utiliser un modèle d'embedding
L'embedding transforme les phrases en vecteurs.
raw chunk
-> [0.12, -0.03, ...]
docs_chunk
-> [0.11, -0.02, ...]
cosine similarityAinsi, même si les chaînes ne se chevauchent pas exactement, nous recherchons le contenu le plus proche.
Dans le cas où l'embedding est nécessaire pour ce projet :
1. Lorsque le document est descriptif et que le code et le mot diffèrent
2. Lorsque les noms d'API ne se chevauchent pas mais représentent le même concept
3. Lorsque le fragment de tutoriel est réparti en plusieurs expressions
4. Lorsque BM25 renvoie 0 résultat et qu'un repli est nécessaireCas où l'embedding doit être exclu :
1. Correspondance précise de l'api_mapping source_api
2. Détermination de la version Godot3/Godot4
3. Suppression des faux positifs ne correspondant qu'à target_api
4. Confirmation de la règle de migrationEn d'autres termes :
embedding = extension du rappel
BM25/exact = preuve directe
reranker/Qwen validator = organisation et vérification des candidatsCaractéristiques par modèle
voyage-code-3
Ce projet correspond le mieux.
Raison :
La requête n'est pas une question en langage naturel, mais un bloc de code GDScript.
Le JSONL cible de recherche contient également des blocs de code, des noms d'API et des descriptions de documentation mélangés.Selon la documentation officielle de Voyage, voyage-code-3 est un modèle optimisé pour la récupération de code, avec un contexte de 32 K, une dimension de base de 1024, et il prend en charge les dimensions 256/512/1024/2048. Dans la présentation de Voyage, il est indiqué qu'il a obtenu des performances moyennes supérieures à celles d'OpenAI text-embedding-3-large et de CodeSage-large sur 32 jeux de données de récupération de code. (Voyage AI)
Caractéristiques :
Avantages :
Fort pour les requêtes de code
Capable de traiter de gros chunks
Possibilité de choisir 1024/2048
Adapté à la recherche code → docs
Inconvénients :
Dépendance aux API externes
Coûts engendrés
Pas un modèle spécialisé pour GodotRecommandations d'utilisation:
voyage-code-3 1024 floatSi l’on ne considère que la qualité, 2048 est également possible, mais 1024 + reranker est plus réaliste.
OpenAI text-embedding-3-large
C’est un embedding général de haute qualité.
Selon la documentation officielle d’OpenAI, text-embedding-3-large a par défaut 3072 dimensions, et text-embedding-3-small a par défaut 1536 dimensions. (OpenAI développeur)
Caractéristiques:
Avantages :
- récupération sémantique polyvalente puissante
- recherche de description de documents stable
- bon écosystème OpenAI
Inconvénients :
- pas dédié à la récupération de code
- 3072 dimensions entraînent des coûts de stockage/indice élevés
- le “GDScript chunk -> JSONL” de ce projet est moins direct que voyage-code-3Recommandation :
2e prioritéGemini Embedding
Google Gemini embedding est de 3072 dimensions par défaut, et vous pouvez choisir une taille comme 768/1536/3072 avec output_dimensionality. La documentation Google explique également que l’utilisation de dimensions plus petites permet de réduire l’espace de stockage et le coût de calcul tout en limitant la perte de qualité. (Google AI for Developers)
Caractéristiques :
Avantages:
- Polyvalent / récupération sémantique multilingue puissante
- Idéal pour la récupération de type description de documents
- Réduction de dimension possible
Inconvénients:
- Pas une option dédiée uniquement à la récupération de code
- Priorise la similarité sémantique plutôt que la précision du code API
- Risque d’utilisation isolée pour juger précisément la migration de GodotRecommandation :
Ce serait bien de se concentrer sur la QA des documents
Si c'est centré sur la recherche de morceaux de code, sous voyage-code-3Jina embeddings v4
Jina embeddings v4 est un modèle qui excelle dans la recherche de documents complexes, le multilingue, le multimodal, ainsi que la récupération de documents visuellement riches tels que les tableaux, graphiques et images. Selon la description de Jina, il met l’accent sur la prise en charge de longues entrées et la récupération de documents multimodaux. (jina.ai)
Caractéristiques :
Avantages:
La portée de recherche des documents est large
Fort pour les documents multimodaux/combinés
Il existe également une série d'adaptateurs de code
Inconvénients:
Votre projet est actuellement centré sur markdown/code
La récupération d'images/tableaux n'est pas essentielle
Cela peut être un choix excessifRecommandation :
Pour le moment, priorité basseCas d’utilisation de Qwen pour la recherche
Qwen, comme vous l’avez indiqué, concerne actuellement la génération/validation de JSONL.
Il peut également être utilisé pour la recherche.
Il existe deux manières de l’utiliser.
1. Générateur de profil de requête Qwen
2. Validateur / réordonnanceur QwenGénérateur de profil de requête Qwen
raw chunk
-> Qwen génère un JSON pour la recherche
-> Recherche BM25/vectorAvantages:
Réduction du codage en dur
Possibilité d'inférence de contexte Godot
Possibilité de résumer les blocs de code complexesInconvénients:
hallucination possible
Injection d'intention incorrecte possible avant la recherche
Lenteur
Coût présentValidateur Qwen
raw chunk
+ retrieved JSONL
-> Déterminer si ce JSONL est une preuve directeCeci est puissant.
Dans le document d'observation du projet, le critère « il faut que le champ JSONL et la chaîne de chunk correspondent directement, plutôt que la similarité de sujet large » est déjà établi.
Recommandation:
Il est plus sûr d’utiliser Qwen comme validateur de preuves directes après la recherche plutôt que de générer des requêtes avant la recherche.Flux de succès/échec basé sur le chunk
Flux de succès : BM25 + embedding + reranker
Entrée:
raw chunk tel quelLe bruit du BM25 de première étape :
first_2d_game / coding_the_player
Justification :
Input.is_action_pressed
move_right
move_left
velocity.normalized
AnimatedSprite2D.play
AnimatedSprite2D.stopLe BM25 de deuxième phase est du bruit:
same page / clamp section
Base:
AnimatedSprite2D
position.clamp
Vector2.ZERO
screen_sizeL'embedding est complété :
player movement
2D movement
animation based on movement
screen boundsRésumé du reranker :
1er:
first_2d_game / coding_the_player
2e:
same page / clamp and AnimatedSprite2D explanation
Inférieur:
first_3d_game / player_movement_codeJSONL final :
{"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"]}}Ce n’est pas un succès.
Flux d’échec 1 : tsquery brut actuel
Entrée:
raw chunk tel quelRequête interne :
func & process & delta & var & velocity & vector2 & zero
& input & is_action_pressed & move_right & move_left
& length & normalized & speed & animatedsprite2d
& play & stop & position & clamp & screen_sizeRésultat:
0 cas possibleRaison de l'échec:
Échouer si tous les mots ne sont pas présents dans un chunk JSONLCe texte doit être réécrit.
Flux d'échec 2 : BM25 uniquement
Résultat :
1ère first_2d_game / coding_the_player
2ème same page / clamp section
3ème first_3d_game / player_movement_codeRaison de l'échec:
first_3d_game partage également Input.is_action_pressed, move_left, move_right, normalized.BM25 ne comprend pas parfaitement si c’est “2D ou 3D”.
Il calcule simplement le score des mots.
Ainsi, BM25 only n’est pas suffisant.
Flux d'échec 3 : embedding only
Résultat attendu:
2D player movement
3D player movement
scripting player input
vector math
animation player docsRaison de l'échec:
En termes de sens, tout est un mouvement du joueur, procheLes embeddings trouvent bien les éléments sémantiquement proches, mais la précision de l'API est faible.
Flux d'échec 4 : Profil de requête Qwen uniquement
Qwen réussira s’il est sélectionné aussi bien.
{"important_terms":["Input.is_action_pressed","AnimatedSprite2D","position.clamp","Vector2.ZERO"]}Cependant, si vous le choisissez ainsi, cela échoue.
{"migration_intent":"Godot 3 to Godot 4 migration","important_terms":["AnimatedSprite","AnimatedSprite2D"]}Raison de l'échec:
Dans le raw chunk, il n’y a pas d’AnimatedSprite, seulement AnimatedSprite2D.
C’est du code correct pour Godot 4, mais il est possible d’apporter le mapping de migration.Ainsi, il est dangereux d'utiliser Qwen uniquement comme générateur de requêtes avant la recherche.
Un validateur après la recherche est plus sûr.
3 recommandations finales
Option 1 : la complexité la plus faible
raw chunk
-> BM25
-> top JSONLUtilisation:
PoC 1ère phase
Vérifier rapidement la qualité de recherche à l'œilAvantages:
Simplicité
Rapide
Transparence
Pas de coût de modèleInconvénients:
false positive présence
signification non recherchée
si la représentation du document diffère, omissionDans le chunk :
Le succès est atteint
Mais le mouvement 3D est mélangéOption 2 : Type équilibré
-> BM25 top 50
-> embedding top 50
-> union
-> score pondéré
-> retour JSONL
-> validation de direct-evidence QwenUtilisation:
L'étape intermédiaire la plus réaliste pour le projet actuelAvantages:
BM25 et amélioration par embedding
Suppression du JSONL non lié à Qwen
Hardcoding écritInconvénients:
Nécessité d'ajuster le score
Sans reranker, le classement est légèrement instableDans le chunk :
first_2d_game est stable et supérieur
Le mouvement 3D diminue lors de la validation QwenOption 3 : Qualité avant tout
- BM25 top 80
- voyage-code-3 embedding top 80
- union
- rerank-2.5
- Qwen direct-evidence validator
- JSONL finalUtilisation:
Recommandation finaleAvantages:
La meilleure qualité
Minimisation du codage en dur
Maintien des conditions de raw chunk
Le reranker réduit les faux positifs BM25/embedding
Le validateur Qwen supprime les JSONL sans preuve directeInconvénients:
Coût
latence
De nombreuses étapes de mise en œuvreDans le chunk :
Acceptation finale :
docs_chunks / first_2d_game / coding_the_player
Rejet final ou rang inférieur :
first_3d_game / player_movement_code
unrelated api_mapping
migration label_prototypesJugement final
Si je renverse ce projet maintenant, je procéderai ainsi.
Le texte d’entrée reste uniquement un chunkText.
1ᵉʳ recherche : BM25.
Raison : c’est la méthode la plus transparente et puissante pour la recherche de chaînes de code/API.
2ᵉ recherche : embedding voyage‑code‑3.
Raison : la requête est un chunk de code, donc un modèle de récupération de code est approprié.
3ᵉ tri : rerank‑2.5.
Raison : pour faire remonter en tête les JSONL réellement correspondants parmi les candidats similaires obtenus par BM25 et l’embedding.
Validation finale : validateur Qwen direct‑evidence.
Raison : si aucun texte ou motif correspondant directement au chunk n’est présent dans le JSONL, il faut le rejeter.Résumé en une phrase :
Entrée du raw chunk tel quel → génération de candidats parallèles BM25 + code embedding → réordonnancement par le reranker → validation directe des preuves par Qwen est la réponse.
Il est préférable de ne pas inclure l’extracteur de signaux API de Godot.
Même si vous l’ajoutez, il ne doit servir qu’à un « bonus de score ». La recherche de base doit se faire via BM25/vector basé sur le raw chunk, conformément à votre intention.