金融量化AI研究--Claude, Python

这里用来记录一些本人运用Claude编程的心得或笔记

导航

实战部署Graphiti + mcp -- 给 AI 用的「动态知识图谱大脑」

官方资源

🌟 GitHub: https://github.com/getzep/graphiti
📚 文档: https://help.getzep.com/graphiti/getting-started/welcome
📄 论文: Zep: A Temporal Knowledge Graph Architecture for Agent Memory(arXiv:2501.13956)
📦 MCP Server: 仓库 mcp_server/
🌐 Zep 平台: getzep.com

相关资源

Zep 博客:State of the Art in Agent Memory
Quickstart 示例
LangGraph + Graphiti 构建 Agent
Neo4j / FalkorDB / Kuzu / Amazon Neptune 各自文档(部署与版本要求)

功能与适用

Graphiti的核心能力在于:
• 整合与维护动态信息: 无缝集成用户交互和业务数据,保持信息的时效性。
• 支持基于状态的推理与任务自动化: 让AI智能体能够根据历史和当前状态做出更智能的决策和行动。
• 复杂演化数据的查询: 支持语义、关键词和基于图的三种搜索方法,精确查询不断变化的数据。

  • Agent 与记忆系统开发者:需要时间感知、可增量更新的图存储与检索
  • RAG/知识库进阶:从纯向量或批处理 GraphRAG 升级到动态图 + 混合检索
  • 图数据库使用者:已在用 Neo4j/FalkorDB/Kuzu/Neptune,希望接入 LLM 抽取与语义检索
  • Claude/Cursor 集成:通过 MCP 为助手提供「图记忆」与检索能力

一张图举例:
image

image

  • graphiti-mcp
    • 用于我作为 CLI/AI 侧的长期记忆。
    • 适合记录当前项目里的持续性上下文:
      • 预览 worktree 分支用途
      • 已切出的提交簇和验证结论
      • 某条线为什么暂缓
      • 某个已知环境阻塞,比如 GPU 语法错误、GitNexus staged 误报
    • 我会按稳定 group_id 使用,不把不同任务线混在一起。
  • graphiti-api
    • 用于项目代码、脚本、工作流如果要程序化接入 Graphiti。
    • 适合后续做:
      • 提交/任务/验证结果写入知识图
      • 项目文档、任务报告、运行事件沉淀
      • 后端脚本或服务显式调用 /messages、/search、/episodes/

面向项目的落地原则(举例):

  • 我做代码清理和分提交时,优先把“决策、阻塞、验收结果”写到 graphiti-mcp。
  • 如果后面你要我给 mystocks_spec 真正加一层 Graphiti 集成,我会走 graphiti-api,不把业务系统直接绑到 MCP。
  • group_id 我会按项目/分支/任务线隔离,不会把所有记忆都塞进一个默认组。

一句话先讲透GitNexus 与 Graphiti 区别

GitNexus = 给 AI 用的「代码仓库智能操作系统」
Graphiti = 给 AI 用的「动态知识图谱大脑」

一个管代码 / 仓库 / 工程,一个管知识 / 事实 / 关系 / 时间,完全是两个赛道,但可以完美配合。
我给你用最清晰、最直白的方式对比👇

  1. 核心定位区别(最关键)
    GitNexus
    领域:Git 仓库、代码工程、开发工作流
    作用:让 AI 能看懂、操作、管理代码仓库
    能力:worktree、diff、变更检测、代码验证、沙箱运行、E2E、端口管理
    本质:AI 的代码工程助理 + 仓库操作系统

Graphiti
领域:知识、事实、实体关系、时序事件
作用:让 AI 能记住事实、理解关联、回溯历史、做推理
能力:知识抽取、图谱构建、时序查询、混合检索
本质:AI 的长期记忆 + 知识推理引擎

  1. 解决的问题完全不同
    GitNexus 解决
    AI 不会操作 Git
    AI 不能安全地在仓库里写代码
    AI 无法验证自己改的代码对不对
    多分支、worktree、环境冲突

Graphiti 解决
AI 记不住长期知识
AI 无法理解实体之间的关系
AI 没有时间概念(不知道事情何时发生)
AI 无法做深度知识推理

  1. 数据结构区别
    GitNexus
    数据:代码、文件、diff、commit、分支、脚本、配置
    结构:文件树 + Git 版本结构
    输出:可运行的工程、验证结果、服务状态

Graphiti
数据:实体、关系、事件、时间、文档
结构:知识图谱(点 + 边 + 时间)
输出:知识答案、推理结果、关联检索

  1. 与 AI Agent 的配合方式
    GitNexus
    让 AI Agent 会写代码、会改工程、会验证、会部署。

Graphiti
让 AI Agent 有记忆、有知识、有逻辑、有历史。

  1. 最直观的比喻
    GitNexus = AI 的「IDE + Git + 沙箱环境」
    Graphiti = AI 的「大脑记忆 + 知识图谱 + 时间线」

  2. 它们可以一起用吗?
    完全可以,而且是超强组合!
    例如:
    GitNexus 负责代码工程
    Graphiti 负责记录代码变更历史、需求、实体关系、架构知识
    AI 既能写代码,又能记住架构知识
    这就是 AI 软件开发 + 知识记忆 的终极形态。

终极总结

项目 定位 核心能力 数据对象
GitNexus AI 代码工程平台 代码操作、Git 管理、验证、运行 代码、文件、分支、脚本
Graphiti AI 知识图谱引擎 知识抽取、图谱、时序、检索 实体、关系、事件、记忆

图片

Graphiti 的核心优势与差异

时序感知与事件链建模:Graphiti 本身就是为动态数据场景而生,它为每条关系添加了显式的有效区间(生效与失效时间),能够处理事实随着时间演化的情况。当新事件到来时,Graphiti 会增量地抽取其中的实体和关系,并根据时序判断是否与现有知识发生冲突。对于已过期或被新事实覆盖的信息,Graphiti 会“失效”旧边而保留历史记录。这种双时态(bi-temporal)模型允许系统在任意时刻查询过去状态,甚至分析知识如何随时间变化。相比之下,传统 RAG 方法仅具备基本的时间戳记录,且需要对静态文档进行批量处理,难以应对实时环境。
混合检索与图遍历:Graphiti 将语义检索和图算法相结合,不依赖 LLM 二次摘要即能完成查询。例如,当用户的问题涉及复杂关系时,Graphiti 可以沿着图谱路径直接找出关联实体,而不是简单地拼接先前的对话内容。这使得检索结果既考虑了自然语言匹配,又保留了知识结构,从而提高了准确度和响应速度。Zep 的相关研究表明,在标准基准测试中,Graphiti 驱动的系统在准确率上远超基于文本回溯的记忆方案,同时显著降低了延迟。
动态更新与高适应性:与 Graphiti 不同,GraphRAG 之类的图检索方法依赖预先对静态语料进行社区分群和汇总,在数据更新时需要耗费大量时间重新计算。而 Graphiti 设计用于高频更新环境,它能持续接受新“事件集”(episodes)并即时更新图谱而无需全图重建。这意味着在用户行为发生变化时,系统可以迅速反映最新状态。根据腾讯报道,与其他知识图谱引擎相比,Graphiti 特别强调了“时间提取”和“边失效”机制,正是用来管理这些动态更新。换言之,Graphiti 在动态场景下表现出更高的适应性和实时性。
与其他系统的差异:相比之下,memGPT、LangGraph、Zep 等传统记忆系统在设计时更多考虑如何“记住”对话内容。memGPT 通过多级记忆层扩充上下文窗口,LangGraph 则将聊天日志存入长期记忆以保持跨会话上下文。Zep 平台虽然提出了基于知识图的记忆层,但其核心仍是在知识图上进行状态记忆和检索。这些方案都更侧重于对已有信息的提取和总结,而 Graphiti 则将重点放在构建描述行为因果链的认知图谱上。简言之,Graphiti 构建的图谱直接刻画了“兴趣→冷却→流失”的演化路径,能够从结构化的用户历史中发现触发状态变化的关键因素,是一种更贴近用户行为语义的记忆模型。

应用场景示例

