GBrain MCP 集成技术日志:Raspberry Pi 5 上的知识图谱 + Hermes Agent

目录
1. 项目背景与目标
2. 环境准备
6. 核心问题与解决方案
7. 最终工作流程
8. 文件修改清单
9. 附录: 常用命令速查
1. 项目背景与目标
1.1 什么是 GBrain
GBrain 是 Garry Tan 开发的开源个人知识大脑,基于 PostgreSQL + pgvector 构建,提供:
- 知识图谱: 页面之间的自动链接提取
- 向量搜索: 语义相似度检索
- 全文搜索: PostgreSQL FTS (Full-Text Search)
- 混合搜索: RRF (Reciprocal Rank Fusion) 融合关键词 + 向量结果
- MCP 协议: 通过 Model Context Protocol 与 AI Agent 集成
1.2 集成目标
将 GBrain 通过 MCP 协议集成到 Hermes Agent 中,使 Hermes 能够:
1. 持久化存储对话中的重要信息到知识图谱
2. 通过语义搜索检索历史知识
3. 自动提取实体关系构建知识网络
1.3 平台挑战
| 挑战 | 说明 |
|---|---|
| Bun WASM 限制 | `bun build` 的二进制在 ARM64 上无法运行 WASM,必须用 `bun src/cli.ts` |
| 中文支持 | PostgreSQL `english` 分词器不支持中文 |
| 网络代理 | 通过 mihomo (127.0.0.1:7890) 访问外部 API |
2. 环境准备
2.1 已安装依赖
# 系统级
- Debian trixie (aarch64)
- Ollama 0.6.6 (本地 LLM 推理)
- Tailscale 1.96.4 (异地组网)
- mihomo (HTTP 代理 127.0.0.1:7890)
# 应用级
- Bun (JavaScript 运行时)
- Node.js / npm
- Python 3 + Hermes Agent v0.11.0
2.2 GBrain 安装
# 克隆仓库
git clone https://github.com/garrytan/gbrain.git ~/gbrain
cd ~/gbrain
# 安装依赖
bun install
# 验证安装
bun src/cli.ts --help
2.3 嵌入模型配置
由于无法使用 OpenAI 官方 API,改用 BitFun 提供的 Qwen3-Embedding-0.6B:
| 参数 | 值 |
|---|---|
| 维度 | 1024 |
| API 端点 | `https://api.openbitfun.com/v1` |
| 费用 | 免费 |
3. Phase 1: 底层验证
3.1 目标
验证 GBrain 核心功能在 ARM64 + 自定义嵌入模型下正常工作。
3.2 修改嵌入层
文件: src/core/embedding.ts
原始代码硬编码了 OpenAI 的 text-embedding-3-large (3072 维),需要修改为支持环境变量配置:
// 修改前: 硬编码 OpenAI 配置
const DEFAULT_MODEL = 'text-embedding-3-large';
const DEFAULT_DIMS = 3072;
// 修改后: 支持环境变量
const DEFAULT_MODEL = process.env.GBRAIN_EMBED_MODEL || 'text-embedding-3-large';
const DEFAULT_DIMS = parseInt(process.env.GBRAIN_EMBED_DIMENSIONS || '3072', 10);
const DEFAULT_BASE_URL = process.env.GBRAIN_EMBED_BASE_URL;
const DEFAULT_API_KEY = process.env.GBRAIN_EMBED_API_KEY;
3.3 修改 Schema 维度
文件: src/core/pglite-schema.ts
// 修改前
embedding vector(3072),
model TEXT NOT NULL DEFAULT 'text-embedding-3-large',
// 修改后
embedding vector(1024),
model TEXT NOT NULL DEFAULT 'Qwen/Qwen3-Embedding-0.6B',
3.4 初始化数据库
export GBRAIN_EMBED_MODEL="Qwen/Qwen3-Embedding-0.6B"
export GBRAIN_EMBED_DIMENSIONS="1024"
export GBRAIN_EMBED_BASE_URL="https://api.openbitfun.com/v1"
export GBRAIN_EMBED_API_KEY="sk-xxx"
cd ~/gbrain
bun src/cli.ts init
输出:
Brain ready at /home/harryfan/.gbrain/brain.pglite
0 pages. Engine: PGLite (local Postgres).
3.5 验证核心功能
# 添加测试页面
echo "# GBrain 树莓派测试
这是一个测试页面。" | bun src/cli.ts put raspberry-pi-test
# 查看统计
bun src/cli.ts stats
# Pages: 1, Chunks: 1, Embedded: 1
# 搜索测试
bun src/cli.ts search "测试"
# [0.3040] raspberry-pi-test -- # GBrain 树莓派测试
3.6 Phase 1 结论
✅ GBrain 在 ARM64 + Qwen Embedding 下工作正常
4. Phase 2: MCP 集成
4.1 目标
将 GBrain 作为 MCP Server 接入 Hermes Agent。
4.2 MCP 协议简介
Model Context Protocol (MCP) 是 Anthropic 提出的标准协议,允许 AI Agent 通过 stdio 或 SSE 与外部工具通信:
┌─────────────┐ stdio ┌─────────────────┐
│ Hermes Agent │ ◄────────────► │ GBrain MCP Server│
│ (Client) │ JSON-RPC │ (stdio mode) │
└─────────────┘ └─────────────────┘
4.3 创建 MCP 启动脚本
文件: ~/gbrain/start-mcp.sh
#!/bin/bash
export PATH="$HOME/.bun/bin:$PATH"
export GBRAIN_EMBED_MODEL="Qwen/Qwen3-Embedding-0.6B"
export GBRAIN_EMBED_DIMENSIONS="1024"
export GBRAIN_EMBED_BASE_URL="https://api.openbitfun.com/v1"
export GBRAIN_EMBED_API_KEY="sk-xxx"
# 清理可能残留的进程
pkill -9 -f "bun src/cli.ts serve" 2>/dev/null
sleep 1
cd "$HOME/gbrain"
exec bun src/cli.ts serve --stdio 2>/dev/null
> 关键: exec 确保子进程替换 shell 进程,2>/dev/null 防止日志干扰 MCP 协议解析。
4.4 配置 Hermes MCP
文件: ~/.hermes/config.yaml
mcp:
gbrain:
command: /home/harryfan/gbrain/start-mcp.sh
timeout: 180
connect_timeout: 120
> 注意: connect_timeout 必须设长(120s),因为 PGLite 首次初始化需要 ~30 秒。
4.5 发现 MCP 工具
# 在 Hermes 中调用
from hermes_agent.tools.mcp_tool import discover_mcp_tools
tools = await discover_mcp_tools()
print(f"发现 {len(tools)} 个工具")
输出:
发现 45 个 GBrain 工具
连接耗时: 0.8s
工具列表包括:
- get_stats - 获取数据库统计
- list_pages - 列出所有页面
- get_page - 获取单个页面
- put_page - 创建/更新页面
- query - 混合搜索
- search_keyword - 关键词搜索
- search_vector - 向量搜索
- ... (共 45 个)
4.6 验证工具调用
# 测试 get_stats
result = await handle_function_call("get_stats", {})
# {"pages": 6, "chunks": 6, "embedded": 2, "links": 1, "tags": 9}
# 测试 put_page
result = await handle_function_call("put_page", {
"slug": "hermes-mcp-integration",
"content": "# Hermes Agent MCP Integration\n\nIntegration verified..."
})
# {"slug": "hermes-mcp-integration", "status": "created_or_updated"}
# 测试 query
result = await handle_function_call("query", {
"query": "MCP integration"
})
# 返回搜索结果列表
4.7 关键问题: 进程残留
现象: 每次 MCP 调用后,bun src/cli.ts serve 进程未自动关闭,导致后续调用卡死。
原因: Hermes 的 _run_on_mcp_loop 没有正确管理子进程生命周期。
临时解决方案:
# 每次调用前清理残留进程
pkill -9 -f "bun src/cli.ts serve"
长期方案: Phase 3a 创建管理脚本。
4.8 Phase 2 结论
✅ MCP 集成成功,45 个工具可用
⚠️ 进程残留问题待优化(Phase 3 解决)
5. Phase 3: 优化与持久化
5.1 3a: 进程管理脚本
问题: MCP 调用后 GBrain 进程残留
解决方案: 创建管理脚本
文件: ~/gbrain/gbrain-manager.sh
#!/bin/bash
GBRAIN_DIR="$HOME/gbrain"
PIDFILE="/tmp/gbrain-mcp.pid"
export PATH="$HOME/.bun/bin:$PATH"
export GBRAIN_EMBED_MODEL="Qwen/Qwen3-Embedding-0.6B"
export GBRAIN_EMBED_DIMENSIONS="1024"
export GBRAIN_EMBED_BASE_URL="https://api.openbitfun.com/v1"
export GBRAIN_EMBED_API_KEY="sk-xxx"
case "$1" in
start)
pkill -f "bun src/cli.ts serve" 2>/dev/null
sleep 1
cd "$GBRAIN_DIR"
bun src/cli.ts serve --stdio > /dev/null 2>&1 &
echo $! > "$PIDFILE"
echo "Started (PID: $(cat $PIDFILE))"
sleep 2
;;
stop)
[ -f "$PIDFILE" ] && kill -9 $(cat "$PIDFILE") 2>/dev/null
rm -f "$PIDFILE"
pkill -9 -f "bun src/cli.ts serve" 2>/dev/null
echo "Stopped"
;;
status)
if [ -f "$PIDFILE" ] && kill -0 $(cat "$PIDFILE") 2>/dev/null; then
echo "Running (PID: $(cat $PIDFILE))"
else
echo "Not running"
fi
;;
*) echo "Usage: $0 {start|stop|status}" ;;
esac
使用:
~/gbrain/gbrain-manager.sh start # 启动
~/gbrain/gbrain-manager.sh stop # 停止
~/gbrain/gbrain-manager.sh status # 查看状态
5.2 3b: 持久化环境变量
文件: ~/.profile
# ── GBrain 环境变量 ─────────────────────────────────────────────
export GBRAIN_EMBED_MODEL="Qwen/Qwen3-Embedding-0.6B"
export GBRAIN_EMBED_DIMENSIONS="1024"
export GBRAIN_EMBED_BASE_URL="https://api.openbitfun.com/v1"
export GBRAIN_EMBED_API_KEY="sk-xxx"
export PATH="$HOME/.bun/bin:$PATH"
# ────────────────────────────────────────────────────────────────
文件: ~/.gbrain/env.sh (供脚本 source 使用)
export GBRAIN_EMBED_MODEL="Qwen/Qwen3-Embedding-0.6B"
export GBRAIN_EMBED_DIMENSIONS="1024"
export GBRAIN_EMBED_BASE_URL="https://api.openbitfun.com/v1"
export GBRAIN_EMBED_API_KEY="sk-xxx"
export PATH="$HOME/.bun/bin:$PATH"
5.3 3c: 中文搜索支持
问题: PostgreSQL english 分词器不支持中文
分析:
-- english 分词器行为
SELECT to_tsvector('english', '中文知识图谱测试');
-- 结果: '' (空,所有中文被过滤)
-- simple 分词器行为
SELECT to_tsvector('simple', '中文知识图谱测试');
-- 结果: ''中文知识图谱测试':1' (整句作为一个词)
核心问题: simple 分词器对中文按整句分词,导致子串搜索失败:
SELECT to_tsvector('simple', '中文知识图谱测试')
@@ plainto_tsquery('simple', '知识');
-- 结果: false ("知识" 不等于 "中文知识图谱测试")
解决方案: 双重策略
1. 全局替换 english → simple(支持中英文混合)
2. CJK Fallback: 当 tsvector 无结果时,自动使用 ILIKE 匹配
修改 1: src/core/pglite-schema.ts
-- 修改前
setweight(to_tsvector('english', coalesce(NEW.title, '')), 'A')
-- 修改后
setweight(to_tsvector('simple', coalesce(NEW.title, '')), 'A')
修改 2: src/core/pglite-engine.ts
// 修改搜索 SQL
ts_rank(cc.search_vector, websearch_to_tsquery('simple', $1))
// 添加 CJK Fallback
if (rows.length === 0 && /[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/.test(query)) {
// 使用 ILIKE 进行子串匹配
const likePattern = `%${query}%`;
// ... ILIKE 查询
}
效果:
- 英文查询: websearch_to_tsquery('simple', query) → 精确匹配
- 中文查询: tsvector 失败 → 自动 fallback 到 ILIKE '%关键词%'
5.4 3d: 宽松 Dedup 阈值
问题: 小数据集下搜索结果容易被过滤为空
分析: GBrain 的 4 层去重管道过于严格:
| 层级 | 原始值 | 修改后 | 说明 |
|---|---|---|---|
| 类型多样性比例 | 0.6 | 0.8 | 同类型页面占比上限 |
| 每页最大块数 | 2 | 3 | 每页保留的 chunk 数 |
文件: src/core/search/dedup.ts
// 修改前
const COSINE_DEDUP_THRESHOLD = 0.85;
const MAX_TYPE_RATIO = 0.6;
const MAX_PER_PAGE = 2;
// 修改后
const COSINE_DEDUP_THRESHOLD = 0.92;
const MAX_TYPE_RATIO = 0.8;
const MAX_PER_PAGE = 3;
5.5 3e: 验证与备份
测试验证:
# 中文搜索
$ bun src/cli.ts search "知识"
[0.5000] chinese-knowledge -- # 中文知识图谱测试
# 英文搜索
$ bun src/cli.ts search "Graph"
[0.3040] english-knowledge -- # English Knowledge Graph Test
# 混合搜索
$ bun src/cli.ts search "test"
[0.3040] english-knowledge -- # English Knowledge Graph Test
备份:
~/.gbrain-backup-phase3-20260426-163533/
├── pglite-schema.ts # FTS simple 分词器
├── pglite-engine.ts # simple 搜索 + CJK fallback
├── dedup.ts # 宽松阈值
├── start-mcp.sh # MCP 启动脚本
├── gbrain-manager.sh # 进程管理脚本
├── config.yaml # Hermes MCP 配置
└── MODIFICATIONS.md # 修改摘要
6. 核心问题与解决方案
6.1 问题汇总表
| # | 问题 | 原因 | 解决方案 |
|---|---|---|---|
| 2 | 嵌入模型不兼容 | 硬编码 OpenAI 3072 维 | 修改 embedding.ts 支持环境变量 |
| 3 | 向量维度不匹配 | Schema 硬编码 3072 | 修改 pglite-schema.ts 为 1024 |
| 4 | 首次启动超时 | PGLite 初始化需 30s | connect_timeout 设为 120s |
| 5 | 进程残留 | MCP 客户端未正确关闭子进程 | 启动脚本添加 pkill 清理 |
| 6 | 中文搜索无结果 | english 分词器过滤中文 | 改为 simple + CJK ILIKE fallback |
| 7 | 小数据集搜索为空 | dedup 阈值过于严格 | 放宽阈值 (0.85→0.92, 2→3) |
| 8 | MCP SDK 兼容性 | mcp 1.6.0 内部 API 变更 | 重装 mcp 包修复 |
6.2 关键调试技巧
# 1. 检查 GBrain 进程
ps aux | grep "bun src/cli.ts"
# 2. 强制清理残留
pkill -9 -f "bun src/cli.ts serve"
# 3. 查看 PGLite 数据
ls -la ~/.gbrain/brain.pglite/
# 4. 直接查询数据库
bun -e "
import { PGlite } from '@electric-sql/pglite';
const db = await PGlite.create({ dataDir: '/home/harryfan/.gbrain/brain.pglite' });
const result = await db.query('SELECT slug, title FROM pages');
console.log(result.rows);
"
# 5. 检查 MCP 工具
python3 -c "
import asyncio
from hermes_agent.tools.mcp_tool import discover_mcp_tools
tools = asyncio.run(discover_mcp_tools())
print(f'{len(tools)} tools discovered')
"
7. 最终工作流程
7.1 日常使用流程
7.2 Hermes 调用 GBrain 的两种方式
方式 1: handle_function_call (推荐)
from hermes_agent.model_tools import handle_function_call
# 存储知识
result = await handle_function_call("put_page", {
"slug": "project-idea-2026",
"content": "# 项目想法\n\n这是一个新的项目构思..."
})
# 检索知识
results = await handle_function_call("query", {
"query": "项目构思",
"limit": 5
})
方式 2: GBrain CLI
# 直接操作数据库
bun src/cli.ts put my-page --content "# 标题\n\n内容"
bun src/cli.ts search "关键词"
bun src/cli.ts query "问题描述"
bun src/cli.ts stats
7.3 数据流
用户输入
│
▼
┌─────────────┐
│ Hermes Agent │
│ (推理决策) │
└──────┬──────┘
│
├────────────┬────────────┐
▼ ▼ ▼
┌───────┐ ┌────────┐ ┌─────────┐
│put_page│ │ query │ │get_stats│
└───┬───┘ └───┬────┘ └────┬────┘
│ │ │
▼ ▼ ▼
┌──────────────────────────────────┐
│ GBrain MCP Server │
│ ┌─────────┐ ┌─────────────┐ │
│ │ PGLite │◄──►│ pgvector │ │
│ │ (本地) │ │ (HNSW 索引) │ │
│ └────┬────┘ └─────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ ┌───────────┐ │
│ │ FTS (simple)│ │ 知识图谱 │ │
│ │ + ILIKE │ │ (links) │ │
│ └─────────────┘ └───────────┘ │
└──────────────────────────────────┘
│
▼
返回结果给 Hermes
7.4 启动顺序
# 1. 确保环境变量已加载
source ~/.profile
# 2. 启动 GBrain MCP (如果需要独立运行)
~/gbrain/gbrain-manager.sh start
# 3. Hermes 会自动通过 start-mcp.sh 启动 GBrain
# 无需手动干预
8. 文件修改清单
8.1 GBrain 源码修改
| 文件 | 修改类型 | 说明 |
|---|---|---|
| `src/core/pglite-schema.ts` | 修改 | FTS `english` → `simple`, 维度 3072 → 1024 |
| `src/core/pglite-engine.ts` | 修改 | 搜索 `english` → `simple`, 添加 CJK fallback |
| `src/core/search/dedup.ts` | 修改 | 放宽去重阈值 |
8.2 新建文件
| 文件 | 说明 |
|---|---|
| `~/gbrain/gbrain-manager.sh` | 进程管理脚本 |
| `~/.gbrain/env.sh` | 环境变量加载脚本 |
| `~/.gbrain-backup-phase3-*/` | 配置备份目录 |
8.3 Hermes 配置
| 文件 | 修改 |
|---|---|
| `~/.profile` | 添加 GBrain 环境变量 |
9. 附录: 常用命令速查
9.1 GBrain CLI
# 数据库管理
bun src/cli.ts init # 初始化数据库
bun src/cli.ts stats # 查看统计
bun src/cli.ts doctor # 健康检查
# 页面操作
bun src/cli.ts list # 列出页面
bun src/cli.ts get # 获取页面
bun src/cli.ts put --content "..." # 创建/更新页面
bun src/cli.ts delete # 删除页面
# 搜索
bun src/cli.ts search # 关键词搜索
bun src/cli.ts query # 混合搜索 (RRF)
bun src/cli.ts ask # query 别名
# 导入/导出
bun src/cli.ts import # 导入目录
bun src/cli.ts export # 导出为 markdown
bun src/cli.ts sync # Git 同步
# MCP
bun src/cli.ts serve --stdio # 启动 MCP server
9.2 进程管理
# GBrain 管理
~/gbrain/gbrain-manager.sh start # 启动
~/gbrain/gbrain-manager.sh stop # 停止
~/gbrain/gbrain-manager.sh status # 状态
# 强制清理
pkill -9 -f "bun src/cli.ts serve"
9.3 Hermes MCP 工具调用
# Python 异步调用
from hermes_agent.model_tools import handle_function_call
# 获取统计
stats = await handle_function_call("get_stats", {})
# 列出页面
pages = await handle_function_call("list_pages", {"limit": 10})
# 获取页面
page = await handle_function_call("get_page", {"slug": "my-page"})
# 创建页面
result = await handle_function_call("put_page", {
"slug": "new-page",
"content": "# Title\n\nContent here"
})
# 混合搜索
results = await handle_function_call("query", {
"query": "搜索内容",
"limit": 5
})
# 关键词搜索
results = await handle_function_call("search_keyword", {
"query": "关键词",
"limit": 5
})
9.4 环境变量
# 必须设置
export GBRAIN_EMBED_MODEL="Qwen/Qwen3-Embedding-0.6B"
export GBRAIN_EMBED_DIMENSIONS="1024"
export GBRAIN_EMBED_BASE_URL="https://api.openbitfun.com/v1"
export GBRAIN_EMBED_API_KEY="sk-xxx"
export PATH="$HOME/.bun/bin:$PATH"
# 可选调试
export GBRAIN_SEARCH_DEBUG="1" # 搜索调试日志
总结
本次集成成功将 GBrain 知识大脑通过 MCP 协议接入 Hermes Agent,主要成果:
1. 完整的中文支持: 通过 simple 分词器 + CJK ILIKE fallback 实现中英文混合搜索
2. ARM64 兼容: 解决 Bun WASM 限制,使用源码直接运行
3. 自定义嵌入模型: 集成 BitFun Qwen3-Embedding-0.6B (1024维)
4. 进程管理: 创建管理脚本解决进程残留问题
5. 配置持久化: 环境变量写入 ~/.profile,重启后自动生效
下一步建议:
- 测试大规模数据下的性能表现
- 配置自动同步机制(Git / 定时任务)
- 探索 GBrain 的知识图谱可视化功能
*日志生成时间: 2026-04-26*
*GBrain 版本: v0.22.0*
*Hermes 版本: v0.11.0*