# LangGraph Sidecar 迁移设计 **日期**: 2026-07-20 **状态**: 草稿 **版本**: 1.0 --- ## 1. 概述 将 cfc-backend 的 AI 能力从 Dify 迁移到自建的 Python LangGraph sidecar 服务。Java 端的 JDK 8 / Spring Boot 2.7.18 保持不变。 ### 目标 - 消除对 Dify 平台的依赖(数据安全、黑盒 prompt、不可控的发布节奏) - 获得 LangGraph 的 Agent 编排、有状态持久化、HITL 能力 - 团队完全掌控 AI 层的 prompt、模型、知识库 ### 非目标 - 不改动 Java 端 JDK/Spring Boot 版本 - 不改动 cfc 业务逻辑 - 不引入额外的中间件(PG 可选, Chroma 文件模式优先) --- ## 2. 架构 ``` ┌──────────────────────────────────────────────────────────────────────┐ │ User (微信小程序 / Web) │ └─────────────────────────────┬────────────────────────────────────────┘ │ HTTP ┌─────────────────────────────▼────────────────────────────────────────┐ │ cfc-backend (Java 8, Spring Boot 2.7.18) │ │ │ │ ┌──────────────┐ ┌──────────────────┐ ┌───────────────────────┐ │ │ │ 业务 Controller│ │ AI Gateway │ │ Context Provider │ │ │ │ (不变) │ │ AIService.java │ │ AiContextService.java │ │ │ │ │ │ (HTTP→Python) │ │ (Java→Python 数据源) │ │ │ └──────────────┘ │ + Dify Fallback │ └───────────────────────┘ │ │ └────────┬─────────┘ │ │ │ HTTP (内网) │ └─────────────────────────────┼────────────────────────────────────────┘ │ ┌─────────────────────────────▼────────────────────────────────────────┐ │ langgraph-service (Python 3.11) │ │ │ │ ┌──────────────────────────────────────────────────────────────┐ │ │ │ FastAPI 网关 (port 9000) │ │ │ │ POST /api/v1/chat → ChatAgent │ │ │ │ POST /api/v1/recommend → RecommendAgent │ │ │ │ POST /api/v1/analyze → AnalysisAgent │ │ │ │ POST /api/v1/agent → LangGraph Orchestrator │ │ │ │ POST /api/v1/tongue → MultiModalAgent │ │ │ └──────────────────────────────────────────────────────────────┘ │ │ │ │ │ ┌──────────────────────────▼───────────────────────────────────┐ │ │ │ LangGraph Engine │ │ │ │ │ │ │ │ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │ │ │ │ │ StateGraph │ │ Checkpointer │ │ Memory Manager │ │ │ │ │ │ (条件路由/循环) │ │ (PG / Memory) │ │ (3层记忆) │ │ │ │ │ └────────────────┘ └────────────────┘ └────────────────┘ │ │ │ └──────────────────────────────────────────────────────────────┘ │ │ │ │ │ ┌──────────────────────────▼───────────────────────────────────┐ │ │ │ RAG Pipeline │ │ │ │ ┌────────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ │ │Document │→│Text │→│Embedding │→│VectorStore│ │ │ │ │ │Loader │ │Splitter │ │ │ │(Chroma) │ │ │ │ │ └────────────┘ └──────────┘ └──────────┘ └──────────┘ │ │ │ │ │ │ │ │ │ ┌─────────────────────────────────▼──────────────────────┐ │ │ │ │ │ EnsembleRetriever (向量 + BM25) → Rerank → Compressor │ │ │ │ │ └────────────────────────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────────────┘ │ │ │ │ │ ┌──────────────────────────▼───────────────────────────────────┐ │ │ │ Agent 工具层 │ │ │ │ @tool search_product() — HTTP → Java / 直连 MySQL │ │ │ │ @tool get_health_report() — HTTP → Java AiContextService │ │ │ │ @tool get_emotion_data() — HTTP → Java EmotionCheckin │ │ │ │ @tool search_knowledge() — 本地 RAG 检索 │ │ │ └──────────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────┐ │ LLM API │ │ DeepSeek-V3 (聊天/分析) / Qwen2.5 (推荐) / Embedding API │ └──────────────────────────────────────────────────────────────────────┘ ``` ### 关键设计决策 1. **Tool 通过 HTTP 调 Java 而非直连 DB** — Python 不直连 MySQL,数据主权在 Java 侧,安全可控 2. **ChromaDB 文件模式** — 无需额外容器,数据存在 `data/chroma_db/`,打包备份方便 3. **Checkpointer 先用 MemorySaver** — Phase 1-2 不依赖 PostgreSQL,后续按需升级 4. **与现有 Dify 体系共存** — 配置开关控制流量切分,异常自动 fallback --- ## 3. 项目结构 ``` cfc-langgraph/ # 新建 Python 项目 ├── pyproject.toml # 依赖管理 (pip / poetry) ├── Dockerfile # 容器构建 ├── docker-compose.yml # 编排 (可选) ├── .env.example # 环境变量模板 │ ├── app/ │ ├── __init__.py │ ├── main.py # FastAPI 入口 + 路由注册 │ ├── config.py # 配置管理 │ │ │ ├── api/ # HTTP 接口层 │ │ ├── __init__.py │ │ ├── chat.py # POST /api/v1/chat │ │ ├── recommend.py # POST /api/v1/recommend │ │ ├── analyze.py # POST /api/v1/analyze │ │ └── health.py # GET /api/v1/health │ │ │ ├── agents/ # LangGraph Agent 定义 │ │ ├── __init__.py │ │ ├── chat_agent.py # 家庭聊天 Agent │ │ ├── recommend_agent.py # 推荐 Agent │ │ ├── analysis_agent.py # 报告解读 Agent │ │ ├── task_agent.py # 任务解析 Agent │ │ └── orchestrator.py # 主管 Agent (多Agent编排) │ │ │ ├── graphs/ # LangGraph StateGraph 定义 │ │ ├── __init__.py │ │ ├── chat_graph.py # 聊天流程图 │ │ ├── recommend_graph.py # 推荐流程图 │ │ └── analysis_graph.py # 分析流程图 │ │ │ ├── tools/ # Agent Tool 定义 │ │ ├── __init__.py │ │ ├── product_tools.py # 商品/活动/文章检索 │ │ ├── report_tools.py # 健康报告查询 │ │ ├── emotion_tools.py # 情绪数据查询 │ │ ├── user_tools.py # 用户信息查询 │ │ └── knowledge_tools.py # 知识库 RAG 检索 │ │ │ ├── rag/ # RAG Pipeline │ │ ├── __init__.py │ │ ├── loader.py # 文档加载器 │ │ ├── splitter.py # 文本分块策略 │ │ ├── embeddings.py # Embedding 封装 │ │ └── retriever.py # 混合检索 + 重排序 │ │ │ ├── memory/ # 记忆管理 │ │ ├── __init__.py │ │ ├── store.py # 记忆存储接口 │ │ └── schemas.py # 记忆数据结构 │ │ │ └── models/ # Pydantic 数据模型 │ ├── __init__.py │ ├── chat.py # 聊天请求/响应 │ ├── recommend.py # 推荐请求/响应 │ └── common.py # 通用模型(用户/上下文) │ ├── data/ # 运行时数据 (gitignore) │ ├── chroma_db/ # ChromaDB 持久化文件 │ └── logs/ # 日志 │ └── tests/ # 测试 ├── conftest.py ├── test_agents/ ├── test_tools/ └── test_rag/ ``` --- ## 4. API 设计 ### 4.1 聊天 ```http POST /api/v1/chat Content-Type: application/json { "query": "小明最近肠胃不好,有什么建议?", "user_id": 12345, "conversation_id": "conv_abc", // 空串=新会话 "context": { // Java 侧传来的业务上下文 "child_id": 67890, "report_id": 1024, "mascot_code": "dolphin" } } Response: { "answer": "根据小明的健康报告...", "conversation_id": "conv_abc", "sources": [ {"type": "knowledge", "title": "儿童肠胃调理指南", "score": 0.92}, {"type": "tool", "name": "get_health_report", "result": "..."} ], "tasks": [ // 自动提取的任务 {"title": "每天喝一杯益生菌", "dimension": "身", "points": 10} ], "trace_id": "trc_xxx" // LangSmith Trace ID } ``` ### 4.2 推荐 ```http POST /api/v1/recommend Content-Type: application/json { "user_id": 12345, "tags": ["肠胃", "益生菌", "消化"], "types": ["product", "activity"], // 不传=全类型 "limit": 5, "context": { "family_id": 333 } } Response: { "items": [ { "type": "product", "id": 201, "name": "益生菌粉剂", "score": 0.95, "reason": "适合肠胃调理" } ], "source": "hybrid" // sql / vector / hybrid } ``` ### 4.3 健康 ```http POST /api/v1/analyze Content-Type: application/json { "report_id": 1024, "user_id": 12345, "focus": "nutrition" // 可选: nutrition/gut/chronic/overall } Response: { "summary": "...", "findings": [...], "recommendations": [...] } ``` --- ## 5. 记忆设计 ``` ┌──────────────────────────────────────────────────────────────┐ │ Memory Manager │ ├──────────────────────────────────────────────────────────────┤ │ Layer 1: 工作记忆 (BufferMemory) │ │ ├─ 当前会话最后 20 轮 (内存) │ │ └─ 超出 → ConversationSummaryBufferMemory 自动摘要 │ │ │ │ Layer 2: 长期事实 (EntityMemory) │ │ ├─ 自动提取实体: 偏好 / 健康指标 / 家庭成员 │ │ ├─ 跨会话跟踪, 按置信度排序 │ │ └─ 替代现有 AiUserFact (Java 侧可同步) │ │ │ │ Layer 3: 语义记忆 (VectorStoreRetrieverMemory) │ │ ├─ 每次对话结束后自动向量化存储 │ │ ├─ 新对话时召回前 3 条最相似的历史片段 │ │ └─ 实现"我记得你上次说…"的能力 │ └──────────────────────────────────────────────────────────────┘ 同步策略: Python 是记忆的主写入端 Java 侧的 ChatMirrorService 作为只读镜像 (同步 conversation + message) AiUserFact / AiConversationSummary → 随迁移推进逐渐废弃 ``` --- ## 6. 迁移阶段 ### Phase 1 (第1-2周): 基建 + 推荐 Agent **目标**: Python 服务跑起来, 第一个 Agent 上线 ``` Java 侧修改: ├── 新增 AiGateway.java (HTTP → Python, fallback → Dify) │ ├── 连接池: 5连接, 超时 15s │ ├── 熔断: 3次失败→停30s │ └── 配置开关: python.enabled=true/false └── RecommendationController.search() 先调 Python → 超时/异常 → fallback 现有 Java SQL 搜索 Python 侧: ├── FastAPI 骨架 + 配置管理 ├── RecommendAgent (最简单的单个 Agent, 无图) │ ├── @tool: search_product, search_article │ └── 调用 LLM 返回推荐理由 └── ChromaDB 初始化 + 知识库文章加载 交付物: ├── Python 服务可启动, health check 通过 ├── /api/v1/recommend 可返回结果 └── Java 侧灰度开关: 5% 流量走 Python ``` ### Phase 2 (第3-4周): 聊天 Agent + RAG **目标**: 替代 Dify 核心聊天能力 ``` Python 侧: ├── ChatAgent (LangGraph StateGraph) │ ├── Node: classify_intent → 意图分类 │ ├── Node: load_context → 调 Java Context API │ ├── Node: llm_call → LLM + Tool │ ├── Node: parse_tasks → [TASK] 提取 │ └── Edge: 条件路由(chat/analysis/recommend) ├── Memory 接入 │ ├── SummaryBufferMemory │ └── VectorStoreRetrieverMemory └── RAG Pipeline ├── 混合检索 (向量 + BM25) └── 重排序 + 压缩 Java 侧: ├── AIService.sendMessage() → 优先调 Python ├── AiContextService 改为 HTTP 数据接口 (Python 调) └── AiUserFact / AiConversationSummary 设为只读 交付物: ├── 家庭聊天通过 Python 完成 ├── 记忆层可追溯 └── 灰度 30% 流量 ``` ### Phase 3 (第5-6周): 高级 Agent + 知识库管理 **目标**: 剩下场景迁移 + 知识库自动化 ``` Python 侧: ├── AnalysisAgent (报告解读) │ ├── @tool: get_report_detail, get_survey_data │ └── LangGraph 图: 分析→发现→建议 ├── MultiModalAgent (舌诊, 保留 Dify Workflow fallback) ├── KnowledgePipeline (自动化知识库更新) │ ├── 定时任务: 从 Java 拉文章→分块→向量化 │ └── 增量更新: 只处理有变动的文档 └── LangSmith Trace 接入 (调试用) Java 侧: ├── DifySyncService.java 标记废弃 └── 知识库管理接口调整为 Python 侧触发 交付物: ├── 全场景 AI 能力由 Python 覆盖 ├── 知识库自动同步 └── 灰度 100% (Dify 降级为冷备) ``` ### Phase 4 (第7-8周): 收尾 **目标**: 运维完善, 代码清理 ``` Python 侧: ├── 性能调优 (连接池、缓存、异步) ├── 监控接入 (指标暴露 / 日志聚合) ├── 部署文档 + 运维手册 └── Docker Compose 编排 Java 侧: ├── 清理废弃代码 (Dify 相关) ├── 调整 ChatMirrorService 同步策略 └── 移除 Dify 配置项 交付物: ├── 运维手册完成 ├── 老代码清理 PR └── 架构文档更新 ``` --- ## 7. 部署方案 ### 方案 A: Docker Compose (推荐) ```yaml version: "3.8" services: cfc-backend: build: ./cfc-backend ports: "9082:9082" networks: [app-net] langgraph-svc: build: ./cfc-langgraph ports: "9000:9000" environment: - LLM_API_KEY=${LLM_API_KEY} - LLM_BASE_URL=${LLM_BASE_URL} - JAVA_CONTEXT_URL=http://cfc-backend:9082/api/ai/context - CHROMA_DB_PATH=/data/chroma_db - LANGCHAIN_TRACING_V2=true - LANGCHAIN_API_KEY=${LANGCHAIN_API_KEY} volumes: - langgraph-data:/data networks: [app-net] restart: unless-stopped networks: app-net: volumes: langgraph-data: ``` ### 方案 B: 直接 systemd + 文件模式 ``` Python: systemd 管理, Python 3.11 venv Chroma: 文件模式, 目录 /var/lib/cfc-langgraph/chroma_db 日志: 文件 → rsyslog / 直接 stdout 部署: git pull → pip install -r requirements → systemctl restart ``` ### 资源需求 | 资源 | 最低 | 推荐 | |------|------|------| | CPU | 0.5 核 | 1 核 | | 内存 | 256MB | 512MB | | 磁盘 | 1GB (代码+Chroma) | 5GB (含日志) | --- ## 8. 风险与缓解 | 风险 | 概率 | 影响 | 缓解措施 | |------|------|------|---------| | Python 服务不稳定 | 中 | 高 | Phase 1 灰度 5% + Dify Fallback + 熔断 | | LangGraph 学习成本 | 高 | 中 | Phase 1 从最简 Agent 开始, 不追逐复杂图结构 | | 记忆数据迁移丢失 | 低 | 中 | Phase 2 前 Java 侧保持双写, 验证对齐后再切 | | LLM API 费用增加 | 中 | 低 | Agent 多轮多约 10% token, 对比 Dify 调用成本基本持平 | | ChromaDB 性能瓶颈 | 低 | 中 | 10 万条内单机足够, 超出后切 PGVector 或 Milvus | --- ## 9. 目录清单 ``` cfc-langgraph/ ├── pyproject.toml ├── Dockerfile ├── docker-compose.yml ├── .env.example ├── .gitignore ├── app/ │ ├── __init__.py │ ├── main.py │ ├── config.py │ ├── api/ │ ├── agents/ │ ├── graphs/ │ ├── tools/ │ ├── rag/ │ ├── memory/ │ └── models/ ├── data/ └── tests/ ``` ``` cfc-backend (修改清单): src/main/java/.../service/AiGateway.java (新增) src/main/java/.../service/AIService.java (改造: 加 Python 路由) src/main/java/.../service/AiContextService.java (改造: 加 HTTP API) src/main/java/.../controller/ai/AIChatController.java (改造: 调 AiGateway) application.yml (加 python.* 配置) ```