教育场景:学习动机衰减拐点。在在线教育中,学生的学习行为可以看作一系列时间序列事件:提交作业、参加测验、提问讨论等。Graphiti 可以将这些事件和学生、课程等实体建模为知识图谱,通过时序查询识别学习动机的拐点。已有研究指出,图结构在刻画学生学习进展方面非常有效。例如,当 Graphiti 在图谱中发现某学生在经历几次失败后的交互频率急剧下降时,就可以标记为潜在的动力衰减节点。此外,研究中也曾采用图卷积网络对学生的行为模式进行分类,Graphiti 提供了这样的行为图结构基础,便于及时发现低动力趋势并触发针对性干预。
金融场景:客户流失风险路径。在金融领域,客户的活动记录(交易、登录、客服沟通等)可以视为异构数据源。Graphiti 可以将这些与客户相关的各类数据事件串联成时序图,帮助分析客户状态变化路径。例如,当客户连续数月交易次数减少、并伴随投诉事件,Graphiti 图谱中会形成从“活跃”到“观望”再到“潜在流失”的可视化路径。权威报道指出,知识图谱特别适用于包括客户流失分析在内的决策场景。通过对 Graphiti 图谱应用社区检测或嵌入算法,可以揭示与流失相关的行为特征。例如,Graphiti 的图嵌入方法能够学习客户行为模式并捕捉异常路径——类似于报告中提到的“客户旅程”特征。综上,Graphiti 的因果和时序建模能力使企业能够从复杂的多源数据中识别出导致用户流失的关键因素和路径,从而进行早期预警和精准营销。

如何Dockers部署graphiti

准备数据库 FalkorDB‌ (或neo4j,实际上我用的是它)

https://github.com/FalkorDB/FalkorDB
DOCS:https://docs.falkordb.com/
FalkorDB‌ 是一个高性能、多租户的图数据库,专为生成式 AI、Agent 记忆、云安全和欺诈检测等场景优化。它基于 Redis 构建,采用稀疏矩阵和线性代数技术实现亚毫秒级查询延迟,并兼容 OpenCypher 查询语言。
核心特性:
‌稀疏矩阵表示‌:使用稀疏矩阵存储图的邻接矩阵,显著提升存储效率与查询性能。
‌线性代数查询‌:通过线性代数运算执行图查询,加速复杂图算法。
‌Property Graph 模型‌:支持带属性的节点和关系,符合主流图数据模型。
‌OpenCypher 支持‌:兼容标准 Cypher 语法,并提供扩展功能。
‌多租户架构‌:支持隔离的图命名空间,适合 SaaS 和共享环境。
‌LLM 集成友好‌:专为 Large Language Models(LLMs)设计,适用于 GraphRAG、知识图谱构建等场景。


falkordb/falkordb:latest
docker run -p 6379:6379 -p 3000:3000 -it --rm falkordb/falkordb:latest
docker run -p 6379:6379 -p 3000:3000 -it --rm -v ./data:/var/lib/falkordb/data falkordb/falkordb

以下是 Neo4j 和 FalkorDB 的对比分析,帮助你根据场景选择:
对比总览
┌───────────────┬───────────────────────────┬──────────────────────────┐
│ 维度 │ Neo4j │ FalkorDB │
├───────────────┼───────────────────────────┼──────────────────────────┤
│ 类型 │ 原生图数据库 │ Redis 图数据库模块 │
│ 成熟度 │ ⭐⭐⭐ 非常成熟 │ ⭐⭐ 相对较新 │
│ 性能 │ 优秀 │ 基于 Redis,读写性能极高 │
│ 许可证 │ 社区版 AGPL(商业需授权) │ 开源(Apache 2.0) │
│ 全文搜索 │ 原生支持 │ 支持(RedisSearch) │
│ 向量搜索 │ 支持 │ 支持 │
│ 社区规模 │ 大(生态丰富) │ 小 │
│ Graphiti 支持 │ 主选,测试最充分 │ 支持,profile 模式 │
└───────────────┴───────────────────────────┴──────────────────────────┘

详细对比

  1. 选择 Neo4j 如果你:
  • 需要稳定性和成熟度:Neo4j 是业界标准,Graphiti 的大多数测试和示例都基于 Neo4j
  • 使用 Graphiti 的全部功能:某些高级搜索和索引功能在 Neo4j 上实现最完善
  • 需要丰富工具生态:Neo4j Browser、Neo4j Bloom 等可视化工具
  • 能接受 AGPL 许可证(或个人/开源项目)
  • 有团队熟悉 Cypher 查询语言
   # Neo4j 部署
   docker-compose up -d

或使用外部 Neo4j 实例

  1. 选择 FalkorDB 如果你:
  • 需要极致性能:基于 Redis 的内存存储,读写延迟更低
  • 许可证敏感:需要更宽松的开源许可证
  • 已经在使用 Redis:可以复用现有 Redis 基础设施
  • 数据量可控:内存存储,适合中等规模数据
  • 喜欢尝试新技术:愿意接受相对较小的社区

