Skip to content

Python: VolatileMemoryStore.get_batch and get_nearest_matches ignore with_embeddings=False (deepcopy result is discarded) #14522

Description

What happens

VolatileMemoryStore.get_batch and get_nearest_matches take a flag (with_embeddings) that is documented as "Whether to include the embeddings in the results". With the flag False (the default) the embeddings are still returned. The code makes a deepcopy and clears the embedding on the copy, but the loop variable is rebound and the copy is thrown away, so the original records are returned unchanged.

get (the single-record version) does this correctly, which shows the intended behavior.

Where

python/semantic_kernel/memory/volatile_memory_store.py on current main.

get_batch:

        if not with_embeddings:
            # create copy of results without embeddings
            for result in results:
                result = deepcopy(result)
                result._embedding = None
        return results

get_nearest_matches:

        if not with_embeddings:
            # create copy of results without embeddings
            for result in top_results:
                result = deepcopy(result)
                result[0]._embedding = None
        return top_results

In the second case deepcopy(result) copies the (record, score) tuple, and the copy is dropped. Note that a naive fix of removing the deepcopy would clear the embedding on the stored record itself, so the fix has to return copies.

Reproduce

import asyncio, numpy as np
from semantic_kernel.memory.volatile_memory_store import VolatileMemoryStore
from semantic_kernel.memory.memory_record import MemoryRecord

async def main():
    s = VolatileMemoryStore()
    await s.create_collection("c")
    await s.upsert("c", MemoryRecord.local_record("id1", "text", "desc", None, np.array([1.0, 0.0])))
    ms = await s.get_nearest_matches("c", np.array([1.0, 0.0]), limit=1)
    print("get_nearest_matches:", ms[0][0]._embedding)
    b = await s.get_batch("c", ["id1"])
    print("get_batch:", b[0]._embedding)
    g = await s.get("c", "id1")
    print("get:", g._embedding)

asyncio.run(main())

Output on semantic-kernel main (also 1.44.1):

get_nearest_matches: [1. 0.]
get_batch: [1. 0.]
get: None

Expected

All three return None for the embedding when the embeddings flag is False, and the stored records keep their embeddings. I am happy to send a fix with tests.

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    pythonPull requests for the Python Semantic Kerneltriage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions