个人写作分身 Agent 架构演进问答

Cursor Blinking|AI 生成内容架构|字数 17,113|阅读时长 ≈ 43 分钟

更新: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. 写作分身、风格、学习和记忆到底是什么关系?

问:写作分身是不是换了名字的风格画像?

答:不是。风格画像只是写作分身的一项能力。

当前领域关系是:

Codemermaid
图表将在进入视口后显示

三项能力平行存在:

  • Style 回答“这个分身通常怎么写”;
  • Learning 回答“这个分身对助手修改有哪些稳定偏好”;
  • Memory 回答“这个分身可以使用哪些有来源证据的个人事实”。

Writing Persona Version 不混合三者,只固定一组可复现的组件版本。

完整配置包含 Style、Learning 和 Memory。每个分身版本必须有 Style;关闭 Learning 或 Memory 后,对应能力可以不启用。

问:那编辑器里的“写作风格”和“编辑预设”又是什么?

答:它们都是比 Persona 更轻的快捷方式,但解决的问题不一样。

编辑器现在有四种用法:

  1. 选择 Writing Persona:相当于说“请按这个长期分身来帮我”,系统会固定 Style、Learning、Memory,并自动找参考文章;
  2. 选择写作风格:相当于说“这次请写成技术教程、新闻特写或清晰简洁的风格”;
  3. 选择编辑预设:相当于说“别重新代写,按这套编辑规则把原文改得更清楚”;
  4. 什么都不选:只执行输入框里这一次的要求。

这三类个性化选项一次只能选一个。原因很好理解:一边要求“像我的分身”,一边又要求“完全按另一套写法”,系统很难判断到底该听谁的。

当前内置的编辑预设叫“六条文章强化规则”。它强调删掉废话、使用更有力的动词、明确动作主体、减少没必要的行话和套话,同时保留原文事实、观点和作者声音。它是“编辑方法”,不是新的作者人格。

Codemermaid
图表将在进入视口后显示

客户端会在选择其中一项后清空并禁用另外两项;服务端也会再检查一遍。也就是说,即使绕过界面直接调 API,也不能把三套规则混在一次请求里。

问:为什么 Memory 和 Learning 不直接挂在风格画像下面?

答:因为它们含义不同,更新节奏也不同。

  • Style 常在代表作或来源语料变化时更新;
  • Learning 随建议接受 / 拒绝积累观察;
  • Memory 随来源文章版本、事实冲突和证据资格变化而重建。

如果三者共用一条版本链,新增一段工作经历也会被记录成“文风变化”。这会混淆版本含义,也会增加排查成本。

2. 当前能力状态,先讲清再开麦

问:哪些能力是真落地,哪些只是架构插槽?

答:

表格将在进入视口后显示3 columns / 23 rows

问:既然还没有通用 Orchestrator,为什么仍然叫 Agent?

答:因为产品已经围绕“理解作者并协助写作”形成闭环,但执行层仍然是一条看得见、查得到的流程。

简单说,系统现在先把事实、权限、版本和失败边界管好,再考虑让它更自主。这样速度慢一点,但出了问题知道该去哪里查。

3. 整个演进过程,可以压成一张图吗?

问:从选区润色到写作分身,中间发生了什么?

答:

Codemermaid
图表将在进入视口后显示

这张图看起来名词不少,主线其实只有一句话:先让 AI 能改,再让修改可追踪,然后让它逐步理解作者,最后再谈自主编排。

4. 第一阶段:我只想让 AI 改一下选中的文字

问:最简单的 AI 编辑是什么样?

答:选中文字,点击“改善表达”“精简”或“扩写”,模型返回一段纯文本建议。

系统仍保留一条轻量兼容路径。当完整的写作助手或版本能力关闭时,浮动工具栏可以退回直接流式生成。

Codemermaid
图表将在进入视口后显示

优点是链路短、响应快。

问题是:它只能回答“这次生成了什么”,无法证明建议后来是否成为文章事实。

5. 第一次转向:正文不是字符串,而是 FlowDocument

问:为什么不能让模型直接返回 Markdown 或 HTML?

答:因为这套内容系统把 FlowDocument 作为正文的唯一可信格式。

