主题色
250
壁纸模式
壁纸设置
特效设置
固定导航栏
字体选择
文章列表布局
7550 字
19 分钟
从框架到产品:拆解一个 Agent 操作系统是怎么长出来的
2026-08-04

引子:从能跑到敢托付#

一个最小的 agent 并不复杂:模型读上下文,决定是否调用工具,把工具结果放回上下文,继续循环,直到输出答案。几十行代码足以跑通这个闭环。

真正困难的是把它变成可以长期托付的系统。接入飞书时,要处理验签、消息归一化、群聊权限和重复投递;任务运行几小时后,要面对上下文超限、失败重试和成本失控;安装第三方技能时,要防止提示注入和凭证泄露;部署到服务器后,还要保证重启不丢状态、并发不串会话。

这些问题不属于“把模型调通”的范畴,而属于模型之外的基础设施。前文《2026:Agent 基础设施七大难题》给出了一张地图;本文换一个视角,沿着 AgentScope 框架和 QwenPaw 产品的代码边界,观察一套个人 Agent 系统如何从骨架长出血肉。

先给结论:框架负责稳定的抽象,产品负责具体的策略。AgentScope 提供消息、循环、中间件和事件等扩展点;QwenPaw 在这些扩展点上填入 Scroll 上下文、循环门、渠道队列、权限治理和沙箱。两者的边界,正是理解系统取舍的入口。

这条边界可以先压缩成一张表:

层次AgentScope 主要提供QwenPaw 主要补齐需要回答的问题
执行消息、ReAct、中间件、事件工作模式、循环门任务如何继续和停止
上下文压缩接口、消息持久化钩子Scroll、ReMe历史如何保存和召回
连接模型 formatter、工具抽象drivers、渠道、定时任务外部能力如何接入
治理权限决策形状、挂起事件规则、扫描、沙箱自主执行如何受控
运行状态和事件接口会话、队列、部署、观测系统如何恢复和排错

这不是功能清单,而是后文的阅读顺序。每一层都先看框架留下什么接口,再看产品为何选择当前实现。

一、先画出边界:一次请求经过哪些层#

读源码之前,先把一次请求的路径固定下来。无论消息来自 Console、飞书还是定时任务,系统都要经过类似的链路:

flowchart LR input[消息或定时事件] --> channel[渠道归一化与鉴权] channel --> queue[按会话排队] queue --> runtime[Runtime 加载状态] runtime --> agent[AgentScope ReAct 循环] agent --> policy[工具权限与沙箱] policy --> tool[本地或远程工具] tool --> agent agent --> persist[历史、记忆、统计] persist --> output[流式或一次性回复]

这张图只保留会影响设计判断的中转层:渠道把外部协议变成统一请求,队列保证同一会话串行,运行时装配状态,框架执行循环,治理层决定工具能否运行,持久化层负责恢复。后文所有机制都可以放回这条路径定位。

二、框架骨架:消息、ReAct 和中间件#

AgentScope 的核心不是某一个模型,而是一个稳定的内部表示。Msg 把发送者、角色、消息 ID 和内容统一起来;content 不是单一字符串,而是由 TextBlock、ThinkingBlock、ToolCallBlock、ToolResultBlock 和 DataBlock 等内容块组成。一次 assistant 消息可以同时包含文本、思考和多个工具调用。

这层抽象解决的是“各家模型 API 方言不同”的问题。formatter 把统一的 Msg 翻译成不同供应商需要的请求格式,并负责多模态工具结果的降级处理。上层的 ReAct、权限和上下文逻辑只操作统一消息,不需要为每家模型写一套循环。

ReAct 循环本身可以概括为两步:reasoning 产生文本或工具调用,acting 执行工具并把结果写回上下文。复杂度来自循环周围的横切逻辑:记录调用、检查权限、压缩上下文、切换模型、处理取消。把这些逻辑直接塞进循环,任何一次改动都会扩大核心代码的风险。

