Repository navigation
Memory Refactor: Simplify Memory Interfaces, Remove Unnecessary Generics, Move Vector Stores to Connectors - #308
Merged
Adrian Bonar (adrianwyatt) merged 50 commits intoApr 6, 2023
Conversation
annoying generics
Abby Harrison (awharrison-28)
requested review from
Adrian Bonar (adrianwyatt) and
Gil LaHaye (glahaye)
April 5, 2023 22:39
Lee Miller (lemillermicrosoft)
previously approved these changes
Apr 5, 2023
Lee Miller (lemillermicrosoft)
left a comment
Member
There was a problem hiding this comment.
Agree with a few other comments but otherwise LGTM overall.
…emoryExceptions are only thrown in the QdrantMemoryStore; passed inner exceptions to QdrantMemoryException where applicable
Adrian Bonar (adrianwyatt)
approved these changes
Apr 6, 2023
Adrian Bonar (adrianwyatt)
enabled auto-merge (squash)
April 6, 2023 00:21
Adrian Bonar (adrianwyatt)
disabled auto-merge
April 6, 2023 00:21
Adrian Bonar (adrianwyatt)
enabled auto-merge (squash)
April 6, 2023 00:22
Desmond Howard (dehoward)
pushed a commit
to lemillermicrosoft/semantic-kernel
that referenced
this pull request
Jun 1, 2023
…ics, Move Vector Stores to Connectors (microsoft#308) ### Motivation and Context Existing memory interfaces are overly complicated, leading to confusion about how to implement a custom Memory Store. This PR condenses `IMemoryStore` + `IEmbeddingIndex` + `IDataStore `-> **`IMemoryStore`** and eliminates the use of generics spread by the Embedding struct. It makes the codebase much easier to read and IMemoryStore easier to implement. As part of the effort, SqliteMemoryStore was properly implemented (it was not previously). Additionally, this PR moves the MemoryStore 'skills' to the connectors namespace. Addresses several points called out in microsoft#202 ### Description - `QdrantMemoryStore` was moved from Skills to Connectors. Unit tests were added for the memory store object. Created an IQdrantVectorDbClient interface to better enable testing of the memory store through mocks. - Modified QdrantVectorDbClient calls to default batched calls to reduced the amount of HTTP traffic when possible. `GetVectorById -> GetVectorsById`, `UpsertVector -> UpsertVectors`, `DeleteVector -> DeleteVectors`. - Generally, for a vector store, the unique id passed by the user to associate with a saved memory will become the indexed ID for the vector store as well. However, Qdrant enforces a user-provided GUID or hex string as the index key. Added a nullable key field to `MemoryRecord` to support vector storage services that act similarly. Depending on the backing storage, this key is not necessary to pass to subsequent calls. `SemanticTextMemory` does not utilized this parameter. For now, this is only for direct interaction with the `QdrantMemoryStore`. **Note**: It is understood that Qdrant will be enabling service-side GUID generation in the near future, significantly reducing the stress on the client to produce unique values for every data entry. - Eliminated the dependency on the core kernel in the connectors by replacing `Embeddings` struct references with `IEnumerable<float>`. - `SqliteMemoryStore` was moved from Skills to Connectors. `SqliteMemoryStore` now properly implements `IMemoryStore` and the unit tests were updated to reflect this fact. - The generic `TEmbedding` was removed from all Kernel and Connector files. **If a memory store expects a non-FP32 vector, it is currently up to the `IMemoryStore` implementation to perform the necessary conversions.** - `DataEntry` is now a base class that enforces nullable Key and Timestamp fields. It is not strictly used for anything other than MemoryRecord. It may serve useful for connecting to data stores that are for structures other than embeddings, or vector stores that calculate embeddings server-side. - Removed existing collection checks for `Upsert` calls. Depending on the implementation, this has the potential to drastically increase HTTP traffic or local compute resources when making batch calls. The call has been moved to SemanticTextMemory for now to avoid additional breaking changes, but will be addressed in a better fashion in a follow-up PR. - Added a very simple example to `KernelSyntaxExamples `on how to create a read-only `IMemoryStore` that imports vectors from a json string. - Renamed `VectorDbException` -> `QdrantMemoryException`. Ensured that these exceptions can only be thrown by the `QdrantMemoryStore` and can accept an inner exception as a paramter. Additional small edits: - removed unnecessary namespace from KernelSyntaxExamples Example21 and Example22 - Removed unused references in `RestApiOperations.cs` and `JsonPathSkill.cs` ---------------- OUT OF SCOPE, COMING SOON ---------------- - The addition of a value string to MemoryRecord. This is very important for metadata flexibility, but it will come in a follow-up PR. - The ability to optionally return the vector to the user. In many cases, the vector is not important for get/search calls, thus it makes no sense to pass such large amounts of data around the kernel application. - Disambiguation of SemanticTextMemory interfaces, classes, and constructors. - Unit tests for QdrantVectorDbClient. Qdrant will be making breaking changes to their API very soon. TBD whether integration tests will be added as well.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation and Context
Existing memory interfaces are overly complicated, leading to confusion about how to implement a custom Memory Store.
This PR condenses
IMemoryStore+IEmbeddingIndex+IDataStore->IMemoryStoreand eliminates the use of generics spread by the Embedding struct. It makes the codebase much easier to read and IMemoryStore easier to implement. As part of the effort, SqliteMemoryStore was properly implemented (it was not previously).Additionally, this PR moves the MemoryStore 'skills' to the connectors namespace.
Addresses several points called out in #202
Description
QdrantMemoryStorewas moved from Skills to Connectors. Unit tests were added for the memory store object. Created an IQdrantVectorDbClient interface to better enable testing of the memory store through mocks.GetVectorById -> GetVectorsById,UpsertVector -> UpsertVectors,DeleteVector -> DeleteVectors.MemoryRecordto support vector storage services that act similarly. Depending on the backing storage, this key is not necessary to pass to subsequent calls.SemanticTextMemorydoes not utilized this parameter. For now, this is only for direct interaction with theQdrantMemoryStore. Note: It is understood that Qdrant will be enabling service-side GUID generation in the near future, significantly reducing the stress on the client to produce unique values for every data entry.Embeddingsstruct references withIEnumerable<float>.SqliteMemoryStorewas moved from Skills to Connectors.SqliteMemoryStorenow properly implementsIMemoryStoreand the unit tests were updated to reflect this fact.TEmbeddingwas removed from all Kernel and Connector files. If a memory store expects a non-FP32 vector, it is currently up to theIMemoryStoreimplementation to perform the necessary conversions.DataEntryis now a base class that enforces nullable Key and Timestamp fields. It is not strictly used for anything other than MemoryRecord. It may serve useful for connecting to data stores that are for structures other than embeddings, or vector stores that calculate embeddings server-side.Upsertcalls. Depending on the implementation, this has the potential to drastically increase HTTP traffic or local compute resources when making batch calls. The call has been moved to SemanticTextMemory for now to avoid additional breaking changes, but will be addressed in a better fashion in a follow-up PR.KernelSyntaxExampleson how to create a read-onlyIMemoryStorethat imports vectors from a json string.VectorDbException->QdrantMemoryException. Ensured that these exceptions can only be thrown by theQdrantMemoryStoreand can accept an inner exception as a paramter.Additional small edits:
RestApiOperations.csandJsonPathSkill.cs---------------- OUT OF SCOPE, COMING SOON ----------------
Contribution Checklist
dotnet format