产品机制
Morphz 如何管理上下文与记忆?
从观察记录与认知帧,到上下文事务、分阶段退役和认知图召回:Morphz 如何让智能体更新记忆、保留证据,并在长期工作中使用积累的经验。
把一项工作交给 Agent,过几个小时、甚至几天再回来,我们希望它能接着上次的进度继续:记得用户提出的要求,知道哪些问题已经解决,也能说清某个决定是根据什么作出的。工作持续得越久,新的消息、报告和工具结果就越多,记忆也需要随之更新。
Morphz 用结构化上下文组织这些记忆。智能体在推进任务时,从新信息中形成认知,修订已有判断,记录它们的关系,再把处理完的材料移出当前上下文。运行时负责保存原始记录、校验和提交这些修改,并在下一次调用模型时提供更新后的上下文。
结构化上下文里保存了什么
Morphz 的上下文按信息的用途组织。用户消息、工具结果等新输入保存为观察记录;智能体已经形成的判断、用户偏好和工作经验保存为认知帧。认知帧之间还可以建立明确的关系,例如“测试通过”支持“准备发布”。会话和任务的运行状态也在上下文中单独呈现。
认知帧有稳定标识和修订版本,正文由模型根据事情本身组织:发布安排可以包含目标和阶段,构建方法可以包含命令、产物和适用条件。帧还可以通过 sources 记录来源,通过带名称的关系连接其他帧。这些帧和连接共同构成认知图;模型负责形成和修改认知,运行时管理节点身份、版本和生命周期。
以软件发布为例。回归测试返回了通过的报告,任务可以进入打包。智能体需要将进度从“等待测试”改为“准备打包”,同时保留测试报告作为依据。下面这张图展示了它如何在同一次响应中安排下一步工作,并完成这次记忆更新。
测试日志怎样改变智能体的记忆
测试报告先作为一条观察记录进入上下文。它有一个稳定的事件身份;图中的 @e42 是运行时提供给模型使用的短引用。原始报告保存在事件历史中,智能体现在可以读到它,也可以在以后按引用找回。
发布任务当前的安排保存在名为 release 的认知帧中:目标是发布新版本,进度是等待测试。测试日志记录工具实际返回了什么,release 表达智能体目前怎样理解发布任务。
读到 @e42 后,模型可以在同一次响应中提出打包命令和一笔上下文事务。图中事务的核心内容可以写成:
(context-tx
(base-version 12)
(reason "测试结果已吸收,继续准备发布")
(derive test-result (from @e42) (tests passed))
(revise release (goal ship-v1) (stage packaging))
(relate test-result supports release)
(retire @e42))
derive 从测试报告形成一条带来源的新认知 test-result;以后要核实“测试通过”从何而来,可以沿来源找到 @e42。revise 把原有的 release 更新到准备打包,同时保留发布目标。这里必须把 goal 再写一遍,因为修订会替换整个帧的正文,而不是只改其中一个字段。
接着,relate 记录“测试通过”支持当前发布安排。这是一条明确的认知关系,不是运行时替智能体作出的业务推断。最后,retire 让已经读完的日志退出活动上下文;它的原始内容仍在事件历史中。
事务携带它依据的上下文版本。运行时检查引用、操作和版本,整组修改一起提交;其中一步不合法,整组都不会写入。打包命令则走另一条执行路径,并不与这笔认知修改共享数据库事务。此刻留下的记忆是“测试已通过,准备打包”,而不是“打包已成功”。打包工具返回后,结果会成为新的观察,智能体再据此决定是否更新进度。
为什么观察记录和认知帧采用不同的退役机制
测试日志可能有几千行,而当前工作只需要其中的结论。test-result 已经表达“本轮回归测试通过”,也保留了报告的来源,模型便可以先根据这条认知继续工作,需要细节时再读原文。这里涉及两份不同的记录:Observation 保存收到的材料,Frame 保存模型从材料中形成的理解。
Morphz 将持久保存与本次模型输入分开。事件历史保留原始消息、工具输出和已提交的认知修改;认知状态保留帧、来源与关系。每次调用模型,运行时从这些持久记录中编出活动上下文。retire 改变的是内容是否继续进入这份输入,原始记录及认知关系仍然保留。
对已经消化的 Observation,退役可以立即生效。前面的 (retire @e42) 提交成功后,这份测试日志就退出下一次活动输入,test-result 中的来源引用仍指向它。当前请求尚未交付的用户原始要求则受运行时保护,必须先完成答复或工作交付,才能退役,避免智能体在执行中丢掉任务依据。
Frame 已经包含模型付出推理成本形成的判断、经验或约束。若一遇到容量压力就将它移出输入,智能体可能来不及整理这些认知。因此,普通 Frame 的 retire 分成申请和生效两步:先从 active 进入 retiring,正文继续留在上下文中,模型也能看到退役原因和剩余整理时间;整理期结束后,再进入 retired。
| 退役对象与条件 | 提交后的状态 | 下一次模型输入 |
|---|---|---|
| 已处理的 Observation | 立即退役 | 移出该观察记录 |
| 普通 Frame,尚无明确承接它的后继帧 | 进入整理期 | 仍保留正文,暂不释放这部分容量 |
| 已申请退役的 Frame,有带来源和取代关系的后继帧 | 立即完成退役 | 移出旧帧正文,保留后继帧 |
整理期按认知活动计算。每个认知上下文有一个持久的逻辑计数器 cognitive_tick。运行时认领一批新的输入并建立一次求值时,如果这批输入包含用户消息、工具结果或其他外部事实,计数器推进一次;同一批输入只计一次。模型内部续推、请求重试和认知事务回执都不让计数器增加。
当前默认整理窗口为 8 个 tick,可以配置。例如,在 tick 100 申请退役的 Frame,要等到 tick 108 才到期。关机三天或在线空闲三天,计数器都停在原处。这个窗口衡量的是智能体又接触了多少批新信息,给后续认知活动留出整理机会。持续活跃的 Frame 会一直保留,只有显式申请退役的 Frame 才进入窗口。
窗口内,revise 可以将该帧改写为更精简的认知,同时取消原退役申请;restore 可以直接取消申请;protect 可以取消申请并保护该帧,后续退役前须显式解除保护。重复提交 retire 会沿用原到期点。到期时,运行时还要核对申请代次和 Frame 修订版本:如果另一条线程已经修订、恢复或保护了它,旧的到期动作就失效,不能把更新后的认知移出输入。
从具体经历归纳出可复用的方法
整理期为归纳留下了机会。一次发布完成后,模型可以将实际用过的命令、产物位置和结果保存为案例帧,来源指向这次的执行记录。假设它积累了两个前端项目的发布案例:
| 案例内容 | release-case-a |
release-case-b |
|---|---|---|
| 项目布局 | 单包项目 | 工作区中的 web 包 |
| 测试命令 | npm test |
pnpm --filter web test |
| 构建命令 | npm run build |
pnpm --filter web build |
| 产物位置 | dist/ |
apps/web/dist/ |
| 本轮结果 | 测试、构建和产物核验通过 | 测试、构建和产物核验通过 |
两次工作的共同流程是测试、构建、核验产物,再打包;差异是项目布局决定了命令和路径。模型可以将共同顺序写成一条方法,将差异保留为条件分支,让下一次工作根据当前项目选择。单次运行的完整日志留在案例的来源中。对应的归纳事务可以写成:
(context-tx
(base-version 42)
(reason "将两次发布经验归纳为可复用流程")
(derive release-procedure
(from release-case-a release-case-b)
(steps "测试通过后构建,核验本次产物,再打包。")
(single-package
(test "npm test")
(build "npm run build")
(artifact "dist/"))
(workspace
(test "pnpm --filter web test")
(build "pnpm --filter web build")
(artifact "apps/web/dist/"))
(applicability "先核对当前项目布局和脚本,再选择对应分支。"))
(relate release-procedure supersedes release-case-a)
(relate release-procedure supersedes release-case-b)
(retire release-case-a release-case-b))
对于本笔或此前事务中已申请退役的旧帧,运行时在事务的最终状态中检查:后继帧仍未退役,它的 sources 包含旧帧,并且存在“后继帧 supersedes 旧帧”的取代关系。满足这些结构条件,旧帧就可以立即退役,跳过剩余整理期。若旧帧已经处于 retiring,后续事务建立符合条件的后继帧,也会使原退役申请立即生效,无须再次提交 retire。
sources 记录方法从哪些经历形成,supersedes 表达模型决定让新方法接替旧案例。是否提炼得正确、是否遗漏了关键前提,仍需要模型根据证据判断;运行时负责让这次认知替换有明确声明、可以校验并且一起提交。方法正文由模型撰写,运行时不会自动把几段文本压成摘要。
归纳后,活动上下文可以主要保留 release-procedure,旧案例的正文退出输入,但各自的内容、来源及取代关系仍在。更多工作积累后,模型还可以继续修订方法,或将多条方法归纳为新的认知。这些保留下来的连接,使后续召回可以从一个简洁的方法逐层找到具体经历和原始证据。
沿认知图召回旧知识和原始证据
下一次发布,智能体可以先读取 release-procedure,根据项目布局选择命令和产物路径。如果用户追问“工作区分支真的构建成功过吗,产物在哪里”,智能体需要找到 release-case-b,再核对当时的工具结果。
recall 的 Frame 模式会遍历认知图。以上面的结构为例,release-procedure 的来源是两个案例帧,案例帧的来源再指向执行记录。从方法出发,第一跳可以读到案例,第二跳可以到达原始事件。即使案例和日志已经退役,这些节点仍可被访问。调用 recall 时可以指定:
{
"frame_id": "release-procedure",
"depth": 2,
"direction": "ancestors",
"include_bodies": true,
"include_events": false,
"max_nodes": 8
}
这次调用会返回节点和边。Frame 节点包含正文、修订版本、来源和 active、retiring 或 retired 状态;事件叶子包含可继续读取的引用和预览。include_events: false 让原始报告先以预览出现,需要全文时可以用返回的事件引用分块读取;设为 true 则会在图结果中展开事件原文。沿 release-case-b 读到执行记录后,智能体便可以核对那次命令的结果及产物位置,而不只复述方法里的字段。
来源引用还需要区分身份与版本。sources 保存的是稳定 ID,没有锁定来源 Frame 的某个旧修订。图召回返回当前认知状态中的 Frame 正文和修订版本;来源若指向事件,则对应那条不可变的原始记录。如果案例后来被恢复并修订,当前图就会读到修订后的案例。要核对方法形成时案例写过什么,可以另行召回方法和案例各自当时提交的认知事务文本,查看 derive、revise 写入的正文及实际提交的 base-version,再按事务版本对照。当前图读取与历史写入查阅是两条不同的路径。
来源与业务关系都参与遍历,但方向需要明确。ancestors 沿 sources 回到来源,并沿 Frame 关系的主项走向宾项;descendants 查找引用当前帧的后续帧,并反向沿关系查找;both 合并两个方向。例如,前文的关系是 test-result supports release,从 release 找到支持它的 test-result,就要选反向或双向遍历。关系名称由模型赋予含义,运行时按已保存的边行走。
遍历采用广度优先,先展开近处节点,再逐层深入,已经访问过的节点不会重复展开,因此有环的关系也能处理。当前深度上限为 4,max_nodes 控制每页返回的节点数,上限为 128;它限制返回页,而不是整个深度范围内的访问数量。结果还会按节点大小分页,返回 next_cursor 供继续读取。分页按完整节点分割,单个大节点不会切片,因此大日志适合先取预览,再按事件引用分块读取。
图召回限定在当前认知上下文中。游标绑定查询参数和认知版本;图在分页间被修改时,需要从新版本重新开始。模型调用的图召回也核对本次上下文视图的版本,避免把并发更新后的节点混进旧视图。
不知道从哪个帧开始时,可以先用关键词或时间范围寻找入口。词法检索同时索引 Frame 和历史事件,已退役内容也保留在检索范围内。索引和查询使用相同的 Unicode 规范化与 ICU4X 分词规则,再交给数据库索引检索。搜索负责定位可能相关的记录,图召回负责展开它们的来源和连接;从一个高阶认知出发,就能检查支撑它的具体材料。
词法索引是可重建的派生数据。事实提交时同时保存索引更新意图,后台再完成索引更新,因此搜索可能短暂落后于刚提交的认知。按 ID 读取 Frame、遍历关系和读取原始事件,则依据持久认知状态与事件历史。这也让索引重建可以独立进行,保留下来的记忆及其关系无需重写。
召回、恢复与修订分别改变什么
图召回取得的是材料。返回的内容作为工具结果进入观察输入,Frame 自身的活动状态保持原样。智能体可以读一条已退役的构建方法,回答关于旧项目的问题,而不将这条方法重新长期留在当前上下文中。需要继续使用时,再通过 restore 把它恢复为活动认知。
如果查阅证据后发现原判断有误,则需要修改认知。例如,测试报告有一项失败被遗漏,模型应修订 test-result,撤销它支持发布的关系,并重新安排 release;这些变更仍通过 context_tx 提交。如果待修订的帧已经正式退役,须先 restore 再 revise,两步可以顺序写在同一笔事务中。recall 提供核实所需的证据,restore 决定什么重新进入活动上下文,revise 和关系操作更新当前判断。退役本身只改变活动状态;一条判断是否仍然成立,要在它的正文和关系中表达。
这几种操作共同支持长期工作:当前输入保留正在使用的认知,详细经历留在持久记录中,遇到问题时沿图展开,形成新判断后再更新记忆。容量接近上限时,运行时会报告输入压力;进入必须维护的阶段后,新的外部动作暂缓,让模型先消化观察记录、精简 Frame 或建立后继帧。普通 Frame 的退役申请暂不释放正文容量,因此事务回执会区分当下已释放的容量与整理期后才可能释放的容量。
两项工作同时更新记忆
同一智能体的多条执行线程可以共享认知。测试线程看到 @e42,准备把 release 更新为打包中;另一条线程同时收到用户要求:“先暂停发布。”如果两边都根据旧版本修改同一个 release,只让后提交的一方覆盖前一方,最终状态就可能丢掉重要变化。
Morphz 的事务会检查具体的修改边界。两笔事务修改彼此独立的认知帧或关系时,运行时会核对它们显式引用的内容是否发生变化,符合条件的较旧事务可以应用到新版本。两边都修改 release 时,冲突的一方需要重新读取当前状态,再决定怎样同时处理“测试通过”和“暂停发布”。
这种检查依据操作目标、from 来源和关系端点等明确引用。假如一条发布方案依赖另一条认知中的用户限制,模型应把这项依据写进事务的来源;运行时才能检查这条依据的版本。自由文本里隐含的业务依赖,需要模型自己识别。运行时检查这些引用有没有变化,模型判断新旧要求怎样共同影响发布安排。
跨任务记忆的评测结果
我们还检查了这套机制在跨任务工作中的实际使用,以及完整系统的任务表现。在一轮基于 STATE-Bench v0.8.1 的评测中,Morphz 与 Letta、Mem0 向量检索参考智能体作了对照。测试覆盖购物助手、旅行和客户支持三个领域。每个系统在每个领域读取相同的 100 条已完成任务轨迹,积累经验后,再处理相同的 50 项未参与学习的任务,合计每组 150 项。经验保存在各系统的记忆中,基础模型保持不变。
智能体、用户模拟器和评测器统一使用 GPT-5.6 Sol(最高推理强度),每项测试只尝试一次。任务通过需要同时满足工具环境的最终状态要求,以及对话和流程要求,例如用户确认、信息披露和业务政策;执行失败也计入总数。
| 系统 | 完成任务 | 完成率 |
|---|---|---|
| Morphz | 122/150 | 81.33% |
| Letta 0.16.8 | 93/150 | 62.00% |
| Mem0 2.0.19 向量检索参考智能体 | 96/150 | 64.00% |
另一次只读轨迹审计确认,全部 150 项 Morphz 测试任务都从各自领域学习后的第 100 版结构化上下文启动,训练形成的认知帧和关系实际参与了后续模型求值。这轮评测因此同时保留了任务完成结果,以及记忆进入后续工作的执行证据。
这里报告的是使用更新版评测器的本地系统对照结果。其中,对话和流程要求由模型评分,独立人工校准尚未完成。比较对象是完整智能体,包含各自的提示词、记忆维护、工具循环和调度策略。Morphz 在本轮测试阶段使用了更多 token;各组的完成率、运行开销和具体配置都列在完整评测报告中。