AgentScope 用中间件洋葱解决这个问题。MiddlewareBase 为回复、推理、权限、工具执行、模型调用、上下文压缩和系统提示保留钩子。中间件可以在调用前做检查,在调用后改写结果,也可以不调用 next_handler 直接短路。框架在初始化时按钩子分组,只调度真正实现了对应方法的中间件。

以 on_reply 为例,中间件拿到一个 next_handler:调用它会进入下一层,最后一层才执行 _reply_impl。日志可以在调用前记开始时间、调用后记结果;权限中间件可以不再向内调用,直接返回拒绝。洋葱模型把“执行前”“执行后”和“阻断”放进同一接口,比只提供前置回调更容易表达完整策略。

按钩子分组同样重要。一个只实现 on_model_call 的降级中间件,不该出现在权限链或上下文压缩链里。初始化时完成一次能力检测,运行时便不必反复做无效分派。这个细节不会改变功能,却会让扩展点在数量增加后仍然可控。

这里最重要的不是“有七个钩子”,而是职责边界:框架规定扩展点和数据形状,不规定业务策略。PermissionEngine 返回 ALLOW、DENY、ASK 或 PASSTHROUGH,但规则从哪里来、如何和用户或租户绑定,由产品决定。

事件流是另一条框架级基础设施。回复、模型调用、文本块、工具调用和工具结果都有开始、增量、结束等事件。UI 可以消费它做流式渲染,追踪系统可以消费它生成 trace,成本统计可以消费模型结束事件。框架只产生事件,不绑定某一个界面或观测平台。

流式输出和持久化不能混为一谈。发给界面的是增量事件,写入历史的应是组装完成的消息块;否则一次网络中断就可能把半个工具调用留在上下文里。事件负责“现在发生了什么”,完整 Msg 负责“最终发生了什么”。这条边界也是后面做恢复和审计的前提。

三、让循环可控:StopGate 和任务完成#

ReAct 只解决“一次回复里怎么想和怎么做”。长任务还需要回答三件事:什么时候继续,什么时候停止,什么时候需要重新提醒模型。QwenPaw 把这层称为 Loop Engineering,用 StopGate 把判断从主循环中抽出来。

从运行尺度看,系统里至少有三层循环:一轮模型和工具交替的 ReAct 循环,一次用户请求可能触发的多轮回复,以及跨会话持续数小时或数天的目标循环。把这三层都塞进 _reply_impl,会让预算、完成状态和会话恢复互相缠绕。StopGate 管的是 ReAct 之外的循环控制。

一个 gate 返回三种动作:

  • BYPASS:这个 gate 不表态,交给其他 gate 判断。
  • TERMINATE:立即结束当前循环。
  • INTERRUPT_AND_CONTINUE:注入提示,开始下一轮。

三值设计比“停/不停”的二值接口更适合组合。预算 gate 可以负责刹车,完成 gate 可以负责确认,任务提醒 gate 可以负责注入提示;它们互相不必知道实现细节。优先级用于保证预算、超时和死循环等安全条件能够覆盖质量判断。

调度时,TERMINATE 可以立即短路;INTERRUPT_AND_CONTINUE 只记录继续意图,还要允许后面的安全 gate 覆盖它。否则一个“任务尚未完成”的判断可能压过“预算已经耗尽”,循环仍会继续。可组合不等于所有决定平权,资源上限必须拥有最终刹车权。

常见 gate 可以按目的分成三组:

  • 资源限制:迭代次数、token、工具调用次数和超时,防止任务无限消耗资源。
  • 失败检测:记录 (tool_name, args_hash) 序列,识别同一工具和参数被反复调用的死亡循环;先提醒,持续命中再终止。
  • 完成判断:工具调用、完成信号或外部文件三种协议。工具调用最确定,信号最灵活,文件协议最容易被外部系统审计。

这些 gate 组合成不同工作模式。默认模式负责普通对话,Coding 模式主要替换工具和提示,Mission 模式用文件状态跟踪项目进度,Goal 模式用显式的目标更新判断长期任务是否完成。用户还可以通过配置声明 gate 及其参数,编译器负责校验互斥关系和未知字段。

三种完成协议的区别值得单独列出:

