更新:2026-07-27
每次让 AI 帮忙改稿,我们真正担心的往往不是“它会不会写”,而是另外几件事:
- 它会不会编造我没有说过的经历?
- 它改完以后,我还能不能找回原文?
- 我拒绝过的改法,它会不会下次又来一遍?
- 它越来越像我以后,会不会反过来替我做决定?
这篇文章沿着“解决一个写作问题,又撞上下一个工程问题”的主线,聊聊一个普通的选区润色功能,为什么最后会演进成个人写作分身。
你不需要了解这个项目,也不用熟悉数据库、任务队列或 Agent 框架。文中出现技术名词时,我会先说它解决什么问题,再说它叫什么。
阅读时不用背表名。可以先记住一个简单比喻:
- Writing Persona 像一个长期合作、了解你的写作搭档;
- 写作预设像“这次想写成什么样”;
- 编辑预设像“这次准备怎么改”;
- Suggestion 像一张修改建议单,作者签字接受后才会真正改稿。
0. 先把答案放在门口
问:这里说的个人写作分身,究竟是不是 Agent?
答:产品形态上是;执行机制上,它仍是一套受约束的显式工作流。
它不是那种可以自己挑工具、自己反复行动、最后直接替你发文章的“万能 Agent”。它更像坐在编辑器旁边的写作搭档:能参考作者认可的历史文章,也能调用风格、修订偏好和个人事实,但最后交出来的仍是一份候选修改。正文怎么变,决定权还在作者手里。
当前这套系统已经能做到:
- 从作者认可的文章中生成写作分身;
- 分开保存写作风格、修订偏好和有证据的个人事实;
- 在“写作分身、写作预设、编辑预设”之间选择一种工作方式;
- 记住同一篇文章里的有限对话上下文;
- 修改选区、当前区块或整篇文章;
- 自动寻找相关参考文章和个人记忆;
- 把模型输出变成一份可预览、可接受、可拒绝的修改建议;
- 保存文章版本,并支持比较、恢复和冲突保护;
- 防止模型随意改动图片、表格、代码等复杂内容;
- 分开管理不同 AI 功能的并发、额度和 Token 用量;
- 自动保存工作稿,但只在合适的时机形成正式历史版本。
它目前还不是:
- 真正工作的通用 Writing Agent Orchestrator;
- Personal Mind;
- 独立 Review Agent;
- 通用 Tool Registry 和自主工具循环;
- 向量数据库或语义向量召回;
- AI 自动发布;
- 多节点分布式 Worker。
一句话总结:
当前个人写作分身不是“把编辑器交给模型”,而是“让模型在一套可追溯、可拒绝、可恢复的系统里递交修改建议”。
1. 写作分身、风格、学习和记忆到底是什么关系?
问:写作分身是不是换了名字的风格画像?
答:不是。风格画像只是写作分身的一项能力。
当前领域关系是:
三项能力平行存在:
- Style 回答“这个分身通常怎么写”;
- Learning 回答“这个分身对助手修改有哪些稳定偏好”;
- Memory 回答“这个分身可以使用哪些有来源证据的个人事实”。
Writing Persona Version 不混合三者,只固定一组可复现的组件版本。
完整配置包含 Style、Learning 和 Memory。每个分身版本必须有 Style;关闭 Learning 或 Memory 后,对应能力可以不启用。
问:那编辑器里的“写作风格”和“编辑预设”又是什么?
答:它们都是比 Persona 更轻的快捷方式,但解决的问题不一样。
编辑器现在有四种用法:
- 选择 Writing Persona:相当于说“请按这个长期分身来帮我”,系统会固定 Style、Learning、Memory,并自动找参考文章;
- 选择写作风格:相当于说“这次请写成技术教程、新闻特写或清晰简洁的风格”;
- 选择编辑预设:相当于说“别重新代写,按这套编辑规则把原文改得更清楚”;
- 什么都不选:只执行输入框里这一次的要求。
这三类个性化选项一次只能选一个。原因很好理解:一边要求“像我的分身”,一边又要求“完全按另一套写法”,系统很难判断到底该听谁的。
当前内置的编辑预设叫“六条文章强化规则”。它强调删掉废话、使用更有力的动词、明确动作主体、减少没必要的行话和套话,同时保留原文事实、观点和作者声音。它是“编辑方法”,不是新的作者人格。
客户端会在选择其中一项后清空并禁用另外两项;服务端也会再检查一遍。也就是说,即使绕过界面直接调 API,也不能把三套规则混在一次请求里。
问:为什么 Memory 和 Learning 不直接挂在风格画像下面?
答:因为它们含义不同,更新节奏也不同。
- Style 常在代表作或来源语料变化时更新;
- Learning 随建议接受 / 拒绝积累观察;
- Memory 随来源文章版本、事实冲突和证据资格变化而重建。
如果三者共用一条版本链,新增一段工作经历也会被记录成“文风变化”。这会混淆版本含义,也会增加排查成本。
2. 当前能力状态,先讲清再开麦
问:哪些能力是真落地,哪些只是架构插槽?
答:
问:既然还没有通用 Orchestrator,为什么仍然叫 Agent?
答:因为产品已经围绕“理解作者并协助写作”形成闭环,但执行层仍然是一条看得见、查得到的流程。
简单说,系统现在先把事实、权限、版本和失败边界管好,再考虑让它更自主。这样速度慢一点,但出了问题知道该去哪里查。
3. 整个演进过程,可以压成一张图吗?
问:从选区润色到写作分身,中间发生了什么?
答:
这张图看起来名词不少,主线其实只有一句话:先让 AI 能改,再让修改可追踪,然后让它逐步理解作者,最后再谈自主编排。
4. 第一阶段:我只想让 AI 改一下选中的文字
问:最简单的 AI 编辑是什么样?
答:选中文字,点击“改善表达”“精简”或“扩写”,模型返回一段纯文本建议。
系统仍保留一条轻量兼容路径。当完整的写作助手或版本能力关闭时,浮动工具栏可以退回直接流式生成。
优点是链路短、响应快。
问题是:它只能回答“这次生成了什么”,无法证明建议后来是否成为文章事实。
5. 第一次转向:正文不是字符串,而是 FlowDocument
问:为什么不能让模型直接返回 Markdown 或 HTML?
答:因为这套内容系统把 FlowDocument 作为正文的唯一可信格式。
{ "schemaVersion": 1, "blocks": [ { "id": "block-stable-id", "type": "paragraph", "richText": [{ "text": "正文" }] } ]}它不仅有段落,还包含标题、引用、列表、代码、公式、媒体、表格、details、columns、bookmark、file、embed 等结构。
如果模型只交回一大段自由文本,系统就不知道:
- 修改的是哪个稳定块;
- 链接、加粗和行内公式是否保留;
- 图片、表格和代码是否被吞了;
- 新增、删除、移动如何进入块级历史;
- 接受后该形成局部修订还是全文新版本。
FlowDocument 因此守住正文边界:模型可以返回内容,但系统必须先检查结构。
6. 第二次转向:模型生成的不是正文,而是候选操作
问:系统怎样描述一次 AI 修改?
答:使用一套前后端都认识的“候选修改操作”协议。
当前支持的核心操作包括:
| 操作 | 含义 |
|---|---|
| 替换选区 | 替换同一文本块内的选中文字 |
| 替换内容块 | 保留块的稳定身份,只替换内容 |
| 在块前插入 | 在目标块前增加内容块 |
| 在块后插入 | 在目标块后增加内容块 |
| 删除内容块 | 删除块,需要用户明确确认 |
| 替换全文 | 用合法的 FlowDocument 形成全文候选 |
建议还会固定它基于哪个文章版本、当时的正文指纹,以及具体修改操作。
问:为什么修改操作要放在前后端共享的纯逻辑层?
答:客户端要预览,服务端要真正应用,两端必须说同一种“修改语言”。
共享层只做纯逻辑,不访问数据库、DOM 或环境变量。
7. 第三个问题:AI 改完以后,历史在哪里?
问:只保存一份“当前正文”不够吗?
答:它适合保存当前文章,不适合解释写作历史。
当前版本底座包括:
| 数据 | 作用 |
|---|---|
| 完整文章版本 | 保存 v1.r0、v1.r1、v2.r0 这类阶段快照 |
| 版本内区块顺序 | 说明每个版本由哪些内容块组成、顺序如何 |
| 稳定块身份 | 让同一段内容跨版本仍然可以被识别 |
| 不可变块修订 | 保存某个块每一次确定下来的内容 |
| 块来源关系 | 记录修改、拆分、合并和恢复等来源 |
| 编辑事务 | 表示一次用户真正感知到的提交 |
| 编辑事件 | 记录事务中的新增、删除、修改和移动 |
当前正文保存工作稿,版本系统记录已经封存的阶段成果。
问:自动保存每 1.2 秒就创建一个版本吗?
答:不会。当前实现刻意把“别丢稿”和“形成历史版本”拆成两个节奏。
因此,当前工作稿可能暂时比最近一次 checkpoint 更新。服务端会明确标记“还有未封存变化”。页面异常退出后,下次打开会把已经保存但尚未封存的工作稿补成恢复 checkpoint。
这不是历史缺口,而是两个不同承诺:
- draft 承诺“刚写的内容别丢”;
- checkpoint 承诺“这是一个可比较、可恢复的阶段版本”。
如果每次按键都追加版本,版本噪声会淹没真正的阶段变化。
8. 谁真正拥有正文写入权?
问:AI 服务、版本服务和页面都碰正文,会不会出现多条写入路径?
答:正文写入权统一留在服务端,并按职责分成两条命令:
- “保存工作稿”处理人工编辑和文章属性;普通自动保存只更新工作稿,到达 checkpoint 才封存历史版本;
- “提交内容变更”处理已经结构化的修改操作,例如接受 AI 建议和恢复历史版本。
两条命令都在服务端清洗 FlowDocument、维护派生字段,并通过 SQLite 事务提交。模型、后台任务、会话和界面都不能直接写正文;客户端只提交草稿、操作或决定,服务端再把它们写成事实。
Agent 系统里,写入比生成风险更高。Prompt 中的提醒不能替代数据库事务。
9. 当前界面到底支持哪些修改范围?
问:聊天框里还需要用户手工选择“全文 / 小节 / 块”吗?
答:当前 UI 已把范围改成由入口自动决定。
| 入口 | 当前范围 | 个性化与会话 |
|---|---|---|
| 编辑页“AI · 版本”打开写作助手 | 全文 | 可选 Persona、写作预设或编辑预设,并恢复该文章最近会话 |
| 编辑器区块菜单打开写作助手 | 当前内容块 | 沿用同一选择和同一文章会话 |
| 浮动选区工具栏 | 同一文本块里的选中文字 | 沿用右侧栏当前 Persona、写作预设或编辑预设,也共用同一文章会话 |
| 小节修改 | 后端能力已经支持 | 当前主界面还没有开放入口 |
主聊天框默认修改全文,区块入口锁定当前块,选中文字后才显示选区改写。可以把它理解成:入口负责告诉系统“改哪里”,输入框和三类选项负责告诉系统“怎么改”。三个入口共享同一会话,也共享当前选择的 Persona、写作预设或编辑预设。
问:浮动工具栏还是旧路径吗?
答:分情况。
- 开启新版 Assistant 与 Versioning 后,工具栏会恢复该文章最近使用的 Session;没有可用会话时才新建。随后生成 Run、Task 和 pending Suggestion,接受后进入统一版本事务;
- 完整能力关闭时,才降级到旧的轻量流式路径。
因此,用户在选区工具栏里说“再短一点”,右侧会话会记录这次协作;选中的 Persona、写作预设或编辑预设也会沿用。旧路径只承担兼容职责。
10. 为什么需要 Session、Run、Task 和 Suggestion 四个对象?
问:这四个名字看起来像开会名单,分别负责什么?
答:
| 对象 | 回答的问题 |
|---|---|
| Assistant Session | 这篇文章里的哪段协作上下文要继续? |
| Assistant Message | 用户和助手分别说过什么? |
| AI Run | 这次业务运行用了什么模型、Prompt 和上下文? |
| AI Task | 谁执行、执行到第几次、能否取消和重试? |
| Suggestion | 哪组候选操作可以被接受、拒绝或判定冲突? |
Message 适合展示,Suggestion 适合做决定。助手消息可以说“候选已经生成”,真正能进入正文的是它关联的结构化修改操作。
问:Session 现在只是聊天记录,还是会真正进入下一轮生成?
答:会,但受明确预算约束,不会把全部聊天记录塞给模型。
每篇文章默认恢复最近更新的 Session,用户也可以新建或切换历史 Session。任务入队时,服务端最多扫描最近 24 条有效消息:
- 最近 8 条保留较完整内容,每条最多 1000 字符;
- 更早的已扫描消息压缩成限长摘要;
- 扫描范围之外只记录省略数量;
- 助手历史还会标记对应 Suggestion 是 accepted、rejected、conflicted 还是 pending。
当前 instruction、文章版本和选区始终优先。模型不能把已拒绝、已冲突或待决定的旧候选当成用户确认的事实。这样既能续接会话,也不会固化历史误解。
问:正文后来变了,历史消息旁边展示的是哪一版原文?
答:展示消息提交时的原文。
每条用户消息都会保存当时的文章版本,Suggestion 则保存修改范围。读取会话时,服务端从不可变版本重建当时的 FlowDocument,再按原范围解析选区、块、小节或全文。列表先返回限长预览,需要时再通过鉴权接口展开全文。
这能防止界面用当前正文解释历史建议,保证审计证据与当时的请求一致。
11. TaskRunner 已经是什么,又不是什么?
问:当前已经是分布式任务队列了吗?
答:不是。当前是 SQLite 持久任务表加进程内执行器。
它能:
- 持久化排队、运行、成功、失败和取消等状态;
- 按任务类型分发给对应处理器;
- 用进程内调度器启动任务;
- 取消当前进程里的任务;
- 指数退避重试;
- 服务启动时把遗留 running 恢复为 queued;
- 保存顺序 Run Event。
它不能:
- 提供多节点租约;
- 保证跨节点恰好一次执行;
- 代替独立消息队列;
- 在服务进程关闭后继续计算。
它是一辆可靠的小货车,不是跨国物流集团。对单实例个人内容系统而言,这已经够用。
11.1 小货车为什么换了发动机?
问:SQLite 不是一直都在吗,为什么还要专门治理运行时?
答:数据库文件相同,不代表连接语义相同。
旧兼容实现会让每个连接各自把整库载入内存,关闭时再写回完整文件。两个连接先后写入时,后关闭的连接可能覆盖先前结果。任务队列、文章保存和 AI 回调一旦并发,数据就可能丢失。
后来我把运行时统一到同一套原生 SQLite 连接:
它没有把数据库变成分布式系统,而是让所有连接共同操作一个 SQLite 文件,并遵守真实的文件锁。
并发测试会让一个写入者先持有事务锁,再让另一个写入者尝试提交。第二个写入者必须等待前一个完成,最后两笔数据都要保留下来。这里验证的不是“跑起来了”,而是并发时不会互相覆盖。
问:为什么数据库结构也要由服务端统一管理?
答:因为数据库结构是服务端事实,不是前端的副业。
客户端只表达用户操作,不应该顺便决定数据库长什么样。数据库结构、初始化数据和写入事务都由服务端负责;持续集成则从一份空数据库开始重建结构,再运行回归检查。这样可以尽早发现“旧环境能跑,新环境装不起来”的问题。
12. 为什么现在不只剩一个 Model Gateway?
问:每个业务直接调用模型供应商不行吗?
答:短期当然能跑,长期很容易变成三份几乎一样、又各有一点差别的请求代码。到时候换超时、重试或限额规则,就要到处改。
这套系统把模型边界拆成三层:
最底层的 Provider Adapter 不理解文章、阅读助手或写作分身。它只处理供应商协议和可复用的资源策略;业务语义留在上层。
写作侧的 Model Gateway 负责:
- 统一的文本生成和结构化生成入口;
- Prompt 与 Trace Context;
- JSON 对象提取;
- 一次通用结构化修复;
- 写作 usage 和错误映射。
阅读助手保留公开文章校验、访客身份、响应缓存和阅读额度,不再承担全项目的模型基础设施。
问:文章摘要、Slug、分类和标签的 AI 自动填写,算 Writing Agent 的一部分吗?
答:不算。它是一个刻意隔离的窄任务。
文章属性 AI 接收当前标题、FlowDocument 和已有分类标签,只返回符合字段规则的建议。它不读取写作会话、Writing Persona、Style、Learning 或 Memory,也不创建持久化写作任务和 Suggestion。
用户采用建议后,界面仍走普通的工作稿保存流程,不会让模型绕过内容服务直接写数据库。
它复用中性的供应商适配、流传输和资源策略,但持有独立配置与计数器。处理私有或受保护内容前,还必须经过单独授权。
共用基础设施,不等于共用人格和上下文。就像几家公司可以用同一家快递,但不会把客户资料混在一起。生成 Slug 不需要知道作者的 Personal Memory。
问:阅读和写作共享 API Key,为什么额度还要分开?
答:共享供应商账号不等于共享业务预算。
公开阅读请求可能突增,后台长文生成也可能一次消耗大量 token。若两者共用计数器,阅读流量会挤占作者的写作额度。
因此当前阅读、写作和文章属性 AI 都分别拥有自己的策略实例。以阅读与写作为例,两侧分别控制:
- 分钟 / 每日请求上限;
- 用户 / 访客并发;
- 总任务并发;
- 每日 token 预算;
- 独立错误码。
写作、阅读和文章属性 AI 优先读取各自的专用配置。为了兼容旧部署,缺失字段仍可暂时读取旧的通用配置,但系统会明确显示当前使用的是专用配置、兼容配置,还是两边混用,不让兼容路径悄悄存在。
即使底层复用同一组供应商凭据,运行时计数器仍然分开。
问:现在能无缝切换任意供应商吗?
答:还不能。边界已经中性化,但当前只完整实现了一种供应商的流式协议。换供应商仍需要增加对应适配器。
12.1 AI Token 花到哪里,现在看得见了吗?
问:系统以前只限制预算,现在能看到真实用量吗?
答:能。系统增加了一张脱敏的 Token 使用事件表,后台统计页也增加了“AI Token 使用”视图。
可以把它理解成三块独立电表:
| 统计类别 | 记录什么 |
|---|---|
| 前台解释 | 阅读助手真正请求模型完成的解释;缓存命中不重复记账,翻译暂不算在这类里 |
| 后台 AI 助手 | 写作会话中成功完成的内容建议和全文改写 |
| 后台属性填写 | 摘要、Slug、分类和标签等窄任务 |
每条事件只保存 Provider、模型、输入 Token、输出 Token、总 Token、类别和时间。它不保存 Prompt、文章正文、模型回答、访客身份或管理员身份。
后台长任务使用稳定的事件标识去重,所以任务重试不会重复记同一笔账。升级时,已有成功写作任务的用量也会补进统计表。
问:如果记账失败,AI 请求也要一起失败吗?
答:分情况。
- 版本化写作助手把成功 Run、Pending Suggestion 和 Token 用量放在同一个 SQLite 事务里,保证这几份记录不会互相对不上;
- 前台解释和后台属性填写在模型调用完成后使用“安全记账”路径。这里记账失败时,主请求可以继续,但系统会:
- 写一条脱敏告警;
- 增加当前进程的记账失败计数;
- 在统计摘要里返回记账健康状态;
- 在后台页面明确提示“统计可能漏记”。
也就是说,强一致的写作审计事实一起成功、一起回滚;独立入口也不会为了保住一张漂亮的统计图,反过来丢掉已经生成的结果。同时,系统不会假装统计仍然百分之百完整。
13. “模型结构化输出无效”后来怎样治理?
问:模型返回了 JSON,为什么全文候选仍可能失败?
答:JSON 能解析,不代表它符合 FlowDocument 协议。
当前修复分三层:
领域修复明确要求:
- 标题层级只能是 1~4;
- 新文本块只能是 paragraph、heading、quote;
- 未知标题块转 heading,其他未知文本块转 paragraph;
- 原文字不得丢失或改写;
- media、table、code、list、details、equation 等复杂块必须原样保留。
修复失败后,任务直接失败;系统不会把空文档当成成功结果。
14. Writing Persona 怎样生成新版本?
问:用户点“生成分身版本”后,底层发生什么?
答:生成任务会先固定来源版本,再顺序生成已经启用的组件,最后一次性激活。Style 始终生成;Learning 和 Memory 由能力开关决定。
关键边界:
- 来源必须仍是已发布文章;
- 私有 / 口令来源必须经过显式部署开关;
- 生成期间来源变化会返回冲突;
- 任一已启用组件失败,旧 Persona Version 继续生效;
- 所有已启用组件的候选都成功后才切换;
- 用户以后只选择 Persona,不手工拼组件 ID。
15. Style Profile 到底学了什么?
问:风格学习是不是微调模型?
答:不是。当前是生成可版本化、可追溯的结构化画像。
画像主要包含:
- 风格摘要;
- language、syntax、paragraph、structure、narrative、format 等维度;
- 带权重的风格规则;
- 代表性表达模式;
- 不确定项;
- 来源证据;
- learner / Prompt 版本。
来源会固定到文章不可变版本和内容指纹。文章后来改了,旧画像不会偷偷“穿越”到新正文。
问:为什么必须有 evidence?
答:因为“作者常用时间线结构”和“模型认为作者喜欢时间线”不是同一件事。
画像可以不完美,但必须保留结论来源。
15.1 写作预设和编辑预设为什么都要版本化?
问:Preset 不就是一段 Prompt 吗,直接覆盖字符串不就好了?
答:如果只关心下一次请求,覆盖字符串确实最省事。但只要想回答“上周那次 AI 到底用了哪套规则”,就必须保留旧版本。
系统最初准备了 10 套写作预设,并记录它们的来源信息,包括清晰简洁、自然口语、深度分析、技术教程和新闻特写。
后来,同一套预设模型增加了“预设类型”:
- 写作类:决定“写成什么样”;
- 编辑类:决定“怎样修改已有内容”。
系统还内置了一个编辑预设“六条文章强化规则”。它不是六个独立预设,而是一套包含六条规则的编辑方案。
管理员可以分别管理两类预设,包括新增、编辑、复制、排序、归档和恢复。底层可以共用存储结构,但业务含义必须分开。
这里的“编辑预设”是一种预设类型;而管理员“编辑某个预设”,指的是给它追加一个新版本。两件事别混在一起。
创建任务时,服务端会把预设类型、Preset ID、Preset Version ID 和版本号写入 AI Run 摘要与 Task payload。任务真正执行时,读的是当时固定的历史版本。之后即使管理员修改、排序、归档或恢复预设,已经排队的任务也不会突然换规则。
普通选择器只读取 ID、名称、说明和版本元数据,不读取 Prompt 正文。只有管理员接口可以读写 Prompt。这样浏览器不需要自己拼系统提示,历史 Run 也能查清楚到底用了哪一版规则。
问:写作预设或编辑预设会不会顺便使用 Personal Memory 和参考文章?
答:不会。只有 Persona 会自动加载 Style、Learning、Memory 和参考文章。两类 Preset 都只提供一套明确规则,不读取全局 Memory,也不会偷偷变成人格。
界面不再让普通用户额外选择风格强度。Persona 默认使用平衡策略;系统内部仍保留自由、平衡和严格三档规则预算,方便以后扩展。用户只需要在“分身、写作预设、编辑预设、都不选”之间做选择。
16. Personal Memory 为什么有两层?
问:既然 Memory 按 Persona 隔离,为什么还存在用户级 Memory Space?
答:为了复用昂贵的来源抽取,同时保持使用边界隔离。
当前分为:
- 用户级抽取层:按用户维护来源版本和 Memory Observation,可供多个 Persona 复用;
- Persona 级投影层:只用该 Persona 选择的来源,生成独立 Memory Snapshot。
抽取结果可以复用,真正生效的 Memory 必须按 Persona 隔离。
问:系统怎么保证“不能串台”不是一句团队口号?
答:服务层和数据库层同时设防。
服务层现在遵守三条硬规则:
- 写作请求没有选择 Persona,就不加载 Style、Learning 或 Memory;
- Memory 检索必须同时匹配用户、Persona 和被固定的 Snapshot;
- Learning 的读取、重建和规则查询都必须带 Persona,普通通用写作不会悄悄写一条全局偏好。
数据层还会拒绝创建“不属于任何 Persona”的 Memory 或 Learning 快照。旧的全局投影会退出生效状态,只保留必要的历史证据。
管理界面也不再提供“全局人格”入口。所有风格、学习和记忆能力都必须从某个明确的 Persona 进入。
17. Personal Memory 保存的是什么?
问:它是不是把整篇文章塞进一个向量库?
答:不是。
当前 Memory 会把来源文章版本转换为结构化 Observation,再投影为 Memory Item。条目保留:
- 稳定标识和事实类型;
- 事实陈述;
- 时间及精度;
- 置信度;
- 敏感度;
- 已支持、有冲突、受限制等状态;
- 对应的来源文章版本、内容位置和证据指纹;
- 补强、冲突、替代等关系;
- 可检索文本。
Memory 保存有出处的个人事实,既不复制全文,也不允许模型补写无证据的经历。
18. Memory 怎样自动进入一次写作?
问:用户写作时需要手工勾选 Memory 吗?
答:不需要。选择写作分身后,系统会自动检索和使用 Memory。
当前检索不是向量检索,主要使用:
- 全文检索(可用时);
- 词项匹配;
- 置信度;
- 证据数量;
- 条数和字符预算。
它还会排除仅由当前文章提供证据的记忆,避免循环引用。
19. Grounding 怎样阻止模型编经历?
问:Memory 已经提供给模型,为什么还要 Grounding?
答:因为模型看过证据,不代表它只会使用证据。
当前流程是:
第一人称身份、经历、时间、地点、数量和结果,必须由当前输入或检索到的 Memory 支持。
生成完成后,系统还会记录:
- 提供了多少条 Memory;
- 实际使用了多少条;
- 使用了哪些 memory key;
- Grounding 是否通过;
- Memory 来源文章。
界面默认只显示“自动参考 N 篇 · 使用 Memory N 条”,需要核对时再展开。审计信息不会打断写作,但始终可以查看。
20. Learning Snapshot 是怎样来的?
问:用户接受一次建议,系统会立刻修改人格吗?
答:不会。一次接受不足以证明稳定偏好。
Learning Projection 先把接受和拒绝保存为不可变 Observation,再在生成新 Persona Version 时重建。
当前激活门槛包括至少 3 次正向、至少 4 个来源 Observation、置信度不低于 0.7,并经过确定性评估。
问:人工编辑也会成为修订偏好吗?
答:人工编辑会进入文章版本和 manual_edit Observation。但 Learning Projection 生成规则时,主要使用与 Suggestion 关联的 accepted / rejected 决策。
“人工改了哪里”不能直接解释“为什么这样改”,因此系统不会据此推断稳定偏好。
21. 自动参考文章从哪里来?
问:当前还需要用户手工挑参考文章吗?
答:选择 Writing Persona 后,写作助手会自动选择;写作预设、编辑预设和无个性化模式都不会启用这条召回链。
服务端会把以下信息组合成查询:
- 当前文章标题、摘要、分类和标签;
- 写作指令;
- 目标文本;
- 邻近上下文。
然后从其他已发布文章中按分类、标签和关键词规则排序,最多选择 3 篇。
当前没有向量召回。这套算法简单、可解释,也便于测试。
22. 一次真实写作请求的完整链路
问:用户在聊天框输入“结合我的 Android 经历重写全文”后发生什么?
答:
本次 Run 会固定:
- 文章基线版本和正文指纹;
- Writing Persona Version;
- Style Profile Version;
- Learning Snapshot;
- Personal Memory Snapshot;
- 自动参考文章版本;
- Writing Context Snapshot;
- Task payload 中冻结的有界会话上下文;
- Prompt / provider / model 摘要。
这些固定信息能直接解释历史 Run,不必用最新 Persona 和当前正文反推当时的上下文。
选择写作预设后,系统会跳过 Persona、自动参考和 Personal Memory,只固定具体的 Writing Preset Version。
选择编辑预设也一样会跳过 Persona 上下文,但固定的是 Editing Preset Version。界面会在输入框为空时补上一句“按所选编辑预设编辑当前范围,并保留事实、观点和作者声音”,用户仍然可以继续修改这句话。
如果三个选项都没选,系统只使用当前 instruction 和会话上下文。
所以表面上有四种用法,底层最后仍然汇入同一条 Run、Task、校验、Suggestion 和人工接受流程。差别只在这次被冻结的上下文是什么。
23. 接受建议时发生什么?
问:点击接受只是前端把内容塞进编辑器吗?
答:不是。接受由服务端再次校验并创建新版本。
拒绝时,系统只更新 Suggestion 状态并写入 Learning Observation,不改正文。拒绝是有效反馈,不是运行失败。
24. 为什么版本分 v1.r2 和 v2.r0?
问:局部修改和全文改写为什么版本语义不同?
答:
- 局部人工修改、选区或块级建议,形成当前主版本的新 Revision;
- 全文替换候选被接受后创建新的主版本;
- 恢复历史会追加一个“恢复版本”,不会覆盖旧记录。
候选在接受前不创建正式版本,避免试写结果污染版本列表。
25. 旧建议怎样避免覆盖新正文?
问:模型生成期间用户继续修改,怎么办?
答:生成时固定基线,接受时再次检查。
并发保护包括:
| 保护线 | 作用 |
|---|---|
| 文章基线版本 | 当前版本是否仍是生成时那一版 |
| 正文指纹 | 当前物化正文是否发生变化 |
| 目标块修订 | 精确保护准备修改的内容块 |
| 防重复键 | 防止重复点击制造重复事务 |
任一关键基线过期,Suggestion 就会标记为“冲突”,不会自动“聪明合并”。
系统不会自动合并过期建议,避免掩盖事实冲突。
26. 全文改写怎样保护图片、表格和代码?
问:候选通过 FlowDocument 校验就安全了吗?
答:不够。结构合法不等于业务安全。
当前全文候选只允许模型自由重组文本内容。复杂块会比较:
- 数量;
- 稳定块 ID;
- 顺序;
- 稳定序列化内容。
若模型改变 media、table、code、list、callout、details、columns、bookmark、file、embed、equation 等复杂块,系统就拒绝候选。
服务端内部的 section 候选更严格:必须保留原块数量、顺序、ID 和 type,文本块只改 richText,复杂块原样返回。
27. 私有文章为什么需要单独开关?
问:管理员能看私有文章,不就能把它发给模型吗?
答:不能这样推断。
“有权在本站阅读”不等于“同意发送给外部模型供应商”。
当前规则:
- 来源文章必须已经发布;
- 公开来源默认可用;
- 私有或口令保护来源需要部署方明确允许发送给模型;
- Memory 使用私有来源还需要第二层独立授权;
- 服务端在任务开始时重新检查状态和可见性;
- 客户端选择不构成最终授权。
客户端选择不能替代服务端授权。
28. 功能开关之间有什么依赖?
问:为什么不做成一个“AI 总开关”?
答:因为“功能开关”和“数据授权”不是一回事。
写作分身有一个总开关,用来控制版本、风格、助手、学习和记忆等能力是否开放。写作预设和编辑预设虽然不是 Persona 的组成部分,但依赖同一套助手能力,也会跟随这条产品入口启停。
另外还有两类独立控制:
- 模型配置是否完整,决定系统能不能真正发起生成;
- 私有来源是否允许发送给外部模型,决定哪些数据可以离开本地系统。
后一类是数据授权,默认应该关闭,不能因为打开了“写作助手”就顺便打开。
为了兼容旧部署,专用模型配置缺失时可以暂时读取旧的通用配置,但后台必须明确提示配置来自哪里。兼容可以存在,不能隐身。
即使关闭所有 AI 能力,人工编辑、保存、发布和导出也应该继续工作。AI 是增强能力,不是内容系统的地基。
29. 当前总体架构应该怎么画?
问:怎样画一张不夸大现状的架构图?
答:
图中没有“万能 Agent 大脑”。现在负责“踩刹车”和“留记录”的,是领域服务、资源策略和数据库事务。
30. 这些层次分别在管什么?
| 层次 | 一句话职责 |
|---|---|
| 界面层 | 收集“改哪里、怎么改”,展示对话、候选和版本,但不直接决定数据库事实 |
| 写作分身 | 管理来源文章,以及 Style、Learning、Memory 的版本组合 |
| 两类预设 | 用轻量规则表达“写成什么样”或“怎样修改原文” |
| 会话与建议 | 续接有限上下文,把模型结果保存成等待用户决定的候选 |
| 内容与版本 | 保存工作稿,接受结构化修改,并创建可比较、可恢复的历史 |
| 上下文构造 | 选择目标范围、历史消息、参考文章和个人记忆 |
| 模型网关 | 负责 Prompt、结构化输出、修复和领域校验 |
| 资源策略 | 分别治理限流、并发和每日 Token 预算 |
| 运行与任务 | 保存一次业务运行,并支持取消、重试和重启恢复 |
| 数据基础 | 用统一正文协议、事务和不可变记录守住事实边界 |
31. 为什么现在还没有通用 Agent Loop?
问:能力已经这么多,为什么不上 LangGraph 或通用工具循环?
答:因为当前主要任务仍能用显式流程可靠完成。
这些流程分支有限,失败语义明确。通用 Agent Loop 会增加隐藏控制流,目前收益不足。
未来 Orchestrator 可以决定“下一步调用哪个稳定命令”,但不能:
- 绕过 FlowDocument;
- 绕过权限;
- 绕过版本基线;
- 自己接受 Suggestion;
- 自己恢复版本;
- 自己发布文章。
Agent 可以规划调用顺序,但不能扩大命令权限。
32. Personal Mind 为什么还没有进入当前架构?
问:有了 Personal Memory,为什么还需要 Personal Mind?
答:两者解决的问题不同。
- Memory 是有证据的事实层:做过什么、经历过什么、什么时候发生;
- Mind 更接近长期观点、价值判断、认知模型和当前立场。
这套架构已经能比较安全地使用个人事实,但尚未建立稳定的观点冲突、时效、反思和修订协议。过早把观点写成长期人格,会增加纠错难度。
因此,系统先把 Memory 做成有证据、可冲突、可撤回的事实层,再讨论 Mind。
33. 系统失败时怎样降级?
问:模型失败会影响普通编辑吗?
答:不会。AI Run / Task 失败,正文保持不变。
问:结构修复失败呢?
答:Run 失败,不保存可接受 Suggestion。
问:Grounding 两次都不过呢?
答:Run 失败,不允许候选进入接受阶段。
问:接受时版本冲突呢?
答:Suggestion 变成 conflicted,正文不变。
问:服务重启呢?
答:上次中断时仍在运行的任务会重新进入队列,并留下“服务重启后恢复”的事件记录。
问:任务入队后,管理员改了或归档了写作预设呢?
答:不管是写作预设还是编辑预设,任务都继续读取入队时固定的 Preset Version,不会切换到新 Prompt;历史版本即使不再生效,也仍可读。
问:写作 AI 还在使用旧的通用配置呢?
答:兼容回退仍能工作,但后台会明确提示当前正在使用兼容配置,提醒迁移到专用配置。这是“带提示的兼容”,不是永久默认方案。
问:历史消息找不到当时的 Task,或者引用关系坏了呢?
答:系统会明确返回“历史原文数据异常”,并写脱敏错误日志,不再安静地返回空内容。历史证据损坏属于完整性问题,不能伪装成“这条消息刚好没有原文”。
问:Token 记账失败呢?
答:前台解释和后台属性填写使用的安全记账路径会保留主请求结果,同时把统计健康状态标成“不完整”,并在统计页提示可能漏记。版本化写作助手则把 Run、Suggestion 和用量放在同一事务里。两种处理都不允许暗改正文,也不允许假装统计没问题。
问:人工工作稿已经自动保存,但还没来得及形成 checkpoint 就异常退出呢?
答:工作稿已经保存在当前正文里。下次打开时,系统发现“还有未封存变化”,就会把它补成恢复 checkpoint。
问:版本、当前指针或搜索索引写到一半失败呢?
答:SQLite 事务整体回滚。
这些处理遵循同一原则:可以回退的兼容路径要明确提示;涉及证据或数据完整性的问题要直接报错;不管哪一种,正文都不能暗改。
34. 如果 Agent 做错了,怎样排查?
问:最短排查链是什么?
答:
依次问:
- 谁接受了这条建议?
- 接受时基于哪个文章版本,正文指纹是什么?
- 结构化修改操作碰了哪些内容块?
- 生成时使用的是哪个分身版本、写作预设版本,还是编辑预设版本?
- 这一轮冻结了哪些最近消息,旧候选当时是接受、拒绝还是冲突?
- 用户消息记录的文章版本与修改范围,能否重建出当时原文?
- 提供和实际使用了哪些 Memory?
- 自动参考了哪些文章版本?
- 结构化修复或 Grounding 是否发生过?
- Run 是否重试、取消或从重启中恢复?
- 这次模型调用记录了多少 Token;统计健康状态是否提示过漏记?
排查时其实就是顺着“文章版本 → 修改事务 → 建议 → 会话 → Run → Task → 当时的上下文”一路往回找。把“AI 为什么这样写”拆成这些可查询的事实,问题就不再是一团猜测。
35. 常见现场质疑怎么回答?
问:这不就是工作流,不是 Agent 吗?
答:
当前执行层主要是显式工作流。系统先把上下文、模型、任务、建议、版本和权限做成可独立验证的能力,再让未来 Orchestrator 编排它们。仅有自由文本接口,还不足以构成 Agent。
问:为什么不用大模型一次完成所有事情?
答:一次大 Prompt 无法替代来源版本、隐私策略、任务恢复、输出校验、建议决策、并发冲突和数据库事务。它只是把系统复杂度塞进一段更难调试的文字里。
问:为什么不用 Git 保存文章版本?
答:产品需要领域版本:块身份、Run、Message、Suggestion、接受者、幂等键和在线事务。Git 擅长文件历史,不负责理解“这条建议为什么形成 v2.r0”。
问:SQLite 撑得住吗?
答:在单实例、个人内容系统和受控并发下,可以。
运行时统一使用 SQLite 原生连接,并启用 WAL、外键和写锁等待。并发测试覆盖两个真实写入者争抢事务锁并成功提交。数据库结构和运行时也都归服务端所有。
这不表示 SQLite 永远适用。出现持续锁竞争、长事务阻塞、数据库体量与备份窗口失控、多节点 Worker 租约需求,或写入吞吐受限于单机磁盘时,就应评估升级。关键不在表的数量,而在写入模型是否匹配。
问:这些边界怎样持续验证?
答:持续集成会先创建一份临时空数据库,完整重建结构,然后运行:
- 架构与共享层检查;
- 客户端类型和服务端健康检查;
- 旧来源、安全与隐私检查;
- 写作 Agent、阅读助手和搜索回归。
最后再使用临时数据库和独立临时服务执行一次真实生产构建。
CI 当然不能证明代码永远正确。它更像出门前的检查清单:不能保证路上绝不出事,但能持续拦住那些已经知道、也有办法自动检查的问题。
36. 下一步最合理的演进顺序
问:现在最该做多 Agent,还是补现有闭环?
答:更稳妥的顺序是:
数据库运行时、AI 资源边界、Persona 隔离、两类 Preset 版本固定、Token 统计和工作稿 checkpoint 都已经有了。下一步更值得做的,不是马上堆更多“Agent”名字,而是继续缩小每个模块的职责,并把“用户接受后又手工改了什么”纳入 Learning 语义。
当前的准备上下文、执行生成、持久化候选和处理决策仍然比较集中。继续拆分这些边界,比急着换一套 Agent 框架更有价值。
写作分身的长期价值来自“越来越理解作者”,不是增加工具调用次数;工程稳定性则来自不断收窄边界。
37. 十分钟架构演讲怎么讲?
问:只有十分钟,主线怎么安排?
答:可以分五段。
第一分钟,讲产品:
这是住在博客编辑器里的写作搭档。想换一种写法,就选写作预设;想在保留原文声音的前提下认真改稿,就选编辑预设;想让它长期“像我一样写”,再选写作分身。无论走哪条路,模型交出来的都只是候选。
第二到三分钟,讲第一个转折:
选区 AI 只需“文字进、文字出”。一旦要回答谁改了什么、能否恢复、能否学习,系统就必须引入 FlowDocument 操作和不可变版本。人工自动保存还要与历史 checkpoint 分开:既不丢稿,也不制造逐按键版本。
第四到六分钟,讲核心链路:
写作请求先恢复文章会话,再固定 Persona Version、Writing Preset Version 或 Editing Preset Version。经过 Run / Task、结构校验和必要的 Grounding 后,系统保存 pending Suggestion。用户接受时,服务端才在一个事务里更新正文、当前版本和索引。
第七到八分钟,讲个性化:
Persona 下的 Style、Learning、Memory 平行版本化。Memory 抽取可以复用,但真正生效的 Snapshot 按 Persona 隔离。写作预设和编辑预设都只是轻量、明确的规则,不会借用某个全局人格。
最后两分钟,讲边界:
当前没有通用自主 Agent。模型传输可以共享,但阅读、写作和文章属性 AI 的上下文与额度分开,Token 用量也按三类入口统计。SQLite 用 WAL 处理单机并发写入,迁移和 CI 从服务端事实开始。未来 Orchestrator 只编排稳定命令,不拥有正文、权限和发布权。
最后收束:
个人写作分身真正的难题,不是让模型多写几段话,而是让每一次 AI 参与都可解释、可拒绝、可恢复,并且最终仍然属于作者。
38. 常见追问速答
问:AI 会自动发布文章吗?
答:不会。
问:AI 会直接覆盖正文吗?
答:不会。先生成 pending Suggestion,接受后才进入版本事务。
问:聊天框默认改哪里?
答:默认全文;从编辑器区块入口打开时自动块级。
问:选区 AI 走什么路径?
答:完整能力开启时,复用该文章当前的 Session,以及当前选择的 Persona、写作预设或编辑预设,再进入 Run + Task + Suggestion;关闭时降级到旧的轻量流式路径。
问:聊天会记得前面说过什么吗?
答:会,但只携带有界上下文。最近 8 条较完整保留,更早记录压缩;当前指令、正文版本和选区优先,未接受的旧候选不算事实。
问:能看到当时送给助手的原文吗?
答:能。服务端从消息记录的文章版本重建历史 FlowDocument,再按当时的修改范围返回预览或完整原文。
问:写作分身、写作风格和编辑预设可以一起选吗?
答:不可以,三者只能选一个。Persona 提供 Style、Learning、Memory 和自动参考;写作预设决定写成什么样;编辑预设决定怎样修改原文。也可以三个都不选。
问:写作预设或编辑预设修改后,会改变已经入队的任务吗?
答:不会。Run 和 Task 固定具体 Preset Version,旧任务继续使用旧 Prompt。
问:小节修改已经有 UI 吗?
答:服务端协议支持,当前主 UI 没有开放入口。
问:参考文章需要手选吗?
答:选择 Persona 时不需要,服务端自动召回最多 3 篇相关已发布文章;只选写作预设、编辑预设或都不选时不会自动召回。
问:Memory 需要手工维护吗?
答:不需要逐条维护。用户只选择 Persona 的已发布来源文章;提取、投影、检索和使用自动进行。
问:不选择写作分身时,会不会偷偷使用某个全局 Memory?
答:不会。不选择 Persona 时,Style、Learning 和 Memory 都为空;单独选择写作预设或编辑预设时,只增加那一版 Preset 的规则。系统没有“全局人格”兜底。
问:怎么知道用了几条 Memory?
答:助手消息会显示使用数量,展开可查看来源解释。
问:风格学习是微调吗?
答:不是,是有版本、来源和证据的结构化画像。
问:Learning 会在一次接受后立刻改变当前分身吗?
答:不会。Observation 先积累,生成新 Persona Version 时才重建和激活 Snapshot。
问:自动保存会不会产生海量版本?
答:不会。约 1.2 秒的 draft 保存只更新工作稿;空闲、时长上限或 AI / 恢复 / 发布 / 离开等边界才创建 checkpoint。
问:现在有向量数据库吗?
答:没有。参考文章使用分类、标签和关键词规则;Memory 使用全文检索和关键词排序。
问:现在有 Personal Mind 吗?
答:没有。
问:现在有通用多 Agent 吗?
答:没有。当前是显式领域服务和持久任务工作流。
问:阅读助手会抢光写作助手额度吗?
答:不会共用运行时额度。两者可以回退使用同一组供应商凭据,但频率、并发和每日 token 预算分别计算。
问:现在能看到 AI 实际用了多少 Token 吗?
答:能。后台统计页按前台解释、后台 AI 助手和后台属性填写三类展示;只记录用量元数据,不保存 Prompt、正文或模型回答。
问:写作 AI 还在回退使用旧配置,管理员能知道吗?
答:能。管理页会明确提示当前正在使用兼容配置或混合配置,并建议迁移到专用配置。
问:文章属性 AI 会读取我的写作分身吗?
答:不会。摘要、Slug、分类和标签建议使用独立配置与额度,不读取 Session、Persona、Style、Learning 或 Memory。
问:SQLite 还会退回“整库加载、整库写回”的兼容方式吗?
答:不会。当前统一使用原生 SQLite 连接,并启用 WAL 和写锁等待。
问:模型能修改图片和表格吗?
答:当前自动改写主要面向文本块,复杂块必须原样保留。
39. 术语表
40. 最后的架构判断
问:这套架构最值得保留的是什么?
答:不是某个模型名,也不是某一版 Prompt,而是这些边界:
- FlowDocument 是正文唯一主协议;
- 客户端不直接写 SQLite,也不持有模型密钥;
- 模型只生成候选,不拥有正文写入权;
- 人工 draft 保存只保护工作进度,checkpoint 才形成不可变历史;异常退出的未封存工作稿可被识别和恢复;
- AI Suggestion 只有用户接受后才会变成结构化内容操作;
- 版本、块修订、事件、当前版本指针和索引保持事务一致;
- Persona、写作预设和编辑预设三者互斥;前者固定组件清单,后两者固定各自不可变 Prompt 版本;
- Persona 下 Style、Learning、Memory 平行且独立版本化;
- Memory 抽取可以复用,Persona Snapshot 必须隔离;
- 没有 Persona 就没有 Persona Style Profile、Learning 和 Memory 上下文,不存在全局人格兜底;
- 自动参考和 Memory 使用都固定到一次 Run;
- 文章三类入口共享 Session,以及当前选择的 Persona、写作预设或编辑预设;会话上下文有界,历史原文从当时的文章版本重建;
- 结构化输出、复杂块和个人事实分别有校验护栏;
- 阅读、写作与文章属性 AI 只共享中性 Provider 基元,不共享业务上下文或运行时额度;
- AI 配置兼容回退必须暴露来源;历史原文等完整性问题必须显式失败,不能安静吞掉;
- AI Token 使用按前台解释、后台助手和后台属性填写分开记录;统计只保存用量元数据,记账失败必须暴露健康状态;
- SQLite 文件连接统一使用原生连接与 WAL,不回退到整库覆盖写回;
- 数据库结构和初始化数据归服务端,客户端不拥有数据库结构定义;
- 持续集成从空数据库重建开始,再验证真实生产构建;
- Run 是业务事实,Task 是执行事实;
- 原始版本和行为事实不可覆盖,投影可以重算;
- 未来 Orchestrator 只编排稳定能力,不成为第二套内容系统。
只要这些边界不丢,模型可以换,后台任务系统可以升级,检索可以演进,Learning 算法也可以重算。
这就是这套架构的核心选择:
先让系统能对 AI 的每一次参与说清楚、兜得住,再慢慢给它更多能力。