Codejson
{  "schemaVersion": 1,  "blocks": [    {      "id": "block-stable-id",      "type": "paragraph",      "richText": [{ "text": "正文" }]    }  ]}

它不仅有段落,还包含标题、引用、列表、代码、公式、媒体、表格、details、columns、bookmark、file、embed 等结构。

如果模型只交回一大段自由文本,系统就不知道:

  • 修改的是哪个稳定块;
  • 链接、加粗和行内公式是否保留;
  • 图片、表格和代码是否被吞了;
  • 新增、删除、移动如何进入块级历史;
  • 接受后该形成局部修订还是全文新版本。

FlowDocument 因此守住正文边界:模型可以返回内容,但系统必须先检查结构。

6. 第二次转向:模型生成的不是正文,而是候选操作

问:系统怎样描述一次 AI 修改?

答:使用一套前后端都认识的“候选修改操作”协议。

当前支持的核心操作包括:

操作含义
替换选区替换同一文本块内的选中文字
替换内容块保留块的稳定身份,只替换内容
在块前插入在目标块前增加内容块
在块后插入在目标块后增加内容块
删除内容块删除块,需要用户明确确认
替换全文用合法的 FlowDocument 形成全文候选

建议还会固定它基于哪个文章版本、当时的正文指纹,以及具体修改操作。

Codemermaid
图表将在进入视口后显示

问:为什么修改操作要放在前后端共享的纯逻辑层?

答:客户端要预览,服务端要真正应用,两端必须说同一种“修改语言”。

共享层只做纯逻辑,不访问数据库、DOM 或环境变量。

7. 第三个问题:AI 改完以后,历史在哪里?

问:只保存一份“当前正文”不够吗?

答:它适合保存当前文章,不适合解释写作历史。

当前版本底座包括:

数据作用
完整文章版本保存 v1.r0、v1.r1、v2.r0 这类阶段快照
版本内区块顺序说明每个版本由哪些内容块组成、顺序如何
稳定块身份让同一段内容跨版本仍然可以被识别
不可变块修订保存某个块每一次确定下来的内容
块来源关系记录修改、拆分、合并和恢复等来源
编辑事务表示一次用户真正感知到的提交
编辑事件记录事务中的新增、删除、修改和移动
Codemermaid
图表将在进入视口后显示

当前正文保存工作稿,版本系统记录已经封存的阶段成果。

问:自动保存每 1.2 秒就创建一个版本吗?

答:不会。当前实现刻意把“别丢稿”和“形成历史版本”拆成两个节奏。

Codemermaid
图表将在进入视口后显示

因此,当前工作稿可能暂时比最近一次 checkpoint 更新。服务端会明确标记“还有未封存变化”。页面异常退出后,下次打开会把已经保存但尚未封存的工作稿补成恢复 checkpoint。

这不是历史缺口,而是两个不同承诺:

  • draft 承诺“刚写的内容别丢”;
  • checkpoint 承诺“这是一个可比较、可恢复的阶段版本”。

如果每次按键都追加版本,版本噪声会淹没真正的阶段变化。

8. 谁真正拥有正文写入权?

问:AI 服务、版本服务和页面都碰正文,会不会出现多条写入路径?

答:正文写入权统一留在服务端,并按职责分成两条命令:

  • “保存工作稿”处理人工编辑和文章属性;普通自动保存只更新工作稿,到达 checkpoint 才封存历史版本;
  • “提交内容变更”处理已经结构化的修改操作,例如接受 AI 建议和恢复历史版本。
Codemermaid
图表将在进入视口后显示

两条命令都在服务端清洗 FlowDocument、维护派生字段,并通过 SQLite 事务提交。模型、后台任务、会话和界面都不能直接写正文;客户端只提交草稿、操作或决定,服务端再把它们写成事实。

Agent 系统里,写入比生成风险更高。Prompt 中的提醒不能替代数据库事务。

9. 当前界面到底支持哪些修改范围?

问:聊天框里还需要用户手工选择“全文 / 小节 / 块”吗?

答:当前 UI 已把范围改成由入口自动决定。

入口当前范围个性化与会话
编辑页“AI · 版本”打开写作助手全文可选 Persona、写作预设或编辑预设,并恢复该文章最近会话
编辑器区块菜单打开写作助手当前内容块沿用同一选择和同一文章会话
浮动选区工具栏同一文本块里的选中文字沿用右侧栏当前 Persona、写作预设或编辑预设,也共用同一文章会话
小节修改后端能力已经支持当前主界面还没有开放入口

