test(memory): cover opposite polarity relevance filtering - #14319
test(memory): cover opposite polarity relevance filtering#14319mikemikimike wants to merge 3 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new .NET unit test to explicitly cover how minRelevanceScore gating behaves in VolatileMemoryStore.GetNearestMatchesAsync when a stored record’s embedding is the opposite direction of the query embedding.
Changes:
- Adds
GetNearestMatchesFiltersOppositePolarityAsyncto validate relevance-threshold filtering behavior with an opposite-direction embedding. - Asserts only the matching-direction record is returned when
minRelevanceScoreis set to0.75.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| var queryEmbedding = new float[] { 1, 0 }; | ||
| string collection = "test_collection" + this._collectionNum; | ||
| this._collectionNum++; | ||
| await this._db.CreateCollectionAsync(collection); | ||
|
|
||
| _ = await this._db.UpsertAsync(collection, MemoryRecord.LocalRecord( | ||
| id: "matching", | ||
| text: "Withhold the study drug when chest tightness is reported.", | ||
| description: "matching polarity", | ||
| embedding: new float[] { 1, 0 })); | ||
| _ = await this._db.UpsertAsync(collection, MemoryRecord.LocalRecord( | ||
| id: "opposite", | ||
| text: "Administer the study drug when chest tightness is reported.", | ||
| description: "opposite polarity", | ||
| embedding: new float[] { -1, 0 })); |
There was a problem hiding this comment.
Addressed in the current head a3e1354a. The test now uses recorded high-positive embeddings for both the matching and opposite-polarity records, asserts both scores are at least 0.75, and documents that this is an offline reproduction of the reported embedding behavior rather than a model call.
| // Act | ||
| var results = await this._db.GetNearestMatchesAsync( | ||
| collection, | ||
| queryEmbedding, | ||
| limit: 2, | ||
| minRelevanceScore: 0.75).ToArrayAsync(); | ||
|
|
||
| // Assert | ||
| var result = Assert.Single(results); | ||
| Assert.Equal("matching", result.Item1.Metadata.Id); | ||
| Assert.True(result.Item2 >= 0.75); | ||
| } |
There was a problem hiding this comment.
Addressed in the current head a3e1354a: the test now defines the relevance threshold once and reuses it for the search call and all assertions, avoiding duplicated magic numbers.
There was a problem hiding this comment.
MAF Automated Review — Iteration 1
Result: No findings
Scope: full PR (1 commit(s)): 7845fa02485a
Model: claude-opus-4.8
Overview
This PR adds a single xUnit [Fact] (GetNearestMatchesFiltersOppositePolarityAsync) to VolatileMemoryStoreTests.cs and changes no production code. It pins the existing cosine-similarity threshold semantics of VolatileMemoryStore.GetNearestMatchesAsync by asserting that an opposite-polarity embedding ({-1,0}, cosine -1.0) is excluded under minRelevanceScore: 0.75 while the matching embedding ({1,0}, cosine 1.0) is returned. The math is exact and deterministic with wide margins from the threshold, record keys are distinct, and per-[Fact] instance isolation (_db and _collectionNum reset per test) prevents cross-test contamination. The only residual caveat is that neither the author nor the review environment could execute the .NET test (no dotnet toolchain); correctness here rests on static analysis, which is strong.
Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
No publishable findings remained after source verification for this scope.
|
Addressed the review feedback in commit |
|
Mike, Thanks for taking this on, and for iterating twice on the review feedback. I want to flag something In id: "matching", ... embedding: new float[] { 0.98f, 0.199f }
id: "opposite", ... embedding: new float[] { 0.98f, 0.199f }Both are That is fixable rather than wasted. This PR says What I think does work, given that a unit test cannot call an embedding model. *Record the vectors Two smaller notes. I am glad to generate the recorded vectors and send them over so you keep authorship here. Say the |
|
Mike, I offered to generate the recorded vectors. Rather than wait on a yes, I built them. Package: https://gist.github.com/poeticize/cfb230f9ae92ad018b649470047cadfb Everything in it runs offline from open weights. No credential, no API budget, no GPU. The What is in it
Encoder. The specimens did change shape. My earlier comment said "the four sentences". While generating I
The gate ranks A above B, and A is the one that contradicts the query. Both memories come from a A caveat about one number. The issue quotes the clinical pair at 0.9608, a figure from the The finding. Python's Not one model's quirk. I measured the same three pairs across all nine encoder configurations in Validation you can run
Two more things: the Python side has no behavioral unit test for Take any of this, change any of it, and keep authorship. If you would rather have the Python version, Scott |
Motivation and Context
Fixes #14295 by adding focused regression coverage for the Python
TextMemoryPlugin.recall()relevance threshold. The issue identifies a test blind spot: high embedding similarity does not establish semantic agreement, and a fixed threshold can also miss semantically equivalent paraphrases.Description
Adds deterministic, offline Python coverage using four recorded sentences in two independent pairs:
0.9748118, so the opposite meaning is recalled through the default0.75threshold.0.7302992, so it is filtered by the same threshold.The vectors were recorded from
nomic-ai/nomic-embed-text-v1.5through the local LM Studio OpenAI-compatible endpoint, with 768 dimensions and float32 serialization. The fixture includes the model checkpoint, endpoint, generation date, dimensions, source texts, measured cosines, and the regeneration script. The model is Nomic; this does not usetext-embedding-3-small.No production behavior is changed. The tests document the limitation of treating cosine similarity as a relevance/semantic-agreement decision while remaining deterministic and offline.
Verification
python tests/unit/memory/generate_recorded_nomic_relevance_embeddings.pypassed with the local LM Studio Nomic endpoint.python -m pytest tests/unit/memory/test_text_memory_plugin_relevance.py -qpassed: 5 tests.git diff --checkpassed.The full repository test suite and .NET validation were not run; this patch adds Python unit tests only and does not change .NET production code.
Contribution Checklist
Related Issues
Fixes #14295