The situation
A company runs a support knowledge base for a product sold across Europe and Asia. Articles are written in whatever language the author works in. Roughly half are English, a quarter French, the rest split across Japanese, German and Spanish. Customers ask questions in their own language too, and the best answer often sits in an article written in a different one. A French customer asking about a billing edge case may be best served by the definitive English article.
The team wants semantic search over the whole corpus, backed by a vector store, feeding a Retrieval-Augmented Generation assistant on Amazon Bedrock. The first prototype embedded everything with an English-only model. It looked fine in the demo, because the demo was in English. In practice a French query returns French articles and misses the English one that answers it, and a Japanese query retrieves almost nothing useful. The vectors for “how do I cancel my subscription” and “comment annuler mon abonnement” land in different regions of the space, so Cosine similarityA measure of how closely two vectors point the same way, used as the default score for “how related is this text?”. between them is near zero.
The decision in front of them is which embedding model to index and query with. That choice sits upstream of the vector store, the distance metric, the storage bill, and whether cross-language retrieval works at all. Re-embedding a large corpus later is slow and expensive.
What actually matters
“Multilingual” covers two separate capabilities, and the gap between them is where this scenario goes wrong. One is per-language coverage: the model handles French text and English text competently, each on its own. The other is cross-lingual alignment, where text with the same meaning lands in the same region of the space whatever language it was written in. A model can be strong on the first and weak on the second. Vendor language lists describe the first.
AWS makes that distinction explicit in its own documentation. Titan Text Embeddings V2 lists more than a hundred languages, and the same page describes the model as optimised for English, marks the multilingual support as preview, and states that cross-language queries return sub-optimal results. A language appearing on a list is not a promise that a query in it will reach a document in another.
Whether you need cross-lingual matching at all is worth deciding deliberately. If every French customer should only ever see French articles, one shared space is not a requirement. Detect the query language, route to a per-language index, and let an English model and a French model each do their own job. That design keeps each index small and multiplies the number of them, and it breaks the moment the best answer exists only in another language. This knowledge base has exactly that shape: one canonical article per topic, in whatever language it was written. Naming the requirement first stops you partitioning a corpus that needed joining.
Embedding dimensionHow many numbers each embedding vector holds – fewer means a smaller, cheaper, faster index and slightly blurrier matching. is the next axis. A higher-dimensional vector can capture more distinction, and every dimension adds storage in the vector store and work for the Nearest-neighbour searchFinding the vectors closest to a query vector; at scale it’s approximated, trading a little accuracy for a lot of speed. on each query. Some models let you choose the output dimension. Across millions of stored vectors that choice moves the storage bill and the query latency together, so on a large corpus it is a real control.
Maximum input length per call decides how you chunk. The limits here differ by orders of magnitude, from 512 tokens to roughly 128,000, and the limit sets the ceiling on ChunkingSplitting documents into retrievable pieces before embedding them – small enough to match precisely, big enough to still make sense.. Past it the text is truncated, and the tail of a long article never reaches the vector. Multilingual tokenisation makes this worse. Japanese and other non-Latin scripts use more tokens per unit of meaning, so less content fits than an English character count suggests.
Two operational constraints sit underneath all of it. The model that indexes the corpus and the model that embeds queries must be the same model, because vectors from two models live in incompatible spaces and comparing them returns meaningless similarity. And the vector store’s distance metric has to match what the model was trained for. These models are trained so that cosine similarity, or inner product on Normalised vectorsScaling every vector to the same length, so comparisons depend only on direction and cosine and dot-product rank results identically., expresses relatedness. Configure the index for Euclidean distance instead, or skip normalisation where the model assumes it, and retrieval quality drops with no error to show for it. Results still come back. They are just worse ones.
What we’ll filter on
- Cross-lingual retrieval, does same-meaning text from different languages land close together, and do we need that or only per-language search?
- Language coverage, is every language in the corpus handled, and is that support generally available rather than preview?
- Maximum input length, how much text fits in one call, and what does that force on chunk size given heavier non-Latin tokenisation?
- Embedding dimension, is the vector size fixed or selectable, and what does the choice do to index size and query latency?
- Indexing and query consistency, can we guarantee the same model on both sides, with a distance metric that matches its training?
The landscape
English-only models. Cohere Embed English v3 (cohere.embed-english-v3) takes 512 tokens per text and returns 1,024 dimensions. Models in this class produce strong vectors for their one language and poor ones for anything else. Fine for a genuinely single-language corpus, wrong here, and the failure is hard to spot because an English demo looks healthy.
Amazon Titan Text Embeddings V2 (amazon.titan-embed-text-v2:0). Accepts up to 8,192 tokens or 50,000 characters, emits 1,024, 512 or 256 dimensions, and normalises the output by default. The long input and the selectable dimension are both genuinely useful. The language support is the problem. AWS documents the model as optimised for English, lists the hundred-plus other languages as preview, and states that cross-language queries return sub-optimal results. Good for a large English corpus where vector size drives cost. Not the model for a French query that has to find an English article.
Cohere Embed Multilingual v3 (cohere.embed-multilingual-v3). AWS describes it as supporting over 100 languages for cross-lingual search and classification, which is the property this corpus needs. It returns 1,024 dimensions, fixed, and its context window is 512 tokens, near 2,048 characters, so chunking has to be tight. The input_type parameter separates search_document from search_query, so an article and a short question are embedded for their different roles.
Cohere Embed v4 (cohere.embed-v4:0). The newer model in the same family, multimodal over text and images, with the same input_type values. It accepts a 128K-token context and selectable output dimensions of 256, 512, 1,024 or 1,536, defaulting to 1,536, and AWS still recommends smaller chunks for retrieval. Neither the AWS model card nor Cohere’s own page states a language count for it, so on the requirement that decides this scenario it is undocumented rather than confirmed.
Per-language partitioned indexes. Not a model but a design: detect the language, route to a language-specific index built with a model chosen for it. Best single-language quality and the smallest indexes, several models and pipelines to run, and no way to match a query to a document in another language. Right only when languages must stay separate by policy or product design.
The metric requirement is not a menu item. Every option above imposes it. Read what the model was trained for, then configure the store to match.
Evaluation
Side by side
| Option | Language coverage | Cross-lingual retrieval | Max input | Dimensions | Best for |
|---|---|---|---|---|---|
| Cohere Embed English v3 | ✗ | ✗ | 512 tokens | 1,024 | Single-language English corpora |
| Titan Text Embeddings V2 | ✓ (preview) | ✗ | 8,192 tokens | 1,024 / 512 / 256 | Large English corpus where vector size drives cost |
| Cohere Embed Multilingual v3 | ✓ 100+ | ✓ | 512 tokens | 1,024 | Cross-lingual retrieval over many languages |
| Cohere Embed v4 | Not stated | Not stated | 128K tokens | 1,536 / 1,024 / 512 / 256 | Long inputs and dimension control |
| Per-language indexes | ✓ (each alone) | ✗ | Per model | Per model | Languages kept separate by design |
Read against this knowledge base, cross-lingual retrieval is required, and that removes the English model, Titan V2 and the partitioned design. What is left is the Cohere pair, and the choice between them turns on chunk size against documented language coverage.
The solution
Cohere Embed Multilingual v3 is the default for this corpus. AWS documents it as covering over 100 languages for cross-lingual search, which takes in all five languages in play, and that documented property is what the scenario hangs on. Embed articles with input_type set to search_document and incoming questions with search_query. The model prepends different tokens for each, which sharpens the match between a short question and a long article.
Its 512-token context window is the constraint to design around, near 2,048 characters of English and fewer of Japanese. Chunk to comfortably under it. The truncate parameter defaults to END, so an over-long chunk is shortened from the tail with no error raised. Set truncate to NONE during indexing and an over-length input returns an error instead, which turns a retrieval-quality problem into a build-time one.
Cohere Embed v4 is the one to evaluate when that window is the binding constraint or when index size is. It takes a 128K-token context and lets you pick 256, 512, 1,024 or 1,536 dimensions, so you can measure retrieval quality at one size and re-embed smaller if it holds. Because neither AWS nor Cohere publishes a language list for it, treat cross-lingual quality as something to measure on your own corpus rather than something documented. Run a set of known French-question-to-English-article pairs through both models and compare the ranks.
Titan Text Embeddings V2 is the easy mistake here. Its language list includes French, Japanese, German and Spanish, its 8,192-token window suits long articles, and its selectable dimension is a genuine cost control. None of that meets the requirement. AWS documents the model as optimised for English, marks the wider language support as preview, and says cross-language queries return sub-optimal results. Keep it for a single-language index.
Three decisions are not optional whichever model you use. Use the same model for indexing and for queries, because a query vector from a different model lands in an incompatible space and retrieval collapses. Match the vector store’s metric to the model, normalising and using cosine or inner product on both sides. And chunk to the real token limit, remembering that French, German and especially Japanese use more tokens per unit of meaning than English, so a chunk size that fits an English article truncates its Japanese equivalent.
Worked example
Take the concrete failure. An English article, “Cancelling your subscription”, is the canonical answer for billing cancellations. A French customer asks “comment annuler mon abonnement”. Under the first prototype every article was embedded with an English-only model, so the French query produced a vector nowhere near the English article’s. Cosine similarity came back near zero. The retriever returned three loosely related French articles instead.
Re-index the corpus with cohere.embed-multilingual-v3. Split articles into chunks that fit inside 512 tokens with room to spare, embed each with an input_type of search_document, and store the 1,024-dimension vectors in an index configured for cosine similarity. At query time, embed the customer’s question with the same model and an input_type of search_query. The French question and the English article now map to nearby points, because the model was trained so that translations align. The nearest neighbour is the English article, and the assistant answers the French customer from the definitive English content.
Two failure modes are worth checking for afterwards. If Japanese articles retrieve worse than French ones, measure the token counts: a chunk size derived from English character counts will be truncating them. If quality drops after a model change on one side only, the pairing has broken, and the French-misses-English gap reopens in a form that is harder to diagnose the second time.
What’s worth remembering
- “Multilingual” covers two properties, per-language competence and cross-lingual alignment, and only the second lets a query in one language retrieve a document in another.
- AWS documents Titan Text Embeddings V2 as optimised for English with its hundred-plus other languages in preview, and warns that cross-language queries return sub-optimal results.
- Cohere Embed Multilingual v3 is the Bedrock model AWS documents for cross-lingual search, at 512 tokens in and 1,024 dimensions out.
- Input limits differ by orders of magnitude, 512 tokens for Cohere Embed v3 against 8,192 for Titan V2 and 128K for Cohere Embed v4, and non-Latin scripts use more tokens per unit of meaning.
- Use the same model for indexing and querying, with a distance metric that matches its training; vectors from two models are not comparable.