协议判断依据优点风险
工具调用模型显式调用完成工具状态结构化,容易审计模型可能漏调或过早调用
信号字符串输出约定信号接入简单,适合轻任务容易受自然语言输出干扰
外部文件读取任务文件中的状态可持久化,便于外部验证需要维护额外状态契约

文件协议并不天然比工具调用“更正确”,只是事实来源在模型输出之外。真正可靠的完成判断还要连接测试、审批或其他可验证条件。

这里的工程判断很明确:任务完成没有一个通用答案。框架只提供循环和状态接口,产品按场景选择协议;真正需要统一的是停止条件的可观测性和可恢复性。

四、上下文管理:摘要和 Scroll 的取舍#

上下文窗口有限,框架默认的办法是摘要压缩:到达阈值后,把旧消息交给模型生成摘要,再用摘要替换原文。它简单、便宜,但原始内容一旦被替换,就无法精确回溯。

QwenPaw 的 Scroll Context 选择保留原始记录。它可以拆成三个动作:

  1. 直写:每轮消息进入活动上下文时,同步写入 SQLite 历史表,并分配全局序号。
  2. 驱逐:窗口接近上限时,把中间轮次移出活动上下文,留下带序号范围的分层索引。
  3. 召回:模型通过 recall_history 按序号、关键词或工具调用 ID 取回原始轮次,结果只注入当前轮。

下面的图只强调一件事:驱逐不会删除历史,索引保存的是可定位地址。

flowchart LR window[活动上下文] -->|同步直写| history[(history.db 原始轮次)] window -->|超限驱逐| index[分层索引地图] history ---|全局 seq| index index --> recall[recall_history] recall -->|按需注入| window

直写失败时不能继续驱逐,否则索引可能指向不存在的序号。这是 Scroll 最关键的容错边界。它还需要排除召回工具自身的查询,避免搜索结果被自己的查询污染,并防止活动轮次产生回声。

Scroll 不是“更高级的摘要”,而是另一种存储模型:摘要用于快速保留任务状态,原始历史用于精确回溯。代价是 SQLite、索引进位、全文搜索和召回工具带来的复杂度。短对话客服通常不需要这套机制;需要跨周或跨月工作的个人助手,才值得为可逆性付出成本。

索引地图本身也会增长,因此 Scroll 使用分层折叠:低层保存近期条目的标题和序号范围,达到容量后再向高层合并。活动窗口只保留近期尾部、当前轮和归档地图。模型先看地图,再决定是否付出一次工具调用去展开原文。

这套设计把“记得全部”和“每轮都看全部”分开了。数据库保存全部并不意味着模型拥有全部;召回质量仍取决于标题、关键词和模型是否意识到需要查询。Scroll 解决的是信息可逆性,不自动解决检索召回率。

QwenPaw 还提供视觉压缩。它在模型调用前把旧文本渲染成图片,减少本次请求的 token,但不改变持久化消息,也不删除原生媒体。这种压缩和 Scroll 互相独立:前者优化单次请求的表示,后者管理长期历史。

ReMe 则位于更高一层:它把对话和资源蒸馏为可读、可编辑、可搜索的 Markdown 笔记。活动上下文、逐字历史、长期知识分别解决“现在要看什么”“过去发生了什么”“长期应该记住什么”,不应混成一个检索库。

记忆层保存内容主要用途
活动上下文近期消息、索引、当前任务状态支撑下一轮推理
原始历史完整消息和工具结果精确回溯、审计
长期知识偏好、决策、项目事实等蒸馏笔记跨会话复用

动态状态还有一个容易忽略的问题:当前时间、未完成任务和上下文余量会变化,不适合不断改写系统提示。AgentScope 的 HintBlock 可以把这些信息作为独立内容块注入,在保持系统提示前缀稳定的同时,让模型感知运行时变化。提示块跟随完整消息持久化,压缩后如果任务痕迹消失,再由运行时重新注入。

五、协议和渠道:把外部世界接进来#

