Cómo mejorar la calidad de recuperación para texto japonés con Sudachi, Milvus/Zilliz y AWS Bedrock
Esta publicación se publicó originalmente en Qiita y se traduce y publica aquí con permiso.
Introducción
Cuando empecé a crear sistemas de Retrieval-Augmented Generation (RAG) para usuarios japoneses, me encontré con un problema que probablemente le resulte familiar a cualquiera que haya trabajado con texto en japonés: la precisión de búsqueda simplemente no es tan directa como en inglés. El idioma tiene peculiaridades—variaciones ortográficas, vocales largas, escrituras mezcladas, diferencias en las formas superficiales—que rompen con frecuencia tanto los métodos de recuperación densos como los dispersos cuando se usan de forma aislada.
La búsqueda vectorial densa es excelente para comprender el contexto y la similitud semántica, pero se desmorona rápidamente cuando necesitas coincidencias exactas—números de modelo, identificadores de artículos legales, códigos internos o entidades muy específicas como “金商法第37条 (Artículo 37 de la Ley de Instrumentos Financieros y Bolsa).” Los métodos basados en palabras clave como BM25 manejan bien estos casos, pero no pueden seguir el ritmo cuando la entrada incluye pequeñas variaciones ortográficas (“サーバー” frente a “サーバ”) o cuando la misma idea puede expresarse de múltiples formas.
Para solucionarlo, creé un pipeline de búsqueda híbrida que combina las fortalezas de ambos enfoques. La solución utiliza:
Sudachi: un tokenizador japonés que proporciona normalización y tokenización estable en textos inconsistentes.
Zilliz Cloud (el servicio Milvus totalmente gestionado): una base de datos vectorial de alto rendimiento que admite vectores densos, vectores dispersos e incluso generación automática de vectores BM25, lo que facilita mucho la implementación de la búsqueda híbrida.
AWS Bedrock: utilizado para generar embeddings densos de alta calidad (Titan Embeddings v2), que forman el lado semántico del pipeline de recuperación.
En esta publicación, explicaré cómo combiné estas piezas para crear un sistema de búsqueda híbrida en japonés de alta precisión. También incluiré un ejemplo práctico para que puedas probar el mismo flujo de trabajo por tu cuenta y adaptarlo a tus propios proyectos RAG.
Descripción general de la arquitectura
El sistema de búsqueda híbrida de este artículo se basa en una pila simple pero eficaz. Cada componente resuelve un problema específico que surge al tratar con texto en japonés, y juntos forman un pipeline de recuperación que equilibra la comprensión semántica con la precisión de coincidencia exacta. Aquí tienes el desglose de cómo se ve la pila y por qué importa cada parte.
SudachiPy — Tokenizador / Análisis morfológico
El texto en japonés suele contener ortografías inconsistentes, irregularidades de espaciado y variaciones en la notación. En lugar de depender de una tokenización ingenua, uso SudachiPy y su API normalized_form() para limpiarlo todo. Esto garantiza que “サーバー” y “サーバ” se asignen al mismo token normalizado, y que los documentos que de otro modo se pasarían por alto sigan apareciendo en los resultados de búsqueda. Este único paso mejora drásticamente el recall en general.
Zilliz Cloud (Managed Milvus): Una base de datos vectorial de alto rendimiento
Milvus es la base de datos vectorial de código abierto más adoptada, con más de 43K estrellas en GitHub y un gran ecosistema de colaboradores. Zilliz Cloud utiliza el mismo núcleo de Milvus, pero elimina todo el trabajo operativo—configuración de clústeres, autoescalado, ajuste de rendimiento, copias de seguridad, actualizaciones de versión—sin dejar de exponer la misma API de Milvus. En la práctica, eso significa que puedo desarrollar localmente con Milvus de código abierto y desplegar exactamente el mismo código en Zilliz Cloud cuando necesito un entorno de nivel de producción.
Esto importa porque muchos proyectos de búsqueda vectorial se topan con el mismo obstáculo: el prototipo funciona, pero escalarlo se vuelve demasiado caro o demasiado impredecible. Los servicios de búsqueda PaaS totalmente gestionados como Azure AI Search o los almacenes vectoriales propietarios suelen convertirse en cuellos de botella de coste mucho antes de que se cumplan los requisitos de rendimiento. Zilliz Cloud ofrece un camino más eficiente: mayor rendimiento, menor latencia y más control sobre la distribución de los datos, sin el aumento progresivo de costes que suele aparecer a escala.
En esta arquitectura, Zilliz Cloud se encarga de todo el almacenamiento y la recuperación de embeddings. Es compatible con:
Búsqueda vectorial densa para similitud semántica
Búsqueda vectorial dispersa para recuperación basada en palabras clave
A partir de Milvus v2.4, la base de datos también incluye una función Function que genera automáticamente vectores dispersos BM25 a partir de texto sin procesar. Esto supone una gran ventaja operativa. No tengo que calcular BM25 del lado del cliente, mantener pipelines de indexación adicionales ni sincronizar metadatos entre varios sistemas. Todo —desde embeddings densos hasta BM25 y ranking híbrido— vive en una sola base de datos, lo que mantiene todo el flujo de trabajo de recuperación simple, rápido y fácil de mantener.
AWS Bedrock (Titan Embeddings v2): El modelo de embeddings
Para embeddings vectoriales densos, uso Titan Embeddings v2 de AWS Bedrock. Funciona bien en varios idiomas y maneja texto japonés de forma fiable, lo cual es importante cuando estás generando embeddings de contenido mixto como consultas cortas, documentos de políticas largos, descripciones de productos y texto tipo FAQ.
Reciprocal Rank Fusion (RRF): El método de reranking
La búsqueda híbrida solo funciona si puedes combinar de forma significativa los resultados de la búsqueda densa y dispersa, y los dos espacios de puntuación son fundamentalmente diferentes. RRF (Reciprocal Rank Fusion) resuelve esto de forma limpia al fusionar resultados en función del ranking en lugar de las puntuaciones sin procesar. Produce resultados híbridos estables y fáciles de razonar sin ningún ajuste manual de pesos ni trucos de normalización.
Tutorial de búsqueda híbrida apto para principiantes
Con la arquitectura ya explicada, pasemos a algo que puedas ejecutar de verdad. Preparé un repositorio de GitHub con todo el código y los datos de ejemplo que necesitas, así que la configuración es intencionalmente ligera. Una vez que pongas en marcha un clúster gratuito de Zilliz Cloud y agregues tu clave de API de AWS Bedrock, podrás probar tres modos de recuperación en paralelo:
Búsqueda vectorial densa
Búsqueda de texto completo dispersa (BM25)
Búsqueda híbrida (fusión RRF)
Todo el flujo de trabajo se ejecuta a bajo coste: solo las llamadas de embeddings de Bedrock generan cargos.
Paso 1: Clona el repositorio desde GitHub
Primero, clona el repositorio:
git clone [https://github.com/Beginnersguide138/rag-with-sudachi.git](https://github.com/Beginnersguide138/rag-with-sudachi.git)
Entra en el directorio del proyecto y configura el entorno de Python:
cd rag-with-sudachi
uv sync # Install Python dependencies using uv
cp .env.example .env # Create an environment file based on the template
Paso 2: Configura Zilliz Cloud (nivel gratuito)
Zilliz Cloud se ejecuta en todos los principales proveedores de nube: AWS, GCP y Azure. Puedes registrarte directamente en el sitio web de Zilliz o suscribirte a través de los respectivos marketplaces en la nube. En este tutorial, usaré la ruta de AWS Marketplace, ya que es una forma rápida de poner en marcha un clúster Milvus totalmente gestionado sin tocar ninguna infraestructura.
- Ve al listado de Zilliz Cloud en AWS Marketplace y haz clic en “Try for free.” Esto crea un clúster Milvus serverless sin coste:
nunca se convertirá automáticamente en un plan de pago
Tiene algunas limitaciones (p. ej., funciones de monitoreo restringidas)
El clúster es más que suficiente para este tutorial de búsqueda híbrida
2. Abre la consola de Zilliz Cloud después de que se complete la suscripción:
Crea una nueva Organización (solo un contenedor lógico para tus proyectos).
Verás un clúster serverless gratuito ya aprovisionado.
Obtén el Cluster Endpoint y la API Key; los necesitarás al conectarte desde tu código.
Paso 3: Configurar variables de entorno
Pega tus credenciales de Zilliz y Bedrock en el archivo .env:
# Zilliz Cloud connection
ZILLIZ_CLOUD_URI=https://your-cluster-id.serverless.region.cloud.zilliz.com
ZILLIZ_CLOUD_API_KEY=your-api-key-here
# AWS Bedrock short-term API key
AWS_BEARER_TOKEN_BEDROCK=bedrock-api-key-your-token-here
Nota de código: Los tokens a corto plazo de Bedrock caducan cada 12 horas. Esto es intencional: reducen el radio de impacto de la exposición de credenciales y son ideales para el desarrollo local.
Paso 4: Iniciar el Notebook o ejecutar el script
Abre el repositorio en VS Code. El tutorial principal se encuentra en:
notebooks/hybrid_search_with_bm25.ipynb
Si prefieres un flujo de trabajo de Python puro en lugar de Jupyter Notebook, puedes ejecutar:
python run_hybrid_search.py
Ambas versiones:
Crean el esquema de Milvus
Aplican la normalización de Sudachi
Insertan vectores densos y dispersos
Comparan los resultados de la búsqueda semántica, por palabras clave e híbrida
Detalles técnicos
1. La clave para el procesamiento del japonés: normalización de texto con Sudachi
En los sistemas de recuperación para contenido en japonés, una gran parte de la precisión depende de cómo se preprocesa el texto durante la indexación. El texto extraído de archivos PDF a menudo contiene espaciado inconsistente, variaciones ortográficas o ruido, lo que frecuentemente provoca coincidencias perdidas y una menor recuperación.
Para abordar este problema, esta implementación utiliza la función de normalización de Sudachi. Este proceso estandariza los tokens antes de la indexación para que el sistema de búsqueda pueda tratar diferentes grafías y representaciones como equivalentes.
Código: envoltorio de normalización de Sudachi
class SudachiAnalyzer:
def __init__(self):
self.tokenizer = dictionary.Dictionary(dict="core").create()
self.mode = tokenizer.Tokenizer.SplitMode.C
def analyze(self, text: str) -> str:
if not text:
return ""
tokens = self.tokenizer.tokenize(text, self.mode)
# Return as a space-separated string
return " ".join(\[t.normalized_form() for t in tokens if t.surface().strip()\])
analyzer = SudachiAnalyzer()
Por qué importa la normalización
El uso de normalized_form() unifica variaciones como:
Katakana: 「サーバー」 ⇔ 「サーバ」
Notación numérica: 「第1条」 ⇔ 「第一条」
Ruido de espaciado en PDF: 「第 一 条」(不自然なスペース) ⇔ 「第一条」
Sin normalización, estas variaciones provocan:
Coincidencias BM25 perdidas
Tokenización incorrecta de vectores dispersos
Menor recuperación para consultas con estructura legal
Al normalizar tanto documentos como consultas, el sistema híbrido aumenta drásticamente la probabilidad de coincidencia.
2. Diseño del esquema en Zilliz Cloud (Milvus administrado)
Milvus, el núcleo de Zilliz Cloud, proporciona una función Function (disponible en v2.4 y posteriores) que genera automáticamente vectores dispersos basados en BM25 en la base de datos. Esto elimina la necesidad de precalcular vectores BM25 en el lado del cliente.
Definición del esquema
# Create schema (auto ID disabled for explicit ID assignment)
schema = MilvusClient.create_schema(auto_id=False, enable_dynamic_field=True)
# Field definitions
schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True)
schema.add_field(
field_name="text",
datatype=DataType.VARCHAR,
max_length=65535,
enable_analyzer=True,
analyzer_params={
"tokenizer": "whitespace"
}, # Sudachi already provides whitespace-separated input
)
schema.add_field(
field_name="dense_vector", datatype=DataType.FLOAT_VECTOR, dim=1024
) # Titan Embeddings v2 outputs 1024 dimensions
schema.add_field(field_name="sparse_vector", datatype=DataType.SPARSE_FLOAT_VECTOR)
# Define the BM25 function
bm25_function = Function(
name="text_bm25_emb",
input_field_names=\["text"\],
output_field_names=\["sparse_vector"\],
function_type=FunctionType.BM25,
)
schema.add_function(bm25_function)
Este diseño elimina la necesidad de pasar explícitamente vectores dispersos durante la inserción de datos, lo que reduce significativamente la complejidad operativa.
Al trasladar la generación de vectores BM25 al propio Milvus:
La canalización de ingesta se vuelve más sencilla
No se requiere ningún cálculo explícito de vectores dispersos
Evitas mantener código adicional de preprocesamiento
El escalado se vuelve mucho más fácil
Esto reduce significativamente la carga operativa.
Diseño de índices y estrategia de optimización
# Index definitions
index_params = client.prepare_index_params()
index_params.add_index(
field_name="dense_vector", index_type="HNSW", metric_type="COSINE"
)
index_params.add_index(
field_name="sparse_vector",
index_type="SPARSE_INVERTED_INDEX",
metric_type="BM25",
params={"inverted_index_algo": "DAAT_MAXSCORE"},
)
Índice de vectores densos: HNSW
HNSW (Hierarchical Navigable Small World) es un algoritmo ANN basado en grafos ampliamente utilizado en bases de datos vectoriales. Ofrece:
Recuperación de alta velocidad
Alta exhaustividad
Sólido rendimiento a escala
COSINE se utiliza como métrica de similitud porque Titan Embeddings opera en un espacio coseno normalizado.
Índice de vectores dispersos: índice invertido con optimización MaxScore
Los vectores dispersos utilizan una estructura tradicional de índice invertido. La optimización adicional DAAT_MAXSCORE proporciona:
Procesamiento documento a documento para un recorrido eficiente
Poda temprana de documentos que no pueden alcanzar las puntuaciones top-k
Reducción del cálculo sin comprometer la precisión
Esto conduce a una búsqueda BM25 significativamente más rápida.
3. Implementación de búsqueda híbrida usando RRF
Para fusionar de manera justa los resultados de búsquedas densas (semánticas) y dispersas (por palabras clave), el sistema utiliza Reciprocal Rank Fusion (RRF). RRF es robusto, fácil de aplicar y no requiere ajuste ni normalización entre tipos de puntuación.
Código de búsqueda híbrida
from pymilvus import AnnSearchRequest, RRFRanker
def search_hybrid(client, collection_name, query_text, query_vector, top_k=5):
# Normalize and tokenize the query using Sudachi
query_processed = analyzer.analyze(query_text)
# Dense semantic search request
req_dense = AnnSearchRequest(
data=\[query_vector\],
anns_field="dense_vector",
param={"metric_type": "COSINE"},
limit=top_k * 2,
)
# Sparse BM25 keyword search request
req_sparse = AnnSearchRequest(
data=\[query_processed\],
anns_field="sparse_vector",
param={"metric_type": "BM25"},
limit=top_k * 2,
)
# Perform hybrid search using RRF
res = client.hybrid_search(
collection_name=collection_name,
reqs=\[req_dense, req_sparse\],
ranker=RRFRanker(), # Fuse rankings using RRF
limit=top_k,
output_fields=\["text", "original_text"\],
)
return res\[0\]
Comparación de resultados de búsqueda reales
El tutorial evalúa los resultados utilizando documentos disponibles públicamente de la Agencia de Servicios Financieros de Japón. El notebook permite la comparación lado a lado de:
Búsqueda semántica (vector denso)
Búsqueda de texto completo (vector disperso)
Búsqueda híbrida (densa + dispersa mediante RRF)
Caso de estudio: consulta con muchas palabras clave
Consulta: “指定ADR機関が存在しない場合の苦情処理措置”
Nota: la consulta significa “Un procedimiento para la gestión de quejas cuando no existe una organización ADR designada.”
Resultados:
Búsqueda de vectores densos: A menudo devuelve pasajes conceptualmente relacionados, pero tiene dificultades para mostrar cláusulas regulatorias exactas.
Búsqueda dispersa BM25: Identifica correctamente documentos que contienen términos como “organización ADR designada” y “medidas de gestión de quejas”, clasificándolos en las posiciones más altas.
Búsqueda híbrida: Combina la capacidad de coincidencia precisa de BM25 con contexto relevante adicional recuperado mediante búsqueda densa.
Esto demuestra que la búsqueda solo densa corre el riesgo de pasar por alto resultados críticos cuando los usuarios consultan con terminología especializada. La búsqueda híbrida es esencial para la recuperación de documentos empresariales.
Resumen y aplicaciones
En este artículo, recorrimos una configuración práctica de búsqueda híbrida que combina normalización basada en Sudachi con Zilliz Cloud (Milvus gestionado). El objetivo era simple: crear una canalización de recuperación que funcione bien con texto japonés, donde importan tanto la similitud semántica como la coincidencia exacta. Al combinar vectores densos, vectores dispersos BM25 y fusión basada en RRF, el sistema se mantiene preciso, fácil de ejecutar y adaptable a cargas de trabajo reales de producción.
Beneficios clave
Robusto ante variaciones ortográficas: La normalización de Sudachi suaviza diferencias ortográficas, problemas de espaciado y ruido de extracción de PDF, evitando fallos comunes de recuperación en la búsqueda de texto japonés.
Baja sobrecarga operativa: Milvus Functions gestiona la generación de vectores dispersos BM25 dentro de la base de datos. Sin trabajos de preprocesamiento adicionales, sin servicio de búsqueda externo y sin lógica de indexación duplicada.
Alta precisión general: RRF combina recuperación densa y dispersa sin ajustes complejos de pesos. Obtienes resultados híbridos estables que gestionan con elegancia tanto consultas conceptuales como identificadores exactos.
Posibles casos de uso
Este enfoque híbrido destaca en escenarios en los que los usuarios pueden alternar entre consultas precisas y estructuradas y lenguaje abierto:
Búsqueda interna de políticas y manuales: Admite referencias exactas (por ejemplo, números de artículos) y, al mismo tiempo, gestiona consultas vagas o exploratorias.
Búsqueda de productos en comercio electrónico: Permite la búsqueda precisa por número de pieza y ofrece recomendaciones basadas en similitud.
Bases de conocimiento de atención al cliente: Coincide con términos estructurados como códigos de error y, aun así, interpreta la entrada natural del usuario (“画面が真っ黒です”, “ログインできない”).
El código fuente completo y el Jupyter Notebook utilizados en este artículo están disponibles en el siguiente repositorio: GitHub: rag-with-sudachi
El coste de probarlo todo es mínimo: solo se facturan las llamadas de embeddings de AWS Bedrock. El nivel serverless gratuito de Zilliz Cloud es suficiente para ejecutar todo el flujo de trabajo.
Si estás explorando la búsqueda híbrida para sistemas de producción o prototipos internos, este ejemplo es un excelente punto de partida.
Sigue leyendo

Creating Collections in Zilliz Cloud Just Got Way Easier
We've enhanced the entire collection creation experience to bring advanced capabilities directly into the interface, making it faster and easier to build production-ready schemas without switching tools.

8 Latest RAG Advancements Every Developer Should Know
Explore eight advanced RAG variants that can solve real problems you might be facing: slow retrieval, poor context understanding, multimodal data handling, and resource optimization.

DeepSeek-VL2: Mixture-of-Experts Vision-Language Models for Advanced Multimodal Understanding
Explore DeepSeek-VL2, the open-source MoE vision-language model. Discover its architecture, efficient training pipeline, and top-tier performance.



