Skip to content

[Store] Forward platform options from Retriever to the vectorizer - #2367

Open
wachterjohannes wants to merge 1 commit into
symfony:mainfrom
wachterjohannes:eve/retriever-platform-options
Open

wachterjohannes wants to merge 1 commit into
symfony:mainfrom
wachterjohannes:eve/retriever-platform-options

Conversation

@wachterjohannes

Copy link
Copy Markdown
Member
Q A
Bug fix? no
New feature? yes
Docs? yes
Issues -
License MIT

Retriever::createQuery() calls $this->vectorizer->vectorize($query) with no options, so nothing on the query side can reach the platform that does the embedding.

That is a problem for embedding models with asymmetric input modes. Cohere embeds a stored document and a search query differently, so that a short question lands next to the longer passage that answers it, and expects to be told which of the two it is looking at. Its default is search_document, which is right for indexing and wrong for retrieval. Today a Retriever embeds the query as if it were a document, and there is no option to change that. The results still look plausible, which is what makes it easy to miss: the two sides are simply misaligned.

The indexing side already has the answer. DocumentProcessor::process() reads a platform_options key out of its options and forwards it to the vectorizer. This does the same for the query side, so both halves of a RAG pipeline are configured the same way:

use Symfony\AI\Platform\Bridge\Cohere\InputType;

$documents = $retriever->retrieve('send email', [
    'maxItems' => 5,
    'platform_options' => ['input_type' => InputType::SearchQuery],
]);

Notes:

  • platform_options is consumed by the Retriever and stripped from the options handed to the store, since it configures the embedding and not the store query. That matters: the MongoDB bridge merges the options it receives straight into its $vectorSearch stage, so leaving the key in would send an unknown field to the vector database. Every other option is passed to the store unchanged.
  • Blanket-forwarding all options to the vectorizer was not an option either, since bridges like OpenAI's embeddings client merge their options straight into the request body.
  • A PreQueryEvent listener can set platform_options as well, since listeners can already rewrite the options.
  • No BC break: without the key, vectorize() is called with an empty array, exactly as before.

Tests cover the vector and hybrid paths, the listener case, that plain store options do not leak into the vectorizer, and that platform_options does not leak into the store. src/store: 422 tests green, PHPStan clean, CS fixer run.

@chr-hertel

chr-hertel commented Aug 2, 2026 •

Copy link
Copy Markdown
Member

were you using the Retriever directly in user land or via SimilaritySearch?

Comment thread docs/components/store.rst Outdated
Comment on lines +101 to +102
This mirrors the ``platform_options`` key of :class:`Symfony\\AI\\Store\\Indexer\\DocumentProcessor`,
which does the same for the indexing side.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we can drop that part here, not sure it adds something

// Configures the query embedding, not the store query, so it must not reach the store:
// bridges like MongoDB merge the options they get straight into their query payload.
$platformOptions = $options['platform_options'] ?? [];
unset($options['platform_options']);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm wondering if we should restore the platform_options after the store->query call so the PostQuery has knowledge of it - WDYT?

@wachterjohannes

Copy link
Copy Markdown
Member Author

Directly. Through SimilaritySearch it cannot be reached at all, since __invoke() takes a bare string $searchTerm and calls retrieve($searchTerm) with no options. RetrieveCommand and direct use are the only ways in.

Which is the uncomfortable half of the answer, because the case this fixes is a RAG one: with Cohere the query is embedded as search_document today, so it lands in the wrong corner of the space from the passages that should answer it. The results still look plausible, which is exactly why nobody notices. SimilaritySearch being the main RAG entry point and having no way to carry options is then its own gap, and I would rather close it in a separate PR than widen this one.

Dropped the DocumentProcessor sentence, you are right that it does not earn its place in a retrieval section.

On restoring platform_options for PostQuery: I would leave it out, and RerankerListener is why. It reads $event->getOptions()['topK'], so there getOptions() means "the options the store query ran with". Putting back a key the store never received turns that into a mixed bag with nothing telling a listener which half it holds.

The asymmetry with PreQueryEvent follows from the order rather than from a gap: pre-query runs before the split and therefore sees the caller's full input. That is also what makes a pre-query listener able to set platform_options centrally, instead of every call site repeating it.

If a post-query listener ever needs the embedding mode, I would add a dedicated accessor on the event rather than smuggle it back through the store options.

@wachterjohannes
wachterjohannes force-pushed the eve/retriever-platform-options branch from a7715ff to 89bc2d0 Compare September 1, 2026 19:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature New feature Status: Reviewed Status: Waiting feedback Store Issues & PRs about the AI Store component

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants