All Products
Search
Document Center

AnalyticDB:Integration guide for AnalyticDB for PostgreSQL long-term memory and Spring AI

Last Updated:Mar 28, 2026

AnalyticDB for PostgreSQL (ADB-PG) provides persistent, semantically searchable memory for large language model (LLM) applications built on Spring AI. Unlike conversation history, which stores every message in sequence, long-term memory uses vector similarity search to surface the most relevant facts from past interactions—regardless of when they occurred or how many messages have passed.

The spring-ai-alibaba component handles this end to end: it extracts structured facts from raw conversations using a configured LLM, stores those facts as vectors in ADB-PG, and retrieves them at query time to give the model persistent context across sessions.

Prerequisites

Before you begin, ensure that you have:

How it works

A request flows through three layers:

  1. Advisor layerAdbpgChatMemoryAdvisor intercepts each ChatClient call, retrieves relevant memories from ADB-PG using similarity search, and injects them into the prompt context.

  2. Memory service — The server-side component extracts structured facts from new conversation messages using the configured LLM and stores them as vectors via the embedding model.

  3. Storage layer — ADB-PG persists the vector embeddings and metadata, enabling filtered retrieval by user, agent, time range, or custom attributes.

The fact extraction step is what distinguishes long-term memory from a simple message store. A raw message such as "I'm travelling to San Francisco" is stored as a structured fact: "User plans to travel to San Francisco". This normalized representation improves retrieval accuracy across sessions.

Set up the integration

Step 1: Add dependencies

The dependency packages are not yet available on Maven Central. To get them, contact Alibaba Cloud support on DingTalk (ID: 1rr-h38w9hwtt5).

Add the following to your pom.xml:

<properties>
    <!-- Replace with the version you received -->
    <spring-ai-alibaba.version>1.0.0.4</spring-ai-alibaba.version>
</properties>

<dependencies>
    <!-- Core starter for ADB-PG long-term memory -->
    <dependency>
        <groupId>com.alibaba.cloud.ai</groupId>
        <artifactId>spring-ai-alibaba-starter-memory-adbpg</artifactId>
        <version>${spring-ai-alibaba.version}</version>
    </dependency>

    <!-- Auto-configuration for ADB-PG long-term memory -->
    <dependency>
        <groupId>com.alibaba.cloud.ai.autoconfigure.memory.adbpg</groupId>
        <artifactId>spring-ai-alibaba-autoconfigure-memory-adbpg</artifactId>
        <version>${spring-ai-alibaba.version}</version>
    </dependency>
</dependencies>

Step 2: Configure the connection

Add the following to your application.yml. The auto-configuration initializes all required beans when the server node is present.

spring:
  ai:
    dashscope:
      api-key: sk-xxxx  # Your DashScope API key

    alibaba:
      adbpg:
        # Server-side: controls how memories are stored and processed in ADB-PG
        server:  # This node must exist to trigger auto-configuration
          vector-store:
            provider: adbpg
            config:
              port: 3000        # Internal port for the memory service
              dbname: postgres
              user: test_user
              password: xxxx
              # Must match the vector dimensions of the embedding model below
              embedding-model-dims: 1024

          llm:
            provider: qwen      # LLM used for fact extraction
            config:
              api-key: ${spring.ai.dashscope.api-key}
              base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
              model: qwen3-32b  # Other options: qwen-plus, qwen-max

          embedder:
            provider: openai    # Uses DashScope's OpenAI-compatible endpoint
            config:
              api-key: ${spring.ai.dashscope.api-key}
              model: text-embedding-v4
              openai-base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
              embedding-dims: 1024  # Must match embedding-model-dims above

          # Optional: override the default fact extraction prompt
          custom-fact-extraction-prompt: classpath:/prompts/custom_fact_extraction_prompt.st

        # Client-side: JDBC connection for your application to read/write memories
        client:
          url: jdbc:postgresql://gp-xxxx-master.gpdb.rds.aliyuncs.com:5432/postgres
          username: test_user
          password: xxxx

Key constraints:

  • embedding-model-dims and embedding-dims must be identical. A mismatch causes vector storage errors.

  • The server node must exist in the config. Removing it disables auto-configuration.

  • The embedder.provider is set to openai because DashScope exposes an OpenAI-compatible API. It does not call OpenAI.

Step 3: Initialize the controller

Wire AdbpgChatMemoryAdvisor into your ChatClient at construction time. The advisor automatically retrieves relevant memories before each call and injects them into the prompt context.

import com.alibaba.cloud.ai.memory.adbpg.advisor.AdbpgChatMemoryAdvisor;
import com.alibaba.cloud.ai.memory.adbpg.core.AdbpgServiceClient;
import com.alibaba.cloud.ai.memory.adbpg.model.AdbpgServerRequest;

public class ADBPGMemoryController {
    private static final Logger logger = LoggerFactory.getLogger(ADBPGMemoryController.class);

    private final ChatClient chatClient;         // Spring AI interface for LLM calls
    private final VectorStore store;             // Spring AI vector store interface
    private final AdbpgServiceClient adbpgServiceClient; // Client for direct memory operations

