745 lines
22 KiB
Markdown
745 lines
22 KiB
Markdown
|
|
# LangGraph Agent - 全能个人助手系统
|
|||
|
|
|
|||
|
|
该模块负责将个人助手从"查询型"升级为"全能执行型",通过 LangGraph 子图架构实现通讯录管理、智能词典、增强研究分析等核心功能。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🔧 公共工具与共享组件
|
|||
|
|
|
|||
|
|
三个子图共享一套统一的基础设施和通用工具,避免重复实现,确保架构一致。
|
|||
|
|
|
|||
|
|
### 公共工具架构
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|||
|
|
│ 公共工具层 (Shared Tools) │
|
|||
|
|
├─────────────────────────────────────────────────────────────────┤
|
|||
|
|
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────┐ │
|
|||
|
|
│ │意图理解工具 │ │人工审核工具 │ │格式化输出 │ │状态管理│ │
|
|||
|
|
│ └──────────────┘ └──────────────┘ └──────────────┘ └──────────┘ │
|
|||
|
|
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────┐ │
|
|||
|
|
│ │检查点持久化 │ │条件路由 │ │LLM 调用 │ │数据库 │ │
|
|||
|
|
│ └──────────────┘ └──────────────┘ └──────────────┘ └──────────┘ │
|
|||
|
|
└─────────────────────────────────────────────────────────────────┘
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|||
|
|
│ 子图层 (Subgraphs) │
|
|||
|
|
├─────────────────────────────────────────────────────────────────┤
|
|||
|
|
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
|||
|
|
│ │ 通讯录子图 │ │ 智能词典子图│ │ 研究分析子图│ │
|
|||
|
|
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
|||
|
|
└─────────────────────────────────────────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 公共工具详解
|
|||
|
|
|
|||
|
|
#### 1. 意图理解工具 (Intent Understanding Tool)
|
|||
|
|
|
|||
|
|
**技术栈**:LangChain LLM + 少样本提示词 + 结构化输出
|
|||
|
|
|
|||
|
|
**使用方法**:
|
|||
|
|
```python
|
|||
|
|
from agent_subgraphs.common.intent import parse_intent
|
|||
|
|
|
|||
|
|
result = parse_intent(
|
|||
|
|
user_input="添加张三电话13800138000",
|
|||
|
|
intent_categories=["contact", "dictionary", "research", "chat"]
|
|||
|
|
)
|
|||
|
|
# 返回: {
|
|||
|
|
# "intent_type": "contact",
|
|||
|
|
# "sub_intent": "add",
|
|||
|
|
# "extracted_info": {"name": "张三", "phone": "13800138000"}
|
|||
|
|
# }
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**实现逻辑**:
|
|||
|
|
- 使用 LLM 进行意图分类,输出结构化 JSON
|
|||
|
|
- 关键词匹配兜底(如"保存"、"添加" → contact)
|
|||
|
|
- 自动提取关键信息(实体、参数)
|
|||
|
|
- 支持自定义意图分类器
|
|||
|
|
|
|||
|
|
**所有子图共用**:在 `agent_subgraphs/common/intent.py`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 2. 人工审核工具 (Human-in-the-loop Tool)
|
|||
|
|
|
|||
|
|
**技术栈**:LangGraph `interrupt()` + 状态持久化
|
|||
|
|
|
|||
|
|
**使用方法**:
|
|||
|
|
```python
|
|||
|
|
from agent_subgraphs.common.human_loop import human_approval_node
|
|||
|
|
|
|||
|
|
def email_send_workflow(state: dict) -> dict:
|
|||
|
|
# 生成邮件草稿...
|
|||
|
|
state["pending_action"] = {"type": "email_send", "draft": draft}
|
|||
|
|
return human_approval_node(state) # 挂起等待用户确认
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**实现逻辑**:
|
|||
|
|
- 使用 `interrupt()` 触发挂起
|
|||
|
|
- 支持三种操作:确认、修改、取消
|
|||
|
|
- 超时自动取消(可配置超时时间)
|
|||
|
|
- 用户反馈结构化存储
|
|||
|
|
- 支持断点续作
|
|||
|
|
|
|||
|
|
**共享位置**:`agent_subgraphs/common/human_loop.py`
|
|||
|
|
|
|||
|
|
**应用场景**:
|
|||
|
|
- 通讯录:邮件发送、联系人删除
|
|||
|
|
- 研究分析:信息源确认、报告结构调整
|
|||
|
|
- 智能词典:批量删除确认
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 3. 格式化输出工具 (Formatting Tool)
|
|||
|
|
|
|||
|
|
**技术栈**:Jinja2 模板 + Markdown 生成
|
|||
|
|
|
|||
|
|
**使用方法**:
|
|||
|
|
```python
|
|||
|
|
from agent_subgraphs.common.format import format_output
|
|||
|
|
|
|||
|
|
result = format_output(
|
|||
|
|
template="contact_result",
|
|||
|
|
data={"contact": contact_data, "action": "added"}
|
|||
|
|
)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**实现逻辑**:
|
|||
|
|
- 预定义输出模板库
|
|||
|
|
- 支持 Markdown、HTML、纯文本三种格式
|
|||
|
|
- 自动处理列表、表格等复杂结构
|
|||
|
|
- 支持用户自定义模板
|
|||
|
|
|
|||
|
|
**共享位置**:`agent_subgraphs/common/format.py`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 4. 检查点持久化工具 (Checkpoint Tool)
|
|||
|
|
|
|||
|
|
**技术栈**:LangGraph CheckpointSaver + SQLite / PostgreSQL
|
|||
|
|
|
|||
|
|
**使用方法**:
|
|||
|
|
```python
|
|||
|
|
from agent_subgraphs.common.checkpoint import get_checkpointer
|
|||
|
|
|
|||
|
|
checkpointer = get_checkpointer(db_url="sqlite:///checkpoints.db")
|
|||
|
|
|
|||
|
|
# 在图编译时传入
|
|||
|
|
graph = workflow.compile(checkpointer=checkpointer)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**实现逻辑**:
|
|||
|
|
- 自动在每个节点执行后保存检查点
|
|||
|
|
- 支持断点续作
|
|||
|
|
- 状态版本管理
|
|||
|
|
- 支持查询历史状态
|
|||
|
|
|
|||
|
|
**共享位置**:`agent_subgraphs/common/checkpoint.py`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 5. 条件路由工具 (Conditional Routing Tool)
|
|||
|
|
|
|||
|
|
**技术栈**:LangGraph 条件边 + 路由函数
|
|||
|
|
|
|||
|
|
**使用方法**:
|
|||
|
|
```python
|
|||
|
|
from agent_subgraphs.common.routing import route_by_intent
|
|||
|
|
|
|||
|
|
def my_router(state: dict) -> str:
|
|||
|
|
return route_by_intent(
|
|||
|
|
state,
|
|||
|
|
{
|
|||
|
|
"translate": "translate_node",
|
|||
|
|
"lookup": "lookup_node",
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**实现逻辑**:
|
|||
|
|
- 标准化的意图路由
|
|||
|
|
- 支持复杂条件判断
|
|||
|
|
- 路由函数可组合
|
|||
|
|
- 自动处理默认分支
|
|||
|
|
|
|||
|
|
**共享位置**:`agent_subgraphs/common/routing.py`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 6. LLM 调用工具 (LLM Invocation Tool)
|
|||
|
|
|
|||
|
|
**技术栈**:LangChain ChatOpenAI + 重试 + 流式输出
|
|||
|
|
|
|||
|
|
**使用方法**:
|
|||
|
|
```python
|
|||
|
|
from agent_subgraphs.common.llm import call_llm, call_llm_stream
|
|||
|
|
|
|||
|
|
# 同步调用
|
|||
|
|
result = call_llm(prompt="翻译这句话", system_prompt="你是翻译官")
|
|||
|
|
|
|||
|
|
# 流式调用
|
|||
|
|
async for chunk in call_llm_stream(prompt="写一篇文章"):
|
|||
|
|
print(chunk.content, end="")
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**实现逻辑**:
|
|||
|
|
- 统一的 LLM 调用接口
|
|||
|
|
- 自动重试(指数退避)
|
|||
|
|
- 支持流式和非流式
|
|||
|
|
- Token 计数和监控
|
|||
|
|
- 模型 fallback 机制
|
|||
|
|
|
|||
|
|
**共享位置**:`agent_subgraphs/common/llm.py`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 7. 数据库工具 (Database Tool)
|
|||
|
|
|
|||
|
|
**技术栈**:SQLAlchemy + PostgreSQL / SQLite
|
|||
|
|
|
|||
|
|
**使用方法**:
|
|||
|
|
```python
|
|||
|
|
from agent_subgraphs.common.db import get_db, add_record, query_records
|
|||
|
|
|
|||
|
|
# 获取 session
|
|||
|
|
with get_db() as db:
|
|||
|
|
# 添加记录
|
|||
|
|
add_record(db, Contact, {"name": "张三", "phone": "13800138000"})
|
|||
|
|
# 查询记录
|
|||
|
|
contacts = query_records(db, Contact, filters={"name": "张三"})
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**实现逻辑**:
|
|||
|
|
- 统一的 ORM 会话管理
|
|||
|
|
- 标准 CRUD 操作封装
|
|||
|
|
- 支持事务
|
|||
|
|
- 自动错误处理
|
|||
|
|
|
|||
|
|
**共享位置**:`agent_subgraphs/common/db.py`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 8. 状态基类工具 (State Base Classes)
|
|||
|
|
|
|||
|
|
**技术栈**:TypedDict + 类型注解
|
|||
|
|
|
|||
|
|
**使用方法**:
|
|||
|
|
```python
|
|||
|
|
from agent_subgraphs.common.state import BaseSubgraphState
|
|||
|
|
|
|||
|
|
class ContactState(BaseSubgraphState):
|
|||
|
|
# 继承基础字段
|
|||
|
|
contact_data: Optional[dict]
|
|||
|
|
# 自定义字段...
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**实现逻辑**:
|
|||
|
|
- 预定义基础状态字段
|
|||
|
|
- 类型安全
|
|||
|
|
- 状态验证
|
|||
|
|
- 状态合并辅助函数
|
|||
|
|
|
|||
|
|
**共享位置**:`agent_subgraphs/common/state.py`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 公共工具目录结构
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
agent_subgraphs/
|
|||
|
|
├── common/ # 公共工具层
|
|||
|
|
│ ├── __init__.py
|
|||
|
|
│ ├── intent.py # 意图理解工具
|
|||
|
|
│ ├── human_loop.py # 人工审核工具
|
|||
|
|
│ ├── format.py # 格式化输出工具
|
|||
|
|
│ ├── checkpoint.py # 检查点持久化工具
|
|||
|
|
│ ├── routing.py # 条件路由工具
|
|||
|
|
│ ├── llm.py # LLM 调用工具
|
|||
|
|
│ ├── db.py # 数据库工具
|
|||
|
|
│ ├── state.py # 状态基类
|
|||
|
|
│ └── prompts/ # 公共提示词模板
|
|||
|
|
│ ├── intent.j2
|
|||
|
|
│ └── format.j2
|
|||
|
|
├── contact/ # 通讯录子图(简化版,使用公共工具)
|
|||
|
|
├── dictionary/ # 智能词典子图(简化版,使用公共工具)
|
|||
|
|
└── research/ # 研究分析子图(简化版,使用公共工具)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 公共配置项
|
|||
|
|
|
|||
|
|
所有子图共享的配置项(在 `.env` 中配置):
|
|||
|
|
|
|||
|
|
```env
|
|||
|
|
# LLM 配置
|
|||
|
|
LLM_PROVIDER=deepseek
|
|||
|
|
LLM_MODEL=deepseek-chat
|
|||
|
|
LLM_API_KEY=***
|
|||
|
|
LLM_TEMPERATURE=0.7
|
|||
|
|
LLM_MAX_TOKENS=2000
|
|||
|
|
|
|||
|
|
# 数据库配置
|
|||
|
|
DB_URL=postgresql://user:pass@localhost/agent_db
|
|||
|
|
|
|||
|
|
# 检查点配置
|
|||
|
|
CHECKPOINT_DB_URL=sqlite:///checkpoints.db
|
|||
|
|
|
|||
|
|
# 人工审核配置
|
|||
|
|
HUMAN_LOOP_TIMEOUT=3600
|
|||
|
|
|
|||
|
|
# 格式化配置
|
|||
|
|
DEFAULT_OUTPUT_FORMAT=markdown
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 使用公共工具开发新子图
|
|||
|
|
|
|||
|
|
创建新子图的步骤:
|
|||
|
|
|
|||
|
|
1. **继承状态基类**
|
|||
|
|
```python
|
|||
|
|
from agent_subgraphs.common.state import BaseSubgraphState
|
|||
|
|
|
|||
|
|
class MySubgraphState(BaseSubgraphState):
|
|||
|
|
my_field: str
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
2. **使用公共意图理解**
|
|||
|
|
```python
|
|||
|
|
from agent_subgraphs.common.intent import parse_intent
|
|||
|
|
|
|||
|
|
def intent_node(state: MySubgraphState) -> MySubgraphState:
|
|||
|
|
result = parse_intent(state["user_input"], ["my_intents])
|
|||
|
|
state.update(result)
|
|||
|
|
return state
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
3. **使用公共人工审核**
|
|||
|
|
```python
|
|||
|
|
from agent_subgraphs.common.human_loop import human_approval_node
|
|||
|
|
|
|||
|
|
def my_workflow(state: MySubgraphState) -> MySubgraphState:
|
|||
|
|
return human_approval_node(state)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
4. **使用公共格式化输出**
|
|||
|
|
```python
|
|||
|
|
from agent_subgraphs.common.format import format_output
|
|||
|
|
|
|||
|
|
def format_node(state: MySubgraphState) -> MySubgraphState:
|
|||
|
|
state["final_result"] = format_output("my_template", state)
|
|||
|
|
return state
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📑 目录导航
|
|||
|
|
|
|||
|
|
- [核心功能](#-核心功能) - 三大子图功能和技术特性
|
|||
|
|
- [技术架构](#️-技术架构) - 技术栈、子图架构图、数据流
|
|||
|
|
- [子图设计](#-子图设计) - 三个核心子图的详细说明
|
|||
|
|
- [状态管理](#-状态管理) - 主状态和子状态定义
|
|||
|
|
- [安全与边界](#️-安全与边界) - 安全机制和边界控制
|
|||
|
|
- [快速开始](#-快速开始) - 开发环境搭建
|
|||
|
|
- [实现指南](#-实现指南) - 子图开发、工具集成
|
|||
|
|
- [未来规划](#-未来规划) - 多模态、流式输出等
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🎯 核心功能
|
|||
|
|
|
|||
|
|
### 三大核心子图
|
|||
|
|
|
|||
|
|
| 子图模块 | 功能概述 | 关键特性 |
|
|||
|
|
|---------|---------|---------|
|
|||
|
|
| **通讯录子图** | 联系人 CRUD、邮件读取与审核、外发邮件、智能嗅探 | 人工审核强制、敏感信息加密、IMAP 邮箱绑定 |
|
|||
|
|
| **智能词典子图** | 翻译、查词、每日一词、专业名词提炼、生词本管理 | 联想记忆法、艾宾浩斯遗忘曲线、Anki 导出 |
|
|||
|
|
| **研究分析子图** | 联网搜索、报告生成、引用溯源、可视化图表 | 人工干预点、可定制报告结构、引用验证 |
|
|||
|
|
|
|||
|
|
### 通用机制
|
|||
|
|
|
|||
|
|
- ✅ **人工审核(Human-in-the-loop)**:通用节点,用于邮件发送、重要操作前的确认
|
|||
|
|
- ✅ **自动联系人嗅探**:对话中出现"人名+联系方式"时,主动询问是否保存
|
|||
|
|
- ✅ **流式输出**:所有 LLM 生成内容均采用流式传输,提升交互体验
|
|||
|
|
- ✅ **长期记忆**:PostgreSQL + pgvector 实现持久化记忆和语义检索
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🏗️ 技术架构
|
|||
|
|
|
|||
|
|
### 技术栈总览
|
|||
|
|
|
|||
|
|
| 层级 | 组件 | 技术选型 | 版本 | 说明 |
|
|||
|
|
|------|------|---------|------|------|
|
|||
|
|
| **Agent 框架** | 工作流编排 | LangGraph + LangChain | latest | 子图架构,状态机驱动 |
|
|||
|
|
| **LLM 服务** | 模型调用 | 智谱 AI / DeepSeek / 本地模型 | latest | 多模型路由 |
|
|||
|
|
| **向量数据库** | 语义检索 | Qdrant / pgvector | v1.12+ | 对话记忆、联系人语义索引 |
|
|||
|
|
| **关系数据库** | 结构化存储 | PostgreSQL | v16 | 联系人、生词本、邮件配置 |
|
|||
|
|
| **邮件协议** | IMAP/SMTP | `imaplib` / `smtplib` | 内置 | 邮件读取和发送 |
|
|||
|
|
| **后端框架** | API 服务 | FastAPI + Uvicorn | v0.115+ | 子图执行、状态管理 |
|
|||
|
|
|
|||
|
|
### 主图架构流程图
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
graph TB
|
|||
|
|
Start[START] --> Intent[意图分类节点]
|
|||
|
|
|
|||
|
|
Intent -->|contact| ContactSubgraph[通讯录子图]
|
|||
|
|
Intent -->|dictionary| DictSubgraph[智能词典子图]
|
|||
|
|
Intent -->|research| ResearchSubgraph[研究分析子图]
|
|||
|
|
Intent -->|chat| ChatNode[普通对话节点]
|
|||
|
|
|
|||
|
|
ContactSubgraph --> Final[最终响应]
|
|||
|
|
DictSubgraph --> Final
|
|||
|
|
ResearchSubgraph --> Final
|
|||
|
|
ChatNode --> Final
|
|||
|
|
|
|||
|
|
Final --> End[END]
|
|||
|
|
|
|||
|
|
style Start fill:#e1f5ff
|
|||
|
|
style Intent fill:#fff4e1
|
|||
|
|
style ContactSubgraph fill:#e8f5e9
|
|||
|
|
style DictSubgraph fill:#f3e5f5
|
|||
|
|
style ResearchSubgraph fill:#ffebee
|
|||
|
|
style Final fill:#fff9c4
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 子图架构总览
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
graph TB
|
|||
|
|
MainGraph[主图<br/>MainState]
|
|||
|
|
|
|||
|
|
MainGraph --> ContactSub[通讯录子图<br/>ContactSubState]
|
|||
|
|
MainGraph --> DictSub[词典子图<br/>DictSubState]
|
|||
|
|
MainGraph --> ResearchSub[研究子图<br/>ResearchSubState]
|
|||
|
|
|
|||
|
|
ContactSub --> ContactNodes[内部节点<br/>parse_intent<br/>add_contact<br/>list_contacts<br/>generate_draft<br/>human_approval<br/>send_email]
|
|||
|
|
DictSub --> DictNodes[内部节点<br/>translate<br/>lookup<br/>extract_terms<br/>daily_word]
|
|||
|
|
ResearchSub --> ResearchNodes[内部节点<br/>decompose<br/>web_search<br/>extract_info<br/>generate_report]
|
|||
|
|
|
|||
|
|
ContactNodes --> PG[(PostgreSQL<br/>联系人)]
|
|||
|
|
DictNodes --> PG2[(PostgreSQL<br/>生词本)]
|
|||
|
|
ResearchNodes --> Qdrant[(Qdrant<br/>向量检索)]
|
|||
|
|
|
|||
|
|
style MainGraph fill:#e1f5ff
|
|||
|
|
style ContactSub fill:#e8f5e9
|
|||
|
|
style DictSub fill:#f3e5f5
|
|||
|
|
style ResearchSub fill:#ffebee
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 状态传递机制
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
主状态 (MainState)
|
|||
|
|
│
|
|||
|
|
├─→ input: {user_input: messages[-1].content}
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
子图状态 (SubState)
|
|||
|
|
│
|
|||
|
|
├─→ 内部处理...
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
output: {messages: [AIMessage(final_result)], last_action: sub_state}
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
主状态更新
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📂 项目结构
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
Agent1/
|
|||
|
|
├── agent_subgraphs/ # LangGraph 子图模块
|
|||
|
|
│ ├── __init__.py
|
|||
|
|
│ ├── contact/ # 通讯录子图
|
|||
|
|
│ │ ├── README.md
|
|||
|
|
│ │ ├── __init__.py
|
|||
|
|
│ │ ├── state.py # 子图状态定义
|
|||
|
|
│ │ ├── graph.py # 子图构建器
|
|||
|
|
│ │ ├── nodes.py # 子图节点实现
|
|||
|
|
│ │ ├── tools.py # 子图工具集
|
|||
|
|
│ │ └── prompts.py # 提示词模板
|
|||
|
|
│ ├── dictionary/ # 智能词典子图
|
|||
|
|
│ │ ├── README.md
|
|||
|
|
│ │ ├── __init__.py
|
|||
|
|
│ │ ├── state.py
|
|||
|
|
│ │ ├── graph.py
|
|||
|
|
│ │ ├── nodes.py
|
|||
|
|
│ │ ├── tools.py
|
|||
|
|
│ │ └── prompts.py
|
|||
|
|
│ └── research/ # 研究分析子图
|
|||
|
|
│ ├── README.md
|
|||
|
|
│ ├── __init__.py
|
|||
|
|
│ ├── state.py
|
|||
|
|
│ ├── graph.py
|
|||
|
|
│ ├── nodes.py
|
|||
|
|
│ ├── tools.py
|
|||
|
|
│ └── prompts.py
|
|||
|
|
├── backend/ # 现有后端模块
|
|||
|
|
│ └── app/
|
|||
|
|
│ ├── graph/ # 主图构建
|
|||
|
|
│ │ ├── graph_builder.py # 主图 + 子图集成
|
|||
|
|
│ │ └── state.py # 主状态定义
|
|||
|
|
│ └── ...
|
|||
|
|
└── ...
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🎯 状态管理
|
|||
|
|
|
|||
|
|
### 主状态定义 (MainState)
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
from typing import TypedDict, List, Optional, Annotated
|
|||
|
|
from langchain_core.messages import BaseMessage
|
|||
|
|
from langgraph.graph import add_messages
|
|||
|
|
|
|||
|
|
class MainState(TypedDict):
|
|||
|
|
messages: Annotated[List[BaseMessage], add_messages]
|
|||
|
|
intent: str # 顶层意图:contact / dictionary / research / chat
|
|||
|
|
sub_intent: str # 细分意图
|
|||
|
|
|
|||
|
|
# 工具通用
|
|||
|
|
tool_call: Optional[dict] # 当前要执行的工具调用
|
|||
|
|
tool_result: str
|
|||
|
|
|
|||
|
|
# 控制流
|
|||
|
|
next_node: str
|
|||
|
|
human_feedback: Optional[str] # 用于挂起重启
|
|||
|
|
|
|||
|
|
# 子图结果
|
|||
|
|
last_contact_action: Optional[dict]
|
|||
|
|
last_dict_action: Optional[dict]
|
|||
|
|
last_research_action: Optional[dict]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 状态映射函数
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# 通讯录子图输入映射
|
|||
|
|
def contact_input_mapper(state: MainState) -> dict:
|
|||
|
|
return {
|
|||
|
|
"user_input": state["messages"][-1].content,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 通讯录子图输出映射
|
|||
|
|
def contact_output_mapper(sub_state: dict, original: MainState) -> dict:
|
|||
|
|
return {
|
|||
|
|
"messages": [AIMessage(content=sub_state["final_result"])],
|
|||
|
|
"last_contact_action": sub_state,
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🎯 主图实现
|
|||
|
|
|
|||
|
|
### 主图构建器
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
from langgraph.graph import StateGraph, START, END
|
|||
|
|
from agent_subgraphs.contact import build_contact_subgraph
|
|||
|
|
from agent_subgraphs.dictionary import build_dict_subgraph
|
|||
|
|
from agent_subgraphs.research import build_research_subgraph
|
|||
|
|
|
|||
|
|
def build_main_graph() -> StateGraph:
|
|||
|
|
main_graph = StateGraph(MainState)
|
|||
|
|
|
|||
|
|
# 添加子图节点
|
|||
|
|
main_graph.add_node(
|
|||
|
|
"contact_module",
|
|||
|
|
build_contact_subgraph(),
|
|||
|
|
input=contact_input_mapper,
|
|||
|
|
output=contact_output_mapper,
|
|||
|
|
)
|
|||
|
|
main_graph.add_node(
|
|||
|
|
"dict_module",
|
|||
|
|
build_dict_subgraph(),
|
|||
|
|
input=dict_input_mapper,
|
|||
|
|
output=dict_output_mapper,
|
|||
|
|
)
|
|||
|
|
main_graph.add_node(
|
|||
|
|
"research_module",
|
|||
|
|
build_research_subgraph(),
|
|||
|
|
input=research_input_mapper,
|
|||
|
|
output=research_output_mapper,
|
|||
|
|
)
|
|||
|
|
main_graph.add_node("chat_node", chat_node)
|
|||
|
|
main_graph.add_node("final_response", final_response_node)
|
|||
|
|
|
|||
|
|
# 主图路由
|
|||
|
|
main_graph.add_conditional_edges(
|
|||
|
|
START,
|
|||
|
|
route_main_intent,
|
|||
|
|
{
|
|||
|
|
"contact": "contact_module",
|
|||
|
|
"dictionary": "dict_module",
|
|||
|
|
"research": "research_module",
|
|||
|
|
"chat": "chat_node",
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 所有路径汇聚到最终响应
|
|||
|
|
main_graph.add_edge("contact_module", "final_response")
|
|||
|
|
main_graph.add_edge("dict_module", "final_response")
|
|||
|
|
main_graph.add_edge("research_module", "final_response")
|
|||
|
|
main_graph.add_edge("chat_node", "final_response")
|
|||
|
|
main_graph.add_edge("final_response", END)
|
|||
|
|
|
|||
|
|
return main_graph.compile()
|
|||
|
|
|
|||
|
|
def route_main_intent(state: MainState) -> str:
|
|||
|
|
"""顶层意图分类"""
|
|||
|
|
user_input = state["messages"][-1].content
|
|||
|
|
# 使用 LLM 分类
|
|||
|
|
# 返回 contact / dictionary / research / chat
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🔒 安全与边界
|
|||
|
|
|
|||
|
|
### 安全机制
|
|||
|
|
|
|||
|
|
| 风险点 | 对策 | 实现位置 |
|
|||
|
|
|--------|------|---------|
|
|||
|
|
| 邮箱密码泄露 | 使用环境变量存储,永不写入日志 | `agent_subgraphs/contact/tools.py` |
|
|||
|
|
| 恶意邮件发送 | 强制人工审核,单日发送数量限制 | 人工审核节点 |
|
|||
|
|
| 联系人隐私 | 向量检索结果脱敏展示,仅交互时完整显示 | 通讯录子图节点 |
|
|||
|
|
| 搜索内容安全 | 过滤成人内容,屏蔽高风险域名 | 研究子图搜索工具 |
|
|||
|
|
| 敏感词输出 | 流式输出后处理过滤 | 最终响应节点 |
|
|||
|
|
|
|||
|
|
### 人工审核节点
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
from langgraph.graph import interrupt
|
|||
|
|
|
|||
|
|
def human_approval_node(state: dict) -> dict:
|
|||
|
|
"""人工审核节点:挂起图,等待外部输入"""
|
|||
|
|
pending_action = state["pending_action"]
|
|||
|
|
|
|||
|
|
# 触发中断,等待外部通过 update_state 传入 human_feedback
|
|||
|
|
return interrupt(
|
|||
|
|
{
|
|||
|
|
"type": "human_approval",
|
|||
|
|
"message": f"请确认操作:{pending_action}",
|
|||
|
|
"options": ["确认", "修改", "取消"],
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🚀 快速开始
|
|||
|
|
|
|||
|
|
### 环境配置
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 激活虚拟环境
|
|||
|
|
source venv/bin/activate
|
|||
|
|
|
|||
|
|
# 安装依赖(新增)
|
|||
|
|
pip install langgraph langchain-experimental
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 配置文件
|
|||
|
|
|
|||
|
|
在 `.env` 中新增:
|
|||
|
|
|
|||
|
|
```env
|
|||
|
|
# 通讯录模块
|
|||
|
|
IMAP_SERVER=imap.qq.com
|
|||
|
|
IMAP_PORT=993
|
|||
|
|
SMTP_SERVER=smtp.qq.com
|
|||
|
|
SMTP_PORT=587
|
|||
|
|
EMAIL_USER=your_email@qq.com
|
|||
|
|
EMAIL_PASSWORD=your_auth_code
|
|||
|
|
|
|||
|
|
# 词典模块
|
|||
|
|
DEEPL_API_KEY=your_deepl_key
|
|||
|
|
YOUDAO_API_KEY=your_youdao_key
|
|||
|
|
|
|||
|
|
# 研究模块
|
|||
|
|
SEARCH_API_KEY=your_search_key
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 运行测试
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
from backend.app.graph.graph_builder import build_main_graph
|
|||
|
|
|
|||
|
|
# 编译主图
|
|||
|
|
graph = build_main_graph()
|
|||
|
|
|
|||
|
|
# 调用子图
|
|||
|
|
result = graph.invoke({
|
|||
|
|
"messages": [HumanMessage(content="添加张三电话 13800138000")]
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
print(result["messages"][-1].content)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📖 实现指南
|
|||
|
|
|
|||
|
|
### 添加新子图
|
|||
|
|
|
|||
|
|
1. 在 `agent_subgraphs/` 下创建新文件夹
|
|||
|
|
2. 创建 `state.py` 定义子图状态
|
|||
|
|
3. 创建 `nodes.py` 实现子图节点
|
|||
|
|
4. 创建 `graph.py` 构建子图
|
|||
|
|
5. 在主图 `graph_builder.py` 中注册新子图
|
|||
|
|
|
|||
|
|
### 子图开发最佳实践
|
|||
|
|
|
|||
|
|
- ✅ 子图拥有独立的状态,避免与主状态命名冲突
|
|||
|
|
- ✅ 使用 `input`/`output` 映射函数进行状态转换
|
|||
|
|
- ✅ 子图内部节点之间直接连接,主图只负责路由到子图入口
|
|||
|
|
- ✅ 将工具封装在子图内部,通过节点调用
|
|||
|
|
- ✅ 提供子图级别的单元测试
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🎯 未来规划
|
|||
|
|
|
|||
|
|
### Phase 1: 基础功能(当前)
|
|||
|
|
|
|||
|
|
- [ ] 通讯录子图完整实现
|
|||
|
|
- [ ] 智能词典子图完整实现
|
|||
|
|
- [ ] 研究分析子图完整实现
|
|||
|
|
- [ ] 主图集成和状态管理
|
|||
|
|
|
|||
|
|
### Phase 2: 增强功能
|
|||
|
|
|
|||
|
|
- [ ] 流式输出改造(所有 LLM 调用)
|
|||
|
|
- [ ] 多模态语音输入(STT)
|
|||
|
|
- [ ] 可视化图表生成
|
|||
|
|
- [ ] Anki 生词本导出
|
|||
|
|
|
|||
|
|
### Phase 3: 高级特性
|
|||
|
|
|
|||
|
|
- [ ] 智能家居控制子图
|
|||
|
|
- [ ] 日程管理子图
|
|||
|
|
- [ ] 更多工具集成
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📚 相关文档
|
|||
|
|
|
|||
|
|
- [通讯录子图 README](./contact/README.md) - 详细了解通讯录模块
|
|||
|
|
- [智能词典子图 README](./dictionary/README.md) - 详细了解词典模块
|
|||
|
|
- [研究分析子图 README](./research/README.md) - 详细了解研究模块
|
|||
|
|
- [主项目 README](../README.md) - 了解整体架构
|
|||
|
|
|