02 - 架构设计经验
从 Sice 项目开发总结的 AI 原生应用架构设计经验。
AI 原生应用的特点
AI 应用和传统 Web 应用有什么不同?
- 多语言栈:通常需要前端 + Python (AI/Agent) + Rust (原生能力)
- 流式输出:需要支持 SSE 流式响应
- 工具调用:Agent 需要调用各种工具(MCP、本地工具)
- 状态管理:多轮对话需要状态持久化
- 安全敏感:Agent 能访问文件系统,需要权限控制
推荐架构:三层分层架构
对于桌面端 AI 应用,推荐三层架构:
┌─────────────────────────────────────────────────────────┐
│ 前端 UI 层 │
│ (Tauri + React + TypeScript) │
│ - 用户交互、流式渲染 │
│ - 直接调用 Agent HTTP API │
└────────────────┬────────────────────────────────────────┘
│
│ HTTP + SSE
│
┌────────────────▼────────────────────────────────────────┐
│ Agent 服务层 │
│ (Python + Deep Agents + FastAPI) │
│ - Agent 编排、工具调用、状态管理 │
│ - 权限控制、安全检查 │
└────────────────┬────────────────────────────────────────┘
│
│ 进程间调用 (预留)
│
┌────────────────▼────────────────────────────────────────┐
│ 原生能力层 │
│ (Tauri + Rust) │
│ - 进程生命周期管理、端口/令牌管理 │
│ - 文件系统访问、系统能力 │
└─────────────────────────────────────────────────────────┘各层职责
| 层级 | 职责 | 技术选型 |
|---|---|---|
| 前端 UI | 用户交互、流式渲染 | Tauri + React 19 + Tailwind + shadcn/ui |
| Agent 服务 | Agent 编排、工具调用、权限控制 | Python + Deep Agents + LangGraph + FastAPI |
| 原生能力 | 进程管理、本地系统能力 | Rust (Tauri 原生 API) |
通信方式
- 前端 → Agent:HTTP + SSE 流式响应,LangChain
useStream直接处理 - Agent → 原生:预留接口,需要时再实现(当前项目推荐简化,前端直连 Agent)
安全设计经验
1. 动态令牌 + 动态端口
原则:
- Agent 启动时随机生成令牌和端口
- 写入状态文件,权限
0600(仅当前用户可读写) - 前端读取状态文件得到令牌和端口
- 每次请求都需要令牌验证
json
// ~/.sice/agent-state.json
{
"port": 51234,
"token": "random-generated-token",
"pid": 12345
}2. 权限分级控制
| 层级 | 存储位置 | 内容 | 可修改性 |
|---|---|---|---|
| 高敏感限制 | 二进制内置 | 禁止命令列表、禁止目录 | 不可修改 |
| 用户授权 | 用户配置文件 | 允许访问的目录 | 用户可修改 |
运行模式:
| 模式 | 条件 | 允许操作 |
|---|---|---|
| 正常模式 | GUI 已连接 | 全部操作,敏感操作需用户确认 |
| 受限模式 | GUI 断开连接 | 仅预授权操作,其他排队等待 |
3. 安全设计要点
- 禁止:Agent 默认禁止执行任意 shell 命令
- 确认:敏感操作(写文件、访问私有目录)需要用户确认
- 日志:日志中不打印完整令牌,只打印前几位
多运行模式设计
好的架构应该支持多种运行模式,便于开发和部署:
| 模式 | 使用场景 | 启动方式 |
|---|---|---|
| LangGraph Dev 模式 | 开发调试 | langgraph dev |
| FastAPI 服务模式 | 服务器部署 | uvicorn 或 sice-cli serve |
| CLI 单机模式 | 终端用户 | 打包后的单可执行文件 |
CLI 命令设计
推荐二级命令结构:
sice-cli serve <command>
• sice-cli serve up 启动前台运行
• sice-cli serve start 启动后台运行
• sice-cli serve stop 停止服务
• sice-cli serve status 查看状态
• sice-cli serve logs 查看日志
sice-cli config <command>
• sice-cli config get key
• sice-cli config set key value目录结构经验
Python Agent 推荐目录
agent/
├── pyproject.toml # 项目配置
├── langgraph.json # LangGraph 配置
├── uv.lock # 依赖锁文件
├── scripts/ # 脚本
│ ├── run.sh # 开发启动
│ └── build-bin.sh # Nuitka 打包
└── app/ # 代码根目录
├── __init__.py # 版本信息
├── __main__.py # CLI 入口
├── agent.py # Agent 初始化 (Deep Agents)
├── main.py # FastAPI 工厂 (生命周期管理)
├── config.py # 配置管理 (pydantic-settings)
├── cli.py # CLI 命令定义 (Typer)
├── auth.py # 令牌验证
├── api/ # 路由层
│ ├── health.py # /health
│ ├── chat.py # /chat
│ └── sse.py # SSE 封装
├── types/ # 类型定义
│ └── schemas.py # Pydantic 模型
└── sice_agent/ # 业务能力
├── tools/ # 工具实现
├── prompts/ # 提示词模板
└── utils/ # 工具函数关键设计决策
| 文件 | 职责 | 理由 |
|---|---|---|
agent.py | Agent 初始化 | 符合 LangGraph/Deep Agents 标准,支持 Dev 模式 |
main.py | FastAPI 工厂 + 生命周期 | 使用 FastAPI 原生 lifespan,减少依赖 |
config.py | 配置管理 | pydantic-settings 统一管理环境变量 |
渐进式迁移经验
如果你需要从旧技术栈迁移到新技术栈:
原则:保留原有实现,新建模块,逐步迁移。
packages/
└── agent-sdk/ # 旧实现(保留备用)
agent/ # 新实现(Python + Deep Agents)好处:
- 产品始终可运行
- 风险可控,随时可以停止迁移
- 对比两种实现,总结经验
打包经验
Python Agent 打包为单二进制
推荐使用 Nuitka:
- 优点:编译后的单文件性能好、启动快
- 适用场景:Tauri sidecar 模式
bash
# 打包脚本示例
./scripts/build-bin.sh输出:单个可执行文件,直接被 Tauri 调用。
大小估算
| 组件 | 大小 |
|---|---|
| Python Runtime | ~15MB |
| FastAPI + Uvicorn | ~5MB |
| LangGraph + LangChain | ~20MB |
| Deep Agents | ~5MB |
| 业务代码 | ~1MB |
| 总计 | ~50MB |
总结:架构设计要点
- 分层清晰:每层职责单一,便于理解和维护
- 简化通信:能直连就不要加中间层
- 安全内嵌:安全设计从一开始就要考虑
- 多模式支持:开发调试方便,部署灵活
- 渐进演进:不追求一步到位,逐步完善