
sidebar.wechat

sidebar.feishu
sidebar.chooseYourWayToJoin

sidebar.scanToAddConsultant
Every conversation is an island - this is the pain point of traditional AI assistants. User-stated preferences, corrected mistakes, and established context are all lost in the next conversation. AskTable's newly introduced permanent memory system is breaking this困局.
┌─────────────────────────────────────────┐
│ Conversation 1 │
│ User: What's East China sales? │
│ AI: 12 million │
│ User: For what time period? From now on │
│ when answering sales metrics, │
│ include specific time │
│ AI: Got it. Q1 2026 East China sales │
│ is 12 million │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ Conversation 2 (any time later) │
│ User: How's East China profit? │
│ AI: Q1 2026 net profit 3.5 million, │
│ YoY +18%, QoQ +5% │ ← Automatically with time
└─────────────────────────────────────────┘
Root cause: In traditional architecture, conversation history is only valid within a single session.
This "amnesia" leads to:
AskTable chose mem0 OSS as the memory framework, core reasons:
| Consideration | mem0 Advantage |
|---|---|
| Ready to use | Built-in deduplication, conflict resolution, expiration mechanism |
| Simple API | Four core methods: add / search / get_all / delete |
| Replaceability | Abstracted through Protocol, can switch to custom solution later |
| Async support | Native AsyncMemory, perfectly fits asyncio architecture |
┌─────────────────────────────────────────────────────────────┐
│ AskTable Vector Storage Architecture │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Qdrant │ │ Qdrant │ │
│ │ (existing) │ │ (memory- │ │
│ │ metadata │ │ dedicated) │ │
│ │ retrieval │ │ cross-session│ │
│ │ │ │ memory │ │
│ └──────────────┘ └──────────────┘ │
│ │
│ Shared infrastructure, reduced operations cost │
│ │
└─────────────────────────────────────────────────────────────┘
Reuses existing Qdrant instance, no new infrastructure dependencies introduced.
┌─────────────────────────────────────────────────────────────┐
│ Memory System Workflow │
├─────────────────────────────────────────────────────────────┤
│ │
│ Conversation starts │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Memory Search │ ← Search related memories with query │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Format and inject│ ← Splice into System Prompt │
│ │ memory_context │ │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Agent generates │ ← Carry memory context │
│ │ response │ │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Memory Write │ ← Async write after conversation ends │
│ └─────────────────┘ (fire-and-forget) │
│ │
└─────────────────────────────────────────────────────────────┘
Read (Search) at request start:
Write (Add) after response completes:
┌─────────────────────────────────────────────────────────────┐
│ Memory Isolation Model │
├─────────────────────────────────────────────────────────────┤
│ │
│ DataAgent-A │
│ ┌─────────────────────────────────┐ │
│ │ Memory space: agent_id = "agent-a"│ │
│ │ - User preferences │ │
│ │ - Common reports │ │
│ │ - Analysis habits │ │
│ └─────────────────────────────────┘ │
│ │
│ DataAgent-B (independent memory) │
│ ┌─────────────────────────────────┐ │
│ │ Memory space: agent_id = "agent-b"│ │
│ │ - Different user preferences │ │
│ │ - Different business scenarios │ │
│ └─────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
Design principle: All users under the same Data Agent share memory (team knowledge base mode).
class MemoryService(Protocol):
"""Memory service abstraction, supports later replacement"""
async def add(
self,
messages: list[dict],
agent_id: str,
metadata: dict | None = None
) -> list[str]: ...
async def search(
self,
query: str,
agent_id: str,
top_k: int = 5
) -> list[MemoryItem]: ...
async def get_all(
self,
agent_id: str
) -> list[MemoryItem]: ...
async def delete(
self,
memory_id: str
) -> None: ...
Value: Through Protocol abstraction, ensuring mem0 is just one implementation, can smoothly switch to custom solution later.
# Extract key info from memory, format as natural language
MEMORY_CONTEXT_TEMPLATE = """
## Historical Memory
{relevance_memories}
Here are historical information relevant to you. Please answer user questions combined with this context.
"""
Example output:
## Historical Memory
- When user asks about sales, profit margin and other metrics, should include specific time period (2026-04-01)
- User mainly focuses on East China region data (2026-03-15)
- Prefers showing YoY and QoQ growth rates in charts (2026-03-20)
Here are historical information relevant to you. Please answer user questions combined with this context.
async def run_conversation_task(ctx: Context, ...):
# ... Execute conversation ...
# After releasing lock, async write memory
await release_lock()
await stream_end()
# Fire-and-forget, doesn't block user receiving response
asyncio.create_task(
memory_service.add(
messages=full_conversation,
agent_id=data_agent_id
)
)
Before (no memory):
User: What's East China sales?
AI: 12 million
User: For what time period?
AI: This is Q1 data
User (another day): How's East China profit?
AI: Q1 2026 net profit 3.5 million
[No time dimension, don't know which time period]
After (has memory):
User: What's East China sales?
AI: 12 million
User: For what time period? From now on when answering sales metrics, should include specific time
AI: Got it. Q1 2026 East China sales is 12 million
User (another day): How's East China profit?
AI: Q1 2026 net profit 3.5 million, YoY +18%, QoQ +5%
← Automatically with time dimension, no need to repeat
| Scenario | No Memory | Has Memory |
|---|---|---|
| Data query | Ask region, time range every time | Automatically use preference settings |
| Report generation | Specify format every time | Auto-generate per habit |
| Anomaly analysis | Explain focus metrics every time | Automatically track historical concerns |
| Trend interpretation | Explain business context every time | Automatically associate historical insights |
The system added a "Memories" Tab to the Data Agent configuration page:
Challenge: mem0 needs 1-2 LLM calls per add() for fact extraction.
Response:
memory_enabled switch)Challenge: mem0's fact extraction prompt mainly targets English.
Response:
Challenge: When memory errors occur, need to trace mem0 internal链路.
Response:
| Solution | Memory Granularity | Implementation Difficulty | Maintenance Cost | Applicable Scenario |
|---|---|---|---|---|
| Session Storage | Session level | Low | Low | Temporary storage |
| User KV Store | User level | Medium | Medium | Simple preferences |
| mem0 | Agent level | Medium | Medium | Complex context |
| Custom vector DB | Flexible | High | High | Deep customization |
AskTable's choice: mem0 is the "fast validation" path, Protocol abstraction leaves room for "long-term evolution".
If mem0 performs poorly in Chinese data analysis scenarios, can switch to custom solution:
Existing infrastructure:
├── Qdrant (vector storage)
├── BAAI/bge-small-zh-v1.5 (Embedding)
└── Langfuse (observability)
Custom development needs to solve:
├── Fact extraction Prompt
├── Deduplication/conflict strategy
└── Memory decay mechanism
AskTable permanent memory system's introduction marks AI data analysis assistant's evolution from "reactive tool" to "intelligent partner":
Core value:
Technical highlights:
Product significance: Memory system lets AI truly "recognize" users, not just answer questions. This is the key step from "tool" to "assistant".
sidebar.noProgrammingNeeded
sidebar.startFreeTrial