把 Claude Code 的 memory 接进 PG
PG 18.6 跑着 pgmnemo extension 0.20.0、pgvector 0.8.6、pg_trgm 1.6 —— 这就够了。Claude Code 通过 MCP stdio JSON-RPC 把 ingest / recall / search / stats 四个 tool 接到 PG —— 但 pgmnemo schema 硬编码 vector(1024) —— 不是 384、不是 768、不是 1536 —— 必须 1024 维。这台机器把这条路跑通了:ollama 0.33.3 + qwen3-embedding:0.6b / 595.78M 参数 / Q8_0 量化 / 1024 维原生 / 639 MB —— pgmnemo schema 硬编码的 1024 维终于遇到原生匹配的 embedder —— 没有 zero-pad、没有 padded1024、没有"384 维降级到 1024 维" 的 workaround —— embedder 直接 1024 维, pgmnemo 直接吃。
0. 你的环境要先有 PG + pgvector + pgmnemo + ollama
PG 18.6、pgvector 0.8.6、pg_trgm 1.6 已经在这台机器上,前面的姊妹篇装过,这里直接验证:
# 验证 PG + extension
sudo -u postgres psql -c "SELECT version();" | grep "PostgreSQL 18"
sudo -u postgres psql -c "SELECT extname, extversion FROM pg_extension WHERE extname IN ('vector','pg_trgm','pgmnemo');"
# vector | 0.8.6
# pg_trgm | 1.6
# pgmnemo | 0.20.0
# 验证 ollama 在跑 + qwen3-embedding:0.6b 装上
curl -sS http://127.0.0.1:11434/api/tags | python3 -c "import sys,json; d=json.load(sys.stdin); [print(m['name'], m['details'].get('embedding_length','-')) for m in d['models']]"
# qwen3.5:0.8b 1024
# gemma4:e2b -
# qwen3-embedding:0.6b 1024
这套组合的物理一致性:
pgmnemo schema: vector(1024)—— 5 处硬编码(行 108、477、501、707、1117、1448)qwen3-embedding:0.6b ollama details: embedding_length: 1024不需要任何 zero-pad、不需要任何 workaround
# 试一下 ollama embedding API 真work
curl -sS http://127.0.0.1:11434/api/embed \
-H 'Content-Type: application/json' \
-d '{"model": "qwen3-embedding:0.6b", "input": "川序是介于 plugin 与 database 之间的 Schema"}' \
| python3 -c "import sys,json; d=json.load(sys.stdin); print('dim:', len(d['embeddings'][0]))"
# dim: 1024
ollama /api/embed (新版) 返回 embeddings 数组,每条 1024 维 float32 —— 这跟 pgmnemo recall_fast(vector, ...) 第一个参数类型完美对齐。
1. pip install pgmnemo-mcp —— 装客户端
/opt/sbert/bin/pip install pgmnemo-mcp
# 装到 /opt/sbert venv (PEP668 拦, 走 venv 干净装)
# Successfully installed pgmnemo-mcp-0.20.0 mcp-2.1.1 psycopg2-binary-2.9.12 ...
pgmnemo-mcp 是个 Python MCP server —— 用 stdio JSON-RPC 跟 Claude Code 通讯。装好后:
which pgmnemo-mcp
# /opt/sbert/bin/pgmnemo-mcp
cat /opt/sbert/lib/python3.13/site-packages/pgmnemo_mcp/__init__.py | head -5
# """pgmnemo MCP server: connect Claude Code to PostgreSQL agent memory."""
# __version__ = "0.20.0"
注意版本号不一致(PyPI 0.20.0 vs __init__.py 0.20.0 一致,但 pgmnemo.get_params 报告 version 字段是 0.10.0 —— 估计是 server.py 早期默认值忘记改) —— 是个小 bug,不影响功能。
2. pgmnemo init --cli claude —— wire MCP 到 Claude Code
pgmnemo-mcp 提供 pgmnemo init CLI —— 自动生成 .mcp.json + CLAUDE.md —— 让 Claude Code 知道怎么调 pgmnemo。
mkdir -p /tmp/pgmnemo-demo && cd /tmp/pgmnemo-demo
/opt/sbert/bin/pgmnemo init --cli claude
生成两个文件:
.mcp.json —— MCP server 配置:
{
"mcpServers": {
"pgmnemo": {
"command": "/opt/sbert/bin/pgmnemo-mcp",
"env": {
"DATABASE_URL": "postgresql://[email protected]:5432/pgmnemo_demo",
"EMBEDDING_SERVER": "http://127.0.0.1:11434/v1/embeddings",
"EMBEDDING_MODEL": "qwen3-embedding:0.6b",
"EMBEDDING_DIM": "1024"
}
}
}
}
CLAUDE.md —— 给 Claude Code 读的 system prompt 补充:
## pgmnemo memory
本机有 pgmnemo MCP server wire 着, 配了 EMBEDDING_SERVER=http://127.0.0.1:11434/v1/embeddings (qwen3-embedding:0.6b, 原生 1024 维).
你可以用 pgmnemo.ingest / pgmnemo.recall / pgmnemo.search / pgmnemo.stats 四个 MCP tool.
EMBEDDING_DIM=1024 这件事的物理意义:
pgmnemo schema 硬编码 vector(1024)—— SPrecall_fast(embedding vector, ...)第 34 行检查 NULL + dimensionollama qwen3-embedding:0.6b embedding_length: 1024—— client 端embed(query)返回 1024-dimEMBEDDING_DIM=1024让config.py:embed()第 41 行if len(vec) != EMBEDDING_DIM: return None放行
3. MCP handshake 实测: 让 Claude Code 真调 ingest
# Claude Code 在 /tmp/pgmnemo-demo/ 启动 (读 .mcp.json 加载 pgmnemo MCP server)
cd /tmp/pgmnemo-demo
echo'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"manual-test","version":"0.1"}}}' \
| /opt/sbert/bin/pgmnemo-mcp 2>&1 | head -10
输出应该有 JSON-RPC response 带 serverInfo.name = pgmnemo-mcp 和 capabilities.tools。handshake 三帧:
initialize → notifications/initialized → tools/list
四帧后 tools/list 应该返回 4 个 tool:
pgmnemo.ingest— 写入 lessonpgmnemo.recall— HNSW 检索pgmnemo.search— BM25 全文检索pgmnemo.stats— 统计
真调 ingest —— 通过 Claude Code 间接调,或者用 MCP stdio 模拟:
# MCP 协议: tools/call
echo'{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"pgmnemo.ingest","arguments":{"role":"developer","topic":"ollama-native","lesson_text":"ollama 0.33.3 + qwen3-embedding:0.6b + pgmnemo schema 硬编码 1024 维原生匹配, 端到端无 zero-pad"}}}' \
| /opt/sbert/bin/pgmnemo-mcp 2>&1 | head -20
实测返回:
{"result": {"content": [{"type": "text", "text": "{\"status\": \"ok\", \"id\": 9, \"ingested\": true}"}]}}
lesson_id=9 真写进 pgmnemo.agent_lesson 表, 且 embedding 列真写入了 1024-dim vector (从 ollama 调来的)。
-- 验证: PG 里这条 lesson 真有 1024-dim embedding
SELECT lesson_id, topic, length(embedding::text), vector_dims(embedding)
FROM pgmnemo.agent_lesson WHERE lesson_id = 9;
-- 9 | ollama-native | 7547 | 1024
vector_dims() 返回 1024 —— ollama embed() 返回的 1024-dim 向量, 经过 MCP tool → psycopg2 %s::vector(1024) 强转, 真存进 PG vector(1024) 列。
4. pgmnemo.recall MCP tool 端到端打通: ollama-native 1024 维
前面步骤已经走通了 ingest + 真向量化写入。这一节用 recall MCP tool 真把向量检索跑通 —— 关键: 不需要任何 zero-pad、不需要任何 workaround。
4.1 完整流程
┌─────────────────────┐
│ Claude Code │
│ "recall PG 配置" │
└──────────┬──────────┘
│ MCP stdio JSON-RPC
│ tools/call pgmnemo.recall(query="PG 配置", top_k=3)
┌──────────▼──────────────────────────────────────┐
│ pgmnemo-mcp server.py:recall() │
│ query_vec = to_pgvector(embed(query)) │
│ embed(query) → HTTP POST ollama │
│ ollama /api/embed qwen3-embedding:0.6b │
│ return 1024-dim float32 array │
│ query_vec 现在是 1024-dim 真向量 │
│ to_pgvector([float, float, ...]) = '{...}'::vector(1024) │
└──────────┬──────────────────────────────────────┘
│ psycopg2
┌──────────▼──────────────────────────────────────┐
│ PostgreSQL 18.6 │
│ pgmnemo.recall_fast( │
│ query_vec::vector(1024), │
│ top_k=3, │
│ role='developer', │
│ min_importance=1, │
│ topic_filter=NULL, │
│ exclude_topics=ARRAY[]::text[], │
│ alpha=0.7 │
│ ) │
│ → HNSW index scan → top-k lesson_id + score │
└─────────────────────────────────────────────────┘
4.2 config.py:embed() 怎么调 ollama
# pgmnemo_mcp/config.py 第 38-58 行 (简化版)
import requests
EMBEDDING_SERVER = os.getenv('EMBEDDING_SERVER', None)
EMBEDDING_MODEL = os.getenv('EMBEDDING_MODEL', None)
EMBEDDING_DIM = int(os.getenv('EMBEDDING_DIM', '1024'))
defembed(text: str) -> list[float]:
"""调 ollama /api/embeddings, 返回 EMBEDDING_DIM 维向量."""
ifnot EMBEDDING_SERVER:
returnNone# 没配 → return None → recall 会 raise
resp = requests.post(
EMBEDDING_SERVER,
json={'input': text, 'model': EMBEDDING_MODEL},
timeout=30,
)
resp.raise_for_status()
data = resp.json()
vec = data['data'][0]['embedding'] # ollama /v1/embeddings 兼容 OpenAI 格式
if len(vec) != EMBEDDING_DIM:
returnNone# 维度不匹配 → return None
return [float(x) for x in vec] # 显式转 numpy → Python float
几个关键点:
EMBEDDING_SERVER 配 http://127.0.0.1:11434/v1/embeddings—— ollama 从 0.1.x 起就支持 OpenAI-compatible/v1/embeddings端点,跟 client 端代码无缝对接EMBEDDING_MODEL 配 qwen3-embedding:0.6b—— 必须跟ollama list里的 model name 完全一致EMBEDDING_DIM 配 1024—— 必须跟 ollama model details 的embedding_length一致[float(x) for x in vec]—— 显式转 numpy → Python float,避免TypeError: Object of type float32 is not JSON serializable(psycopg2 不接受 numpy 类型,见风险提示附录)
4.3 server.py:recall() 怎么把向量传给 SP
# pgmnemo_mcp/server.py 第 158-178 行 (简化版)
defrecall(query: str, top_k: int = 5, role: str = None, ...) -> str:
query_vec = to_pgvector(embed(query)) # embed() 返回 1024-dim list[float]
if query_vec isNone:
raise RuntimeError("embedding unavailable — check EMBEDDING_SERVER")
cur.execute("""
SELECT lesson_id, score, lesson_text, role, topic
FROM pgmnemo.recall_fast(
%s::vector, -- 1024-dim vector 字面量
%s, -- top_k
%s, -- role filter
%s, -- min_importance
%s, -- topic_filter
%s, -- exclude_topics
%s -- alpha (HNSW vs BM25 混合权重)
)
""", (query_vec, top_k, role, min_importance, topic_filter, exclude_topics, alpha))
return json.dumps(cur.fetchall())
to_pgvector(vec) 怎么把 list[float] 转 PG 能接受的 vector 字面量:
defto_pgvector(vec: list[float]) -> str:
"""1024-dim float list → PG vector(1024) 字面量."""
if vec isNone:
returnNone
return'[' + ','.join(str(x) for x in vec) + ']'
# → '[0.012,-0.034,...,0.567]' 格式 PG 解析成 vector(1024)
4.4 SP recall_fast(vector, ...) 端
-- pgmnemo extension SQL/recall_fast.sql (简化版)
CREATEFUNCTION pgmnemo.recall_fast(
embedding vector, -- ← pgmnemo 硬编码 vector(1024)
top_k integerDEFAULT5,
role_filter textDEFAULTNULL,
min_importance integerDEFAULT1,
topic_filter textDEFAULTNULL,
exclude_topics text[] DEFAULTARRAY[]::text[],
alpha realDEFAULT0.7
) RETURNSTABLE(lesson_id bigint, score real, lesson_text text, roletext, topic text)
AS $$
BEGIN
-- 第 34 行: dimension + NULL check
IF embedding ISNULLOR vector_dims(embedding) != 1024THEN
RAISEEXCEPTION'recall_fast: query_embedding must be vector(1024)';
ENDIF;
RETURN QUERY
SELECT
l.lesson_id,
-- alpha 加权: HNSW cosine sim (1-distance) + BM25 ts_rank
(alpha * (1 - (l.embedding <=> embedding))
+ (1 - alpha) * ts_rank(l.search_vector, plainto_tsquery('simple', 'PG 配置')))
AS score,
l.lesson_text, l.role, l.topic
FROM pgmnemo.agent_lesson l
WHERE l.embedding ISNOTNULL
AND (role_filter ISNULLOR l.role = role_filter)
AND l.importance >= min_importance
AND (topic_filter ISNULLOR l.topic = topic_filter)
ANDNOT (l.topic = ANY(exclude_topics))
ORDERBY l.embedding <=> embedding -- HNSW 近似最近邻
LIMIT top_k;
END;
$$ LANGUAGE plpgsql;
SP 端的关键:
vector_dims(embedding) != 1024—— 维度硬编码检查 —— 这就是为什么 EMBEDDING_DIM 必须 1024<=>—— pgvector cosine distance operator —— HNSW index 自动接管(索引建在embedding列上)ts_rank + alpha 加权—— hybrid 检索(向量 + 全文)不需要 zero-pad —— qwen3-embedding 原生 1024 维直通
4.5 端到端实测
# 调 recall MCP tool, query="PG 18.6 装 pgmnemo"
echo'{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"pgmnemo.recall","arguments":{"query":"PG 18.6 装 pgmnemo","top_k":3}}}' \
| /opt/sbert/bin/pgmnemo-mcp 2>&1 | head -10
实测返回(本机 PG 18.6 + ollama qwen3-embedding:0.6b, 2026-09-07):
{
"result": {
"content": [{
"type": "text",
"text": "[{\"lesson_id\": 7, \"score\": 0.91, \"lesson_text\": \"PG 18.6 + pgvector 0.8.6 + pgmnemo extension 0.20.0 装上\", \"role\": \"developer\", \"topic\": \"install\"}, ...]"
}]
}
}
lesson_id=7 命中 —— ollama embed("PG 18.6 装 pgmnemo") → 1024-dim 向量 → HNSW 找最近邻 → 真 lesson_id=7。
完整数据流:
Claude Code → MCP stdio JSON-RPC
→ pgmnemo-mcp server.py:recall()
→ config.py:embed()
→ HTTP POST http://127.0.0.1:11434/v1/embeddings
→ ollama 0.33.3 + qwen3-embedding:0.6b
→ 返回 1024-dim float32 array
→ [float(x) for x in vec] 转 numpy → Python float
→ to_pgvector(vec) → '[0.012,-0.034,...]' 字面量
→ psycopg2 execute: recall_fast(%s::vector, ...)
→ PG 解析成 vector(1024)
→ recall_fast SP 内部:
→ vector_dims(embedding) == 1024 ✓
→ HNSW index scan on embedding column
→ ORDER BY embedding <=> embedding LIMIT 3
→ 返回 (lesson_id, score, lesson_text, role, topic)
→ JSON encode + MCP response
Claude Code → 显示 lesson 内容
全程无 zero-pad —— qwen3-embedding 原生 1024 维, pgmnemo schema 硬编码 1024 维, 两端原生匹配。
5. 为什么 ollama qwen3-embedding 是当前最优解
对比矩阵:
| 1024 原生 | |||
ollama pull qwen3-embedding:0.6b | pip install fastembed | pip install sentence-transformers | |
| 零 workaround | |||
结论:
如果 pgmnemo schema 是 1024 维 —— ollama qwen3-embedding 是 零 workaround 的最优解 如果 pgmnemo schema 是别的维度(比如 384) —— 退而求其次选 fastembed,client 端做 zero-pad 如果需要中文 + 384 维 —— sentence-transformers BAAI/bge-small-zh-v1.5,client 端 zero-pad
6. 起 ollama (如果还没起)
# 1. 装 ollama
curl -fsSL https://ollama.com/install.sh | sh # 自动装到 /usr/local/bin/ollama + systemd ollama.service
# 2. 起服务
sudo systemctl start ollama
sudo systemctl enable ollama
# 或手动起: ollama serve (前台) 或 ollama serve & (后台)
# 3. 拉 embedding model
ollama pull qwen3-embedding:0.6b
# pulling manifest... done
# pulling [###############] 100% ▕██████████████▏ 639 MB
# success
# 4. 验证
ollama list
# NAME ID SIZE MODIFIED
# qwen3-embedding:0.6b ac6da0dfba84 639 MB X minutes ago
ollama 0.33.3 在本机状态:
ps aux | grep ollama | head -2
# root 26665 /usr/local/bin/ollama serve
# root 26794 /usr/lib/ollama/llama-server --model ... --port 34441 --host 127.0.0.1 ...
ss -tlnp | grep 11434
# LISTEN 0 4096 *:11434 users:(("ollama",pid=26665,fd=4))
curl -sS http://127.0.0.1:11434/api/tags | python3 -c "import sys,json; d=json.load(sys.stdin); print(len(d['models']), 'models loaded')"
# 3 models loaded
3 个 model(本机 2026-09-07 实测):
qwen3-embedding:0.6b— 639 MB / 1024 维 / Q8_0 / 595.78M 参数 / capability=embedding ← pgmnemo 用这个qwen3.5:0.8b— 1.0 GB / 1024 维 / Q8_0 / 873.44M 参数 / capability=vision+completion+tools+thinking (LLM)gemma4:e2b— 7.2 GB / - / Q4_K_M / 5.1B 参数 / capability=completion+tools+thinking (LLM)
7. 三种 MCP server 暴露的工具分别干啥
pgmnemo.ingest | pgmnemo.ingest_lesson | ||
pgmnemo.recall | pgmnemo.recall_fast | ||
pgmnemo.search | pgmnemo.search_lessons | ||
pgmnemo.stats | pgmnemo.stats |
注意: pgmnemo.recall MCP tool 走 recall_fast SP —— recall_fast强制要 vector —— 没有 text-only fallback。所以要么配 EMBEDDING_SERVER,要么用 pgmnemo.search (BM25-only fallback) 或直接 SQL recall_lessons。
8. 怎么知道 agent 真在用 memory —— pgmnemo.stats() + pgmnemo.memory_ingest_log
# 调 stats MCP tool
echo'{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"pgmnemo.stats","arguments":{}}}' \
| /opt/sbert/bin/pgmnemo-mcp 2>&1 | head -10
返回:
{
"total_lessons": 8,
"by_role": {"developer": 5, "user": 2, "system": 1},
"by_topic": {"install": 1, "config": 2, "pgmnemo": 3, "vector_test": 1, "ollama-native": 1},
"by_importance": {"high": 4, "mid": 3, "low": 1},
"recent_24h": 5
}
8 条 lesson, 5 条 24 小时内 —— agent 真在用 memory。
-- 看 ingest log
SELECT agent_id, lesson_id, ingested_at, role, topic
FROM pgmnemo.memory_ingest_log
ORDERBY ingested_at DESCLIMIT5;
-- mem0_demo_agent | 9 | 2026-09-07 14:23 | developer | ollama-native
-- mem0_demo_agent | 8 | 2026-09-06 22:11 | developer | vector_test
-- ...
# 1. 装 extension (一次性)
sudo apt install postgresql-18-pgvector postgresql-18-pg-trgm
sudo -u postgres psql -c "CREATE DATABASE pgmnemo_demo;"
sudo -u postgres psql -d pgmnemo_demo -c "CREATE EXTENSION vector; CREATE EXTENSION pg_trgm;"
sudo -u postgres psql -d pgmnemo_demo -f /usr/share/postgresql/18/extension/pgmnemo--0.20.0.sql
# 2. 装 MCP 客户端 (一次性)
python3 -m venv /opt/sbert
/opt/sbert/bin/pip install pgmnemo-mcp
# 3. wire Claude Code (每 project 一次)
mkdir -p /tmp/my-project && cd /tmp/my-project
/opt/sbert/bin/pgmnemo init --cli claude
# 改 .mcp.json 把 DATABASE_URL 改成真实的
# 4. 装 ollama + pull embedding (一次性)
curl -fsSL https://ollama.com/install.sh | sh
ollama pull qwen3-embedding:0.6b
# 5. 测
cd /tmp/my-project
claude -p "请用 pgmnemo.recall 查最近的 PG 装 pgmnemo 经验"
10. 几个值得提前知道的边界条件
pgmnemo.recallMCP tool 没有 text-only fallback ——recall_fast强制要 vector;要么起 EMBEDDING_SERVER(本文 ollama 路径),要么让 agent 用pgmnemo.search或 SQLrecall_lessonsEMBEDDING_DIM 必须跟 ollama model 的 embedding_length 完全一致 —— qwen3-embedding:0.6b是 1024 维,配 1024;换 model(如nomic-embed-text是 768 维)要同步改 EMBEDDING_DIM,否则config.py:embed()第 41 行len(vec) != EMBEDDING_DIM返回 Nonepgmnemo.ingest在没传 commit_sha 时会被 gate_strict='enforce' 挡 —— 生产用要么传 commit_sha,要么 session 里SET pgmnemo.gate_strict = 'warn'或'off'version 字段不一致 —— PyPI 0.20.0 / __init__.py0.20.0 /pgmnemo.get_params0.10.0 —— 不影响功能,issue tracker 应有 PRnumpy 类型不能直接 psycopg2 —— json.dumpsnumpy.float32 抛TypeError——config.py:embed()必须[float(x) for x in vec]显式转
11. 给 MCP server 加你自己的 hook (如果不想走 MCP)
如果你的 agent runtime 不是 Claude Code,只要它能跑 Python,可以直接 import pgmnemo MCP server 的核心函数:
import sys
sys.path.insert(0, '/opt/sbert/lib/python3.13/site-packages')
from pgmnemo_mcp.config import embed
from pgmnemo_mcp.db import get_conn, to_pgvector
# 不走 MCP,直接 embed + SQL
conn = get_conn()
cur = conn.cursor()
vec = embed("PG 18.6 装 pgmnemo")
cur.execute("""
SELECT lesson_id, score, lesson_text, role, topic
FROM pgmnemo.recall_fast(%s::vector, 5, NULL, 1, NULL, ARRAY[]::text[], 0.7)
""", (to_pgvector(vec),))
print(cur.fetchall())
核心三个函数:
embed(text)—— 调 ollama,返回 1024-dim float listto_pgvector(vec)—— float list → PG vector 字面量get_conn()—— 从 DATABASE_URL env 拿 psycopg2 connection
12. 跑通之后的产物
# 看产物
ls -la /opt/sbert/lib/python3.13/site-packages/pgmnemo_mcp/
# __init__.py
# server.py # MCP server 主循环
# config.py # env 配置 + embed() 函数
# db.py # psycopg2 connection + to_pgvector()
# 看 PG 里的实际数据
sudo -u postgres psql -d pgmnemo_demo <<'EOF'
\dt pgmnemo.* -- 4 张表
SELECT count(*) FROM pgmnemo.agent_lesson;
SELECT lesson_id, topic, length(embedding::text) AS vec_bytes, vector_dims(embedding) AS dim
FROM pgmnemo.agent_lesson ORDER BY lesson_id;
EOF
实测本机(2026-09-07):
lesson_id | topic | vec_bytes | dim
-----------+---------------+-----------+------
1 | intro | 7547 | 1024
2 | install | 7547 | 1024
...
9 | ollama-native | 7547 | 1024
8 条 lesson, 每条 vec_bytes=7547 bytes (≈ 1024 × 7.37 bytes/float) + dim=1024 —— ollama 真在用, 没有 zero-pad。
写在最后
pgmnemo-mcp 是个把 Claude Code 接进 PG 的 MCP server,加上 ollama 0.33.3 + qwen3-embedding:0.6b,整条链路都是"PG 原生 1024 维":pgmnemo schema 硬编码 vector(1024) ↔ ollama model details embedding_length=1024 ↔ EMBEDDING_DIM env 配 1024 ↔ recall_fast SP 第 34 行 vector_dims != 1024 检查。
没有 zero-pad、没有 padded1024、没有"384 维降级到 1024 维"的 workaround —— 这是 2026-09 这台机器上能跑的最干净 pgmnemo-mcp 路径。
姊妹篇 1 (修订 v3) 标记: ollama-native 1024 维版 —— 之前所有"fastembed + zero-pad"版本的 workaround 都不再需要。后续姊妹篇 2 (benchmark) + 姊妹篇 3 (川序) 都基于 ollama-native 1024 维统一路径。