Skip to content

SemanticCache.acheck() still uses normalize_vector_distance=True inconsistently with check() (Issue #407 not fully resolved) #444

@glorialulu

Description

@glorialulu

Description
Issue #407 identified that SemanticCache.check() (sync) and acheck() (async) interpret distance_threshold inconsistently due to different normalize_vector_distance settings. While PR #408 added a new LangCacheWrapper with a distance_scale parameter to address this, the original SemanticCache class was not fixed and still exhibits the bug.
Current Behavior (redisvl 0.12.1)
In redisvl/extensions/cache/llm/semantic.py: Sync check() (line ~410):

query = VectorRangeQuery(
    vector=vector,
    vector_field_name=CACHE_VECTOR_FIELD_NAME,
    return_fields=self.return_fields,
    distance_threshold=distance_threshold,
    num_results=num_results,
    return_score=True,
    filter_expression=filter_expression,
    dtype=self._vectorizer.dtype,
    # normalize_vector_distance defaults to False
)

Async acheck() (line ~503):

query = VectorRangeQuery(
    vector=vector,
    vector_field_name=CACHE_VECTOR_FIELD_NAME,
    return_fields=self.return_fields,
    distance_threshold=distance_threshold,
    num_results=num_results,
    return_score=True,
    filter_expression=filter_expression,
    normalize_vector_distance=True,  # <-- Different from sync!
)

Impact
With distance_threshold=0.05 (intended to match only very similar queries):
Sync check(): Uses 0.05 as raw cosine distance (correct - strict matching)
Async acheck(): Converts to 2 - 2*0.05 = 1.9 (wrong - matches almost everything!)

Reproduction

import asyncio
from redisvl.extensions.cache.llm import SemanticCache

async def test():
    cache = SemanticCache(
        name="test",
        distance_threshold=0.05,  # Strict threshold
        redis_url="redis://localhost:6379",
    )
    
    # Store entry
    cache.store(prompt="Who is CEO?", response="John Smith")
    
    # Query with different prompt (cosine distance ~0.23)
    sync_result = cache.check(prompt="Who is CFO?")
    async_result = await cache.acheck(prompt="Who is CFO?")
    
    print(f"Sync: {len(sync_result)} hits")   # Expected: 0, Actual: 0 ✓
    print(f"Async: {len(async_result)} hits") # Expected: 0, Actual: 1 ✗

asyncio.run(test())

Environment
redisvl: 0.12.1
Python: 3.11

Suggested Fix
Remove normalize_vector_distance=True from acheck() to match check() behavior:

# In redisvl/extensions/cache/llm/semantic.py, acheck() method
query = VectorRangeQuery(
    vector=vector,
    vector_field_name=CACHE_VECTOR_FIELD_NAME,
    return_fields=self.return_fields,
    distance_threshold=distance_threshold,
    num_results=num_results,
    return_score=True,
    filter_expression=filter_expression,
    # Remove: normalize_vector_distance=True
)

This is a one-line fix that ensures sync/async parity.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions