尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

SKILL.state:用显式状态替代对话历史,重塑Agent记忆架构

SKILL.state:用显式状态替代对话历史,重塑Agent记忆架构 做 AI Agent 类功能时我一直有一种很难说清的不安只要任务一长我就没办法准确判断模型到底“进行到哪一步了”。对话框里滚动着几十轮历史每一步都像写在水面上看起来还在实际已经模糊。最近看到 Google 一项研究的标题——SKILL.state 以显式状态替代对话历史——立刻说中了我长期以来的工程直觉把 Agent 的“记忆”建立在对话历史上本身就是一条过于脆弱的路。这个方向真正值得关心的点不是要不要保留对话记录而是要不要把隐式记忆变成一种可以被读取、校验和恢复的显式状态。我在下面的内容里不会把 SKILL.state 当成一个可以直接下载安装的开源项目来介绍。从目前公开的标题看它更像是一种 Agent 设计的思路转向从“让模型从前面的每一句话里自己找状态”变成“我们主动定义一个状态结构每次执行完任务就更新它并让模型只依赖这份结构化状态继续工作”。对我而言这个转向的价值远远超过“省 token”这种表面收益。1. 对话历史是 Agent 最脆弱的记忆层在讨论显式状态之前要先把对话历史的局限性说透。很多 Agent 应用尤其是基于在线大模型对话接口开发的多步任务工具几乎都在做同一件事把上一轮对话完整拼进下一轮请求。这种做法实现起来简单但它掩盖了一个深层问题——对话历史并不能等价于“任务当前的真实状态”。1.1 三个必然出现的失控信号用过一段时间 Agent 的人应该都见过这三种现象任务越跑越慢请求体越来越大。每轮都要携带前面的全部文字历史一长接口响应时间和 token 成本一起上涨。中间步骤出现一次错误后面很难纠正。因为模型判断依据的是“前面说了什么”而不是“现在真正需要什么”一旦早期某轮理解偏差偏差会在历史中持续累积。关键结果被淹没。前面某步已经拿到了一个重要文件路径或者一个结论数值但几十轮之后模型已经无法确定这条信息是否仍然有效于是它可能重新查一遍也可能直接忽略。从工程经验看这三个信号的根源不是“模型笨”而是记忆结构本身太粗糙。对话历史是一份无差别的流水账里面既有用户原始需求又有模型中间推理还有工具返回结果甚至有各种试探和修正。让模型每一次都从这份流水账里重新理解任务本质上是在用庞大的上下文掩盖状态管理的缺失。1.2 历史是“过去发生了什么”状态是“现在还需要什么”这两者经常被混为一谈。我们可以用一个生活场景对照如果你在外地出差手机备忘录里存的不是旅行日记而是“酒店地址、当前进度、下一步要办的三件事”你随时知道自己该去哪、该做什么。但如果只给你一本每天都写的旅行流水账你需要在每次行动前翻遍前几页才能推断自己现在到底在哪一步。对话历史就是那本旅行流水账显式状态才是那张应该被放在最前面的任务卡片。对 Agent 来说记录每一步历史当然有它的价值比如调试、审计、回溯。但把它当成驱动下一步决策的“唯一依据”这个设计是有问题的。因为模型每读一遍长历史就要做一次概率推断而推断结果并没有保证。显式状态的意义在于减少推断直接把当前需要的关键事实交给模型。这里的核心判断是对话历史适合用来理解任务是怎么演变的但不太适合单独用来支撑任务接下来该怎么走。真正应该丢给模型的是“已经收敛后的状态”不是“收敛前所有原始话语”。2. SKILL.state 的设计意图把记忆从日志变成工作区“SKILL.state 以显式状态替代对话历史”这个标题可以拆成两个更具体的研究问题一是 Agent 的执行能力要用什么样的单元来承载二是 Agent 的记忆应该以什么样的形态存储。前者是 Skill也就是可复用技能后者是 State也就是任务状态。2.1 从命名看技能与状态正在被分离在常见的 Agent 设计里技能和状态往往是纠缠在一起的。一段历史里既包含“技能步骤描述”又包含“状态变化过程”。模型需要自己区分哪些过程已经完成、哪些还未完成。这种纠缠在短任务里不致命任务长度一旦上升问题就会被放大。而 SKILL.state 的命名暗示了一种更清晰的分层Skill固定的、可复用的操作流程和工具调用方式。它更像“一段可重复执行的函数逻辑”。State当前任务的可变数据快照。它包含已完成的步骤、中间结果、待办事项、外部资源引用等。两者关系技能负责“怎么做”状态负责“当前进行到哪”。当技能和状态分离后模型下一次调用不再需要重读所有过程描述只需要结合当前状态来决定调用哪个技能、传入什么参数。2.2 显式状态会带来四个层面的变化如果“显式状态替代对话历史”这条思路落地从工程角度看至少会有四层变化上下文长度更可控。系统传给模型的不是不断增长的聊天记录而是一份紧凑的状态文档这可以让长任务运行得更稳定也更接近固定成本的调用。状态可以被程序校验。显式状态一旦变成对象就能在代码层做检查必填字段有没有、上一阶段产物是否存在、某项任务是否标记为完成。对话历史本身无法被结构化校验。支持恢复和分支。如果把每个关键阶段的状态保存成检查点任务中断后可以恢复实验多个方案时也能从同一个状态分叉而不是回看整段对话。技能之间可以更干净地协作。不同阶段负责不同任务的 Skill 之间不再通过自然语言描述“接力”而是通过状态文件交接。这更接近程序函数之间的“返回值传递”。这四条变化叠加起来意味着 Agent 会从一个“全靠模型临时推理的系统”慢慢变成“有明确输入输出和工序定义的可维护系统”。我认为这是标题背后最有长期价值的含义。2.3 一个合适的参照状态不再需要每轮完整重读如果把这段研究和现在常见的“上下文压缩/自动摘要”做对比差异会更清晰上下文压缩的思路是尽量把历史总结得更短再塞给模型。它省的是 token但没有改变历史驱动的本质。因为摘要仍然是模型生成的仍然存在信息丢失的可能仍然没有一个程序可以精确判断“这份摘要里的结论是不是已经落库”。显式状态的思路则是不再让模型负责从历史里提取状态而是由系统在代码层主动更新状态。真正关键的数据由工具返回和程序处理直接写入结构化字段。模型只是在某一步需要做判断时读取这个状态而不是反复用自己的理解去解释过去。这个差异决定了系统的可控性上限。用开发里常见的模型来比喻对话历史像一份超级大的运行日志显式状态像程序运行时的变量内存。日志当然有用但程序下一轮逻辑不会靠重读日志来运行而是靠变量当前的值。变量可以被检查、被修改、被回滚运行日志很难做到同样的事情。3. 就算没有官方实现这套思路也可以指导 Agent 开发对多数开发者而言SKILL.state 目前还只是一个研究层面的信号不会立刻有一个现成插件或框架供我们直接接入。但这并不妨碍我们把这套设计理念应用到自己的 Agent 项目里。我建议从最小可运行流程开始逐步把对话历史驱动的 Agent改造成显式状态驱动的 Agent。3.1 第一步先给任务定义一份状态结构不要一开始就追求状态覆盖所有字段。先分析一个具体任务最常用的“关键事实”把它们写成 JSON 或类似的结构。比如做一个“自动写行业调研报告”的 Agent初始状态可以这样设计{ task: { goal: 生成一份AI编程工具行业调研报告, lang: zh-CN, max_steps: 5 }, progress: { current_stage: outline, completed_stages: [], next_action: collect_materials }, artifacts: { outline_id: null, materials_id: null, report_id: null }, pending_decisions: [ 是否需要补充竞品对比章节 ] }注意这里最重要的不是格式多完美而是让任务的“关键事实”成为可读取字段。人工一眼就能看出当前到哪一步、还差什么、下一步做什么。这比让模型重新理解 50 轮对话要可靠得多。3.2 第二步每次工具调用后同步更新状态一个常见的实现误区是把状态文件写好了但每次调用模型时仍然把完整对话历史一起塞进去。这不算显式状态方案只是多了一个侧写文档。真正的做法应该是请求模型之前只从状态中组装当前任务上下文。模型返回决策后由代码解析出“要调用哪个工具、更新哪些字段”。工具返回结果后把结果写入状态文件再开始下一轮。更新操作最好在代码层完成而不是让模型自己去改 JSON。即使模型只是输出一段结构化标记也应该经过一层校验再落盘。这样可以避免模型产生幻觉字段或覆盖掉关键信息。3.3 第三步把关键节点变成可恢复的检查点在设计流程时要给状态加一个“阶段校验”。例如进入“资料收集”阶段前确认上一阶段的提纲文件存在且非空。进入“生成初稿”阶段前确认资料文件已经被引用。每隔一段把状态文件复制一份并用时间戳命名形成检查点。这样做的直接好处是当某一次模型调用产生坏结果时可以回到上一个检查点重跑而不是被迫重新开始整段对话。这也是显式状态相对对话历史最有实感的优势之一可控回退。落地时最值得投入的是把“状态更新逻辑”和“技能调用逻辑”分开写。同一个 Skill 可以在多个任务中复用State 则永远只属于当前任务。这个分离越彻底后续扩展越容易。4. 给 Agent 状态建模的五步设计法如果你之前完全没做过 Agent 的状态管理很容易一头扎进“应该存哪些历史消息”的讨论里。这里我把自己常用的建模方法拆成五个步骤可以当成一个通用框架来用。4.1 先圈定任务边界不追求通用第一步是确定当前 Agent 只处理哪一类任务。例如“只做资料检索与摘要”“只做多仓库代码审阅”“只做定时数据分析”。范围越明确状态里的字段就越有可能被精简。不要一开始就做一个“什么都能聊的对话式通用助手”然后给它配一套万能状态。这类系统需要的不是状态管理而是灵活对话设计。SKILL.state 式管理更适合解决“任务型 Agent”的可控性问题。4.2 区分四类状态信息我在给状态建模时会先把信息分成四类任务元信息用户研究目标、输出语言、约束条件。它们从头到尾基本不变。执行进度当前处在哪个阶段、哪些阶段已完成、下一步动作是什么。产物引用中间文件、数据库记录、生成文档的引用信息。环境上下文外部系统连接情况、可用工具列表、当前权限、运行目录。这四类信息不一定都要落到同一个 JSON 文件里但设计时必须独立考虑。容易出现的一个问题是把“执行进度”和“产物引用”混在一起导致模型判断步骤时拿不到清晰的状态边界。4.3 为每个阶段设计“出口条件”状态建模不是只记流水账。每个阶段在执行完以后都要能回答一个问题“现在有没有资格进入下一阶段” 这就是出口条件。比如“资料收集”阶段的出口条件是所有指定站点都已抓取提取文本超过一定数量文件已保存到数据目录。只有当这些条件满足状态里的 current_stage 才能从“collect”变成“summarize”。这里的关键是判断出口条件是否满足应该由代码、脚本或规则来做基础检查模型只做语义层面的判断。两种判断都留在模型身上系统依然会不可控。4.4 定义状态更新与读取的权限在多人工程里还要考虑一个问题哪些模块可以读状态哪些模块可以写状态。一般建议是工具调用层可以写自己产生的产物引用编排层可以更新 current_stage 和 next_action模型本身更适合做“读取并决策”而不是直接修改状态文件。这样即使模型在某个环节判断错误也不会直接污染持久化状态只会在下次状态更新时被拦下来。设计时可以画一个简单的表状态字段谁负责写入谁负责读取更新时机task.goal起始配置所有技能任务创建时progress.current_stage编排层决策层每阶段结束时artifacts.report_id工具输出层后续技能报告生成成功时pending_decisions模型决策模型自身每次判断结束后这种清晰边界看起来有点像工程里的“权限治理”但对于 Agent 长期运行和多人协作来说能避免大量“以为状态更新了但实际没有”的隐性 bug。4.5 最后才是考虑对话历史去留显式状态替代的是“驱动任务继续进行的上下文”不代表要彻底删掉对话历史。完整历史仍然可以保存用于审计、调试、离线分析和用户回看。但在 Agent 每一步的运行时请求里往模型里传的内容应该以状态为主而不是以原始对话为主。这套框架值得长期使用的原因不是它能让模型变得更聪明而是它让 Agent 系统中的“推理”和“记忆”被解耦。推理归模型记忆归状态工程能力才能被用得上。5. 影响 Agent 稳定性的常见排查链路与坑点做 Agent 应用最让人头疼的不是某一次调用报错而是它有时能成、有时不能成而且看不出规律。面对这种问题如果你还在不断改提示词大概率会越改越乱。下面这套排查顺序能够帮助你更快定位问题是不是出在“状态”层面。5.1 先按四层结构排查 Agent 异常当 Agent 出现结果不稳定、中途停滞、重复执行、字段缺失时我会按以下顺序排查状态层当前状态里的 current_stage 是否准确next_action 是否还指向一个已完成的动作产物引用是否为空技能层要调用的技能代码是否真的存在输入参数和状态字段名能否对得上技能返回格式是否符合预期历史层模型是否仍然被塞入了太多冗余历史导致它忽略状态文件里的关键信息上下文层当前上传的状态是否充足模型是否缺少一个决定“用哪个技能下一步”必须的信息这个顺序的逻辑是先验证系统的“记忆”没有被污染再看“手”有没有问题最后才怀疑“决策模型”。很多问题的根源其实是第 1 步的状态没有更新干净但开发者却一直在第 4 步反复调提示词。5.2 三个极容易踩中的实践坑坑一状态文件永远只存最新一份没有历史记录。一旦坏状态覆盖了好状态无法回退。建议先做时间戳检查点再谈漂亮的 JSON 结构。坑二让模型自己更新状态却没有校验规则。模型经常会在状态里添加一些它自己“希望存在”的信息这其实是另一种幻觉。状态更新需要经过 schema 校验或人工审查。坑三显式状态做了一堆字段但请求模型时一个字段都没有使用。如果从拼接 Prompt 到最终请求都没有把状态转成模型可读的文本块那状态就只是一个摆设。5.3 如何判断一次状态化改造是否真的有效说到判断改造效果不要只看几轮对话“感觉变聪明了”尝试用三个更可测量的信号来验证执行一次完整流程记录从开始到完成用了多少轮请求、多少 token。在中间某一步注入一个错误结果看系统能否从上一个检查点恢复。把任务重新跑三遍统计结果一致性和字段完整度。如果以上指标表现稳定说明显式状态不只是减少了 token还真的让系统更可维护。如果指标没有明显变化问题可能不在记忆层而在任务的技能编排层需要继续往下查。在实际工程里“单次跑通”和“能稳定重复地跑通”是两件完全不同的事。单次跑通只能说明链路没有被断开而稳定重复需要的是状态一致、校验完整、错误可恢复。6. 显式状态不是银弹但它解决的是 Agent 工程化的关键短板讨论到最后还是要回到一个清醒的判断显式状态替代对话历史并不会让 Agent 自动变得强大也不会解决所有提示词层面的问题。它真正解决的是 Agent 从“演示品”变成“生产工具”过程中最关键的一块短板——可观测性和可控性。对话历史驱动的 Agent更像一位记忆力不太靠谱却自信心很强的助理。你让它做一件三步之内的小事它表现很出色。但遇到一个需要两天时间、跨越多个工具、来回修改十几遍的长期任务它一旦忘记最初的目标约束就会产出让你哭笑不得的结果。显式状态相当于给这位助理配了一本实时更新的任务手册每次它做下一步之前都先翻一下手册而不是靠回忆。从边界上看以下场景未必适合直接套用这种思路单轮创意生成、闲聊、内容润色不需要复杂的长期状态。纯探索式开放对话用户本来就不需要任务有明确进度。一个只需要两三步就能完成的工具调用引入状态可能增加成本。但只要是真正的多步骤、多次工具调用、跨文件或跨模块协作的任务我认为显式状态会成为越来越主流的做法。原因也很简单任何需要长期维护和团队协作的系统都不可能依赖一段不断膨胀的对话文本作为事实来源。事实必须被存成数据数据必须具备结构结构必须能被程序检查和修正。Google 从标题层面给出了一个新的研究信号。对普通开发者而言与其等待某个官方产品上线不如先把“从对话历史到显式状态”这个思路迁移到自己的项目里哪怕只是给现有 Agent 加一个非常简单的状态 JSON你都会很快体会到“可恢复、可检查、可交接”带来的差别。长期来看真正定义下一代 Agent 能力的未必是模型又变大了多少而是我们能不能把任务里那些会变的东西管理得清清楚楚。
返回列表