Gemma Embed Search
Recupera archivos locales por su significado. Un único espacio de embedding alberga imágenes, audio y texto, de modo que una consulta escrita devuelve las imágenes, clips o documentos que coinciden. El modelo se ejecuta en el hardware del usuario a través de un servidor local; no se sube nada a ningún sitio.
scripts/embed_search.py realiza cuatro acciones: doctor verifica el servidor, init guarda la
conexión, index incrusta archivos en una caché y search los clasifica según la consulta.
Configuración local
La configuración reside en config.json, nunca en este archivo:
- Linux y macOS:
~/.config/gemma-embed-search/config.json - Windows:
%USERPROFILE%\.config\gemma-embed-search\config.json
Lee ese archivo primero. Si contiene url y model, todos los comandos posteriores funcionan sin
necesidad de banderas de conexión y puedes saltarte el Paso 2.
Si falta o está incompleto, pide al usuario la URL del servidor y la carpeta a indexar, ejecuta
doctor para listar los modelos que realmente ofrece el servidor, y luego ejecuta init para
escribir el archivo. init fusiona, por lo que es seguro añadir una configuración a la vez.
Nunca adivines un nombre de modelo.
Copiar config.example.json de esta carpeta a esa ruta y editarlo hace el mismo trabajo
que init, para un usuario que prefiera editar el archivo directamente. Añade "api_key" allí solo si
el servidor la necesita.
Nunca guardes la configuración dentro de la propia carpeta de la habilidad. Al actualizar la habilidad se reemplaza cada archivo en ella, y cualquier dato escrito allí se perderá.
Lista de verificación
Progreso:
- Paso 1: Confirmar el servidor y elegir un nombre de modelo (
doctor) - Paso 2: Guardar la conexión (
init) - Paso 3: Indexar una prueba de 20 archivos y revisar una consulta
- Paso 4: Indexar toda la carpeta
- Paso 5: Responder a la consulta real del usuario, con
--htmlpara que pueda ver los resultados
Omite el Paso 2 si config.json ya tiene url y model.
Ejecuta el script con uv run scripts/embed_search.py (instala Pillow desde los metadatos
en línea del script) o python3 scripts/embed_search.py si Pillow ya está disponible.
Paso 1 — encontrar el servidor y el nombre del modelo. Nunca adivines el nombre del modelo; lée la información del servidor.
uv run scripts/embed_search.py --url http://127.0.0.1:1235 doctor
doctor muestra los modelos que ofrece el servidor y prueba un embedding. Si el usuario aún no ha
iniciado un servidor, lee references/setup.md y dale el comando
para su modelo.
Paso 2 — guardarlo para que las llamadas posteriores no necesiten banderas. Pasa --api-key solo si el servidor
lo requiere; se escribe en el archivo de configuración con modo 0600. Pasa --root en cualquier comando
posterior para trabajar en una carpeta diferente sin cambiar lo guardado.
uv run scripts/embed_search.py --url http://127.0.0.1:1235 --model <nombre-del-doctor> init --root <carpeta>
uv run scripts/embed_search.py index --limit 20
Paso 3 — prueba antes del proceso largo. Indexar es el paso costoso: aproximadamente 0.25 s por imagen en una GPU de escritorio, por lo que 10 000 archivos son unos 40 minutos. Indexa 20 archivos, ejecuta una consulta y confirma que los resultados sean correctos antes de comprometerte con el proceso completo.
Paso 4 — indexación completa. Volver a ejecutar index solo incrusta archivos nuevos o modificados, por lo que una
interrupción se reanuda automáticamente.
uv run scripts/embed_search.py index
Paso 5 — búsqueda.
uv run scripts/embed_search.py search "un labrador negro en una playa" --top 20 --html hits.html
Recetario de consultas
| Intención | Comando |
|---|---|
| Búsqueda semántica simple | search "un mercado nocturno concurrido" |
| Dos facetas que ambas deben cumplirse | search "una mujer" --must "el color amarillo" |
| Sinónimos para que una frase no domine | search "una mujer" --also "una niña" --also "retrato femenino" |
| Encontrar cada imagen que contenga X | search "personajes con pelo rojo" --top 60 --html hits.html |
| Sujeto más una restricción de color real | search "una mujer" --color amarillo --min-color 0.05 |
| Mayormente monocromático o fotogramas oscuros | search "cualquier imagen" --max-color azul --modality image |
| Solo un tipo de archivo | search "sonidos de sirena" --modality audio |
| Legible por máquina para trabajo posterior | search "..." --json --top 50 |
| Más rápido, puntuación ligeramente menos precisa | search "..." --dims 256 |
--also promedia vectores de paráfrasis en una sola consulta. --must mantiene la puntuación de la
faceta más débil, que es cómo se expresa AND. Usa --also para sinónimos y --must para
condiciones independientes.
Interpretación de la salida
La salida simple es puntuación [modalidad] ruta, de la mejor a la peor. Las ejecuciones con color insertan la
proporción de píxeles después de la puntuación. --json emite {"query", "index", "total", "filtered_out", "results": [{"rank", "score", "color", "modality", "path"}]} en stdout; todo el progreso va a stderr,
por lo que stdout siempre se puede redirigir limpiamente a jq.
Las puntuaciones de coseno de esta familia de modelos se sitúan entre aproximadamente 0.3 y 0.8. El número absoluto importa poco; la brecha entre aciertos y fallos es lo que realmente cuenta. Si la parte superior de la lista es incorrecta, la consulta es incorrecta; reformúlala en lugar de confiar en la clasificación. Nunca presentes una lista larga como gualmente buena: indica dónde terminan los resultados fiables y comienzan las suposiciones.
Una lista corta no es la respuesta completa. Cada archivo indexado obtiene una puntuación, por lo que total en la
salida cuenta todo el corpus y nunca te dice cuántos resultados son plausibles. Encuentra el escalón — el punto donde las puntuaciones dejan de caer abruptamente. Si la lista que mostraste termina antes de él,
di que los resultados están truncados y ofrece una ejecución más larga: un --top más grande solo cuesta una
hoja de contacto más, no otra indexación. Respeta un número que el usuario nombre, y aún así indica el límite que
aplicaste. Nunca afirmes "no hay ninguno" sin una lista ampliada, --top 100 o más, que alguien realmente haya
revisado.
Para una revisión visual, ofrece siempre --html: escribe una hoja de contacto de miniaturas con
puntuaciones y nombres de archivo que el usuario puede abrir en el navegador. Un --html sin más escribe hits.html
en el directorio de trabajo; --html ARCHIVO establece la ruta. Las miniaturas se incrustan como base64, por lo que
la hoja es autónoma y se puede transportar por sí sola. La hoja incrusta miniaturas reales de los archivos
coincidentes, por lo que trátala como una copia de esa parte de la biblioteca: mantenla fuera del control de versiones
y de cualquier cosa que reenvíes. Tienen 512 px de ancho por defecto; aumenta
--thumb-width para una inspección detallada.
Errores comunes
- Una palabra de color dentro del texto de la consulta es una pista suave, no un filtro.
"una mujer con tema amarillo"clasifica a una mujer con una chaqueta naranja primero. Usa--color amarillo --min-color 0.05para una restricción real; se calcula a partir de píxeles, no del modelo. - Una palabra de estilo también es una pista suave, y más débil.
"una mujer fotorrealista con pelo rojo"clasifica una ilustración a tinta de una mujer pelirroja primero, porque los sustantivos del sujeto predominan sobre el estilo. Mueve el estilo a--mustpara que se puntúe como su propia faceta y fija el atributo visual con--color. Ninguno es un filtro real:--musttoma el mínimo entre las facetas, por lo que presionar mucho en una sacrifica la otra. - Varios sujetos en un solo fotograma se mezclan en un único vector, por lo que el fotograma obtiene peor puntuación en una
consulta de un solo sujeto que un fotograma dedicado a ese sujeto: un retrato de una mujer pelirroja
junto a un hombre puede estar muy abajo en una búsqueda de
"mujer con pelo rojo"mientras se clasifica cerca de la parte superior de"personajes con pelo rojo". Los sinónimos de la misma idea singular no ayudan; la forma plural o colectiva sí lo hace. Amplía--topcuando la pregunta sea "encontrar todo lo que contenga X". --colornecesita que el índice contenga estadísticas de color, que soloindexcalcula. Un índice construido con una versión anterior informa 0.0 para todo: vuelve a indexar con--forcesi el filtrado de color excluye silenciosamente cada archivo.- La indexación y la consulta deben usar el mismo modelo. Cambiar
--modelmezcla silenciosamente vectores incompatibles; vuelve a indexar con--forcedespués de cualquier cambio de modelo y anota el modelo enstats. - El servidor debe ejecutar el modelo de embedding con agrupación de media (
mean pooling) y su proyector de visión (--mmproj) cargado. Sin el proyector, las solicitudes de imagen fallan o devuelven un vector que ignora la imagen.doctorverifica que el texto funciona; ejecuta una consulta de imagen para verificar la visión. - Las imágenes se recodifican a JPEG con el lado más largo de 1536 antes de enviarse. La recodificación es
obligatoria, no cosmética: los servidores suelen rechazar WebP, archivos de 16 bits o mal etiquetados, y
Pillow los lee en su lugar. El modelo no tiene límite de píxeles — el servidor remuestrea cada imagen
a un presupuesto fijo de tokens de visión — por lo que
--resizeintercambia tamaño de subida por fidelidad, no corrección. Los números medidos y los detalles están en references/setup.md. - Los formatos HEIC y RAW de cámara no se leen a menos que Pillow se haya compilado con el complemento. El
script registra
skip <archivo>: cannot identify image filey continúa; compruebaskipped_errorsen el resumen del índice en lugar de asumir una cobertura completa. searchen una carpeta que nunca se indexó sale con código 4 y un mensaje. No trates una lista de resultados vacía como "sin coincidencias" hasta que el recuento del índice enstatsparezca correcto.- El audio está limitado por el contexto del servidor: aproximadamente 5.5 minutos por clip a 25 tokens por segundo. Los archivos más largos fallan como un error de solicitud, no como una falta de coincidencia.
- Las puntuaciones no son comparables entre distintos corpus ni entre distintas cuantizaciones. Nunca prometas un
umbral; ajusta
--min-colory--topen función de lo que vea el usuario.
Referencia del script
doctor Verifica el servidor, lista modelos, prueba un embedding
init [--root DIR] Guarda url, model, key y root por defecto en el archivo de configuración
index --root DIR Incrusta archivos nuevos y modificados (incremental, reanudable)
[--modality auto|image|audio|text] [--include '*.png,sub/*.jpg']
[--exclude-dir node_modules,.git] [--limit N] [--batch 16] [--resize 1536]
[--force] [--compact]
search "consulta" Clasifica archivos indexados; imprime puntuación, modalidad, ruta
[--also P]... [--must P]... [--color NOMBRE --min-color F | --max-color F]
[--modality image] [--dims 512|256|128] [--top 20] [--offset 0]
[--json] [--html [ARCHIVO]] [--thumb-width 512]
stats Recuento de entradas, mezcla de modalidades, modelo, tamaño del índice
Códigos de salida: 0 éxito, 2 error de uso, 3 servidor inalcanzable o autenticación rechazada,
4 índice faltante, 5 nada que hacer, 6 error del servidor durante la ejecución. Ejecuta
scripts/embed_search.py <comando> --help para la documentación completa de banderas.
La resolución de configuración es: bandera > entorno (EMBED_SEARCH_URL, EMBED_SEARCH_MODEL,
EMBED_SEARCH_API_KEY, EMBED_SEARCH_ROOT) > archivo de configuración en
~/.config/gemma-embed-search/config.json. El índice por defecto es
~/.cache/gemma-embed-search/<carpeta>-<hash>.jsonl, un registro JSON por archivo, por lo que es
seguro mantener varios índices para diferentes carpetas.
Más información
- references/setup.md — iniciar un servidor, modelo y requisitos de banderas, qué significa
doctor - references/query-guide.md — construcción de consultas, lógica de facetas, umbrales de color, ajuste con resultados reales
- references/errors.md — cada código de salida y la solución para cada modo de fallo