Files
ailine/backend/app/agent_subgraphs/README.md

745 lines
22 KiB
Markdown
Raw Normal View History

# 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) - 了解整体架构