模型协议和工具协议都在变化,产品不能把上层逻辑绑定到某一家 API。AgentScope 通过 Msg 和 formatter 隔离模型差异;QwenPaw 的 drivers 层则把本地函数和 MCP、A2A、ACP 等外部能力收敛到统一的驱动接口。每次调用仍需经过策略检查,凭证独立存储,协议适配不应绕过权限边界。

所谓“协议中立”不是假装所有协议都相同。adapter 只能统一发现、调用、取消和错误等公共能力;流式语义、鉴权方式和远程状态仍然可能不同。上层依赖最小公共契约,协议特性留在 adapter 内部,才不会为了追求统一而丢失必要能力。

渠道层面对的是另一类异质性:飞书、钉钉、Discord 等消息格式、媒体能力和回调方式各不相同。QwenPaw 的 BaseChannel 负责接收、归一化和渲染,ChannelManager 让一个工作区服务多个渠道。渠道差异停留在两端,中间的运行时只处理统一请求和统一回复。

入队前使用原生消息结构而不是最终的 AgentRequest,有两个好处:可以在归一化前做防抖合并,也可以保留渠道特有元数据。队列按 (channel_id, session_id, priority) 切分,同一会话严格串行,不同会话并行;/stop 等控制命令走高优先级路径,不能被普通任务堵住。

访问控制至少要区分显示名称和稳定的发送者 ID。显示名称会变化,也可能在群聊中复用;白名单、黑名单和待审批列表应绑定稳定 ID,并按渠道隔离。被动消息、外部事件和定时任务最终都汇聚到同一运行入口,才能共享鉴权、幂等和会话恢复逻辑。

定时任务还需要会话选择:复用用户会话可以保留历史,隔离会话可以避免历史污染。一个实用做法是执行前快照并清空活动上下文,任务结束后恢复并追加结果。它把“干净执行”和“持续记录”分开处理。

渠道渲染是归一化的逆过程。文本、工具状态和媒体先变成内部内容块,再根据渠道是否支持 Markdown、代码块、消息更新和文件上传选择输出方式。不能流式更新的渠道等待完整回复,能够更新消息的渠道消费文本增量。核心运行时不应因为某个渠道缺少富文本能力而出现另一套执行逻辑。

六、多 Agent:隔离比“多开几个循环”更重要#

当一个 agent 同时拥有搜索、编程、文档和浏览器能力时,工具描述和上下文都会膨胀。多 Agent 的价值不是把同一个循环复制几份,而是按职责隔离工具、提示、记忆和失败范围。

QwenPaw 的子 agent 通过本地 API 派生,拥有独立的会话和工作区。主 agent 拿到的是结构化工具结果,而不是把子 agent 的所有中间思考直接塞回主上下文。这样可以限制上下文污染,也方便对子任务设置并发和数量上限。

隔离也带来成本:派生需要装载状态,结果需要序列化,取消和超时要跨边界传播。如果父任务已经终止,子任务仍在后台运行,就会继续消耗模型和工具预算。因此派生协议至少要包含父任务 ID、子任务 ID、状态、取消信号和最终结果,而不只是一个“启动子 agent”的函数。

跨系统协作则通过 ACP 等协议完成。远端 agent 在本地看来仍是一种能力调用,但 adapter 不能成为权限旁路:调用者身份、目标能力、审批结果和错误都要被记录。跨系统调用的延迟和失败率也应纳入任务预算,而不是假设网络永远可靠。

框架提供 Msg 和基础多 Agent 能力,产品决定派生方式、结果协议和失败恢复。企业工作流可能更需要消息队列和持久化状态;个人助手更适合本机派生和少量远程协作。编排方式没有脱离场景的标准答案。

七、Agent OS:治理、沙箱和人在环中#

自主执行的风险不只来自恶意输入,也来自模型误解、工具副作用和第三方技能。QwenPaw 把治理拆成三个相互配合的部分:决策、执行隔离和供应链检查。

治理层可以输出四类结果:ALLOW、DENY、ASK 和 SANDBOX_FALLBACK。评估通常按类型检查、深度扫描、规则匹配、兜底处理的顺序进行。未知工具不能默认放行;敏感路径、危险 shell 模式和未命中的外部命令需要更保守的策略。STRICT、SMART、AUTO 等执行级别,是便利性和审批成本之间的旋钮。

