Files
knowledge-base/AI/mem0/deploy.md
2026-06-01 15:37:47 +00:00

8.8 KiB
Raw Blame History

mem0 自托管部署

镜像

ccr.ccs.tencentyun.com/tei_agent/mem0:latest

依赖服务tei namespace

服务 地址 用途
PostgreSQL 192.168.3.49:5432 关系数据存储
Qdrant qdrant:6333 向量存储
TEI (BGE-M3) tei:8080 Embedder文本→向量

环境变量

ConfigMap (mem0-env)

变量 说明
APP_DB_NAME mem0 数据库名
QDRANT_HOST qdrant Qdrant 服务地址
QDRANT_PORT 6333 Qdrant 端口
QDRANT_COLLECTION_NAME mem0 集合名
EMBEDDER_PROVIDER tei Embedder 使用 TEI
TEI_ENDPOINT http://tei:8080 TEI endpoint
LLM_PROVIDER openai LLM providerMiniMax 兼容 OpenAI 格式)
OPENAI_API_KEY YOUR_MINIMAX_KEY MiniMax API key
OPENAI_BASE_URL https://api.minimax.chat/v1 MiniMax API 地址
AUTH_DISABLED false 启用认证
MEM0_TELEMETRY false 关闭遥测
REQUEST_LOG_RETENTION_DAYS 30 日志保留天数
HISTORY_DB_PATH /app/data/mem0_history.db SQLite 历史数据库路径

Secret (mem0-secrets)

变量 说明
JWT_SECRET JWT 签名密钥
ADMIN_API_KEY 管理后台 API key
POSTGRES_PASSWORD PostgreSQL 密码

数据库迁移 (Alembic)

mem0 server 使用 Alembic 管理 PostgreSQL schema。首次部署前必须先执行迁移,创建 request_logs 等表。

迁移 Job

apiVersion: batch/v1
kind: Job
metadata:
  name: mem0-migrate
  namespace: tei
spec:
  ttlSecondsAfterFinished: 300  # 完成后5分钟自动清理
  template:
    spec:
      restartPolicy: OnFailure
      containers:
        - name: alembic
          image: ccr.ccs.tencentyun.com/tei_agent/mem0:latest
          command: ["alembic", "upgrade", "head"]
          envFrom:
            - configMapRef:
                name: mem0-env
            - secretRef:
                name: mem0-secrets
          env:
            - name: POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: dify-prod-db-secret
                  key: password
          resources:
            limits:
              memory: "512Mi"
              cpu: "500m"

迁移部署步骤

# 1. 先跑迁移(只执行一次)
kubectl apply -f mem0-migrate-job.yaml

# 2. 确认迁移完成
kubectl get job mem0-migrate -n tei -w

# 3. 确认成功后再部署 mem0
kubectl apply -f mem0-deployment.yaml

# 4. 如果迁移失败,查看原因
kubectl logs job/mem0-migrate -n tei

重要:迁移 Job 只跑一次。Pod 重启时不需要重新迁移PostgreSQL schema 不会天天变。

前置要求

  1. pgvector 扩展 — PostgreSQL 需要安装 pgvector
  2. mem0 数据库 — 需要提前创建
  3. mem0-migrate Job — 首次部署前必须先执行迁移
  4. mem0-history PVC — 必须提前创建
  5. Qdrant collection — mem0 启动时自动创建(首次调用时)

部署清单

PVC + ConfigMap + Secret + Deployment + Service

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mem0-history
  namespace: tei
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: standard  # 根据你的 StorageClass 调整
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: mem0-env
  namespace: tei
data:
  APP_DB_NAME: "mem0"
  QDRANT_HOST: "qdrant"
  QDRANT_PORT: "6333"
  QDRANT_COLLECTION_NAME: "mem0"
  EMBEDDER_PROVIDER: "tei"
  TEI_ENDPOINT: "http://tei:8080"
  LLM_PROVIDER: "openai"
  OPENAI_API_KEY: "YOUR_MINIMAX_KEY"
  OPENAI_BASE_URL: "https://api.minimax.chat/v1"
  AUTH_DISABLED: "false"
  MEM0_TELEMETRY: "false"
  REQUEST_LOG_RETENTION_DAYS: "30"
  HISTORY_DB_PATH: "/app/data/mem0_history.db"
---
apiVersion: v1
kind: Secret
metadata:
  name: mem0-secrets
  namespace: tei
type: Opaque
stringData:
  JWT_SECRET: "your-jwt-secret-change-me"
  ADMIN_API_KEY: "your-admin-key-change-me"
  POSTGRES_PASSWORD: "gitlab"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mem0
  namespace: tei
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mem0
  template:
    metadata:
      labels:
        app: mem0
    spec:
      containers:
        - name: mem0
          image: ccr.ccs.tencentyun.com/tei_agent/mem0:latest
          ports:
            - containerPort: 8000
              name: http
          envFrom:
            - configMapRef:
                name: mem0-env
            - secretRef:
                name: mem0-secrets
          volumeMounts:
            - name: mem0-history
              mountPath: /app/data
          resources:
            limits:
              cpu: "2"
              memory: "4Gi"
            requests:
              cpu: "500m"
              memory: "1Gi"
      volumes:
        - name: mem0-history
          persistentVolumeClaim:
            claimName: mem0-history