主聊天框默认修改全文,区块入口锁定当前块,选中文字后才显示选区改写。可以把它理解成:入口负责告诉系统“改哪里”,输入框和三类选项负责告诉系统“怎么改”。三个入口共享同一会话,也共享当前选择的 Persona、写作预设或编辑预设。

Codemermaid
图表将在进入视口后显示

问:浮动工具栏还是旧路径吗?

答:分情况。

  • 开启新版 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,再按原范围解析选区、块、小节或全文。列表先返回限长预览,需要时再通过鉴权接口展开全文。

Codemermaid
图表将在进入视口后显示

这能防止界面用当前正文解释历史建议,保证审计证据与当时的请求一致。

11. TaskRunner 已经是什么,又不是什么?

问:当前已经是分布式任务队列了吗?

答:不是。当前是 SQLite 持久任务表加进程内执行器。

它能:

  • 持久化排队、运行、成功、失败和取消等状态;
  • 按任务类型分发给对应处理器;
  • 用进程内调度器启动任务;
  • 取消当前进程里的任务;
  • 指数退避重试;
  • 服务启动时把遗留 running 恢复为 queued;
  • 保存顺序 Run Event。

它不能:

  • 提供多节点租约;
  • 保证跨节点恰好一次执行;
  • 代替独立消息队列;
  • 在服务进程关闭后继续计算。
Codemermaid
图表将在进入视口后显示

它是一辆可靠的小货车,不是跨国物流集团。对单实例个人内容系统而言,这已经够用。

11.1 小货车为什么换了发动机?

问:SQLite 不是一直都在吗,为什么还要专门治理运行时?

答:数据库文件相同,不代表连接语义相同。

旧兼容实现会让每个连接各自把整库载入内存,关闭时再写回完整文件。两个连接先后写入时,后关闭的连接可能覆盖先前结果。任务队列、文章保存和 AI 回调一旦并发,数据就可能丢失。

后来我把运行时统一到同一套原生 SQLite 连接:

Codemermaid
图表将在进入视口后显示

它没有把数据库变成分布式系统,而是让所有连接共同操作一个 SQLite 文件,并遵守真实的文件锁。

并发测试会让一个写入者先持有事务锁,再让另一个写入者尝试提交。第二个写入者必须等待前一个完成,最后两笔数据都要保留下来。这里验证的不是“跑起来了”,而是并发时不会互相覆盖。

问:为什么数据库结构也要由服务端统一管理?

答:因为数据库结构是服务端事实,不是前端的副业。

客户端只表达用户操作,不应该顺便决定数据库长什么样。数据库结构、初始化数据和写入事务都由服务端负责;持续集成则从一份空数据库开始重建结构,再运行回归检查。这样可以尽早发现“旧环境能跑,新环境装不起来”的问题。

12. 为什么现在不只剩一个 Model Gateway?

问:每个业务直接调用模型供应商不行吗?

答:短期当然能跑,长期很容易变成三份几乎一样、又各有一点差别的请求代码。到时候换超时、重试或限额规则,就要到处改。

这套系统把模型边界拆成三层:

Codemermaid
图表将在进入视口后显示

最底层的 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 协议。

当前修复分三层:

Codemermaid
图表将在进入视口后显示

领域修复明确要求:

  • 标题层级只能是 1~4;
  • 新文本块只能是 paragraph、heading、quote;
  • 未知标题块转 heading,其他未知文本块转 paragraph;
  • 原文字不得丢失或改写;
  • media、table、code、list、details、equation 等复杂块必须原样保留。

修复失败后,任务直接失败;系统不会把空文档当成成功结果。

14. Writing Persona 怎样生成新版本?

问:用户点“生成分身版本”后,底层发生什么?

答:生成任务会先固定来源版本,再顺序生成已经启用的组件,最后一次性激活。Style 始终生成;Learning 和 Memory 由能力开关决定。

Codemermaid
图表将在进入视口后显示