FalkorDB 部署
docker-compose --profile falkordb up -d``

决策流程

开始

├─ 许可证是否敏感?(商业闭源项目)───> FalkorDB

├─ 需要企业级支持? ───> Neo4j 企业版

├─ 数据量 > 100GB? ───> Neo4j(磁盘存储更合适)

├─ 需要高级图算法/可视化工具? ───> Neo4j

├─ 追求极致性能和低延迟? ───> FalkorDB

└─ 其他场景 ───> Neo4j(推荐默认值)

我的建议

推荐 Neo4j 作为默认选择:

  • 更成熟稳定,Graphiti 开发团队主要测试 Neo4j
  • 示例代码和文档大多基于 Neo4j
  • 遇到问题时社区支持更丰富
  • 适合生产环境

推荐 FalkorDB 的场景:

  • 内部工具或实验性项目
  • 对性能要求极高且数据可放入内存
  • 许可证受限的商业环境

快速启动对比
Neo4j(默认):
docker-compose up -d
访问: http://localhost:8000 (API) + http://localhost:7474 (Neo4j Browser)

FalkorDB:
docker-compose --profile falkordb up -d
访问: http://localhost:8001 (API) + Redis CLI 连接 6379 端口

总结:如果你是第一次使用 Graphiti,建议先用 Neo4j;如果有特殊需求(性能、许可证),再考虑 FalkorDB。

Graphiti Docker 部署方案

方案一:快速部署(使用 Docker Hub 预构建镜像)
这是最简单的部署方式,使用官方发布的镜像。

  1. 创建部署目录
    mkdir graphiti-deploy && cd graphiti-deploy

  2. 创建 docker-compose.yml

   version: '3.8'

   services:
     graph:
       image: zepai/graphiti:latest
       ports:
         - "8000:8000"
       healthcheck:
         test:
           [
             "CMD",
             "python",
             "-c",
             "import urllib.request; urllib.request.urlopen('http://localhost:8000/healthcheck')",
           ]
         interval: 10s
         timeout: 5s
         retries: 3
       depends_on:
         neo4j:
           condition: service_healthy
       environment:
         - OPENAI_API_KEY=${OPENAI_API_KEY}
         - NEO4J_URI=bolt://neo4j:7687
         - NEO4J_USER=${NEO4J_USER:-neo4j}
         - NEO4J_PASSWORD=${NEO4J_PASSWORD:-password}
         - PORT=8000
         - db_backend=neo4j

     neo4j:
       image: neo4j:5.26.2
       healthcheck:
         test:
           [
             "CMD-SHELL",
             "wget -qO- http://localhost:7474 || exit 1",
           ]
         interval: 1s
         timeout: 10s
         retries: 10
         start_period: 3s
       ports:
         - "7474:7474"  # HTTP
         - "7687:7687"  # Bolt
       volumes:
         - neo4j_data:/data
       environment:
         - NEO4J_AUTH=${NEO4J_USER:-neo4j}/${NEO4J_PASSWORD:-password}

   volumes:
     neo4j_data:
  1. 创建 .env 文件
    OPENAI_API_KEY=your_openai_api_key_here
    NEO4J_USER=neo4j
    NEO4J_PASSWORD=your_secure_password

  2. 启动服务
    docker-compose up -d

方案二:本地构建部署(适合二次开发)
如果你想修改代码或本地构建镜像:

  1. 克隆代码库
    git clone https://github.com/getzep/graphiti.git
    cd graphiti

  2. 使用项目自带的 docker-compose.yml

   # 创建环境变量文件
   cp server/.env.example .env
   # 编辑 .env 文件,填入 OPENAI_API_KEY 和其他配置

   # 启动服务(Neo4j 后端)
   docker-compose up -d

   # 或者使用 FalkorDB 后端
   docker-compose --profile falkordb up -d

  方案三:仅部署 Graphiti 服务(使用外部数据库)
  如果你已有 Neo4j 实例,只想部署 Graphiti 服务:


   version: '3.8'

   services:
     graph:
       image: zepai/graphiti:latest
       ports:
         - "8000:8000"
       environment:
         - OPENAI_API_KEY=${OPENAI_API_KEY}
         - NEO4J_URI=${NEO4J_URI}  # 例如: bolt://your-neo4j-host:7687
         - NEO4J_USER=${NEO4J_USER}
         - NEO4J_PASSWORD=${NEO4J_PASSWORD}
         - PORT=8000
         - db_backend=neo4j

