Metadata-Version: 2.5
Name: zvec-mem
Version: 0.1.2
Summary: Local-first, agent-ready persistent memory layer for LLM agents, built on Zvec
Project-URL: Homepage, https://zvec.org
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: agent,llm,local-first,mcp,memory,ollama,zvec
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Requires-Python: >=3.12
Requires-Dist: fastmcp>=0.10
Requires-Dist: jinja2>=3.1
Requires-Dist: ollama
Requires-Dist: openai
Requires-Dist: typer>=0.12
Requires-Dist: zvec
Provides-Extra: sparse
Requires-Dist: dashtext; extra == 'sparse'
Description-Content-Type: text/markdown

# zvec-mem

本地优先（local-first）的 Agent 持久记忆层，存储基于 **Zvec**（嵌入式向量库，进程内、零部署）。

> 定位 zvec-grep 的补集：zg 索引"代码/文档里写了什么"，zvec-mem 记忆"用户/agent 历史上发生过什么、偏好在哪"。

## 特性

- **纯本地**：zvec 嵌入式存储 + Ollama 本地模型，默认零出网；远程运行时 deny-by-default
- **Mem0 式记忆语义**：LLM 抽取原子事实 → hash 去重（精确重复 100% 拦截）→ 只增不改（v3 风格）；LLM 冲突决策去重（仅在候选与现有记忆足够相似时询问 LLM ADD/SKIP）
- **混合检索**：dense 向量 + 中文 FTS（jieba BM25）双路，RRF 融合（k=60）
- **双入口**：CLI（`zm`）+ MCP server（9 个工具，Zed / Claude Code / Qoder 可直接接入）
- **运行时可插拔**（provider 抽象）：`ollama/<model>` 现可用；`local/*`（potion/onnx/gguf）执行器后续接入；`bm25/zh` 稀疏路在 Linux/macOS 可用（需要 dashtext）

## 源码安装

```bash
# 从源码安装（开发模式，改代码即生效）
uv tool install --editable /path/to/zvec-mem
# 发布后直接安装
# uv tool install zvec-mem
```

安装后全局得到两个命令（`~/.local/bin`）：**`zm`**（主命令）与 `zvec-mem`（兼容别名），用法完全一致。

```bash
zm --help
```

## 快速开始

```bash
uv tool install zvec-mem
```

前置条件（默认运行时，可用 `.zvec-mem/config.json` 修改）：

```bash
ollama serve
ollama pull qwen3-embedding:latest        # embedding 默认
ollama pull qwen3:8b      # LLM 默认（抽取/决策/摘要）
```

在项目里初始化并写入/检索记忆：

```bash
cd my-project

zm init                                   # ① 探测 embedding 维度 → 创建 .zvec-mem/ + 自动写 .gitignore
zm status                                 # ② 健康检查：embedding/LLM 是否可用、记忆条数

zm memorize "用户不吃香菜，偏好清淡饮食" --user u1    # ③ 写入：抽取 → 去重 → 入库
zm memorize "批量导入功能要赶在下周五上线" --user u1 --agent product-bot

zm search "饮食偏好" --user u1             # ④ 检索（dense + FTS 混合，RRF 融合）
zm get-all --mem-type semantic --user u1  # ⑤ 列出全部记忆
zm status --json                          # 机器可读状态
```

源码开发模式（未全局安装时）：

```bash
uv sync
uv run zm init
uv run zm memorize "..."
```

## CLI 参考（`zm`）

所有子命令前可加全局选项 `-P, --project-dir <dir>`（或环境变量 `ZVEC_MEM_WORKSPACE`）指定操作的项目，默认当前目录。