关键边界:

  • 来源必须仍是已发布文章;
  • 私有 / 口令来源必须经过显式部署开关;
  • 生成期间来源变化会返回冲突;
  • 任一已启用组件失败,旧 Persona Version 继续生效;
  • 所有已启用组件的候选都成功后才切换;
  • 用户以后只选择 Persona,不手工拼组件 ID。

15. Style Profile 到底学了什么?

问:风格学习是不是微调模型?

答:不是。当前是生成可版本化、可追溯的结构化画像。

画像主要包含:

  • 风格摘要;
  • language、syntax、paragraph、structure、narrative、format 等维度;
  • 带权重的风格规则;
  • 代表性表达模式;
  • 不确定项;
  • 来源证据;
  • learner / Prompt 版本。

来源会固定到文章不可变版本和内容指纹。文章后来改了,旧画像不会偷偷“穿越”到新正文。

问:为什么必须有 evidence?

答:因为“作者常用时间线结构”和“模型认为作者喜欢时间线”不是同一件事。

画像可以不完美,但必须保留结论来源。

15.1 写作预设和编辑预设为什么都要版本化?

问:Preset 不就是一段 Prompt 吗,直接覆盖字符串不就好了?

答:如果只关心下一次请求,覆盖字符串确实最省事。但只要想回答“上周那次 AI 到底用了哪套规则”,就必须保留旧版本。

系统最初准备了 10 套写作预设,并记录它们的来源信息,包括清晰简洁、自然口语、深度分析、技术教程和新闻特写。

后来,同一套预设模型增加了“预设类型”:

  • 写作类:决定“写成什么样”;
  • 编辑类:决定“怎样修改已有内容”。

系统还内置了一个编辑预设“六条文章强化规则”。它不是六个独立预设,而是一套包含六条规则的编辑方案。

管理员可以分别管理两类预设,包括新增、编辑、复制、排序、归档和恢复。底层可以共用存储结构,但业务含义必须分开。

这里的“编辑预设”是一种预设类型;而管理员“编辑某个预设”,指的是给它追加一个新版本。两件事别混在一起。

Codemermaid
图表将在进入视口后显示

创建任务时,服务端会把预设类型、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?

答:为了复用昂贵的来源抽取,同时保持使用边界隔离。

当前分为:

  1. 用户级抽取层:按用户维护来源版本和 Memory Observation,可供多个 Persona 复用;
  2. Persona 级投影层:只用该 Persona 选择的来源,生成独立 Memory Snapshot。
Codemermaid
图表将在进入视口后显示

抽取结果可以复用,真正生效的 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。

Codemermaid
图表将在进入视口后显示

当前检索不是向量检索,主要使用:

  • 全文检索(可用时);
  • 词项匹配;
  • 置信度;
  • 证据数量;
  • 条数和字符预算。

它还会排除仅由当前文章提供证据的记忆,避免循环引用。

19. Grounding 怎样阻止模型编经历?

问:Memory 已经提供给模型,为什么还要 Grounding?

答:因为模型看过证据,不代表它只会使用证据。

当前流程是:

Codemermaid
图表将在进入视口后显示

第一人称身份、经历、时间、地点、数量和结果,必须由当前输入或检索到的 Memory 支持。

生成完成后,系统还会记录:

  • 提供了多少条 Memory;
  • 实际使用了多少条;
  • 使用了哪些 memory key;
  • Grounding 是否通过;
  • Memory 来源文章。

界面默认只显示“自动参考 N 篇 · 使用 Memory N 条”,需要核对时再展开。审计信息不会打断写作,但始终可以查看。

20. Learning Snapshot 是怎样来的?

问:用户接受一次建议,系统会立刻修改人格吗?

答:不会。一次接受不足以证明稳定偏好。

Learning Projection 先把接受和拒绝保存为不可变 Observation,再在生成新 Persona Version 时重建。

Codemermaid
图表将在进入视口后显示

当前激活门槛包括至少 3 次正向、至少 4 个来源 Observation、置信度不低于 0.7,并经过确定性评估。

问:人工编辑也会成为修订偏好吗?

答:人工编辑会进入文章版本和 manual_edit Observation。但 Learning Projection 生成规则时,主要使用与 Suggestion 关联的 accepted / rejected 决策。

“人工改了哪里”不能直接解释“为什么这样改”,因此系统不会据此推断稳定偏好。