下面的流程图用于区分“发现风险”和“做出决策”:扫描器只产生发现项,最终动作由规则、执行级别和工具类型共同决定。

flowchart TD call[工具调用] --> type{工具类型} type -->|未知| deny[拒绝] type -->|已注册| scan[敏感路径、危险模式、逃逸扫描] scan --> rule{规则命中?} rule -->|拒绝| deny rule -->|允许| strict{严格模式?} strict -->|是| ask[请求确认] strict -->|否| allow[执行] rule -->|未命中| fallback{是否适合沙箱?} fallback -->|是| sandbox[沙箱执行] fallback -->|否| ask

沙箱是执行层,不是权限判断的替代品。macOS 的 Seatbelt、Linux 的 Bubblewrap/Landlock 和 Windows 的 AppContainer 都只能限制一部分资源;网络、宿主机挂载、凭证注入和内核漏洞仍需单独评估。沙箱违规后可以让人决定是否重试,但模型不能自行把一次拒绝升级为无沙箱执行。

技能扫描解决的是供应链问题。技能是可加载的 Markdown 和脚本集合,应该在进入工作区前检查提示注入、硬编码密钥和外传行为;扫描结果至少要能区分阻止、警告和关闭扫描。规则自动泛化也要设置破坏性命令的硬上限,不能因为用户批准过一次 rm 就生成永久的宽泛放行规则。

技能和工具也要分开。技能主要告诉 agent“如何完成一类工作”,工具提供可执行能力。把所有技能全文永久塞进系统提示,会增加 token 并干扰工具选择;只暴露名称和短描述,需要时再加载正文,才具备扩展性。技能若携带脚本或循环逻辑,还要额外经过可执行内容的权限检查。

治理层与 drivers 层可能采用不同策略模型:本机工具关注文件、进程和 shell 副作用,远程驱动关注调用者、目标能力和凭证范围。风险模型不同可以解释规则差异,但不能让远程工具在框架权限层获得无条件放行。最终审计记录必须能还原到底是哪一层作出了允许决定。

凭证需要和工作区数据分离。API key 和 OAuth token 可以加密落盘,主密钥优先交给系统密钥链;无密钥链环境再回退到严格权限的文件。写入采用临时文件加原子替换,刷新 OAuth token 时也不能把半写状态留在磁盘。

人在环中有三种形态:等待用户确认工具调用、等待外部系统返回结果、接受用户中断。三者都必须有明确的挂起 ID 和恢复状态。中断工具调用时,要补齐未完成的工具结果,保证下一轮上下文仍然闭合。模型失败可以重试或切换备用模型,但重试次数必须有单一的责任边界,避免包装层和模型层叠加重试。

确认不一定只是“允许/拒绝”。用户可以修改工具参数后再批准,恢复时执行修改后的调用。外部执行也不是普通回调:Agent 状态必须记录自己正在等待哪个调用,收到不匹配的结果应直接报错。挂起和恢复严格配对,才能避免把 A 工具的确认错误地用在 B 工具上。

八、从原型到生产:状态、观测和恢复#

生产化最容易被低估的是状态。一个 QwenPaw 工作区至少包含活动上下文、逐字历史、长期记忆、会话进度、工作区文件和凭证。它们的生命周期不同,不能因为“都叫状态”就共用一种存储。

一个更可靠的拆分如下:

状态适合的存储生产要求
活动上下文运行时内存可重建,不作为唯一事实来源
原始对话SQLite 或其他数据库追加写、可查询、可备份
长期记忆Markdown/知识库可编辑、可审计、可回滚
会话进度按会话的持久化记录恢复时不能串会话
工作区文件独立数据卷路径限制、快照、回滚
凭证密钥链或加密文件最小权限、原子写入、轮换

部署时把数据、密钥和备份分卷,重启时按会话 ID 恢复。长任务还需要 checkpoint:记录工作区的可恢复版本,并拒绝任何越过工作区根目录的路径。恢复不仅要恢复文件,还要恢复任务处于“已完成、进行中还是待确认”的状态。