数据库后端选择
┌──────────┬──────────────────────┬─────────────────────────────────────────┐
│ 后端 │ 适用场景 │ 启动命令 │
├──────────┼──────────────────────┼─────────────────────────────────────────┤
│ Neo4j │ 通用场景,社区支持好 │ docker-compose up -d │
│ FalkorDB │ 高性能,Redis 兼容 │ docker-compose --profile falkordb up -d │
└──────────┴──────────────────────┴─────────────────────────────────────────┘

环境变量配置
┌────────────────┬──────┬──────────────────────────────────────┐
│ 变量名 │ 必填 │ 说明 │
├────────────────┼──────┼──────────────────────────────────────┤
│ OPENAI_API_KEY │ 是 │ OpenAI API 密钥(用于嵌入生成) │
│ NEO4J_URI │ 是 │ Neo4j 连接地址,如 bolt://neo4j:7687 │
│ NEO4J_USER │ 否 │ 用户名(默认:neo4j) │
│ NEO4J_PASSWORD │ 否 │ 密码(默认:password) │
│ NEO4J_PORT │ 否 │ 端口(默认:7687) │
│ db_backend │ 否 │ 后端类型(neo4j 或 falkordb) │
│ PORT │ 否 │ 服务端口(默认:8000) │
└────────────────┴──────┴──────────────────────────────────────┘

验证部署

  1. 检查服务状态
    docker-compose ps

  2. 查看服务日志
    docker-compose logs -f graph

  3. 测试 API
    健康检查
    curl http://localhost:8000/healthcheck

查看 API 文档
浏览器访问: http://localhost:8000/docs

  1. 访问 Neo4j 浏览器
    浏览器打开: http://localhost:7474

生产环境建议

  1. 使用强密码:修改默认的 Neo4j 密码
  2. 启用 HTTPS:在 Graphiti 服务前添加 Nginx 反向代理
  3. 持久化数据:确保 volumes 配置正确,避免数据丢失
  4. 限制访问:配置防火墙规则,仅开放必要端口
  5. 监控日志:配置日志收集和分析

推荐选择

  • 快速体验:使用方案一,5 分钟完成部署
  • 开发测试:使用方案二,方便修改代码
  • 生产环境:使用方案三,连接外部托管数据库

Docker 部署 graphiti-mcp

1. 目标架构

当前目标是让 NAS 上同时运行两套 Graphiti 服务:

- `graphiti-api`
  - 面向其他业务项目
  - REST API
  - 外部端口:`8010`
- `graphiti-mcp`
  - 面向 Claude / Cursor / Codex 等 MCP 客户端
  - Streamable HTTP MCP
  - 外部端口:`8011`
- `neo4j-graph-db`
  - 两者共用
  - Bolt:`7687`
  - Browser:`7474`

2. 目录约定

NAS 上部署目录采用:

/volume5/docker5/graphiti/
└── mcp_server/
    ├── .env.nas
    ├── main.py
    ├── pyproject.toml
    ├── uv.lock
    ├── config/
    ├── docker/
    └── src/

关键点:

  • docker/docker-compose-neo4j-external.yml 依赖相对路径
  • 所以文件结构必须保持和仓库里一致
  • 不要只拷一个 YAML 文件到别的目录单独部署

3. 最终可用 YAML

群晖 Container Manager 或 docker compose 最终应使用这份 YAML:

services:
  graphiti-mcp:
    image: docker.1ms.run/zepai/knowledge-graph-mcp:latest #实际是graphiti-mcp-local:hostfix,但被改名成了latest
    container_name: graphiti-mcp
    restart: always
    build:
      context: /volume5/docker5/graphiti/mcp_server
      dockerfile: docker/Dockerfile.standalone
    environment:
      - CONFIG_PATH=/app/mcp/config/config.yaml
      - MCP_ALLOWED_HOSTS=0.0.0.0:*,localhost:*,127.0.0.1:*,192.168.123.104:*
      - NEO4J_URI=bolt://192.168.123.104:7687
      - NEO4J_USER=neo4j
      - NEO4J_PASSWORD=your_neo4j_password
      - NEO4J_DATABASE=neo4j
      - GRAPHITI_GROUP_ID=nas_mcp
      - SEMAPHORE_LIMIT=10
      - LLM_MODEL=glm-5
      - OPENAI_API_KEY=your_openai_api_key
      - OPENAI_API_URL=https://open.bigmodel.cn/api/anthropic
      - EMBEDDER_PROVIDER=openai
      - EMBEDDER_OPENAI_API_KEY=ollama
      - EMBEDDER_OPENAI_API_URL=http://192.168.123.74:11434/v1
      - EMBEDDER_MODEL=qwen3-embedding:0.6b
      - EMBEDDER_DIMENSIONS=1024
    volumes:
      - /volume5/docker5/graphiti/mcp_server/config/config-docker-neo4j-external.yaml:/app/mcp/config/config.yaml:ro
    ports:
      - "8011:8000"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://127.0.0.1:8000/health"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 40s
    command: ["uv", "run", "--no-sync", "main.py"]

