电商智能客服项目,基于 FastAPI + LangGraph + Vue3。
当前版本重点是“可运行的多路对话编排”:登录鉴权、SSE 流式回复、知识检索、多分支路由、附件上传与会话记忆。
- 支持电商客服高频场景:商品咨询、订单相关、售后政策问答。
- 用图编排(LangGraph)实现“分流 + 并行工具 + 最终汇总”。
- 在保证可用性的前提下,逐步从规则/模板演进到更强的 Agent 流程。
- 用户登录/JWT 鉴权
- 聊天(同步 POST + SSE 流式)
- Supervisor 路由分流(general / additional / graphrag / image / file)
- GraphRAG 子图(Guardrails、任务拆分、工具选择、Map-Reduce 汇总)
- Redis 会话记忆 + MySQL 长期画像更新
- 文件上传接口(
/api/chat/upload) - 确认接口(
/api/chat/confirm,兼容action和confirmed)
- 图片理解节点目前仍是占位回复;
file_query已实现低成本第一版解析 - 升级人工流程(
escalation)有模块与字段,但主链路尚未完整接入 - 向量库 Milvus / ES BM25 融合是升级方向,当前知识检索以本地混合检索为主
- Frontend:
Vue 3 + TypeScript + Pinia + Element Plus + Vite - Backend:
FastAPI + LangGraph + LangChain - LLM: DeepSeek(
deepseek-chat,通过langchain-openai接入) - Storage:
- Redis(会话中期记忆)
- MySQL(用户画像、会话记录)
- Neo4j structured(结构化业务图)
- Neo4j unstructured(预留)
backend/app/
├─ api/
│ ├─ auth.py # 登录、JWT校验
│ ├─ chat.py # 对话POST/SSE、上传、确认
│ └─ health.py # 健康检查
├─ graph/
│ ├─ main_graph.py
│ ├─ nodes/
│ │ ├─ router.py
│ │ ├─ general_chat.py
│ │ ├─ image_query.py
│ │ ├─ file_query.py
│ │ └─ hallucination.py
│ └─ subgraphs/
│ ├─ graphrag_query.py
│ └─ additional_info.py
├─ knowledge/
│ ├─ neo4j_client.py
│ ├─ schema_manager.py
│ ├─ cypher_templates.py
│ └─ knowledge_search.py
├─ memory/
│ ├─ session_manager.py
│ ├─ session_lifecycle.py
│ └─ user_profile.py
├─ models/
│ ├─ state.py
│ ├─ schemas.py
│ └─ database.py
└─ safety/
├─ input_sanitizer.py
├─ output_audit.py
└─ escalation.py
你关心的“Agent 怎么互相管理和协作”,核心在 Supervisor + 子图 + 共享状态。
主图入口:backend/app/graph/main_graph.py
analyze_and_route_query负责识别意图并路由- 按路由进入对应业务节点/子图
- 所有分支最终进入
hallucination_check - 统一输出
flowchart TD
A["START"] --> B["analyze_and_route_query"]
B -->|general-query| C["respond_to_general_query"]
B -->|additional-query| D["additional_query_subgraph"]
B -->|graphrag-query| E["graphrag_query_subgraph"]
B -->|image-query| F["create_image_query (placeholder)"]
B -->|file-query| G["create_file_query"]
B -->|faq-hit| H["hallucination_check"]
C --> H
D --> H
E --> H
F --> H
G --> H
H --> I["END"]
子图入口:backend/app/graph/subgraphs/graphrag_query.py
协作机制:
guardrails:先判定是否在业务范围内(不在范围直接结束)planner:把问题拆分为任务列表taskstool_selection:逐任务选择工具并通过Send分发- 并行执行工具节点(Map)
collect_results汇总(Reduce)generate_answer生成最终答复
flowchart TD
A["START"] --> B["guardrails"]
B -->|continue| C["planner"]
B -->|end| Z["END"]
C --> D["tool_selection"]
D --> E1["cypher_query"]
D --> E2["predefined_cypher"]
D --> E3["graphrag_search"]
D --> E4["vector_search"]
E1 --> F["collect_results"]
E2 --> F
E3 --> F
E4 --> F
F --> G["generate_answer"]
G --> Z
不是多个独立进程互调,而是 LangGraph 状态机内的节点编排:
- Supervisor 决定“去哪个分支”
- 子图内部 Planner 决定“拆成哪些任务”
- Tool Selector 决定“每个任务交给哪个工具节点”
- 状态字段(
SharedState/GraphRAGSubState)是各节点协作的共享总线 operator.add/operator.or_reducer 负责并行结果合并
也就是说,这里的 Agent 管理是 图级调度 + 共享状态合并,不是传统多进程 Agent 框架。
状态定义:backend/app/models/state.py
关键字段:
- 会话元数据:
session_id,user_id,auth_level - 历史消息:
messages(add_messagesreducer) - 路由信息:
router - 执行/结果:
agent_results,pending_confirmation - 缓存:
order_cache,product_cache - 附件:
config(image_path/file_path)
tasks:planner 的任务拆分结果tool_results:并行工具输出,按operator.add聚合final_answer:最终生成结果
这个状态模型就是 Agent 间“契约”。
backend/app/memory/session_manager.py:
- 保存会话消息列表(TTL)
- 保存会话鉴权信息(TTL)
- 保存临时缓存和情绪轨迹(TTL)
backend/app/memory/session_lifecycle.py:
- 每轮对话后异步触发
post_session_process - LLM 生成会话摘要与满意度分析
- 写入
ChatSession - 更新
UserProfile(偏好类目、投诉计数、最近摘要等)
POST /api/auth/loginPOST /api/auth/register(开发用途)
POST /api/chatGET /api/chat/stream?message=...&session_id=...&token=...
SSE 事件类型(data.event):
sessionthinkingstatustokenmessageerrordone
POST /api/chat/upload- 支持扩展名:
.png .jpg .jpeg .webp .pdf .docx .xlsx .csv .txt - 10MB 限制
- 返回:
url+image_path/file_path
POST /api/chat/confirm- 兼容两种请求:
- 新协议:
{ session_id, operation_id, action: "confirm"|"cancel" } - 旧协议:
{ session_id, confirmed: true|false }
- 新协议:
sequenceDiagram
participant U as User
participant FE as Vue Frontend
participant API as FastAPI /api/chat
participant G as LangGraph
participant T as Tool Nodes
participant M as Redis/MySQL
U->>FE: 输入消息/上传附件
FE->>API: /chat 或 /chat/stream
API->>M: 读取历史消息、初始化会话
API->>G: 提交初始状态
G->>G: 路由到主分支/子图
G->>T: 并行工具查询(可选)
T-->>G: 工具结果
G-->>API: 最终消息
API->>M: 写入AI消息 + 异步生命周期处理
API-->>FE: 同步回复 或 SSE token流
FE-->>U: 展示结果
docker compose up -d端口映射:
- Redis:
6379 - MySQL:
3306 - Neo4j structured:
7474/7687 - Neo4j unstructured:
7475/7688 - Elasticsearch:
9200
conda create -n aics python=3.11 -y
conda activate aics
cd backend
pip install -r requirements.txtcd ..
python scripts/init_mysql.py
python scripts/import_neo4j.py后端:
cd backend
python -m uvicorn app.main:app --reload --port 8000前端:
cd frontend
npm install
npm run dev以根目录 .env.example 为准,最关键项:
DEEPSEEK_API_KEYMYSQL_PASSWORDMYSQL_DATABASENEO4J_STRUCTURED_PASSWORDNEO4J_UNSTRUCTURED_PASSWORDJWT_SECRET_KEY
见 backend/requirements.txt。当前保留为实际使用集:
- FastAPI / Uvicorn / Pydantic
- LangGraph / LangChain / langchain-openai
- Neo4j / Redis / SQLAlchemy / aiomysql
- sentence-transformers
- PyJWT / python-multipart
- 图片分支可路由但业务逻辑仍为占位,文件分支已实现第一版解析
- 人工升级流程字段存在,但管理策略尚未完整接入主链路
- 当前缺少系统化自动化测试覆盖
- 实现
image_query视觉模型调用 - 继续增强
file_query(表格结构化抽取、OCR、长文档分级摘要) - 补 API 契约测试和核心图回归测试
- 将
escalation接入主图状态流,形成闭环
- 忽略目录:
frontend/node_modules/,backend/uploads/,__pycache__/ - 上传文件写入:
backend/uploads/ - 若调整端口,务必同步:
docker-compose.yml.env/.env.example- 前后端启动说明
说明:为避免高 token 成本,
file_query已实现“本地解析 + 片段检索 + 小模型汇总”的低成本策略。
.txt.csv.docx.xlsx.pdf
上传仍通过 /api/chat/upload,解析在 backend/app/graph/nodes/file_query.py 内执行。
- 从
state.config.file_path获取文件路径 - 校验文件存在、后缀、大小(10MB)
- 按文件类型做本地解析:
txt: 文本读取csv: 按行读取(限行)docx: 段落提取xlsx: 按 sheet/行提取(限行)pdf: 按页提取(限页)
- 将全文分块(chunk)
- 用 query 关键词对 chunk 打分,挑选少量高相关片段
- 仅把这些片段喂给轻量模型生成回答
- 文件大小限制:
10MB - 文本长度上限:
120000字符 - PDF 页数上限:
20页 - CSV 行数上限:
300行 - XLSX 每个 sheet 行数上限:
300行 - 进入模型的片段数上限:
6 - 单片段长度上限:
900字符 - 使用
get_light_model(max_tokens=420)生成答案
这意味着:不会把整份文件直接送进 LLM,token 消耗可控。
backend/requirements.txt 已新增:
pdfplumber==0.11.7python-docx==1.2.0openpyxl==3.1.5
如运行环境缺失这些依赖,节点会返回“缺少解析依赖”的明确提示,不会无限重试消耗额度。
file_query:已从占位改为可用第一版(低成本策略)image_query:仍为占位逻辑(后续接视觉模型)