---
apiVersion: v1
kind: Service
metadata:
  name: mem0
  namespace: tei
spec:
  ports:
    - port: 8000
      name: http
  selector:
    app: mem0

验证

# 检查 PVC
kubectl get pvc -n tei mem0-history

# 检查 Pod
kubectl get pods -n tei -l app=mem0

# 查看日志
kubectl logs -n tei -l app=mem0 --tail=50

# 健康检查
curl http://mem0:8000/health

History SQLite 说明

mem0 的对话历史存储在 SQLite位于 /app/data/mem0_history.db必须用 PVC 持久化emptyDir 挂载重启后数据丢失。

如果 PVC 空间不足或不需要历史功能,可以改用空目录(数据丢失但不影响核心记忆功能):

# 测试/轻量级环境用 emptyDir
volumes:
  - name: mem0-history
    emptyDir: {}

Dashboard 部署

mem0 dashboard 是 Next.js 应用,需要单独部署。

环境变量

NEXT_PUBLIC_API_URL=http://mem0.tei.svc.cluster.local:8000  # 浏览器调用(通过 Ingress
API_INTERNAL_URL=http://mem0.tei.svc.cluster.local:8000     # 服务端内部调用K8s 内部直连)
NEXT_PUBLIC_INSTANCE_NAME=Mem0

API_INTERNAL_URLK8s 内部服务间通信,直接使用 Service DNS不需要暴露到外部。浏览器无法解析 mem0.tei.svc.cluster.local,所以前端用 NEXT_PUBLIC_API_URL 通过 Ingress 访问。

两者可以相同,但分离部署时:

  • NEXT_PUBLIC_API_URL = 对外域名Ingress
  • API_INTERNAL_URL = 集群内部 mem0.tei.svc.cluster.local:8000

CORS 配置

mem0 server 使用 CORSMiddleware需要通过环境变量配置允许的来源

DASHBOARD_URL=https://mem0.your-domain.com  # dashboard 的外部访问地址

mem0 server 启动时读取 DASHBOARD_URL,设置 allow_origins=[DASHBOARD_URL]

常见问题

  • 浏览器访问 dashboard 登录页时,返回 400 Bad Request
  • OPTIONS 预检请求失败,因为 allow_origins 为空
  • Swagger 能正常登录(同域请求,无 CORS 问题)

确保 DASHBOARD_URL 设为 dashboard 的外部访问地址(与 NEXT_PUBLIC_API_URL 的域名部分一致)。

sentence_transformers 导入错误

mem0 的 huggingface.py 在文件顶部执行 from sentence_transformers import SentenceTransformer,即使走 huggingface_base_url 路径(用 OpenAI 客户端调用 TEI不需要本地模型也会尝试加载造成 ModuleNotFoundError

临时修复(容器内,重启会丢):

sed -i 's/from sentence_transformers import SentenceTransformer/# from sentence_transformers import SentenceTransformer/' /usr/local/lib/python3.12/site-packages/mem0/embeddings/huggingface.py

验证:

python3 -c "from mem0.embeddings.huggingface import HuggingFaceEmbedding"

永久修复:在 Dockerfile 里加这步,或修改本地 mem0 源码后 COPY 进容器。

功能测试

mem0 未为 K8s 做适配,无健康检查端点。手动测试核心 API

cat > /tmp/test_mem0.py << 'TESTEOF'
import urllib.request, json, uuid

BASE = "http://mem0:8000"

def req(method, path, data=None):
    url = BASE + path
    body = json.dumps(data).encode() if data else None
    headers = {"Content-Type": "application/json"}
    try:
        r = urllib.request.urlopen(urllib.request.Request(url, data=body, headers=headers, method=method), timeout=10)
        return json.loads(r.read()), r.status
    except urllib.error.HTTPError as e:
        return json.loads(e.read()), e.code
    except Exception as e:
        return str(e), 0

uid = str(uuid.uuid4())
print("=== 1. 创建用户 ===")
print(req("POST", "/api/v1/users", {"user_id": uid, "email": f"{uid}@test.com"}))

print("=== 2. 添加记忆 ===")
print(req("POST", "/api/v1/memories", {"text": "我叫张三我喜欢Python", "user_id": uid}))

print("=== 3. 搜索记忆 ===")
print(req("GET", f"/api/v1/memories?query=python&user_id={uid}"))

print("=== 4. 获取历史 ===")
print(req("GET", f"/api/v1/history?user_id={uid}"))
TESTEOF
kubectl exec -n tei deploy/mem0 -- python3 /tmp/test_mem0.py