Gemma Embed Search
Récupérez des fichiers locaux par leur sens. Un seul espace d'embedding contient des images, de l'audio et du texte, de sorte qu'une requête tapée renvoie les images, clips ou documents correspondants. Le modèle s'exécute sur le matériel de l'utilisateur via un serveur local ; rien n'est téléchargé ailleurs.
scripts/embed_search.py fait quatre choses : doctor vérifie le serveur, init enregistre la connexion, index intègre les fichiers dans un cache, et search les classe par rapport à une requête.
Configuration locale
Les paramètres se trouvent dans config.json, jamais dans ce fichier :
- Linux et macOS :
~/.config/gemma-embed-search/config.json - Windows :
%USERPROFILE%\.config\gemma-embed-search\config.json
Lisez d'abord ce fichier. S'il contient url et model, toutes les commandes ultérieures fonctionneront sans indicateurs de connexion et vous pouvez passer l'étape 2.
S'il est manquant ou incomplet, demandez à l'utilisateur l'URL du serveur et le dossier à indexer, exécutez doctor pour lister les modèles que le serveur propose réellement, puis exécutez init pour écrire le fichier. init fusionne, donc ajouter un paramètre à la fois est sûr. Ne devinez jamais un nom de modèle.
Copier config.example.json de ce dossier vers ce chemin et le modifier fait le même travail que init, pour un utilisateur qui préfère éditer le fichier directement. Ajoutez "api_key" uniquement si le serveur en a besoin.
Ne sauvegardez jamais les paramètres dans le dossier de la compétence lui-même. La mise à jour de la compétence remplace tous les fichiers qu'elle contient, et tout ce qui y est écrit est perdu.
Liste de vérification pour la configuration
Progression :
- Étape 1 : Confirmer le serveur et choisir un nom de modèle (
doctor) - Étape 2 : Sauvegarder la connexion (
init) - Étape 3 : Indexer un pilote de 20 fichiers et examiner une requête
- Étape 4 : Indexer tout le dossier
- Étape 5 : Répondre à la requête réelle de l'utilisateur, avec
--htmlpour qu'il puisse voir les résultats
Sautez l'étape 2 si config.json contient déjà url et model.
Exécutez le script avec uv run scripts/embed_search.py (installe Pillow à partir des métadonnées en ligne du script) ou python3 scripts/embed_search.py si Pillow est déjà importable.
Étape 1 — trouver le serveur et le nom du modèle. Ne devinez jamais le nom du modèle ; lisez-le depuis le serveur.
uv run scripts/embed_search.py --url http://127.0.0.1:1235 doctor
doctor affiche les modèles proposés par le serveur et teste un embedding. Si l'utilisateur n'a pas encore démarré de serveur, lisez references/setup.md et donnez-lui la commande pour son modèle.
Étape 2 — enregistrez-le pour que les appels ultérieurs n'aient besoin d'aucun indicateur. Passez --api-key uniquement si le serveur en nécessite un ; il est écrit dans le fichier de configuration avec le mode 0600. Passez --root sur n'importe quelle commande ultérieure pour travailler sur un dossier différent sans modifier ce qui est sauvegardé.
uv run scripts/embed_search.py --url http://127.0.0.1:1235 --model <nom-du-doctor> init --root <dossier>
uv run scripts/embed_search.py index --limit 20
Étape 3 — pilote avant la longue exécution. L'indexation est l'étape coûteuse : environ 0,25 s par image sur un GPU de bureau, donc 10 000 fichiers prennent environ 40 minutes. Indexez 20 fichiers, exécutez une requête et confirmez que les résultats semblent corrects avant de vous engager dans le passage complet.
Étape 4 — indexation complète. Réexécuter index n'intègre que les fichiers nouveaux ou modifiés, donc une exécution interrompue reprend d'elle-même.
uv run scripts/embed_search.py index
Étape 5 — recherche.
uv run scripts/embed_search.py search "un labrador noir sur une plage" --top 20 --html hits.html
Livre de recettes des requêtes
| Intention | Commande |
|---|---|
| Recherche sémantique simple | search "un marché de nuit bondé" |
| Deux facettes qui doivent toutes deux être vraies | search "une femme" --must "la couleur jaune" |
| Synonymes pour qu'une formulation ne domine pas | search "une femme" --also "une fille" --also "portrait féminin" |
| Trouver chaque image contenant X | search "personnages aux cheveux roux" --top 60 --html hits.html |
| Sujet plus une contrainte de couleur réelle | search "une femme" --color jaune --min-color 0.05 |
| Images principalement monochromes ou sombres | search "n'importe quelle image" --max-color bleu --modality image |
| Un seul type de fichier | search "sons de sirène" --modality audio |
| Lisible par machine pour un travail ultérieur | search "..." --json --top 50 |
| Plus rapide, score légèrement moins précis | search "..." --dims 256 |
--also moyenne les vecteurs de paraphrase en une seule requête. --must conserve le score de la facette la plus faible, ce qui est la façon d'exprimer un ET. Utilisez --also pour les synonymes et --must pour les conditions indépendantes.
Lecture de la sortie
La sortie simple est score [modality] chemin, meilleur d'abord. Les exécutions de couleur insèrent le rapport de pixels après le score. --json émet {"query", "index", "total", "filtered_out", "results": [{"rank", "score", "color", "modality", "path"}]} sur stdout ; toutes les progressions vont sur stderr, donc stdout se canalise toujours proprement dans jq.
Les scores cosinus de cette famille de modèles se situent entre environ 0,3 et 0,8. Le nombre absolu signifie peu ; l'écart entre les résultats pertinents et les non pertinents compte. Si le haut de la liste est faux, la requête est fausse — reformulez-la plutôt que de faire confiance au classement. Ne présentez jamais une longue liste comme étant également bonne : nommez où s'arrêtent les résultats confiants et où commencent les suppositions.
Une courte liste n'est pas la réponse complète. Chaque fichier indexé obtient un score, donc le total dans la sortie compte l'ensemble du corpus et ne vous dit jamais combien de résultats sont plausibles. Trouvez plutôt la falaise — le point où les scores cessent de chuter fortement. Si la liste que vous avez montrée se termine avant, dites que les résultats sont tronqués et proposez une exécution plus longue : un --top plus grand coûte une planche contact de plus, pas une autre indexation. Honorez un nombre nommé par l'utilisateur, et indiquez toujours la limite que vous avez appliquée. Ne prétendez jamais "il n'y en a pas" sans une liste élargie, --top 100 ou plus, que quelqu'un a réellement regardée.
Pour une revue visuelle, proposez toujours --html : il écrit une planche contact de miniatures avec les scores et les noms de fichiers que l'utilisateur peut ouvrir dans un navigateur. Un --html simple écrit hits.html dans le répertoire de travail ; --html FICHIER définit le chemin. Les miniatures sont intégrées en base64, donc la planche est autonome et se déplace seule. La planche intègre de vraies miniatures des fichiers correspondants, donc traitez-la comme une copie de cette partie de la bibliothèque : gardez-la hors du contrôle de version et de tout ce que vous transmettez. Elles mesurent 512 px de large par défaut ; augmentez --thumb-width pour une inspection rapprochée des détails.
Pièges
- Un mot de couleur dans le texte de la requête est un indice doux, pas un filtre.
"une femme avec un thème jaune"classe une femme en veste orange en premier. Utilisez--color jaune --min-color 0.05pour une contrainte réelle ; elle est calculée à partir des pixels, pas du modèle. - Un mot de style est aussi un indice doux, et plus faible.
"une femme photoréaliste aux cheveux roux"classe une illustration à l'encre d'une femme aux cheveux roux en premier, car les noms du sujet l'emportent sur le style. Déplacez le style dans--mustpour qu'il soit noté comme sa propre facette et fixez l'attribut visuel avec--color. Ni l'un ni l'autre n'est un vrai filtre :--mustprend le minimum entre les facettes, donc insister sur l'un échange l'autre. - Plusieurs sujets dans une seule image se fondent en un seul vecteur, donc l'image obtient un score moins bon pour une requête à sujet unique qu'une image dédiée à ce sujet : un portrait d'une femme aux cheveux roux à côté d'un homme peut se situer loin dans une recherche
"femme aux cheveux roux"tout en étant en haut de"personnages aux cheveux roux". Les synonymes de la même idée singulière n'aident pas ; la forme plurielle ou collective le fait. Élargissez--toplorsque la question est "trouver tout ce qui contient X". --colora besoin que l'index contienne des statistiques de couleur, que seulindexcalcule. Un index construit avec une version plus ancienne signale 0,0 pour tout : réindexez avec--forcesi le filtrage par couleur exclut silencieusement tous les fichiers.- L'index et la requête doivent utiliser le même modèle. Changer
--modelmélange silencieusement des vecteurs incompatibles ; réindexez avec--forceaprès tout changement de modèle et notez le modèle dansstats. - Le serveur doit exécuter le modèle d'embedding avec un pooling moyen et son projecteur de vision (
--mmproj) chargé. Sans le projecteur, les requêtes d'image échouent ou renvoient un vecteur qui ignore l'image.doctorprouve que le texte fonctionne ; exécutez une requête d'image pour prouver la vision. - Les images sont ré-encodées en JPEG avec le côté le plus long à 1536 avant d'être envoyées. Le ré-encodage est obligatoire, pas cosmétique : les serveurs rejettent couramment les fichiers WebP, 16 bits ou mal étiquetés, et Pillow les lit à la place. Le modèle n'a pas de limite de pixels — le serveur ré-échantillonne chaque image à un budget de jetons de vision fixe — donc
--resizeéchange la taille d'envoi contre la fidélité, pas l'exactitude. Les chiffres mesurés et les détails se trouvent dans references/setup.md. - Les formats HEIC et raw d'appareil photo ne sont pas lus à moins que Pillow n'ait été construit avec le plugin. Le script enregistre
skip <fichier> : cannot identify image fileet continue ; vérifiezskipped_errorsdans le résumé de l'index plutôt que de supposer une couverture complète. searchsur un dossier qui n'a jamais été indexé se termine avec le code 4 et un message. Ne traitez pas une liste de résultats vide comme "aucune correspondance" tant que le nombre d'index dansstatsne semble pas correct.- L'audio est limité par le contexte du serveur : environ 5,5 minutes par clip à 25 jetons par seconde. Les fichiers plus longs échouent comme une erreur de requête, pas comme une mauvaise correspondance.
- Les scores ne sont pas comparables entre corpus ou entre quantifications. Ne promettez jamais de seuil ; ajustez
--min-coloret--topen fonction de ce que l'utilisateur voit.
Référence du script
doctor Vérifie le serveur, liste les modèles, teste un embedding
init [--root DOSSIER] Sauvegarde l'URL, le modèle, la clé et le dossier par défaut dans le fichier de configuration
index --root DOSSIER Intègre les fichiers nouveaux et modifiés (incrémental, reprenable)
[--modality auto|image|audio|text] [--include '*.png,sub/*.jpg']
[--exclude-dir node_modules,.git] [--limit N] [--batch 16] [--resize 1536]
[--force] [--compact]
search "requête" Classe les fichiers indexés ; affiche le score, la modalité, le chemin
[--also P]... [--must P]... [--color NOM --min-color F | --max-color F]
[--modality image] [--dims 512|256|128] [--top 20] [--offset 0]
[--json] [--html [FICHIER]] [--thumb-width 512]
stats Nombre d'entrées, répartition des modalités, modèle, taille de l'index
Codes de sortie : 0 succès, 2 erreur d'utilisation, 3 serveur injoignable ou authentification rejetée, 4 index manquant, 5 rien à faire, 6 erreur serveur en cours d'exécution. Exécutez scripts/embed_search.py <commande> --help pour la documentation complète des indicateurs.
La résolution de la configuration est : indicateur > environnement (EMBED_SEARCH_URL, EMBED_SEARCH_MODEL, EMBED_SEARCH_API_KEY, EMBED_SEARCH_ROOT) > fichier de configuration à ~/.config/gemma-embed-search/config.json. L'index par défaut est ~/.cache/gemma-embed-search/<dossier>-<hash>.jsonl, un enregistrement JSON par fichier, donc il est sûr de conserver plusieurs index pour différents dossiers.
Plus de détails
- references/setup.md — démarrer un serveur, modèle et indicateurs requis, ce que signifie
doctor - references/query-guide.md — construction de requêtes, logique de facettes, seuils de couleur, réglage par rapport aux résultats réels
- references/errors.md — chaque code de sortie et la correction pour chaque mode d'échec