Install
openclaw skills install ollama-openclaw-memory-guide在 Windows 环境下部署 Ollama 便携版,实现本地本地向量搜索和多级 OpenClaw 记忆提取管线配置与故障排查。
openclaw skills install ollama-openclaw-memory-guide在 Windows 管控环境下部署 Ollama 便携版,实现 OpenClaw 本地向量搜索和记忆系统。
OpenClaw Gateway
├── memory-tencentdb(主记忆插件)
│ ├── L0: 原始对话记录
│ ├── L1: 提取记录(SQLite FTS5)
│ ├── L2: 场景分块
│ └── L3: 用户画像
├── memorySearch(向量搜索)
│ ├── Provider: Ollama(本地)
│ ├── Model: nomic-embed-text
│ └── Dimensions: 768
└── Ontology(知识图谱)
└── memory/ontology/graph.jsonl
方案 A:GitHub(推荐)
# 克隆官方仓库
git clone https://github.com/ollama/ollama-windows-release.git D:\temp\ollama-windows-release
方案 B:ModelScope 镜像(国内推荐)
# 使用魔搭社区镜像
git clone https://www.modelscope.cn/models/ollama/ollama-windows-release.git D:\temp\ollama-windows-release
方案 C:直接下载 ZIP
# 从 ModelScope 下载便携版 ZIP
Invoke-WebRequest -Uri "https://www.modelscope.cn/models/ollama/ollama-windows/resolve/master/ollama-windows-amd64.zip" -OutFile "D:\temp\ollama-windows-amd64.zip"
# 创建目录结构
New-Item -ItemType Directory -Force -Path "$env:APPDATA\mx\openclaw-home\$env:USERNAME\.openclaw\tools\ollama"
New-Item -ItemType Directory -Force -Path "$env:APPDATA\mx\openclaw-home\$env:USERNAME\.openclaw\ollama-data\models"
# 解压(如果用方案 A/B)
Copy-Item -Path "D:\temp\ollama-windows-release\*" -Destination "$env:APPDATA\mx\openclaw-home\$env:USERNAME\.openclaw\tools\ollama" -Recurse -Force
# 解压(如果用方案 C)
Expand-Archive -Path "D:\temp\ollama-windows-amd64.zip" -DestinationPath "$env:APPDATA\mx\openclaw-home\$env:USERNAME\.openclaw\tools\ollama" -Force
最终目录结构:
.openclaw\
├── tools\
│ └── ollama\
│ ├── ollama.exe
│ └── lib\
├── ollama-data\
│ └── models\ # Ollama 模型存储
└── models\ # GGUF 模型(备用)
# 设置环境变量(模型存储路径)
$env:OLLAMA_MODELS = "$env:APPDATA\mx\openclaw-home\$env:USERNAME\.openclaw\ollama-data\models"
# 切换到 Ollama 目录
Set-Location "$env:APPDATA\mx\openclaw-home\$env:USERNAME\.openclaw\tools\ollama"
# 启动服务(后台运行)
Start-Process -FilePath ".\ollama.exe" -ArgumentList "serve" -WindowStyle Hidden
验证服务:
# 检查版本
.\ollama.exe --version
# 输出: ollama version is 0.30.7
# 检查服务状态
Invoke-RestMethod -Uri "http://localhost:11434/api/version"
# 输出: {"version":"0.30.7"}
# 下载 nomic-embed-text(274 MB,768 维)
.\ollama.exe pull nomic-embed-text
验证模型:
# 列出已下载模型
.\ollama.exe list
# 输出:
# NAME ID SIZE MODIFIED
# nomic-embed-text:latest 0a109f422b47 274 MB 1 minute ago
# 测试 embedding API
python -c "import requests; r = requests.post('http://localhost:11434/api/embeddings', json={'model':'nomic-embed-text','prompt':'test'}); print(f'Dim: {len(r.json()[\"embedding\"])}')"
# 输出: Dim: 768
创建 VBS 启动脚本:
$startupPath = "$env:APPDATA\Microsoft\Windows\Start Menu\Programs\Startup\ollama-serve.vbs"
$vbsContent = @'
Set WshShell = CreateObject("WScript.Shell")
WshShell.Environment("Process").Item("OLLAMA_MODELS") = "D:\Users\YOUR_USERNAME\AppData\Roaming\mx\openclaw-home\YOUR_USERNAME\.openclaw\ollama-data\models"
WshShell.CurrentDirectory = "D:\Users\YOUR_USERNAME\AppData\Roaming\mx\openclaw-home\YOUR_USERNAME\.openclaw\tools\ollama"
WshShell.Run """D:\Users\YOUR_USERNAME\AppData\Roaming\mx\openclaw-home\YOUR_USERNAME\.openclaw\tools\ollama\ollama.exe"" serve", 0, False
Set WshShell = Nothing
'@
# 替换 YOUR_USERNAME 为实际用户名
$vbsContent = $vbsContent -replace "YOUR_USERNAME", $env:USERNAME
# 写入启动文件夹
Set-Content -Path $startupPath -Value $vbsContent -Encoding UTF8
验证:
# 查看启动脚本
Get-Content $startupPath
# 手动运行测试
cscript $startupPath
编辑 openclaw.json(位于 .openclaw\openclaw.json):
{
"agents": {
"defaults": {
"memorySearch": {
"enabled": true,
"provider": "openai",
"model": "nomic-embed-text",
"remote": {
"baseUrl": "http://localhost:11434/v1",
"apiKey": "ollama"
}
}
}
}
}
关键配置说明:
provider: "openai" - 使用 OpenAI 兼容 API(Ollama 支持)baseUrl: "http://localhost:11434/v1" - Ollama 的 OpenAI 兼容端点apiKey: "ollama" - 占位符,Ollama 不需要真实 API Keyprovider: "local" + model: "fts-only"(这是纯文本搜索,没有向量)验证配置:
# 通过 Gateway API 检查
openclaw gateway config.get | ConvertFrom-Json | Select-Object -ExpandProperty agents | Select-Object -ExpandProperty defaults | Select-Object -ExpandProperty memorySearch
确保 openclaw.json 中包含:
{
"plugins": {
"enabled": true,
"allow": ["mx", "memory-tencentdb"],
"load": {
"paths": ["D:\\Users\\YOUR_USERNAME\\AppData\\Roaming\\mx\\openclaw-home\\YOUR_USERNAME\\.openclaw\\plugins\\memory-tencentdb"]
},
"slots": {
"memory": "memory-tencentdb"
},
"entries": {
"memory-tencentdb": {
"enabled": true,
"config": {
"pipeline": {
"everyNConversations": 3,
"enableWarmup": true,
"l1IdleTimeoutSeconds": 10
}
}
}
}
}
}
关键配置说明:
pipeline.everyNConversations: 3 - 每 3 次对话触发 L1 提取pipeline.l1IdleTimeoutSeconds: 10 - 空闲 10 秒后触发提取config.llm(使用 Gateway 内置模型)如果从 fts-only 迁移到向量搜索,需要重建索引:
# 安装依赖
pip install requests tqdm
# 运行重建脚本(断点续传)
python scripts/rebuild_vector_index.py
脚本功能:
workspace/memory/ 下所有 .md 文件memory/main.sqlite 的 embedding_cache 表embeddings_progress.json)预期结果:
[INFO] 向量索引重建完成
[INFO] 总文件数: 310
[INFO] 总 chunks: 1804
[INFO] 数据库大小: 62 MB
[INFO] 向量维度: 768
# 通过 OpenClaw CLI 测试
openclaw memory search "测试查询"
# 通过 API 测试
Invoke-RestMethod -Uri "http://localhost:18790/api/memory/search" -Method Post -ContentType "application/json" -Body '{"query":"测试查询","limit":5}'
症状: bind: Only one usage of each socket address
原因: 端口 11434 被占用
解决:
# 查找占用进程
netstat -ano | findstr :11434
# 终止进程
taskkill /F /PID <PID>
# 或更换端口
$env:OLLAMA_HOST = "127.0.0.1:11435"
.\ollama.exe serve
症状: 配置自动变回 provider: "local", model: "fts-only"
原因: 远程配置服务器覆盖(美信环境)
解决:
# 直接编辑 openclaw.json(不触发重启)
$file = "$env:APPDATA\mx\openclaw-home\$env:USERNAME\.openclaw\openclaw.json"
$content = Get-Content $file -Raw
$content = $content -replace '"provider"\s*:\s*"local"', '"provider": "openai"'
$content = $content -replace '"model"\s*:\s*"fts-only"', '"model": "nomic-embed-text"'
[System.IO.File]::WriteAllText($file, $content)
# Gateway 会自动读取,无需重启
预防: 修改 PRD preset 或 dist JS 白名单(见 MEMORY.md)
症状: tdai_memory_search 返回空数组
排查步骤:
Invoke-RestMethod -Uri "http://localhost:11434/api/version".\ollama.exe listTest-Path "memory/main.sqlite"python -c "import sqlite3; conn = sqlite3.connect('memory/main.sqlite'); print(conn.execute('SELECT COUNT(*) FROM embedding_cache').fetchone())"症状: recall_checkpoint.json 中 last_l1_extraction 长时间未更新
排查:
# 检查 pipeline 状态
Get-Content "memory-tdai/recall_checkpoint.json" | ConvertFrom-Json | Select-Object pipeline_states
# 手动触发提取
openclaw memory extract
# 查看日志
Get-Content "logs/gateway.log" | Select-String "L1 extraction"
症状: pulling manifest: connection refused
原因: 网络问题或 HuggingFace 被墙
解决:
# 使用镜像
$env:OLLAMA_MODELS_MIRROR = "https://www.modelscope.cn/models"
# 或手动下载
Invoke-WebRequest -Uri "https://www.modelscope.cn/models/ollama/nomic-embed-text/resolve/master/model.bin" -OutFile "ollama-data\models\nomic-embed-text.bin"
Ollama 默认会加载模型到内存,占用约 500 MB。
优化方案:
# 设置模型空闲超时(5 分钟后卸载)
$env:OLLAMA_KEEP_ALIVE = "5m"
# 或完全禁用常驻
$env:OLLAMA_KEEP_ALIVE = "0"
批量处理:
# rebuild_vector_index.py 中调整 batch_size
BATCH_SIZE = 8 # 默认值,可根据内存调整
增量更新:
# 只处理新增/修改的文件
python scripts/rebuild_vector_index.py --incremental
清理旧模型:
# 删除未使用的模型
.\ollama.exe rm <model-name>
# 查看模型占用
.\ollama.exe list
压缩向量索引:
-- 重建索引(SQLite)
VACUUM;
# 备份脚本
$backupDir = "D:\backup\openclaw-memory-$(Get-Date -Format 'yyyyMMdd')"
New-Item -ItemType Directory -Path $backupDir
# 备份记忆数据
Copy-Item -Path ".openclaw\memory-tdai" -Destination "$backupDir\memory-tdai" -Recurse
Copy-Item -Path ".openclaw\memory" -Destination "$backupDir\memory" -Recurse
Copy-Item -Path ".openclaw\ollama-data" -Destination "$backupDir\ollama-data" -Recurse
# 备份配置
Copy-Item -Path ".openclaw\openclaw.json" -Destination "$backupDir\openclaw.json"
# 1. 安装 OpenClaw
# 2. 恢复备份
Copy-Item -Path "D:\backup\openclaw-memory-*\*" -Destination ".openclaw" -Recurse
# 3. 启动 Ollama
.\openclaw\tools\ollama\ollama.exe serve
# 4. 验证
openclaw memory search "测试"
{
"agents": {
"defaults": {
"memorySearch": {
"enabled": true,
"provider": "openai",
"model": "nomic-embed-text",
"remote": {
"baseUrl": "http://localhost:11434/v1",
"apiKey": "ollama"
}
}
}
},
"plugins": {
"enabled": true,
"allow": ["mx", "memory-tencentdb"],
"load": {
"paths": ["D:\\Users\\YOUR_USERNAME\\AppData\\Roaming\\mx\\openclaw-home\\YOUR_USERNAME\\.openclaw\\plugins\\memory-tencentdb"]
},
"slots": {
"memory": "memory-tencentdb"
},
"entries": {
"memory-tencentdb": {
"enabled": true,
"config": {
"pipeline": {
"everyNConversations": 3,
"enableWarmup": true,
"l1IdleTimeoutSeconds": 10
}
}
}
}
}
}
Set WshShell = CreateObject("WScript.Shell")
WshShell.Environment("Process").Item("OLLAMA_MODELS") = "D:\Users\YOUR_USERNAME\AppData\Roaming\mx\openclaw-home\YOUR_USERNAME\.openclaw\ollama-data\models"
WshShell.CurrentDirectory = "D:\Users\YOUR_USERNAME\AppData\Roaming\mx\openclaw-home\YOUR_USERNAME\.openclaw\tools\ollama"
WshShell.Run """D:\Users\YOUR_USERNAME\AppData\Roaming\mx\openclaw-home\YOUR_USERNAME\.openclaw\tools\ollama\ollama.exe"" serve", 0, False
Set WshShell = Nothing
MIT-0
Paudy Yin (paudyyin)