21. 自动参考文章从哪里来?

问:当前还需要用户手工挑参考文章吗?

答:选择 Writing Persona 后,写作助手会自动选择;写作预设、编辑预设和无个性化模式都不会启用这条召回链。

服务端会把以下信息组合成查询:

  • 当前文章标题、摘要、分类和标签;
  • 写作指令;
  • 目标文本;
  • 邻近上下文。

然后从其他已发布文章中按分类、标签和关键词规则排序,最多选择 3 篇。

Codemermaid
图表将在进入视口后显示

当前没有向量召回。这套算法简单、可解释,也便于测试。

22. 一次真实写作请求的完整链路

问:用户在聊天框输入“结合我的 Android 经历重写全文”后发生什么?

答:

Codemermaid
图表将在进入视口后显示

本次 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. 接受建议时发生什么?

问:点击接受只是前端把内容塞进编辑器吗?

答:不是。接受由服务端再次校验并创建新版本。

Codemermaid
图表将在进入视口后显示

拒绝时,系统只更新 Suggestion 状态并写入 Learning Observation,不改正文。拒绝是有效反馈,不是运行失败。

24. 为什么版本分 v1.r2 和 v2.r0?

问:局部修改和全文改写为什么版本语义不同?

答:

  • 局部人工修改、选区或块级建议,形成当前主版本的新 Revision;
  • 全文替换候选被接受后创建新的主版本;
  • 恢复历史会追加一个“恢复版本”,不会覆盖旧记录。
Codemermaid
图表将在进入视口后显示

候选在接受前不创建正式版本,避免试写结果污染版本列表。

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. 当前总体架构应该怎么画?

问:怎样画一张不夸大现状的架构图?

答:

Codemermaid
图表将在进入视口后显示

图中没有“万能 Agent 大脑”。现在负责“踩刹车”和“留记录”的,是领域服务、资源策略和数据库事务。

30. 这些层次分别在管什么?

层次一句话职责
界面层收集“改哪里、怎么改”,展示对话、候选和版本,但不直接决定数据库事实
写作分身管理来源文章,以及 Style、Learning、Memory 的版本组合
两类预设用轻量规则表达“写成什么样”或“怎样修改原文”
会话与建议续接有限上下文,把模型结果保存成等待用户决定的候选
内容与版本保存工作稿,接受结构化修改,并创建可比较、可恢复的历史
上下文构造选择目标范围、历史消息、参考文章和个人记忆
模型网关负责 Prompt、结构化输出、修复和领域校验
资源策略分别治理限流、并发和每日 Token 预算
运行与任务保存一次业务运行,并支持取消、重试和重启恢复
数据基础用统一正文协议、事务和不可变记录守住事实边界

31. 为什么现在还没有通用 Agent Loop?

问:能力已经这么多,为什么不上 LangGraph 或通用工具循环?

答:因为当前主要任务仍能用显式流程可靠完成。

Codemermaid
图表将在进入视口后显示

这些流程分支有限,失败语义明确。通用 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 做错了,怎样排查?

问:最短排查链是什么?

答:

Codemermaid
图表将在进入视口后显示

依次问:

  • 谁接受了这条建议?
  • 接受时基于哪个文章版本,正文指纹是什么?
  • 结构化修改操作碰了哪些内容块?
  • 生成时使用的是哪个分身版本、写作预设版本,还是编辑预设版本?
  • 这一轮冻结了哪些最近消息,旧候选当时是接受、拒绝还是冲突?
  • 用户消息记录的文章版本与修改范围,能否重建出当时原文?
  • 提供和实际使用了哪些 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、阅读助手和搜索回归。

最后再使用临时数据库和独立临时服务执行一次真实生产构建。

Codemermaid
图表将在进入视口后显示

CI 当然不能证明代码永远正确。它更像出门前的检查清单:不能保证路上绝不出事,但能持续拦住那些已经知道、也有办法自动检查的问题。

36. 下一步最合理的演进顺序

问:现在最该做多 Agent,还是补现有闭环?

答:更稳妥的顺序是:

Codemermaid
图表将在进入视口后显示

数据库运行时、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. 术语表

表格将在进入视口后显示2 columns / 34 rows

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 的每一次参与说清楚、兜得住,再慢慢给它更多能力。
0