# iAs — 微信 AI 智能助手 Rust 实现的微信 iLink Bot,支持 DeepSeek AI 自动回复、内置工具调用、审批确认、定时任务和长期记忆。 ## 快速开始 ```bash # 1. 配置环境变量(或创建 .env 文件) export DEEPSEEK_API_KEY="sk-xxx" export DATABASE_URL="postgresql://..." # PostgreSQL 可选 # 2. 扫码登录微信 ias login # 3. 启动守护进程(AI 自动回复) ias daemon # 4. 后台运行(配合 systemd) ias daemon --log-file ``` ## 命令一览 | 命令 | 说明 | |------|------| | `ias login` | 扫码登录微信,认证信息存入 PostgreSQL | | `ias daemon` | 守护进程模式(主运行模式,长轮询 + 三消费者架构) | | `ias daemon --log-file` | 守护进程 + 文件日志(配合 systemd) | | `ias send --to --text ` | 手动发送消息 | | `ias whoami` | 查看登录状态 | | `ias usage` | Token 用量统计(默认 7 天) | | `ias task list` | 列出所有定时任务 | | `ias task add --name ...` | 添加定时任务 | | `ias task update ` | 更新定时任务 | | `ias task delete ` | 删除定时任务 | | `ias task toggle ` | 启用/禁用定时任务 | | `ias tools` | 列出所有可用的 LLM 工具 | | `ias tool datetime` | 获取当前时间 | | `ias tool weather <城市>` | 查询天气 | | `ias tool search <关键词>` | 联网搜索 | | `ias tool fetch ` | 提取网页正文 | | `ias tool memos list/add/delete` | 管理备忘录 | | `ias tool amap poi-search/geocode/route-plan/travel-plan` | 高德地图服务 | ## 配置(环境变量) | 变量 | 必须 | 说明 | |------|------|------| | `DEEPSEEK_API_KEY` | ✅ | DeepSeek API 密钥 | | `DEEPSEEK_MODEL` | — | 模型名,默认 `deepseek-v4-flash` | | `DEEPSEEK_BASE_URL` | — | API 地址,默认 `https://api.deepseek.com/v1` | | `DATABASE_URL` | ✅ | PostgreSQL 连接串 | | `WEIXIN_LLM_SYSTEM_PROMPT` | — | 自定义系统提示词 | | `TAVILY_API_KEY` | — | Tavily 搜索 API Key | | `QWEATHER_API_HOST` | — | 和风天气 API 地址 | | `QWEATHER_JWT_KEY_ID` | — | 和风天气 JWT Key ID | | `QWEATHER_JWT_PROJECT_ID` | — | 和风天气项目 ID | | `QWEATHER_JWT_PRIVATE_KEY_FILE` | — | 和风天气 Ed25519 私钥路径 | | `AMAP_WEBSERVICE_KEY` | — | 高德地图 Web 服务 Key(或 `AMAP_KEY`) | 加载顺序:`./.env` → `~/.ias/.env` → 环境变量 ## 架构 ``` ┌──────────────────────────────────────────────────────────────┐ │ iAs CLI (main.rs) │ │ clap 子命令路由 → login / daemon / send / tool / task / ... │ ├──────────────────────────────────────────────────────────────┤ │ Daemon (daemon.rs) │ │ 持有 WeChat 长连接 + 数据库 + 审批管理器 + 长期记忆 │ ├──────────────────────────────────────────────────────────────┤ │ MessageQueue (公平轮转队列) │ │ 按用户轮转出队,防止一个用户刷屏饿死其他人 │ ├────────────────┬────────────────┬───────────────────────────┤ │ LLM Consumer │ Tool Consumer │ Send Consumer │ │ Conversation │ execute_tool │ WeChatClient.send_text() │ │ DeepSeek 流式 │ ApprovalMgr │ 入库 chat_records │ │ 上下文管理 │ 内置工具执行 │ │ ├────────────────┴────────────────┴───────────────────────────┤ │ Context / Memory │ │ ChatSession · Token Budget · 摘要压缩 · MemoryStore │ ├──────────────────────────────────────────────────────────────┤ │ Database (PostgreSQL) │ │ app_state · chat_records · llm_usage · user_memories │ │ pending_approvals · session_summaries · scheduled_tasks │ └──────────────────────────────────────────────────────────────┘ ``` ## 核心数据流 ``` 微信消息到达 → 存 inbound chat_records → enqueue PipelineMessage → MessageQueue 公平轮转 → LLM Consumer 消费 → 加载用户历史 + 记忆 + 摘要 → 构建 LLM 上下文(token budget + 摘要注入) → Conversation.chat_with_tools() ├── LLM 流式回复 ├── 工具调用 → enqueue ToolCall → Tool Consumer │ ├── 高风险工具 → ApprovalManager 审批流程 │ └── 执行工具 → 结果回喂 LLM └── 最终回复 → enqueue LLMReply → Send Consumer → Send Consumer 发送微信消息 + 入库 outbound chat_records ``` ## 源码结构 ``` src/ ├── main.rs CLI 入口 + 命令实现 ├── cli.rs clap 子命令定义(login/daemon/send/tool/task/tools) ├── logger.rs 日志初始化(终端 + 文件日滚) ├── daemon.rs 守护进程核心(长轮询 + 三消费者 + 调度器) ├── scheduler.rs 定时任务调度器(每 5s 轮询到期任务) ├── channel/ │ └── mod.rs ChannelId(平台+用户标识)、IncomingMessage ├── queue/ │ ├── message_queue.rs 公平轮转队列(按用户轮转出队) │ └── runner.rs QueueRunner(出队 → 按类型路由到消费者) ├── context/ │ ├── types.rs ChatSession(消息历史、摘要、checkpoint、token budget) │ ├── builder.rs Token 估算、上下文构建、摘要触发 │ └── tools.rs MemoryStore(长期记忆管理器) ├── db/ │ ├── mod.rs Database 连接池 + 迁移 │ └── models.rs CRUD(auth/chat/usage/summary/memory/task) ├── llm/ │ ├── types.rs Message / Role / ToolCall / StreamChunk / Usage │ ├── provider.rs LlmProvider trait + SSE 解析 + 工厂函数 │ ├── deepseek.rs DeepSeek 流式客户端实现 │ └── conversation.rs Conversation(chat + chat_with_tools 工具循环) ├── tools/ │ ├── types.rs RiskLevel / SkillSpec / SkillResult / ExecutionContext │ ├── tool.rs Tool trait + ToolRegistry(统一注册表) │ ├── api_tool.rs ApiTool(Rust 闭包实现的工具) │ ├── shell_tool.rs ShellTool(shell 命令执行的工具) │ ├── stdio_tool.rs StdioTool(子进程 stdin/stdout 通信的工具) │ ├── builtin.rs BuiltinRegistry(旧接口兼容层) │ ├── approval.rs ApprovalManager(确认码 + oneshot 通道) │ ├── mod.rs 全局注册表 + unpack_call_params + build_capability_guide │ └── builtins/ 内置工具实现 │ ├── datetime.rs 日期时间 │ ├── weather.rs 和风天气(实时/每日预报/逐时预报) │ ├── web_search.rs Tavily 搜索 │ ├── fetch_page.rs 网页抓取(可读性算法) │ ├── memos.rs 备忘录(文件存储,增删查) │ ├── amap.rs 高德地图(POI/地理编码/路径规划/旅游规划/地图链接) │ └── scheduled_task.rs 定时任务管理(增删改查切换) └── wechat/ ├── types.rs iLink API 协议类型 └── client.rs HTTP 客户端(login/poll/send/notify) ``` ## 工具系统 ### 架构设计(两层元工具) LLM 不直接感知每个具体工具,而是通过两个**元工具**间接调用: 1. **`query_capabilities`** — 列出所有可用工具的名称、描述、参数格式 2. **`call_capability`** — 按名称调用工具,参数通过 JSON 传递 ### 工具抽象 所有工具分为三种类型: | 类型 | 说明 | 示例 | |------|------|------| | `ApiTool` | Rust 闭包实现的工具(HTTP API / 本地计算 / 文件 I/O) | 天气、搜索、高德地图 | | `ShellTool` | 通过 shell 命令执行的工具 | 定时任务、系统命令 | | `StdioTool` | 通过子进程 stdin/stdout 通信的工具 | 外部脚本、可执行程序 | ### 内置工具 | 工具名 | 风险 | 说明 | |--------|------|------| | `get_current_datetime` | Low | 获取北京时间 | | `weather_now` | Low | 实时天气(和风天气) | | `weather_forecast` | Low | 每日天气预报 | | `weather_hourly` | Low | 逐时天气预报 | | `web_search` | Low | Tavily 联网搜索 | | `fetch_page` | Low | 网页正文提取(可读性算法) | | `memos_list` | Low | 列出备忘录 | | `memos_add` | Low | 添加备忘录 | | `memos_get` | Low | 查看指定备忘录 | | `memos_delete` | Low | 删除备忘录 | | `amap_poi_search` | Low | POI 搜索 + 周边搜索 | | `amap_geocode` | Low | 地理编码(地址→坐标) | | `amap_reverse_geocode` | Low | 逆地理编码(坐标→地址) | | `amap_route_plan` | Low | 路径规划(步行/驾车/骑行/电动车/公交) | | `amap_travel_plan` | Low | 智能旅游规划 | | `amap_map_link` | Low | 生成地图可视化链接 | | `scheduled_task_list` | Low | 列出定时任务 | | `scheduled_task_add` | Low | 添加定时任务 | | `scheduled_task_update` | Low | 更新定时任务 | | `scheduled_task_delete` | Low | 删除定时任务 | | `scheduled_task_toggle` | Low | 启用/禁用定时任务 | ### 审批流程 High 风险工具需要用户微信确认: ``` LLM 调用 High 工具 → 生成 6 位确认码 → SHA-256 入库 → 微信发送确认消息(含确认码) → 等待用户回复(最多 300s,3 次重试) → 匹配成功 → 执行工具 → 返回结果 → 匹配失败 / 超时 → 返回拒绝信息 ``` LLM 不感知确认码和审批过程,只看到最终的执行结果。 ## 上下文管理 - **Token Budget**:28K tokens,中/英文字符估算 - **Checkpoint**:摘要压缩点,之前的消息已压缩,之后完整保留 - **摘要触发**:token 溢出(overflow)或 12h 空闲(timeout) - **长期记忆**:LLM 按需通过 `read_memories` / `write_memory` 读写 - **用户隔离**:切换用户时清空 session,按需加载新用户历史 ## 消息队列(三消费者架构) ``` ┌──────────────┐ enqueue ──────→ │ MessageQueue │ ← 公平轮转(按用户) └──────┬───────┘ │ dequeue ▼ ┌──────────────┐ │ QueueRunner │ ← 路由循环 └──┬───┬───┬──┘ ┌─┘ │ └─┐ ▼ ▼ ▼ LLM Tool Send Consumer Consumer Consumer ``` 消息路由规则: - `UserMessage` / `ToolResult` / `ScheduledTask` → **LLM Consumer** - `ToolCall` / `ApprovalRequest` → **Tool Consumer** - `LLMReply` → **Send Consumer** ## 数据库表 | 表 | 用途 | |----|------| | `app_state` | 认证信息 KV 存储 | | `chat_records` | 收发消息记录(message_id 去重) | | `llm_usage` | Token 用量统计(含缓存命中率) | | `user_memories` | 长期记忆(按 user_id) | | `pending_approvals` | 待审批记录(SHA-256 确认码) | | `session_summaries` | 会话摘要 | | `scheduled_tasks` | 定时任务(支持 model/system 类型) | ## 部署 ### systemd 服务 ```bash sudo cp systemd/ias.service /etc/systemd/system/ # 编辑 .env 文件确保 API Key 等环境变量已配置 sudo systemctl enable --now ias ``` ### 天气 API 密钥 将和风天气 Ed25519 密钥对放入 `~/.ias/qweather/` 目录: ``` ~/.ias/qweather/ ├── ed25519-private.pem └── ed25519-public.pem ``` ## 依赖 | 依赖 | 用途 | |------|------| | tokio | 异步运行时 | | clap | CLI 参数解析 | | reqwest | HTTP 客户端 | | sqlx | PostgreSQL 驱动 + 迁移 | | serde / serde_json | 序列化 | | chrono | 时间处理 | | tracing | 结构化日志 | | async-trait | 异步 trait | | ed25519-dalek | 天气 API JWT 签名 | | scraper | 网页正文提取(可读性算法) | | sha2 / hex / rand | 审批确认码加密 | | uuid | 会话/任务唯一标识 | | base64 | Base64 编码 | | qrcode / image | 二维码生成 | | rustyline / dialoguer / console | 终端交互 | | futures-util | 流式处理工具 | | dirs | 系统目录路径 |