个人助手 Agent —— 产品与技术方案
基于 Pi Agent 的三层架构思想,从零实现一个跑在 Mac 上、接 DeepSeek、能操作你个人事务的助手 agent。
第一部分 · 产品方案
1. 产品定位
一句话:一个运行在你自己 Mac 上、接 DeepSeek、能通过自然语言操作「提醒事项 / 备忘录 / iMessage / 邮件 / 日历 / 搜索」的个人助手 agent。
关键属性:
| 属性 | 说明 |
|---|---|
| 完全自主可控 | 代码自己写的、模型用 DeepSeek(国内直连)、数据留在本机 |
| 自然语言入口 | 一句话触发多步操作(查 → 建 → 确认),不用记 CLI 命令 |
| 可无限定制 | 内核保持小,能力全在可插拔工具里,想加什么加什么 |
2. 核心价值
| 价值 | 说明 |
|---|---|
| 一个入口统管个人事务 | 提醒、笔记、消息、邮件、日历、搜索,不再各开各的 App |
| 完全掌控 + 可学习 | 从零实现,吃透 Agent 原理,随时改内核和工具 |
| 数据不出本机 | 模型请求走 DeepSeek,但事务数据(日程/笔记)留 Mac,无第三方托管 |
| 危险操作有审批 | 发消息、发邮件前必确认,杜绝"手滑"误操作 |
3. 目标用户
- 你自己(贺培文),个人生产力场景,非团队协作。
4. 功能清单
MVP(第一版,先跑通闭环)
| 功能 | 工具 | 说明 |
|---|---|---|
| 查/加提醒事项 | remindctl |
今天/明天/指定日期,加、完成、删 |
| 查/写备忘录 | memo |
列、搜索、新建、导出 |
| 网络搜索 | 自实现 | 查资讯、查资料 |
| 读写本地文件 | 自实现(fs) | 记笔记、读文档 |
| 常驻对话 + 会话记忆 | JSONL + memory.md | 多轮对话、记住偏好 |
| 危险操作审批 | beforeToolCall hook | 高危写操作先确认 |
进阶(第二阶段)
| 功能 | 工具 | 说明 |
|---|---|---|
| iMessage 收发 | imsg |
读会话、发消息(含图片) |
| 邮件收发 | himalaya |
收件箱、读、发 |
| 日历查/建 | osascript 调 Calendar.app |
查日程、建日程 |
| 定时主动提醒 | 内置 scheduler | "明早 9 点提醒我看日程" |
| 智能家居 | openhue |
控制灯(可选) |
| 接入飞书/微信 | 复用 Hermes 通道思路 | 手机上也能用 |
5. 典型使用场景(对话式)
| 用户说 | Agent 做 | 涉及工具 |
|---|---|---|
| "帮我记一下,明天下午 3 点跟李医生开会" | 建一条提醒,到期时间明天 15:00 | add_reminder |
| "我最近记了什么关于体检的笔记?" | 模糊搜索备忘录,列出相关 | search_notes |
| "查一下 DeepSeek 今天有什么新消息" | 网络搜索,摘要 | web_search |
| "给妈妈发条消息,今晚不回家吃饭" | 找到妈妈的会话 → 弹确认 → 发送 | imsg(审批) |
| "明天有什么安排?" | 汇总明天的提醒 + 日历 | list_reminders + 日历 |
6. 与现有工具的关系(为什么还要做)
| 工具 | 定位 | 与个人助手的差异 |
|---|---|---|
| Hermes(我) | 通用 agent 平台,有飞书/微信通道 | 架构是 Hermes 的,你改不了内核;本方案是你自己从零写的 |
| Codex / Claude Code | coding agent,写代码 | 场景是编程,不是个人事务 |
| 个人助手(本方案) | 个人事务 agent | 聚焦日程/笔记/消息/邮件,完全可控 + 学习 Pi 架构 |
核心动机:不是替代 Hermes/Codex,而是用 Pi 的架构思想亲手做一个完全属于自己的 agent,既是学习 Pi 内核,也是拿到一个可无限定制的个人生产力底座。
第二部分 · 技术方案
7. 技术选型(对抗式审查)
| 决策点 | 候选 | 攻击点 | 结论 |
|---|---|---|---|
| 语言 | TypeScript | 你主力 Java,TS 有学习成本 | ✅ 选 TS:Pi 原生语言,流式/工具 schema/SSE 生态最成熟 |
| Python | agent 生态强但偏重框架 | ❌ 与 Pi 三层思想对应不直接 | |
| Java | coding agent 主战场不在 JVM | ❌ 流式/工具 schema 支持绕 | |
| 模型 | DeepSeek(OpenAI 兼容) | 工具调用协议需自测 | ✅ 选 DeepSeek:你已直连可用,国内免翻墙 |
| OpenAI/Anthropic | 国内不稳 | ❌ | |
| 实现路径 | 参考 Pi 从零实现 | 前期有成本 | ✅ 选:拿到完全可控的最小内核 |
| 直接用 Pi 框架 | 被框架 TUI/扩展绑架 | ❌ | |
| 改 teaching-agent | 教学沙盘离生产有距离 | ⚠️ 作对照参考 | |
| 形态 | CLI 常驻对话(readline) | 多轮状态管理 | ✅ 选:个人助手天然是多轮对话 |
| 一次性命令 | 无上下文延续 | ❌ 只适合 demo | |
| 记忆 | JSONL + memory.md | 要设计读写时机 | ✅ 选:没有记忆的助手每次都是陌生人 |
| 只靠 JSONL | 重启丢、跨会话无记忆 | ❌ |
8. 架构设计(复用 Pi 三层)
┌────────────────────────────────────────────────┐
│ 产品层(CLI 常驻对话) │
│ · 会话 JSONL + memory.md + 工具注册 + 权限审批 │
├────────────────────────────────────────────────┤
│ 内核层:Agent 状态机 + runAgentLoop + hooks │
│ · beforeToolCall(危险工具→确认)/ afterToolCall │
├────────────────────────────────────────────────┤
│ 适配层:Message/Tool/Event 协议 + DeepSeekProvider│
└────────────────────────────────────────────────┘
Pi 三层分工(本方案完整复用):
| 层 | Pi 对应 | 本方案职责 |
|---|---|---|
| 适配层 | pi-ai |
统一消息/工具/事件协议,屏蔽供应商差异,接 DeepSeek |
| 内核层 | pi-agent-core |
Agent 状态机、runAgentLoop、hooks,不碰 UI 和存储 |
| 产品层 | pi-coding-agent |
会话持久化、工具注册、权限审批、CLI 交互 |
两个边界(个人助手的安全地基):
- LLM 边界:进模型前把内部消息转成 DeepSeek 格式,出模型后统一成自己的事件协议——上层循环永远不感知供应商差异。
- 副作用边界:模型不能直接发消息/改日程,只能提 tool call;副作用在本地工具执行,被
beforeToolCall拦住审批。
9. 核心模块
| 模块 | 职责 | 对应 Pi |
|---|---|---|
shared/types.ts |
消息/事件/工具 schema 协议 | pi-ai types |
ai/deepseek.ts |
DeepSeekProvider、streamSimple | pi-ai |
agent/loop.ts |
Agent Loop 主循环 | pi-agent-core |
agent/hooks.ts |
beforeToolCall 审批 / afterToolCall | pi-agent-core |
cli/tools.ts |
工具注册表(包装 CLI) | 产品层 |
cli/store.ts |
JSONL 会话 + memory.md | 产品层 |
cli/index.ts |
readline 常驻对话入口 | 产品层 |
Agent Loop 骨架(所有框架绕不开的,照 Pi 极简版):
async function runAgentLoop(context, config) {
while (true) {
const assistant = await streamAssistantResponse(context, config);
context.messages.push(assistant);
const toolCalls = assistant.content.filter(b => b.type === "toolCall");
if (toolCalls.length === 0) return; // 无工具调用 = 结束
for (const call of toolCalls) {
const tool = context.tools.find(t => t.name === call.name);
const result = await tool.execute(call.arguments);
context.messages.push(toToolResultMessage(call, result)); // 结果写回再循环
}
}
}
10. 工具底座(真实可落地)
工具 = JSON Schema(给模型看参数)+ execute 函数(包装 CLI)。
| 工具 | 底层 | 安装 | 危险级 |
|---|---|---|---|
| 查/加提醒 | remindctl |
brew install steipete/tap/remindctl |
写=中 |
| 查/写笔记 | memo |
brew tap antoniorodr/memo && brew install antoniorodr/memo/memo |
写=低 |
| 查/发消息 | imsg |
brew install steipete/tap/imsg |
写=高 |
| 查/发邮件 | himalaya |
brew install himalaya(配 IMAP/SMTP) |
写=高 |
| 日历 | osascript |
零依赖(Calendar.app) | 写=中 |
| 搜索 | 自实现 | 无 | 无 |
| 文件 | 自实现(fs) | 无 | 写=低 |
工具 schema 示例:
// 把 remindctl 包成 agent 工具
{
name: "add_reminder",
description: "在 Apple 提醒事项新建提醒,可设到期时间和列表",
parameters: {
type: "object",
properties: {
title: { type: "string", description: "提醒内容" },
due: { type: "string", description: "到期时间,如 'tomorrow' 或 '2026-09-20 14:00'" },
list: { type: "string", description: "列表名,如 工作/个人" },
},
required: ["title"],
},
execute: async (args) =>
exec(`remindctl add --title "${args.title}" --due "${args.due ?? "today"}"`),
}
11. 安全边界(个人助手比 coding agent 更敏感)
| 工具类型 | 策略 | 实现 |
|---|---|---|
| 只读(查提醒/笔记/消息/邮件/搜索/文件) | 免审批 | danger: false |
| 低危写(写笔记、写文件) | 免审批 | danger: false |
| 高危写(发消息/邮件、加改日程、删) | 执行前必确认 | danger: true → beforeToolCall 弹 y/n |
一次对话链路(比 coding agent 多两处:记忆注入 + 审批):
用户输入 → 构造上下文(注入 memory.md + 会话历史 + 工具 schema)
→ runAgentLoop → DeepSeek 返回 toolCall
→ beforeToolCall:danger? 弹确认 : 放行
→ 执行工具 → 结果写回 → 再请求模型
→ 无工具调用 → 返回答案 → 持久化会话
12. 落地步骤(7 步,每步可验收)
| 步骤 | 做什么 | 验收 |
|---|---|---|
| 1 | 装工具底座(remindctl/memo/imsg) | 各跑一条只读命令 |
| 2 | shared 协议(消息/事件/工具 schema) | tsc --noEmit 通过 |
| 3 | Loop + MockModel(先不接真模型) | 内存跑通 loop |
| 4 | 工具注册表(先做提醒/笔记/搜索三个) | 工具可执行 |
| 5 | CLI 常驻对话 + JSONL + memory.md | 多轮对话 |
| 6 | 接 DeepSeek + 审批 hook | 真实模型跑通,发消息前弹确认 |
| 7 | 补全工具(imsg/himalaya/日历)+ 长期记忆 | 完整可用 |
先做 MVP:提醒 + 笔记 + 搜索三个工具跑通全链路(工具 → 审批 → 记忆 → 对话),再逐步加消息/邮件。
不要一开始就做(Pi 的反模式):接真模型前先跑通 Mock、别做多 session UI、别做完整权限审批(先路径限制 + 工具白名单)、别做漂亮动画。
13. 风险与对策
| 风险 | 影响 | 对策 |
|---|---|---|
| DeepSeek 工具调用/流式协议兼容性 | 工具调用不稳定 | 先 MockModel 跑通 loop,再接真模型逐步验证 |
| 高危工具误操作 | 发错消息不可逆 | danger 分级 + beforeToolCall 审批 + 只读工具优先 |
| 记忆文件膨胀 | 上下文超窗口 | 上下文压缩(超阈值插 summary)+ memory.md 精简 |
| macOS 自动化权限(自动化/完全磁盘访问) | 工具调不动 App | 首次运行时引导授权(System Settings → Privacy) |
| CLI 工具依赖升级 | 命令格式变化 | 工具 execute 层做适配,内核不感知 |
第三部分 · 落地计划
| 阶段 | 内容 | 交付 |
|---|---|---|
| M1(MVP) | 提醒 + 笔记 + 搜索 + 对话 + 记忆 + 审批 | 一个能跑的个人助手 CLI |
| M2(扩展) | imsg + 邮件 + 日历 | 消息邮件日历全覆盖 |
| M3(主动) | 定时提醒 + 接入飞书/微信 | 主动服务 + 移动端可达 |
下一步:确认方案后,从「装工具底座 + 起项目骨架 + 写 shared 协议」开始动手。
方案基于 Pi Agent(pi.dev / how-pi-agent-works)三层架构思想,工具底座复用本机 macOS CLI(steipete/tap 系列)。