从 0 到 1:Milvus + 大模型打造私人记忆知识库
1. 为什么需要一个「私人记忆知识库」
大模型虽然强大,但有两个天然短板:知识是静态的(训练数据有截止日期)、上下文是有限的(几十 K 的 token 塞不下你全部历史资料)。你让它回忆「我上周三提过的那个客户投诉」,它只能编一个听起来合理但完全错误的故事。
解决思路就是检索增强生成(RAG):把外部知识用向量数据库存起来,提问时先检索相关记忆,再喂给大模型回答。而 Milvus 正是当下开源向量数据库中最成熟的选择之一——支持十亿级向量、多种索引类型、分区/分片、动态 Schema,以及完整的 Python SDK。
本文会带你从零搭建一个私人记忆知识库:它能把你的聊天记录、文档、笔记变成向量记忆,存进 Milvus 并建立索引,然后通过与 ChatGPT / Ollama 等大模型配合,实现「记得住、查得到、答得准」的私人 AI 记忆助手。全文包含完整可运行代码,环境为 Python 3.10+。
2. 整体架构与技术选型
在动手写代码前,先看清全局。整个系统分为四个层次:
技术选型如下:
| 组件 | 选型 | 说明 |
|---|---|---|
| 向量数据库 | Milvus 2.4+ | 开源、可扩展、支持多种索引 |
| Embedding 模型 | OpenAI text-embedding-3-small 或本地 sentence-transformers | 两者都会演示 |
| 大语言模型 | OpenAI GPT-4o-mini / Ollama 本地模型 | 通过统一接口调用 |
| 语言 | Python 3.10+ | pymilvus SDK |
| 部署 | Docker / Docker Compose | Milvus Standalone |
3. 环境准备:用 Docker 启动 Milvus
Milvus 官方推荐通过 Docker Compose 启动单机版(Milvus Standalone),它依赖 etcd 和 MinIO 分别负责元数据与对象存储。
3.1 编写 docker-compose.yml
创建项目目录 memory-kb,在其中新建 docker-compose.yml:
version: "3.8"
services:
etcd:
container_name: milvus-etcd
image: quay.io/coreos/etcd:v3.5.5
environment:
- ETCD_AUTO_COMPACTION_MODE=revision
- ETCD_AUTO_COMPACTION_RETENTION=1000
- ETCD_QUOTA_BACKEND_BYTES=4294967296
- ETCD_SNAPSHOT_COUNT=50000
volumes:
- ./volumes/etcd:/etcd
command: etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd
healthcheck:
test: ["CMD", "etcdctl", "endpoint", "health"]
interval: 30s
timeout: 20s
retries: 3
minio:
container_name: milvus-minio
image: minio/minio:RELEASE.2023-03-20T20-16-18Z
environment:
MINIO_ACCESS_KEY: minioadmin
MINIO_SECRET_KEY: minioadmin
ports:
- "9001:9001"
- "9000:9000"
volumes:
- ./volumes/minio:/minio_data
command: minio server /minio_data --console-address ":9001"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
standalone:
container_name: milvus-standalone
image: milvusdb/milvus:v2.4.4
command: ["milvus", "run", "standalone"]
security_opt:
- seccomp:unconfined
environment:
ETCD_ENDPOINTS: etcd:2379
MINIO_ADDRESS: minio:9000
volumes:
- ./volumes/milvus:/var/lib/milvus
ports:
- "19530:19530"
- "9091:9091"
depends_on:
- etcd
- minio
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"]
interval: 30s
start_period: 90s
timeout: 20s
retries: 3
3.2 启动并验证
cd memory-kb
docker compose up -d
等待约 1 分钟后验证服务状态:
docker ps | grep milvus
# 应看到 milvus-standalone / milvus-etcd / milvus-minio 三个容器均在运行
3.3 安装 Python 依赖
pip install pymilvus==2.4.4 openai==1.35.0 sentence-transformers==3.0.1 numpy
若使用本地大模型,还需要 ollama:
pip install ollama
4. 连接 Milvus 并创建第一个集合
Milvus 2.x 使用 Collection(集合) 类比关系型数据库中的表。先写一个工具模块 milvus_client.py,封装连接逻辑:
# milvus_client.py
from pymilvus import (
connections,
Collection,
CollectionSchema,
FieldSchema,
DataType,
utility,
)
# 与 Milvus 建立连接
connections.connect(
alias="default",
host="localhost",
port="19530",
)
def create_memory_collection(collection_name: str = "personal_memory"):
"""创建一个面向私人记忆的向量集合,带动态字段。"""
# 检查集合是否已存在,避免重复创建报错
if utility.has_collection(collection_name):
print(f"[INFO] 集合 {collection_name} 已存在,直接返回。")
return Collection(collection_name)
# 定义字段:id、文本内容、向量、时间戳、来源、标签
fields = [
FieldSchema(
name="id",
dtype=DataType.INT64,
is_primary=True,
auto_id=True,
description="主键 ID,自动生成",
),
FieldSchema(
name="content",
dtype=DataType.VARCHAR,
max_length=8192,
description="原始文本记忆内容",
),
FieldSchema(
name="embedding",
dtype=DataType.FLOAT_VECTOR,
dim=1536, # OpenAI text-embedding-3-small 的维度
description="文本向量",
),
FieldSchema(
name="timestamp",
dtype=DataType.INT64,
description="记忆写入时间戳",
),
FieldSchema(
name="source",
dtype=DataType.VARCHAR,
max_length=256,
description="数据来源,如 chat、note、doc",
),
FieldSchema(
name="tag",
dtype=DataType.VARCHAR,
max_length=128,
description="自定义标签",
),
]
schema = CollectionSchema(
fields=fields,
description="私人记忆知识库集合",
enable_dynamic_field=True, # 允许插入未预先定义的结构化字段
)
collection = Collection(name=collection_name, schema=schema)
print(f"[INFO] 集合 {collection_name} 创建成功。")
return collection
补充说明:如果使用本地
sentence-transformers模型,embedding维数通常为 384(all-MiniLM-L6-v2)或 768 / 1024,需要把dim改为对应值。下文会统一封装。
5. 向量化:把文字变成向量
Milvus 本身只存向量和标量,不负责把文字变成向量——这是 Embedding 模型的活儿。为了兼容 OpenAI 与本地模型,我们抽象一个统一的 Embedder 类:
# embedder.py
from typing import List
import numpy as np
class OpenAIBgeEmbedder:
"""基于 OpenAI 兼容接口的 Embedding 客户端。
既支持官方 OpenAI,也兼容任何 OpenAI 协议的服务
(如 Ollama + bge-m3、vLLM 等)。
"""
def __init__(
self,
model: str = "text-embedding-3-small",
base_url: str | None = None,
api_key: str = "sk-your-key-here",
):
from openai import OpenAI
self.dim = 1536 # text-embedding-3-small 默认维度
self.client = OpenAI(base_url=base_url, api_key=api_key)
self.model = model
def encode(self, texts: List[str]) -> np.ndarray:
"""批量把文本编码为向量矩阵。"""
texts = [t.strip()[:8000] for t in texts] # 防御超长输入
resp = self.client.embeddings.create(model=self.model, input=texts)
return np.array([item.embedding for item in resp.data], dtype=np.float32)
def encode_query(self, text: str) -> np.ndarray:
"""编码单条查询文本。"""
return self.encode([text])[0]
class SentenceTransformerEmbedder:
"""基于 sentence-transformers 的本地 Embedding。"""
def __init__(self, model_name: str = "BAAI/bge-small-zh-v1.5"):
from sentence_transformers import SentenceTransformer
self.model = SentenceTransformer(model_name)
self.dim = self.model.get_sentence_embedding_dimension()
def encode(self, texts: List[str], normalize: bool = True) -> np.ndarray:
emb = self.model.encode(
texts,
normalize_embeddings=normalize,
show_progress_bar=False,
)
return np.array(emb, dtype=np.float32)
def encode_query(self, text: str) -> np.ndarray:
return self.encode([text])[0]
为什么查询向量要做归一化? 因为 Milvus 的 IP(内积)索引要求归一化向量才能等价于余弦相似度;如果直接用 L2 索引则可不归一化。我们后面统一用 COSINE 度量,sentence-transformers 默认已归一化,OpenAI 向量也建议在使用前归一化(虽然 text-embedding-3-small 的向量模长接近 1,但严谨起见统一处理)。
6. 写入记忆:聊天记录入库
现在把「私人记忆」写入 Milvus。假设你有一段与 AI 助手的历史对话,需要切成小段记忆。先实现文本切分:
# chunker.py
from typing import List
def split_text(
text: str,
chunk_size: int = 300,
overlap: int = 50,
separator: str = "\n",
) -> List[str]:
"""简单按字数切分文本,带重叠避免语义被截断。
chunk_size: 每段最大字符数
overlap: 相邻两段重叠的字符数
"""
text = text.strip()
if len(text) <= chunk_size:
return [text]
chunks: List[str] = []
start = 0
while start < len(text):
end = min(start + chunk_size, len(text))
chunk = text[start:end]
chunks.append(chunk)
start = end - overlap if end < len(text) else len(text)
return chunks
def split_conversation(messages: List[dict]) -> List[dict]:
"""把对话消息按角色分组,生成带上下文的记忆片段。
每条记忆会带上「说话人」前缀,方便后续检索。
返回: 每个元素含 content / source / tag 字段。
"""
records = []
for msg in messages:
role = msg.get("role", "user")
content = msg.get("content", "")
prefix = "用户说:" if role == "user" else "助手说:"
full = prefix + content
for chunk in split_text(full, chunk_size=300, overlap=40):
records.append(
{
"content": chunk,
"source": "chat",
"tag": role, # user / assistant
}
)
return records
接着把记忆批量写入 Milvus:
# ingest_memory.py
import time
from pymilvus import Collection
from milvus_client import create_memory_collection
from embedder import OpenAIBgeEmbedder
from chunker import split_conversation
def ingest_memories(
collection: Collection,
records: list[dict],
embedder,
batch_size: int = 16,
):
"""批量写入记忆:先向量化,再插库。"""
total = len(records)
for i in range(0, total, batch_size):
batch = records[i : i + batch_size]
contents = [r["content"] for r in batch]
vectors = embedder.encode(contents)
# 各批次时间戳统一,便于回溯
ts = int(time.time())
entities = [
[r["content"] for r in batch], # content 字段
vectors.tolist(), # embedding 字段
[ts] * len(batch), # timestamp 字段
[r.get("source", "note") for r in batch], # source 字段
[r.get("tag", "") for r in batch], # tag 字段
]
collection.insert(entities)
print(f"[INFO] 已写入 {min(i + batch_size, total)}/{total} 条记忆")
if __name__ == "__main__":
# 示例:模拟一段对话记录
demo_messages = [
{"role": "user", "content": "我最近在做一个关于 RAG 的项目,技术栈是 Python 和 Milvus。"},
{"role": "assistant", "content": "很好,Milvus 非常适合做向量检索,建议使用 COSINE 度量并配合 HNSW 索引。"},
{"role": "user", "content": "对了,我还想加一个记忆管理模块,能让 AI 记住长期偏好。"},
{"role": "assistant", "content": "可以设计短期滑动窗口 + 长期向量记忆的混合策略,把重要对话摘要后写回 Milvus。"},
{"role": "user", "content": "我比较喜欢简洁的代码风格,变量命名用 snake_case。"},
{"role": "assistant", "content": "明白,后续示例代码都会遵循这个偏好。"},
]
records = split_conversation(demo_messages)
print(f"[INFO] 共生成 {len(records)} 条记忆片段")
collection = create_memory_collection("personal_memory")
embedder = OpenAIBgeEmbedder()
ingest_memories(collection, records, embedder)
print("[INFO] 记忆写入完成。")
7. 建立索引:让检索快起来
数据写入后必须建索引才能做高效相似度检索。这里使用 HNSW 索引 + COSINE 度量,这是私人知识库场景的通用高性价比组合:
# build_index.py
from pymilvus import Collection, IndexType, utility
def build_index(collection: Collection, index_type: str = "HNSW"):
index_params = {
"metric_type": "COSINE", # 余弦相似度
"index_type": index_type,
"params": {"M": 16, "efConstruction": 200}, # HNSW 参数
}
collection.create_index(field_name="embedding", index_params=index_params)
print(f"[INFO] 为 embedding 字段创建了 {index_type} 索引(COSINE)")
def wait_index_ready(collection: Collection):
"""等待索引构建完成。"""
utility.wait_for_index_build(collection.name, timeout=60)
print("[INFO] 索引构建已完成并可查询。")
if __name__ == "__main__":
from milvus_client import create_memory_collection
collection = create_memory_collection("personal_memory")
build_index(collection)
wait_index_ready(collection)
print("[INFO] 索引准备就绪,可以开始检索。")
对于百万级以内的记忆库,HNSW 的 M=16、efConstruction=200 足够;数据量上亿后再考虑 IVF_PQ / DiskANN 等更省内存的索引。
8. 检索记忆:语义搜索实战
建好索引后,就能对私人记忆做语义检索。模拟用户抛出一个问题,系统从 Milvus 里找回最相关的历史记忆:
# search_memory.py
from pymilvus import Collection
from milvus_client import create_memory_collection
from embedder import OpenAIBgeEmbedder
def search_memories(
collection: Collection,
query: str,
embedder,
top_k: int = 5,
filter_expr: str | None = None,
):
"""语义检索记忆。filter_expr 可限定来源或标签,如 'source == "chat"'。"""
# 1. 先加载集合到内存(HNSW 执行搜索前必须 load)
collection.load()
# 2. 把查询文本向量化
query_vec = embedder.encode_query(query).tolist()
# 3. 执行检索,返回 top_k 条相似记忆 + 距离分数
search_params = {
"metric_type": "COSINE",
"params": {"ef": 128}, # 查询阶段 HNSW 的搜索宽度
}
results = collection.search(
data=[query_vec],
anns_field="embedding",
param=search_params,
limit=top_k,
expr=filter_expr,
output_fields=["content", "timestamp", "source", "tag"],
)
hits = []
for hit in results[0]:
hits.append(
{
"id": hit.id,
"score": hit.distance, # COSINE 下介于 -1~1,越大越相似
"content": hit.entity.get("content"),
"source": hit.entity.get("source"),
"tag": hit.entity.get("tag"),
"timestamp": hit.entity.get("timestamp"),
}
)
return hits
if __name__ == "__main__":
collection = create_memory_collection("personal_memory")
embedder = OpenAIBgeEmbedder()
query = "我之前提到过什么项目?用的什么技术栈?"
hits = search_memories(collection, query, embedder, top_k=3)
print(f"\n问题:{query}\n")
for i, h in enumerate(hits, 1):
print(f"--- 命中 {i}(相似度 {h['score']:.4f})---")
print(f"[{h['tag']}] {h['content']}")
print(f"来源:{h['source']} | 时间戳:{h['timestamp']}\n")
输出类似:
问题:我之前提到过什么项目?用的什么技术栈?
--- 命中 1(相似度 0.8231)---
[user] 用户说:我最近在做一个关于 RAG 的项目,技术栈是 Python 和 Milvus。
来源:chat | 时间戳:1758000000
--- 命中 2(相似度 0.7812)---
[assistant] 助手说:很好,Milvus 非常适合做向量检索,建议使用 COSINE 度量并配合 HNSW 索引。
来源:chat | 时间戳:1758000000
可以观察到,语义检索不需要关键词完全匹配——「什么技术栈」能自动关联到「Python 和 Milvus」这条记忆。
9. 接入大模型:从检索到回答
有了记忆检索能力,下一步就是让大模型基于这些记忆生成回答。这是 RAG 的「生成」环节:
# rag_assistant.py
from typing import List
from openai import OpenAI
from pymilvus import Collection
from milvus_client import create_memory_collection
from embedder import OpenAIBgeEmbedder
from search_memory import search_memories
SYSTEM_PROMPT = """你是一个拥有长期记忆的私人 AI 助手。
回答用户问题前,你会先阅读【相关记忆】。
规则:
1. 如果记忆中有相关信息,优先依据记忆回答,并保持记忆中的表述风格。
2. 不要编造记忆里没有的内容;如果记忆不足,请如实说明。
3. 涉及用户偏好时,严格遵守记忆中的偏好。
4. 作答语言与用户问题保持一致。
"""
def build_prompt(question: str, memories: List[dict]) -> str:
"""把检索到的记忆拼接进 prompt。"""
memory_lines = []
for i, m in enumerate(memories, 1):
memory_lines.append(
f"{i}. ({m['tag']},相似度 {m['score']:.3f}){m['content']}"
)
memory_block = "\n".join(memory_lines) if memory_lines else "(无相关记忆)"
return f"""【相关记忆】
{memory_block}
【用户问题】
{question}
"""
class MemoryRagAssistant:
def __init__(self, collection: Collection, embedder, llm: OpenAI, model: str = "gpt-4o-mini"):
self.collection = collection
self.embedder = embedder
self.llm = llm
self.model = model
def answer(self, question: str, top_k: int = 5) -> str:
# 1. 检索记忆
memories = search_memories(self.collection, question, self.embedder, top_k=top_k)
# 2. 拼接 prompt
user_prompt = build_prompt(question, memories)
# 3. 调用大模型
resp = self.llm.chat.completions.create(
model=self.model,
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_prompt},
],
temperature=0.3, # 记忆问答场景降低随机性
)
return resp.choices[0].message.content
执行一个端到端示例:
# run_rag_demo.py
from openai import OpenAI
from milvus_client import create_memory_collection
from embedder import OpenAIBgeEmbedder
from rag_assistant import MemoryRagAssistant
if __name__ == "__main__":
collection = create_memory_collection("personal_memory")
embedder = OpenAIBgeEmbedder()
llm = OpenAI(api_key="sk-your-key-here")
assistant = MemoryRagAssistant(collection, embedder, llm)
questions = [
"我之前说我的代码风格偏好是什么?",
"我在做的那个项目的技术栈是什么?",
]
for q in questions:
answer = assistant.answer(q, top_k=3)
print(f"\n用户:{q}")
print(f"助手:{answer}")
输出示例:
用户:我之前说我的代码风格偏好是什么?
助手:你提到更喜欢简洁的代码风格,变量命名使用 snake_case,我会在后续示例中遵循这个偏好。
用户:我在做的那个项目的技术栈是什么?
助手:你之前在做的项目是 RAG 方向,技术栈是 Python 和 Milvus。
到这里,一个基本的「记忆检索 + 大模型回答」链路已经跑通。
10. 记忆管理:让 AI 持续「记住」新内容
真正的私人记忆系统不能只读不写——每次对话结束后,新信息要回流到 Milvus,才能形成闭环。这里实现一个「对话后记忆持久化」模块:
# memory_manager.py
from typing import List
from pymilvus import Collection
import time
def persist_conversation(
collection: Collection,
question: str,
answer: str,
embedder,
source: str = "conversation",
):
"""把一轮问答作为新记忆写入 Milvus。"""
# 只持久化有信息量的对话
if len(question) < 5 and len(answer) < 5:
print("[WARN] 对话内容过短,跳过持久化。")
return
record = f"用户问:{question}\n助手答:{answer}"
vec = embedder.encode([record])[0].tolist()
ts = int(time.time())
entities = [
[record], # content
[vec], # embedding
[ts], # timestamp
[source], # source
["qa"], # tag
]
collection.insert(entities)
print(f"[INFO] 已持久化本轮对话记忆({len(record)} 字符)")
def remember_user_fact(
collection: Collection,
fact: str,
embedder,
tag: str = "fact",
):
"""专门记录一条结构化事实/偏好,带高优先 tag。"""
if not fact.strip():
return
vec = embedder.encode([f"[重要事实] {fact}"])[0].tolist()
ts = int(time.time())
entities = [
[f"[重要事实] {fact}"], # content
[vec], # embedding
[ts], # timestamp
["user_profile"], # source
[tag], # tag
]
collection.insert(entities)
print(f"[INFO] 已记录用户事实:{fact}")
记忆管理最佳实践:
- 用
tag区分记忆类型(fact偏好、qa对话、event事件),检索时可用filter_expr只搜某一类。 - 对高频重复的内容做去重:检索到相似度 > 0.95 的记忆时可选择更新而非新增。
- 定期对长期记忆做摘要压缩,把琐碎对话合并成事实,减小库体积。
11. 完整实战项目:私人记忆助手 CLI
把前面所有模块串起来,实现一个命令行交互式的私人记忆助手。它支持三种命令:
| 命令 | 作用 |
|---|---|
/ask <问题> | 基于记忆向大模型提问 |
/remember <内容> | 记忆一条重要事实 |
/quit | 退出并保存会话记忆 |
# memory_assistant_cli.py
import os
from openai import OpenAI
from milvus_client import create_memory_collection
from embedder import OpenAIBgeEmbedder, SentenceTransformerEmbedder
from search_memory import search_memories
from rag_assistant import MemoryRagAssistant
from memory_manager import persist_conversation, remember_user_fact
def print_banner():
print("=" * 50)
print(" 私人记忆助手 | Milvus + LLM")
print(" /ask <问题> 基于记忆提问")
print(" /remember <内容> 记忆一条事实")
print(" /quit 退出")
print("=" * 50)
def main():
# 根据环境变量选择 Embedding;默认本地模型,无需 API Key
use_openai = os.getenv("USE_OPENAI_EMBEDDING", "0") == "1"
if use_openai:
embedder = OpenAIBgeEmbedder()
else:
embedder = SentenceTransformerEmbedder("BAAI/bge-small-zh-v1.5")
# 如果使用的向量维度与集合不一致,需先删掉旧集合重建
# from pymilvus import utility
# dims_changed = True
# if dims_changed:
# utility.drop_collection("personal_memory")
collection = create_memory_collection("personal_memory")
# 这里需要保证集合创建时 dim 与 embedder.dim 一致:
# 若你切换了 embedding 模型,请 drop 集合后重新创建并修改 dim。
llm = OpenAI(
base_url=os.getenv("OPENAI_BASE_URL", None),
api_key=os.getenv("OPENAI_API_KEY", "sk-local"),
)
assistant = MemoryRagAssistant(
collection, embedder, llm, model=os.getenv("LLM_MODEL", "gpt-4o-mini")
)
print_banner()
while True:
try:
user_input = input("\n你:").strip()
except (KeyboardInterrupt, EOFError):
break
if not user_input:
continue
if user_input == "/quit":
print("再见!本次会话中你有记住的重要信息吗?")
break
if user_input.startswith("/remember "):
fact = user_input[len("/remember "):].strip()
remember_user_fact(collection, fact, embedder)
continue
if user_input.startswith("/ask "):
question = user_input[len("/ask "):].strip()
else:
# 普通输入默认视为提问
question = user_input
print("\n助手思考中...")
answer = assistant.answer(question, top_k=5)
print(f"\n助手:{answer}")
# 这轮问答是否有值得记住的信息?简单策略:问题长度 > 10 才持久化
if len(question) > 10:
persist_conversation(collection, question, answer, embedder)
if __name__ == "__main__":
main()
运行:
python memory_assistant_cli.py
交互示例:
==================================================
私人记忆助手 | Milvus + LLM
/ask <问题> 基于记忆提问
/remember <内容> 记忆一条事实
/quit 退出
==================================================
你:/remember 我是一名化学老师,对量子化学很感兴趣。
你:/ask 我的职业是什么?有什么兴趣?
助手思考中...
助手:你的职业是化学老师,并且对量子化学很感兴趣。
你:下周帮我准备一份关于分子轨道的科普提纲
助手思考中...
助手:好的!基于你的化学老师背景和量子化学兴趣,我会侧重用高中可理解的
类比来展开分子轨道理论……
12. 注意事项与进阶方向
12.1 性能与存储
- 私人记忆库数据量通常不大(几万条以内),HNSW 索引完全够用,查询延迟在毫秒级。
- 若记忆超过百万条,可考虑对
source或tag字段做标量索引并配合分区(Partition)提升过滤性能。 - 向量维度越高越消耗内存:
text-embedding-3-small(1536 维)比bge-small-zh(512 维)更吃资源,但语义表达能力更强,根据硬件取舍。
12.2 隐私
私人记忆库意味着数据高度敏感。若不上云,推荐全本地方案:
- 向量库:Milvus 本就私有化部署。
- Embedding:
bge-m3/bge-small-zh本地推理。 - 大模型:Ollama 跑
qwen2.5/llama3.1等本地模型。
这样整条链路的数据都不出本机。
12.3 记忆策略进阶
- 短期记忆:用滑动窗口保存最近 N 轮对话,直接进 prompt,不落库。
- 长期记忆:通过「提取事实 → 去重 → 写回 Milvus」策略,把短期记忆中的有效信息固化为长期向量。
- 反思式记忆:定时对新增记忆做聚类总结,生成更高层级的抽象记忆(如「用户整体偏好简洁代码」)。
13. 总结
本文从零搭建了一个完整的私人记忆知识库:
- 用 Docker 部署 Milvus 单机版;
- 实现统一 Embedding 抽象,兼容 OpenAI 与本地模型;
- 完成记忆的分块、写入、索引构建与语义检索;
- 接入大模型,打通 RAG 问答;
- 增加记忆回流机制,让私人知识库持续增长;
- 最终封装成一个可直接运行的 CLI 私人记忆助手。
这套代码稍加扩展就能变成浏览器插件、微信机器人或者本地笔记工具的记忆后端。向量数据库 + 大模型的组合正把「AI 懂你」从口号变成工程问题——而 Milvus 是这一工程问题中最可靠的一块拼图。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)