几天前,我还在认真设计 Iris。
我给它设计数据库,定义 Project、Milestone、Task、Resource 和 Capability;给它接 Cloudflare Worker、D1 和 Git;考虑怎么让 Agent 读取我的状态,怎么主动通知我,甚至开始考虑让 Iris 管理 Iris 自己的开发。
几天后,我决定暂停这个项目。
暂停的时候,Iris 已经可以部署,独立的 Memory Git Repo 也已经接通,v0.2 事实上也已经接近完成。按照原来的路线,下一步会开始做 Notification Adapter,让 Iris 能通过不同渠道主动联系我。我甚至已经开始考虑再往前做一层 Connect Gateway,把不同 Agent、通知渠道和外部系统接到同一个入口上。
技术上没有遇到无法跨越的问题。相反,继续往下做的路线已经相当清楚。
真正变化的是我对这件事本身的理解。
Iris 最开始只是我想给自己做的一个私人 AI。开发到最后,我逐渐发现,真正值得留下来的可能不是这个软件,而是这一过程中形成的一套关于 Personal AI 的理解。
所以我决定停下来,把现有代码整理好、开源,不再继续扩展产品功能。
这篇文章记录的就是这个过程。
我需要一个知道「现在发生了什么」的系统
我手上一直同时存在很多事情。
有正在开发的产品,有广告投放,有服务器和各种在线服务,有财务问题,也有日常生活、孩子、提醒和长期计划。
这些事情本身并不复杂。真正麻烦的是它们长期同时存在。
一个项目今天做到这里,三天以后再回来,需要重新想一遍上次停在哪里;某件事暂时不能处理,一个星期以后可能已经忘了;有些决定是在聊天里形成的,有些资料在 Git,有些任务记在别的地方。
ChatGPT 可以和我讨论问题,Todo 软件可以记任务,日历可以提醒时间,Git 可以存文件。
每一个工具都解决了一部分问题,但缺少一个地方持续维护:
我现在到底处于什么状态。
于是我开始设计 Iris。
最初的想法很简单,我想要一个私人秘书。
它应该知道我有哪些项目,每个项目做到哪里,目前有哪些任务,哪些事情正在等待,什么时间应该提醒我,还有哪些信息值得长期保存。
以后我问一句:
我现在应该干什么?
它不需要重新询问我最近在做什么,也不需要翻几十段聊天记录。
它应该已经知道。
这成为 Iris 后面所有设计的起点。
从私人秘书到 Life OS
开始建模以后,问题很快发生了变化。
如果只是做 Todo,其实完全没有必要自己开发一个系统。
我真正需要描述的是一个人的持续状态。
所以 Iris 最早确定下来的几个核心对象是:
text
Project
Milestone
Task
Resource
Capability
这五个对象后来基本构成了 Iris 的骨架。
Project
我把 Project 定义得很宽。
一个产品当然是 Project,比如 DeepUsername。
广告投放可以是 Project,一个长期生活目标也可以成为 Project。
Project 的意义并不只是「软件项目」。它更像一个长期存在、持续变化的状态容器。
Milestone
Project 下面是 Milestone。
比如:
text
DeepUsername
├── v0.5
└── v1.0
Milestone 描述一个阶段目标。
阶段完成以后,它不会消失,而是成为这个项目历史的一部分。
这样我看到的不只是「还有什么没做」,也能看到一个项目是怎样走到今天的。
Task
真正需要执行的动作才进入 Task。
Task 可以属于某个 Milestone,也可以记录自己的来源,比如某份 PRD、某一章节或者一次讨论。
这一点很重要。
普通 Todo 只记录「做什么」,时间长了以后很容易忘记「为什么要做」。
我希望 Iris 里的任务能够尽量保留上下文。
Resource
随着设计继续往下走,我又把 Resource 单独拆了出来。
Markdown、文档、Git 中的文件和目录都属于 Resource。
Task 是动作,Resource 是动作所依赖或者产生的东西。
把两者分开以后,整个模型清晰了很多。
Capability
最后是 Capability。
脚本、Skill、API,以及其他可调用的执行入口,都属于能力。
Iris 可以知道自己有哪些能力,但这些能力本身不应该和任务、知识或者项目状态混在一起。
到这里,我已经没有把 Iris 当成一个传统的任务管理器了。
它开始更像一个很小的 Life OS。
项目、任务、资料、能力都有明确的位置,Agent 只是运行在这些东西之上的一个角色。
这个区别后来越来越重要。
State First
做 Iris 的过程中,我逐渐形成了一个最核心的判断:
Personal AI 的核心资产应该是 State。
今天大部分 AI 产品仍然以 Conversation 为中心。
典型过程大概是:
text
Conversation
↓
Reasoning
↓
Action
用户说一段话,模型根据上下文理解问题,再采取行动。
这种模式解决一次性问题很好。
长期运行时就开始出现麻烦。
人的生活不是一段无限增长的聊天记录。
比如一个产品现在已经完成了 v0.5,正在准备 v1.0。这是一条状态。
某个供应商需要等对方回复,这也是状态。
某个决定已经做出,短期内不再讨论,同样是一条状态。
这些信息应该直接存在。
于是 Iris 的模式逐渐变成:
text
State
↓
Reasoning
↓
Action
↓
State Update
Agent 每次工作以前先读取世界当前的状态。
执行完成以后,再修改这个状态。
聊天只是产生状态变化的一种入口。
这带来了一个很重要的结果:
Agent 不再等于 Iris。
今天可以让 Hermes 接 Iris。
明天也可以换成另一个 Agent。
模型当然也可以继续变化。
Claude、GPT,或者以后任何新的模型,都只是推理层。
只要 Project、Milestone、Task、Resource、财务、提醒这些状态仍然存在,换掉 Agent 并不会让整个系统重新开始。
我后来越来越确定,长期 Personal AI 最需要保护的东西,就是这一层。
模型可以换,Agent 可以换,执行器也可以换。
状态应该留下来。
SQL 管状态,Git 管长期资源
State First 确定以后,技术架构也自然开始分层。
最终 Iris 大致形成了这样的结构:
text
User
│
Hermes / Agent
│
Iris API
│
┌──────────┴──────────┐
│ │
D1 Git Repo
│ │
Structured State Resources
Projects Markdown
Milestones Knowledge
Tasks Scripts
Schedule Skills
Finance Capabilities
Worker 是控制面。
我选择 Cloudflare Worker,再用 Hono、Drizzle、Zod 和 OpenAPI 建 API。
D1 保存权威的结构化状态。
Git 则承担长期工作区的角色。
我一度考虑过各种知识库设计,后来越来越倾向于让 Git 做最普通的事情:保存 Markdown、脚本、Skill、内容资产以及 Capability 相关资源。
这套结构有一个很朴素的好处。
数据库擅长回答:
当前是什么状态?
Git 擅长回答:
具体内容是什么?它以前是什么样子?
两者不用强行塞进一个系统。
Agent 通过 API 读取和修改结构化状态,需要内容时再访问对应 Resource。
Iris Core Code 和 Iris Memory 也因此可以分开。
代码是一套系统,Memory Repo 是属于某个使用者的长期数据和内容空间。
如果未来真的存在多个 Iris,它们可以使用同一套 Core,但拥有不同的 Memory。
Agent 不应该什么都做
Iris 刚开始的时候,我也经历了 Agent 产品很常见的一段扩张期。
既然已经有 Agent,那么自然会开始想:
能不能让它帮我调研?
能不能让它写代码?
能不能自动做产品设计?
能不能自己发现问题?
能不能自己增加新的能力?
继续想下去,很容易走向一个「什么都能做」的私人 Agent。
这时候我开始主动收缩 Iris 的范围。
我重新定义了它在 v1.0 的职责。
Iris 是秘书。
它负责记录、跟踪、维护项目状态,管理提醒和待办,汇总财务信息,在需要关注某件事情的时候主动通知我。
产品怎么设计、代码怎么写、商业判断怎么做,可以继续交给我以及其他专业工具。
这一轮收缩给了我另一个很重要的原则:
thinking and save your think, build which need.
思想可以继续展开。
值得保存的思想可以留下。
真正进入代码的东西必须有明确需求。
我后来把这个原则概括成了一个词:
Controlled。
代码需要控制,Agent 的执行需要控制,我自己的开发冲动也需要控制。
如果想到一个能力就立刻实现,Iris 最后一定会长成一个巨大而难以维护的系统。
所以思考可以自由,执行必须受到约束。
确定性的东西应该退出 Agent
Controlled 继续往下推,又产生了一个很有意思的问题:
到底什么事情应该由 Agent 完成?
比如:
text
查询 Project
创建 Task
更新 Milestone
读取 Resource
这些操作其实没有多少智能含量。
输入确定,规则确定,结果也确定。
让 Agent 每次临时理解并重新决定如何执行,只会增加不确定性。
这时我开始形成另一个判断:
如果世界是确定性的,API 会越来越多。 如果世界是不确定的,Agent 会越来越多。
查一个项目的状态,用 API。
修改一条 Task,用 API。
某个操作有稳定的输入输出,也应该逐渐固化成 Capability。
真正适合 Agent 的,是这样的事情:
根据我最近的项目状态、时间安排和当前目标,判断今天最值得优先处理什么。
这里没有唯一答案,需要综合大量上下文,也需要推理。
于是 Iris 和 Hermes 的区别开始变得很清楚。
我当时用了一句话概括:
Hermes 沉淀 Skill,而我沉淀 API。
Hermes 更像一个不断学习各种工作方式的 Agent。
Iris 则希望把已经确定的行为逐渐变成稳定接口。
随着系统成熟,Agent 不必越来越重。
很多已经验证过的行为反而应该从 Agent 里退出,进入 API、Script 或 Capability。
智能留给真正存在不确定性的地方。
我甚至开始考虑让 Iris 管理自己的开发
走到这里以后,一个很自然的想法出现了:
Iris 本身也可以是一个 Project。
比如:
text
Project: Iris
Milestone:
v0.1
Tasks:
Git integration
Resource API
Capability API
README
Resources:
PRD
Architecture
Source Code
既然 Iris 可以管理 DeepUsername,当然也可以管理 Iris。
再往前一步,它甚至可以观察自己的使用。
假设我连续几次让 Agent 完成同一种操作,Iris 可以识别:
这个行为已经相对稳定,可能值得固化成一个 Worker API。
接下来它创建一个 Task:
是否把这个操作固化为 Capability?
我批准以后,再调用 Codex 实现。
这个想法一度让我觉得非常有趣。
Iris 开始具备一种有限的自我进化能力。
不过 Controlled 在这里依然有效。
它可以发现需求,可以提出修改,可以创建 Task,但不能因为自己判断应该增加一个功能,就直接修改自己的生产环境。
整个流程应该类似:
text
Observe
↓
Propose
↓
Create Task
↓
Human Approval
↓
Implement
↓
Test
↓
Deploy
自我进化也只是一个受到控制的开发流程。
人仍然保留最后的决定权。
真正开始开发以后,抽象才变成约束
前面的很多东西听起来都属于架构设计。
真正开始写 Iris 以后,它们才逐渐变成实际约束。
早期我先做 Auth 和测试路由,然后接 D1。
接着依次实现 Project、Milestone、Task、Resource 和 Capability。
里面有大量并不宏大的问题。
Token 怎么生成?
测试用户怎么创建?
D1 的时间字段应该怎么处理?
没有 Cloudflare 凭据的时候,本地测试做到哪里?
Resource ID 是否必须存在?
Capability 被其他对象引用以后还能不能删除?
一个 Capability 已经被使用,再进行不兼容修改应该怎么办?
这些问题和「Personal AI」这样的宏大概念没有什么关系,但系统最终是否可靠,恰恰取决于这些细节。
比如我最后给 Capability 设定了一条约束:
已经被引用的 Capability,即使 disabled,也不能随便删除。
发生不兼容修改时,API 应该拒绝。
这就是架构思想落进代码后的样子。
「能力是系统资产」这句话最终必须变成数据库关系、校验规则和 HTTP 错误。
另一个例子是 Resource。
一开始它只是一个抽象概念。
等 GitHub API 真正接进来以后,就必须决定 Git 文件、目录、Markdown 和数据库记录之间如何建立稳定引用。
做到这些地方,我越来越能感觉到一件事情:
设计一个系统的时候,图可以画得很漂亮。
只有开始处理删除、失败、权限、引用和迁移,架构才真正开始接受检验。
Iris 已经走到了主动连接外部世界的前一步
到暂停之前,Iris 已经走过最早的纯概念阶段。
Worker 可以部署。
D1 有了结构化数据。
独立的 Memory Git Repo 已经接进来。
v0.2 也已经接近完成。
部署流程逐渐固定下来:
配置 wrangler.jsonc,设置变量和 GitHub Secret,执行远程 migration,部署 Worker,创建远程 API Token,再给本地 Agent 配置 Iris API 地址和 Token。
最终可以真正跑通:
text
Agent
↓
Iris API
↓
Structured State
↓
Git-backed Resources
做到这里,Iris 已经可以接收信息、保存信息、维护状态,再把这些状态重新提供给 Agent 使用。
接下来要补的,是反方向的链路。
Iris 不能一直等我主动去问它。
所以原计划中的下一步,是 Notification Adapter。
我不希望通知逻辑和某一个具体渠道绑定。Iris 应该产生统一的 Notification,再由 Adapter 决定最终通过什么方式送出去。
可能是 Telegram,也可能是邮件、Push、Conduit,或者以后别的渠道。
结构大概会变成:
text
Iris
↓
Notification
↓
Adapter
├── Telegram
├── Email
├── Push
└── ...
做到这里以后,我又开始考虑 Connect Gateway。
因为问题已经不只剩通知。
未来可能会有不同 Agent 访问 Iris,也可能有多个外部系统向 Iris 输入事件。Hermes 可以是入口,其他 Agent 也可以成为入口;通知渠道、执行器和外部服务同样需要连接。
如果继续往前做,一个 Gateway 很自然会出现:
text
Agents
│
│
External Apps ─ Connect Gateway ─ Notification Channels
│
│
Iris
│
State / Resources
Gateway 负责连接世界。
Iris 继续负责维护状态。
Agent 负责推理。
Adapter 处理具体协议和渠道差异。
做到这个阶段,Iris 已经开始从一个 API 服务走向一个真正能够长期运行、主动感知和主动联系用户的个人系统。
也正是在这个位置,我决定暂停。
问题从「怎么实现」变成了「还需不需要自己实现」
Iris 开始时,我面对的问题是:
我要怎么做一个长期存在的 Personal AI?
所以我要自己解决状态、Memory、Agent、调度、通知、权限、Git、API。
后来甚至已经走到了 Notification Adapter 和 Connect Gateway。
继续做下去,我已经大概知道这些东西应该怎样组合。
真正让我停下来的,是另一个问题:
这些基础设施以后还需要由我自己维护吗?
如果未来的平台能够提供 Persistent Agent,让一个 Agent 长期存在;如果 Personal Context 可以稳定保存个人状态;如果 Connected Apps、Scheduler、Notification 和 Tool Calling 都逐渐成为平台原生能力,那么 Iris 很大一部分代码其实属于基础设施。
甚至 Connect Gateway 本身所要解决的问题,也很可能逐渐成为 AI 平台的标准能力。
我自己做 Iris,是因为我需要一个私人 AI。
维护一套 Auth、数据库、Worker、Agent Runtime、Scheduler、Notification Adapter、Gateway、Memory 和 Git Integration,并不是我的真实目标。
如果有一天现成平台已经能够完整满足这个需求,继续维护 Iris 就失去了意义。
这对我来说是整个项目最后一次,也是最重要的一次范围控制。
Controlled 不应该只约束一个函数该不该写。
它也应该约束一个项目该不该继续。
软件本身也可能成为问题
独立开发很容易出现一种惯性。
一个东西已经写了很多代码,架构也想清楚了,继续做下去似乎很自然。
尤其是 Iris。
它已经不只是一个随手实验。我在里面投入了很多关于 Personal AI、Agent、State 和 Capability 的思考,而且实际开发已经推进到了相当靠后的位置。
这反而让停止变得更难。
但我最后还是觉得,软件存在的意义是解决问题。
我想要的是一个真正理解我的长期 AI。
如果未来 OpenAI 或其他平台提供的 Persistent Agent 可以做到这件事,我直接使用它就可以了。
没有必要为了证明自己设计过一套更完整的架构,继续维护一整套基础设施。
一个原本用来减少认知负担的系统,如果以后每天都需要我维护数据库、部署 Worker、处理 API 兼容、Notification Adapter、Gateway 和 Agent Runtime,它自己就会成为新的认知负担。
做到这里,停下比继续加功能更符合 Iris 自己的设计原则。
所以我决定开源
暂停以后,我没有准备把 Iris 删除。
我会把现有代码整理好,把部署和运行所必需的内容补齐,让别人能够真正部署起来。
代码在这里:github.com/webszy/iris...
README 会说明环境变量、D1 migration、Worker 部署、Token 创建、Memory Repo 以及本地 Skill 的配置。
除此之外,不再继续扩展功能。
它的状态会更接近:
text
Paused
Reference Implementation
我希望它作为一次架构实验留下来。
因为回头看,Iris 已经形成了一套相对完整的 Personal AI 思路:
text
Structured Personal State
+
Replaceable Agent
+
Controlled Execution
+
Persistent Resources
+
Deterministic Capabilities
其中有些判断即使 Iris 永远不再继续开发,我现在依然认同。
Personal AI 需要长期维护结构化状态。
Agent 应该可以替换。
数据不应该属于某一个模型。
确定性的行为应该逐渐沉淀为 API 或 Capability。
真正存在不确定性的部分再交给 Agent。
思考可以自由,执行需要控制。
系统甚至可以观察自己并提出进化建议,但最后的执行边界仍然由人决定。
这些东西比 Iris 当前仓库里有多少个接口重要得多。
最后
就在系统开始越来越像我最初设想的样子时,我又回到了最开始那个非常简单的问题:
我到底想解决什么?
答案依然没有变。
我想要一个长期了解我、维护我的状态、在需要的时候提醒我的私人 AI。
至于这个东西最后是不是由我写的,其实没那么重要。
如果 Iris 必须存在,它可以继续存在。
如果未来的平台已经能够承担这些工作,Iris 也完全可以结束。
所以我不太愿意把这次暂停理解成一次失败。
它更像一次已经完成任务的实验。
我原本试图设计一个 Personal AI,最后反而借着这个项目把 Personal AI 拆开看了一遍:什么应该由模型负责,什么应该留在系统里,什么需要确定性,什么可以交给概率,什么可以自动执行,以及哪些决定必须留在人手里。
代码暂停了。
这些判断留下来了。
对我来说,这已经足够。