| 命令 | 说明 | 常用参数 |
|---|---|---|
| `zm init` | 初始化工作区：探测 embedding 维度、创建 collection、写 `.zvec-mem/config.json` | `--force`（重新探测并覆盖） |
| `zm status` | 运行时健康、存储与配置状态 | `--json` |
| `zm memorize <text>` | 写入记忆（= mem0 add） | `--user` `--agent` `--run` `--no-infer`（原文直存，跳过 LLM 抽取） `--json` |
| `zm search <query>` | 检索记忆（= mem0 search） | `--user` `--agent` `--run` `--mem-type` `--top-k` `--min-score` `--json` |
| `zm get-all` | 列出记忆（= mem0 get_all），默认 JSON | `--user` `--mem-type` `--limit` `--offset` |
| `zm get <memory_id>` | 按 id 读取单条记忆 | — |
| `zm update <memory_id> <text>` | 更新记忆文本（= mem0 update） | `--user` |
| `zm delete <memory_id>` | 删除记忆（= mem0 delete） | — |
| `zm end-run <run_id>` | 结束会话，可选把整段会话压成情景记忆 | `--messages '<json>'`（必填） `--no-summary` |
| `zm auth` | 远程 provider 授权（详见下文） | `status` / `grant` / `revoke` |
| `zm mcp` | 启动 MCP server（stdio） | 配合 `-P` 指定默认项目 |

示例：

```bash
zm -P ../other-proj search "导入需求"        # 从任意目录检索指定项目
zm memorize "用户偏好暗色主题" --user u1 --no-infer   # 跳过 LLM 抽取，原文直存
zm end-run run_20260909 --messages '[{"role":"user","content":"..."}]'
```

- 记忆按项目隔离，存储于项目内 `.zvec-mem/memories/`（已 gitignore，不进仓库），审计日志 `.zvec-mem/audit.jsonl`
- 未 init 的项目执行记忆命令会得到友好提示，不会误连默认配置

## MCP 接入

MCP server 走 stdio，机制同 `zg server --stdio`：每次工具调用可选传 `project_dir`（项目根绝对路径），也可由 server 自动感知。

### 工作区探测优先级

1. **请求级 `project_dir`**：客户端在每次工具调用时传绝对项目路径（最优先）
2. **server 默认值**：启动参数 `-P` / 环境变量 `ZVEC_MEM_WORKSPACE`
3. **walk-up**：都未提供时，从进程 cwd 向上找最近的 `.zvec-mem/config.json`

找不到任何 `.zvec-mem` → 工具返回友好错误（提示先 `zm init`），**不会静默建库**。

### Zed

在项目 `settings.json` 中加（`-P` 指定项目根；省略时依赖 walk-up）：

```json
{
  "context_servers": {
    "zvec-mem": {
      "command": {
        "path": "zm",
        "args": ["-P", "D:/path/to/my-project", "mcp"]
      }
    }
  }
}
```

### Claude Code

```bash
# 项目级（在该项目目录执行，Claude Code 会在项目内初始化）
claude mcp add zvec-mem -- zm mcp --project-dir D:/path/to/my-project
claude mcp list
# 移除：claude mcp remove zvec-mem
```

（Windows 下若 `zm` 不在 PATH，把 `zm` 换成 `C:/Users/<you>/.local/bin/zm.exe`。）

### 通用 stdio 配置

```json
{
  "mcpServers": {
    "zvec-mem": {
      "command": "zm",
      "args": ["mcp"],
      "cwd": "D:/path/to/my-project"
    }
  }
}
```

### 工具面（9 个）

| 工具 | 对应 Mem0 | 说明 | 关键参数 |
|---|---|---|---|
| `recall` | search | 混合检索，RRF 融合 | `query`；`project_dir?` `user_id?` `agent_id?` `run_id?` `mem_type?` `top_k=10` `min_score=0.0` |
| `get_memories` | get_all | 列出记忆 | `project_dir?` `user_id?` `agent_id?` `run_id?` `mem_type?` `limit=20` `offset=0` |
| `get_memory` | get_all | 按 id 读取单条 | `memory_id`；`project_dir?` |
| `memorize` | add | 记忆漏斗写入 | `messages`（`[{role,content},...]`）；`project_dir?` `user_id?` `agent_id?` `run_id?` `metadata?` `infer=true` |
| `update_memory` | update | 更新记忆文本 | `memory_id` `text`；`project_dir?` `user_id?` |
| `delete_memory` | delete | 删除记忆 | `memory_id`；`project_dir?` |
| `begin_run` | run 生命周期 | 开始会话 | `run_id`；`project_dir?` `metadata?` |
| `end_run` | run 生命周期 | 结束会话，可自动摘要为情景记忆 | `run_id` `messages`；`project_dir?` `summarize=true` |
| `status` | watch | 健康与审计状态 | `project_dir?` |