    public ADBPGMemoryController(VectorStore store, AdbpgServiceClient adbpgServiceClient, ChatClient.Builder builder) {
        this.store = store;
        this.adbpgServiceClient = adbpgServiceClient;
        this.chatClient = builder
            .defaultAdvisors(
                AdbpgChatMemoryAdvisor.builder(store).build()
            )
            .build();
    }

    public String call(@RequestParam(value = "message", defaultValue = "Recommend some fun games for me") String message,
                       @RequestParam(value = "user_id", defaultValue = "miao") String userId) {
        return chatClient.prompt(message)
            .advisors(a -> a.params(Map.of(USER_ID, userId)))
            .call().content();
    }
}

Manage memories directly

Use adbpgServiceClient when you need direct control over memory operations—for example, to pre-populate memories, apply custom filters, or clean up stale data.

Add memory

Pass one or more conversation messages to addMemory. The service extracts structured facts from the messages and stores them in ADB-PG.

// Basic: add messages for a user
adbpgServiceClient.addMemory(
    AdbpgServerRequest.MemoryCreate.builder()
        .userId("test")
        .messages(List.of(
            new AdbpgServerRequest.Message("user", "I'm travelling to San Francisco"),
            new AdbpgServerRequest.Message("assistant", "That's great! I'm going to Dubai next month.")
        ))
        .build()
);

// With agent isolation and expiration metadata
adbpgServiceClient.addMemory(
    AdbpgServerRequest.MemoryCreate.builder()
        .userId("test")
        .agentId("agent2")                      // Isolates memories per agent (see table below)
        .messages(List.of(
            new AdbpgServerRequest.Message("user", "I'm travelling to San Francisco"),
            new AdbpgServerRequest.Message("assistant", "That's great! I'm going to Dubai next month.")
        ))
        .metadata(Map.of("expiration_date", "2026-01-01"))  // Custom attribute for filtered queries
        .build()
);

After fact extraction, the raw message "I'm travelling to San Francisco" is stored as a structured fact such as "User plans to travel to San Francisco". This normalized representation improves retrieval accuracy for future similarity searches.

`MemoryCreate` fields:

FieldTypeRequiredWhen to use
messagesList<Message>YesThe conversation turn to store
userIdStringYesScopes memories to a specific user
agentIdStringNoUse when multiple agents share the same user space and need isolated memory pools
runIdStringNoUse to tag memories from a specific session or workflow run for later tracing
metadataMap<String, Object>NoAdd custom attributes (e.g., expiration_date, topic) to enable filtered retrieval

Retrieve memory

Use store.similaritySearch to fetch memories relevant to a query or scoped to a specific user or agent.

// Retrieve all memories for an agent
List<Document> documents = store.similaritySearch(
    AdbpgServerRequest.SearchRequest.builder()
        .userId("test")
        .agentId("agent2")
        .build()
);
logger.info("Agent long-term memory: {}", documents);

// Retrieve by semantic query with metadata filters
documents = store.similaritySearch(
    AdbpgServerRequest.SearchRequest.builder()
        .query("What do you know about me?")
        .userId("test")
        .filters(Map.of(
            "AND",
            Arrays.asList(
                Map.of("created_at", Map.of("gte", "2025-07-29", "lte", "2025-11-30")),
                Map.of("user_id", "test")
            )
        ))
        .build()
);

`SearchRequest` fields:

FieldTypeRequiredWhen to use
queryStringNoProvide a natural language query to retrieve semantically similar memories. Omit to return all memories in scope.
userIdStringNoLimits results to a specific user. Omit only when querying across all users.
agentIdStringNoLimits results to memories stored under a specific agent
runIdStringNoLimits results to a specific session or run
filtersMap<String, Object>NoApplies structured conditions on metadata fields (e.g., date ranges, custom tags)
limitsIntegerNoCaps the number of results returned. Defaults to the server configuration when omitted.

Delete memory

Delete individual memories by ID, or delete all memories for a user.

// Delete a specific memory by ID
adbpgServiceClient.deleteMemory(documents.stream().findFirst().get().getId());

// Delete all memories for a user (pass null for agentId and runId to match all)
adbpgServiceClient.deleteAllMemories("test", null, null);

When to use each approach

ApproachHow it worksBest for
AdbpgChatMemoryAdvisorAutomatically retrieves and injects memories on each ChatClient callStandard conversational AI where memory should be transparent to the application
adbpgServiceClient directlyExplicit add, retrieve, and delete operationsScenarios requiring custom filters, pre-populated memories, scheduled cleanup, or multi-agent memory isolation

What's next

  • To customize fact extraction, create a prompt template at classpath:/prompts/custom_fact_extraction_prompt.st and reference it in custom-fact-extraction-prompt.

  • To scope memories across multiple agents for the same user, set a unique agentId on each MemoryCreate and SearchRequest.

  • To manage memory retention, add an expiration_date field to metadata and filter by it during retrieval.