Skip to main content

系统架构概览

PAI 采用 FastAPI + LangGraph 构建后端,支持多平台即时通讯接入。项目提供两种架构模式:
  • main 分支多节点 Router 架构:Router 节点使用 LLM 意图分类,将请求路由到 6 个专业节点
  • feat/single-agent 分支单 Agent 架构:Agent + Harness 分层,单一 Agent 拥有全部工具并自主决策
当前生产环境运行的是 feat/single-agent 分支。两种架构共享相同的底层服务组成和数据流,核心差别在于 LangGraph 工作流的组织方式。

高层架构

整个系统的请求处理流程如下:
用户 → 平台桥接层 → FastAPI Webhook → LangGraph 工作流 → 响应 → 平台发送
1

用户发送消息

用户通过 Telegram、微信、QQ、飞书、小程序或 Web 等平台发送消息
2

平台桥接层接收

各平台适配器(Webhook / Polling)将消息转换为统一的 UnifiedMessage 格式
3

FastAPI 处理

后端 API 接收标准化消息,进入 handle_message 流程,加载会话上下文、长期记忆等
4

LangGraph 工作流执行

Router 节点根据意图分类,将请求路由到对应的专业节点执行
5

响应回传

通过 UnifiedSender 将响应发送回用户所在平台

服务组成

PAI 通过 Docker Compose 编排以下服务:

backend (FastAPI)

核心后端服务,运行在 8000 端口。负责 Webhook 接收、消息处理、LangGraph 工作流执行、工具调用等全部业务逻辑

memory_worker

独立的记忆处理进程,与 backend 共享同一镜像。负责异步提取和持久化用户长期记忆,避免阻塞主请求流程

frontend (React + Vite)

Web 前端,运行在 3001 端口。提供基于 WebSocket 的流式对话界面

db (PostgreSQL 15)

主数据库,使用 postgres:15-alpine 镜像。存储用户、会话、消息、账单、日程等业务数据,配合 pgvector 扩展支持向量检索

redis (Redis 7)

使用 redis-stack-server:7.4.0-v6 镜像。用于 LangGraph 检查点持久化、会话缓存与消息去重

gewechat

微信个人号接入服务(GeWeChat),运行在 2531 端口。实现微信消息的收发桥接

napcat

QQ 接入服务(NapCat),运行在 3000 端口。通过 OneBot v11 协议将 QQ 消息转发到后端 Webhook

数据流

以下是一条消息从接收到响应的完整数据流:
消息接收 (Webhook/Polling)


消息标准化 (UnifiedMessage)


handle_message
    ├── 去重检查 (is_duplicate)
    ├── 获取/创建用户 (get_or_create_user)
    ├── 确保活跃会话 (ensure_active_conversation)
    ├── 加载上下文消息 (_load_context_messages)
    ├── 检索长期记忆 (retrieve_relevant_long_term_memories)


Graph invoke (LangGraph 工作流)
    ├── main: router_node → 意图分类 → 路由到专业节点
    ├── feat: harness → agent (全部工具自主决策)


响应发送 (UnifiedSender)


异步记忆提取 (memory_worker)
memory_worker 以独立进程运行,通过数据库轮询待处理消息(memory_status = PENDING),异步完成记忆提取和存储,不影响主流程响应速度。

关键设计决策

为什么选择 LangGraph

LangGraph 提供内置的检查点(Checkpointing)机制,支持跨轮次的状态持久化。配合 AsyncRedisSaver,可以在生产环境中可靠地保存和恢复对话状态,无需手动管理状态序列化。
相比线性的 Chain,LangGraph 的 StateGraph 支持条件边(conditional edges),可以根据运行时状态动态决定执行路径。例如 ledger_manager 处理完账单后可以有条件地路由到 chat_manager 继续对话。
每个节点拥有独立的工具集(通过 toolsets.py 中的 NODE_TOOL_NAMES 定义),避免了工具权限混乱,同时便于独立测试和扩展。

两种架构的选择

每个节点专注于一个领域(记账、日程、对话等),拥有独立的系统提示词和工具集。这使得每个节点可以针对特定场景进行深度优化,而不是用一个通用节点处理所有请求。
Router 使用 LLM 进行意图分类(with_structured_output),支持 7 种意图。相比基于规则的路由,LLM 路由可以理解自然语言的模糊表达,并结合会话上下文做出更准确的判断。
添加新的业务能力只需要:定义新节点、在 toolsets.py 注册工具集、在 workflow.py 中添加节点和路由边。无需修改现有节点的逻辑。