这几个字段是关键:

  • image: graphiti-mcp-local:hostfix
    • 用本地镜像名,避免和远端 latest 混淆
  • MCP_ALLOWED_HOSTS=...
    • 解决 421 Invalid Host header
  • command: ["uv", "run", "--no-sync", "main.py"]
    • 避免容器启动时再次 uv sync
  • start_period: 30s
    • 给群晖环境更大的启动缓冲

4. .env.nas 最小可用配置

示例:

MCP_PORT=8011

NEO4J_URI=bolt://192.168.123.104:7687
NEO4J_USER=neo4j
NEO4J_PASSWORD=your_password
NEO4J_DATABASE=neo4j

GRAPHITI_GROUP_ID=nas_mcp
MCP_ALLOWED_HOSTS=localhost:*,127.0.0.1:*,192.168.123.104:*

SEMAPHORE_LIMIT=10

LLM_MODEL=glm-5
OPENAI_API_KEY=your_api_key
OPENAI_API_URL=https://open.bigmodel.cn/api/anthropic

EMBEDDER_MODEL=text-embedding-3-small
EMBEDDER_DIMENSIONS=1536

说明:

  • GRAPHITI_GROUP_ID=nas_mcp
    • 先和 graphiti-api 使用的业务 group_id 隔离
  • MCP_ALLOWED_HOSTS
    • 这是 MCP 对外可访问的关键配置
  • OPENAI_API_URL
    • 当前沿用 OpenAI-compatible 端点
  • EMBEDDER_MODEL
    • 先保留默认值,但后面要看实际 embedding provider 是否可用

5. 从 WSL2 同步文件到 NAS

当前开发环境在 Windows 的 WSL2 中,而容器运行在 NAS。
推荐做法不是在 WSL2 里 build 镜像再搬镜像,而是:

  1. 把源码和配置文件同步到 NAS
  2. 在 NAS 本机 build

推荐命令:

cd /opt/claude/graphiti

rsync -rv --relative \
  mcp_server/main.py \
  mcp_server/pyproject.toml \
  mcp_server/uv.lock \
  mcp_server/.env.nas \
  mcp_server/docker/Dockerfile.standalone \
  mcp_server/docker/docker-compose-neo4j-external.yml \
  mcp_server/config/ \
  mcp_server/src/ \
  john@192.168.123.104:/volume5/docker5/graphiti/

注意:

  • 不要用 rsync -a,群晖上容易因为权限属性报错
  • rsync -rv --relative 足够了

如果出现:

failed to set permissions ... Operation not permitted

通常文件内容已经同步过去了,只是元数据没能完整保留。

6. 为什么不能只改 .env.nas

有两个问题不是光改环境变量能解决的:

6.1 421 Invalid Host header

这个问题的根因不是群晖网络,也不是 YAML 端口映射,而是 mcp 包自身的 transport security。
修复代码落在:

  • mcp_server/src/utils/transport_security.py
  • mcp_server/src/graphiti_mcp_server.py

所以:

  • 只改 .env.nas 不够
  • 必须让更新后的源码进入容器

6.2 容器启动时反复下载依赖

如果 YAML 里用的是:

command: ["uv", "run", "main.py"]

容器启动时会再次尝试同步环境,导致:

  • 健康检查失败
  • 日志里出现 fakerpyrightruff 等依赖下载

这个问题必须通过:

command: ["uv", "run", "--no-sync", "main.py"]

来修复。

7. 为什么 build 成功后镜像名还是旧的

如果构建日志里出现:

naming to docker.1ms.run/zepai/knowledge-graph-mcp:latest

