-
Type:
New Feature
-
Resolution: Unresolved
-
Priority:
Major - P3
-
None
-
Affects Version/s: None
-
Component/s: Symfony
-
None
-
3
-
None
-
PHP Drivers
-
None
-
None
-
None
-
None
-
None
-
None
Summary
symfony/ai-store ships a reranking abstraction, but no Voyage AI bridge implements it. A Symfony user who wants to add a reranking stage to a Voyage-based retrieval pipeline currently has to hand-roll an HTTP client, a ModelClient and a ResultConverter.
Verified against symfony/ai-store 0.14.0 / symfony/ai-voyage-platform 0.14.0.
What already exists
The generic machinery is all there and is provider-agnostic:
- Symfony\AI\Store\Reranker\RerankerInterface — rerank(string $query, array $documents, int $topK = 5): array
- Symfony\AI\Store\Reranker\Reranker — delegates to PlatformInterface::invoke() with the payload ['query' => ..., 'texts' => [...]] and calls ->asReranking() on the result
- Symfony\AI\Platform\Reranking\RerankingEntry and Symfony\AI\Platform\Result\RerankingResult
- Symfony\AI\Store\EventListener\RerankerListener — hooks PostQueryEvent, so a reranker can slot into Retriever without touching the store
What is missing
In symfony/ai-voyage-platform:
- ModelCatalog.php has no rerank-* entries. Voyage currently offers rerank-3, rerank-3-lite, rerank-2.5, rerank-2.5-lite, rerank-2, rerank-2-lite.
- ModelClient.php only routes to /v1/embeddings and /v1/multimodalembeddings, selected on Capability::INPUT_MULTIMODAL. There is no /v1/rerank path.
- ResultConverter.php throws RuntimeException('Response does not contain embedding data.') unless the payload has a data key, and always returns a VectorResult — so ->asReranking() would throw even given a valid rerank response.
Capability::RERANKING exists but has zero usages across the installed tree. Per the ai-bundle changelog only the fireworks and together bridges ship reranking config today.
In symfony/ai-bundle:
- config/options.php has no reranker node, and the retriever node exposes only vectorizer and store — no way to attach a reranker declaratively.
- RerankerListener is never registered as a service, so even the generic path needs manual wiring.
Proposed work
- Add the rerank-* models to the Voyage ModelCatalog with Capability::RERANKING.
- Route reranking models to POST /v1/rerank in ModelClient (query, documents, model, top_k, return_documents).
- Return a RerankingResult from ResultConverter when the response carries results[].relevance_score / results[].index.
- Optionally: a reranker config node in ai-bundle plus a reranker key on retriever, and auto-registration of RerankerListener.
Why it matters
Reranking is the highest-leverage, lowest-effort retrieval improvement available — a cross-encoder scores query and document jointly rather than independently, and is the standard second stage after vector search. MongoDB also ships Voyage rerankers natively via the $rerank aggregation stage (MongoDB 8.3+, public preview), so the Atlas and Symfony stories do not currently line up: an Atlas user on 8.3 gets reranking in the pipeline, while a Symfony user on any other cluster has no supported path at all.
Raised while preparing a conference talk extending the SymfonyCon Amsterdam artefact-matcher demo with a reranking stage, where this gap blocked the straightforward implementation.
References
- Voyage reranker docs: https://docs.voyageai.com/docs/reranker
- Voyage models on MongoDB docs: https://www.mongodb.com/docs/voyageai/models/
- Atlas $rerank stage: https://www.mongodb.com/docs/vector-search/query/aggregation-stages/rerank/