QwenPaw 的容器部署把工作数据、密钥和备份放在不同卷中,这不是目录整理问题,而是权限和恢复策略不同:数据需要频繁读写,密钥需要更严格的访问控制,备份应避免和在线写入共享同一故障域。恢复演练要覆盖数据库、文件和凭证,而不能只验证容器能重新启动。

一次请求在产品运行时还有比 ReAct 更外层的生命周期:分发前归一化,构建 agent 前加载会话,执行前刷新提示和任务状态,回复后保存会话,最终阶段完成清理。trace 应包住整个生命周期;只在模型调用附近打点,会漏掉排队、状态加载、权限等待和持久化失败。

可观测性至少要覆盖三条线:trace 回答“执行了什么”,成本统计回答“用了多少”,评估回答“结果是否满足目标”。AgentScope 的事件流可以作为数据源,QwenPaw 再把它接入 Langfuse 等平台。平台可以替换,事件字段、会话 ID、工具调用 ID 和错误原因不能缺。

不要把评估等同于模型打分。文件协议和目标状态适合机器检查,主观质量仍需要人工抽查 trace。没有错误预算、停止原因和恢复记录,单纯记录 token 数并不能说明系统可靠。

同样,流式界面不能代替可观测性。用户看到“正在执行工具”,开发者仍需要知道工具参数是否通过校验、等待审批多久、重试了几次以及最终写入了哪些状态。前者改善交互反馈,后者支撑排错和治理。

九、这些设计为何适合个人助手#

QwenPaw 的“重量”来自五个场景约束:长期工作、跨渠道使用、自主执行、本地数据和持续在线。长期工作需要可召回的原始历史;跨渠道使用需要统一入口和会话隔离;自主执行需要治理和沙箱;本地数据需要凭证隔离与本地模型选项;持续在线需要持久化、定时调度和恢复。

去掉其中任何一项,系统都可以变轻。短对话的 RAG 问答不需要 Scroll,单渠道机器人不需要多渠道队列,只读工具不需要完整的本机沙箱,无状态任务也不需要 checkpoint。选型时先判断场景,再决定要不要承担这些机制的复杂度。

这也解释了框架和产品的边界:ReAct、消息块、formatter、中间件和事件流是跨产品的骨架;Scroll、具体 gate、渠道、技能市场和治理规则是产品策略。通用能力应沉到框架,场景判断应留在产品。过早把后者抽象进框架,往往会把尚未验证的假设变成所有用户的约束。

十、结语:把取舍写进系统#

从 AgentScope 到 QwenPaw,真正值得复用的不是某个类名或默认参数,而是几条边界:

  • 把消息表示和模型方言分开,换模型不改循环。
  • 把循环控制和 ReAct 核心分开,停止条件可以组合、审计和恢复。
  • 把活动上下文、原始历史和长期知识分开,明确哪些信息可丢、哪些必须可召回。
  • 把渠道适配和会话处理分开,让外部协议变化不影响内部状态。
  • 把权限判断、执行隔离和技能供应链检查分开,任何一层都不能成为另一层的旁路。
  • 把状态、观测和恢复当成产品能力,而不是上线前的补丁。

框架的价值是把这些边界做成稳定的接口;产品的价值是根据真实场景填入策略。一个能跑的 demo 和一套敢托付的系统之间,差的不是更多工具,而是这些取舍有没有被明确地写进代码、状态和运行流程里。

本文是源码设计拆解,不是性能评测。Scroll 的召回开销、沙箱的具体成本、本地模型的任务成功率和插件生态质量,都需要在目标环境中实测;源码只能告诉你系统选择了什么,以及它为这些选择承担了哪些复杂度。

支持与分享

如果这篇文章对你有帮助,欢迎支持作者或分享给更多人

赞助
从框架到产品:拆解一个 Agent 操作系统是怎么长出来的
https://blog.souloss.cn/posts/ai/agent/agent-os-from-framework-to-product/
作者
Tsukimi
发布于
2026-08-04
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时