说明:

  • 当前实际参与构建的 YAML 里,image: 还是旧值
  • 或者群晖 Container Manager 用的是它自己保存的旧项目配置

这不代表 build 失败,但会让你难以判断当前跑的是哪版镜像。
因此最终建议使用:

image: graphiti-mcp-local:hostfix

然后通过:

docker images | grep graphiti-mcp-local

确认本地镜像标签存在。

8. 关键排障过程总结

8.1 初始问题一:421 Invalid Host header

现象:

  • /health 正常
  • /mcp 返回 421 Misdirected Request

定位方式:

  • 用 NAS IP 访问 /mcp 失败
  • 强制 Host: localhost:8011 时成功

结论:

  • 服务能用
  • 只是 Host 校验没放行 NAS IP

修复:

  • 新增 build_transport_security_settings()
  • 在启动时设置 mcp.settings.transport_security
  • 在 YAML 或 .env.nas 中增加 MCP_ALLOWED_HOSTS

8.2 初始问题二:容器启动后健康检查失败

现象:

  • curl: (7) Failed to connect to localhost port 8000
  • 容器日志里看到下载 fakerpyrightruff
    结论:
  • 服务还没启动
  • 容器在运行时重复做环境同步

修复:

  • command 改成 uv run --no-sync main.py

8.3 初始问题三:群晖 build 很慢

现象:

  • 构建阶段长时间停在 docker.io/library/python:3.11-slim-bookworm
    原因:
  • 基础镜像仍然走 Docker Hub
    修复:
  • Dockerfile.standalone 改为:
# syntax=docker.1ms.run/docker/dockerfile:1
FROM docker.1ms.run/python:3.11-slim-bookworm

## 9. 当前最终测试结果
已验证通过:
- `GET /health`
- `POST /mcp initialize`
- `tools/list`
- `tools/call get_status`
- `tools/call add_memory`

也就是说:
- MCP 协议层已经可用
- `graphiti-mcp` 已经能连 Neo4j
- 队列写入也已经通了

仍未通过:
- `search_memory_facts`
错误是:
```text
Error searching facts: No embedding data received

10. 当前剩余限制

这不是 MCP 部署失败,而是 embedding provider 不兼容
当前配置沿用了:

OPENAI_API_URL=https://open.bigmodel.cn/api/anthropic
LLM_MODEL=glm-5

这条 OpenAI-compatible 端点:

  • 足够支持 LLM 推理
  • 但当前看起来不支持 Graphiti 所需的 embeddings 返回

所以现状是:

  • MCP 可访问
  • Neo4j 可连接
  • add_memory 可入队
  • 但搜索阶段会因 embedding 失败而报错

11. 下一个正确方向

下一步不是继续改 MCP 协议层,而是给 graphiti-mcp 单独配置一个可用的 embedder。
推荐方向:

  1. 保留当前 glm-5 继续做 LLM
  2. 单独给 embedder 配置一个真正支持 embeddings 的服务

可选方向:

  • OpenAI 官方 embeddings
  • Voyage embeddings
  • 本地 OpenAI-compatible embedding 服务

12. 重建后验收命令

12.1 健康检查

curl http://192.168.123.104:8011/health

12.2 MCP 初始化

curl -i -X POST http://192.168.123.104:8011/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"smoke-test","version":"1.0"}}}'

12.3 检查修复代码是否在容器内

docker exec graphiti-mcp sh -lc "grep -n 'build_transport_security_settings' /app/mcp/src/graphiti_mcp_server.py"
docker exec graphiti-mcp sh -lc "ls -l /app/mcp/src/utils/transport_security.py"

12.4 检查当前容器使用的镜像名

docker inspect graphiti-mcp --format '{{.Config.Image}}'

13. 经验结论

以后再做同类部署时,优先记住这几条:

  • 不要只同步 YAML;src/main.pypyproject.tomluv.lockDockerfile 都可能参与构建
  • 不要把镜像名继续写成官方 latest,否则很难判断当前到底跑的是哪一版
  • 群晖里如果是 YAML 导入项目,可能会保留自己的旧项目配置;不要假定磁盘上的 YAML 改了,GUI 就会自动跟着变
  • MCP 的 /health 正常,不等于 /mcp 一定正常
  • Graphiti MCP 部署成功,不等于搜索功能一定可用;embedding provider 也必须单独验证

posted on 2026-03-14 15:55  chengjon  阅读(289)  评论(0)    收藏  举报