> 每个工具都接受可选 `project_dir`，客户端（如 Codex/Qoder）可在请求中携带项目根。未 init 时 agent 可先执行 `zm init`，或由项目说明文档引导。

## 配置

优先级（仿 zvec-grep）：`CLI flag > 环境变量（ZVEC_MEM_*）> 工作区 .zvec-mem/config.json > 全局 ~/.zvec-mem/config.json`

### 环境变量

| 变量 | 对应配置键 | 说明 |
|---|---|---|
| `ZVEC_MEM_WORKSPACE` | — | 项目目录（等价 `-P`） |
| `ZVEC_MEM_EMBEDDING` | `embedding_runtime` | 如 `ollama/qwen3-embedding:latest`、`openai/text-embedding-3-small` |
| `ZVEC_MEM_LLM` | `llm_runtime` | 如 `ollama/qwen3:8b`、`openai/gpt-4o-mini` |
| `ZVEC_MEM_STORE` | `store_path` | 存储路径（默认 `.zvec-mem/memories`） |
| `ZVEC_MEM_OLLAMA_HOST` | `ollama_host` | 默认 `http://localhost:11434` |
| `ZVEC_MEM_DEVICE` | `embedding_device` | `auto` / `cpu` / `cuda` |
| `ZVEC_MEM_DIMENSION` | `dimension` | 手动指定 embedding 维度（跳过探测） |
| `ZVEC_MEM_ALLOW_REMOTE` | `allow_remote` | 是否允许远程 provider 调用 |
| `ZVEC_MEM_SPARSE` | `sparse_enabled` | 启用 dashtext BM25 稀疏路 |
| `ZVEC_MEM_RERANK_LLM` | `rerank_llm` | LLM rerank 开关（默认关，见状态节） |
| `ZVEC_MEM_RECALL_STAGE1_TOPN` | `recall_stage1_topn` | RRF 融合的中间结果数（默认 20） |
| `ZVEC_MEM_MODEL_CACHE` | `model_cache` | 本地模型缓存目录 |
| `ZVEC_MEM_<NAME>_API_KEY` | — | 远程 provider 的 API key（`<NAME>` 大写，如 `ZVEC_MEM_OPENAI_API_KEY`） |

### 常用 `.zvec-mem/config.json` 键

```jsonc
{
  "embedding_runtime": "ollama/qwen3-embedding:latest",  // 4096 维
  "llm_runtime": "ollama/qwen3:8b",
  "ollama_host": "http://localhost:11434",
  "dimension": 4096,          // init 时探测写入
  "rerank_llm": false,        // 8B 级本地模型 listwise 会排反，默认关
  "allow_remote": false,      // deny-by-default
  "decision_min_dist": 0.35   // LLM 冲突决策的相似阈值
}
```

## 远程 Provider（OpenAI 兼容，deny-by-default）

支持任何 OpenAI 兼容端点（OpenAI / DashScope compatible-mode / 本地兼容服务），**默认拒绝**，需显式授权：

```bash
# 1. 授权 provider（凭据存 ~/.zvec-mem/providers.json，不进工作区/repo）
zm auth grant openai \
    --base-url https://api.openai.com/v1 \
    --api-key sk-xxx \
    --embedding-model text-embedding-3-small \
    --llm-model gpt-4o-mini \
    --enabled          # 不加 --enabled 则仅保存凭据，调用仍被拦截

# 2. 运行时指向远程（改 .zvec-mem/config.json 或环境变量）
#    embedding_runtime: openai/text-embedding-3-small
#    llm_runtime:       openai/gpt-4o-mini

zm auth status    # 查看授权（api_key 打码）
zm auth revoke openai
```

说明：
- api_key 也可用环境变量 `ZVEC_MEM_<NAME>_API_KEY` 提供（不进盘）
- 远程 URI 前缀 = provider 名（`openai/`、`dashscope/`，或任意自定义名）；未授权 provider 调用会被 deny-by-default 拦截并给出修复提示
- 任意本地 OpenAI 兼容服务（如 Ollama 的 `/v1`）都能以同样方式接入

## 设计参考

- zvec 文档：https://zvec.org/llms.txt
- zg embedding 模型清单：https://zvec.org/zh/docs/zvec-grep/embedding-models/
