Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add JdbcChatMemory #1528

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open

Add JdbcChatMemory #1528

wants to merge 18 commits into from

Conversation

leijendary
Copy link

@leijendary leijendary commented Oct 11, 2024

An option to use a generic JdbcChatMemory with a starter for users that want to use SQL as chat memory.

@leijendary leijendary changed the title Added ChatMemory implementation for PgVector Add ChatMemory implementation for PgVector Oct 11, 2024
@leijendary leijendary changed the title Add ChatMemory implementation for PgVector Add PgVectorChatMemory Oct 11, 2024
@ogbozoyan
Copy link

Is it will be usable with VectorStoreChayMemoryAdvisor? Or what is the point ?

@leijendary
Copy link
Author

@ogbozoyan VectorStoreChatMemoryAdvisor is optional if we have this change. PgVectorChatMemory is an implementation of ChatMemory and the postgres version of CassandraChatMemory which is specialized just for the chat memory/history.

@ogbozoyan
Copy link

@leijendary which advisor you should use with that ChatMemory to process saving ?

@leijendary
Copy link
Author

@ogbozoyan You can use MessageChatMemoryAdvisor and pass in the instance of the PgVectorChatMemory. Then for RAG, you can use RetrievalAugmentationAdvisor. This is what I did for my chatClient bean:

@Bean
fun chatClient(builder: ChatClient.Builder, vectorStore: VectorStore, chatMemory: ChatMemory): ChatClient {
    val memoryAdvisor = MessageChatMemoryAdvisor(chatMemory)
    val documentRetriever = VectorStoreDocumentRetriever.builder()
        .vectorStore(vectorStore)
        .build()
    val ragAdvisor = RetrievalAugmentationAdvisor.builder()
        .documentRetriever(documentRetriever)
        .build()

    return builder
        .defaultAdvisors(memoryAdvisor, ragAdvisor)
        .build()
}

@ogbozoyan
Copy link

@ogbozoyan You can use MessageChatMemoryAdvisor and pass in the instance of the PgVectorChatMemory. Then for RAG, you can use RetrievalAugmentationAdvisor. This is what I did for my chatClient bean:

@Bean
fun chatClient(builder: ChatClient.Builder, vectorStore: VectorStore, chatMemory: ChatMemory): ChatClient {
    val memoryAdvisor = MessageChatMemoryAdvisor(chatMemory)
    val documentRetriever = VectorStoreDocumentRetriever.builder()
        .vectorStore(vectorStore)
        .build()
    val ragAdvisor = RetrievalAugmentationAdvisor.builder()
        .documentRetriever(documentRetriever)
        .build()

    return builder
        .defaultAdvisors(memoryAdvisor, ragAdvisor)
        .build()
}

in this example you passing VectorStore, may be you meant ?

fun chatClient(builder: ChatClient.Builder, **pgVectorChatMemory: PgVectorChatMemory**, chatMemory: ChatMemory): ChatClient {
     val memoryAdvisor = MessageChatMemoryAdvisor(**pgVectorChatMemory**)
     val documentRetriever = VectorStoreDocumentRetriever.builder()
         .vectorStore(vectorStore)
         .build()
     val ragAdvisor = RetrievalAugmentationAdvisor.builder()
         .documentRetriever(documentRetriever)
         .build()
 
     return builder
         .defaultAdvisors(memoryAdvisor, ragAdvisor)
         .build()
}

@leijendary
Copy link
Author

@ogbozoyan

@ogbozoyan You can use MessageChatMemoryAdvisor and pass in the instance of the PgVectorChatMemory. Then for RAG, you can use RetrievalAugmentationAdvisor. This is what I did for my chatClient bean:

@Bean
fun chatClient(builder: ChatClient.Builder, vectorStore: VectorStore, chatMemory: ChatMemory): ChatClient {
    val memoryAdvisor = MessageChatMemoryAdvisor(chatMemory)
    val documentRetriever = VectorStoreDocumentRetriever.builder()
        .vectorStore(vectorStore)
        .build()
    val ragAdvisor = RetrievalAugmentationAdvisor.builder()
        .documentRetriever(documentRetriever)
        .build()

    return builder
        .defaultAdvisors(memoryAdvisor, ragAdvisor)
        .build()
}

in this example you passing VectorStore, may be you meant ?

fun chatClient(builder: ChatClient.Builder, **pgVectorChatMemory: PgVectorChatMemory**, chatMemory: ChatMemory): ChatClient {
     val memoryAdvisor = MessageChatMemoryAdvisor(**pgVectorChatMemory**)
     val documentRetriever = VectorStoreDocumentRetriever.builder()
         .vectorStore(vectorStore)
         .build()
     val ragAdvisor = RetrievalAugmentationAdvisor.builder()
         .documentRetriever(documentRetriever)
         .build()
 
     return builder
         .defaultAdvisors(memoryAdvisor, ragAdvisor)
         .build()
}

The code I provided is correct. I am using it right now. The ChatMemory instance is automatically picked up by spring as PgVectorChatMemory because of PgVectorChatMemoryAutoConfiguration

@eddumelendez
Copy link
Contributor

I wonder if this should be more generic and instead providing a JdbcChatMemory instead. I would be also nice to provide the proper scripts to create the tables, similar to what spring security and spring session does.

@leijendary
Copy link
Author

@eddumelendez I agree. I also originally designed it to be the same as the existing CassandraChatMemory and just used the same columns. I thought of changing the columns to the following:

CREATE TABLE ai_chat_memory (
    session_id character varying(36) NOT NULL,
    content text NOT NULL,
    type character varying(10) NOT NULL, -- USER/ASSISTANT
    "timestamp" timestamp without time zone NOT NULL DEFAULT NOW()
);

Do you also mean that the table should not be automatically created and instead be created manually by the developer?

@eddumelendez
Copy link
Contributor

Do you also mean that the table should not be automatically created and instead be created manually by the developer?

it should be created automatically by detecting the database. I meant having something like https://github.com/spring-projects/spring-session/blob/main/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-postgresql.sql that spring ai can execute, so, if new database should be supported then adding a script should be enough

@ogbozoyan
Copy link

type character varying(10) NOT NULL, -- USER/ASSISTANT

maybe add check ?

CREATE TABLE ai_chat_memory (
    session_id character varying(36) NOT NULL,
    content text NOT NULL,
    type character varying(10) NOT NULL CHECK (type IN ('USER', 'ASSISTANT')), -- USER/ASSISTANT
    "timestamp" timestamp without time zone NOT NULL DEFAULT NOW()
);

@leijendary leijendary changed the title Add PgVectorChatMemory Add JdbcChatMemory Dec 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants