InPage Agent Runtime 架构演进与 OpenMinis 借鉴 (InPage Agent Runtime Evolution from OpenMinis)
1. 背景与体系对比 (Background & Architectural Positioning)
在评估端侧/边缘自主智能体 (Edge & On-Device Autonomous Agent) 的运行时设计时,OpenMinis 与 InPage Agent 处于高度互补且面对相同核心痛点的生态位:
| 维度 | OpenMinis (Native App 端侧 Agent) | InPage Agent (纯前端 In-Browser Agent) |
|---|---|---|
| 宿主环境 | iOS (Swift / SwiftUI) + Android (Kotlin / Compose) | Web 浏览器 (Vite + TypeScript + 原生 Web API) |
| 沙箱模型 | iSH (ARM64 Linux 用户态模拟器) / PRoot Alpine Linux | 无重型沙箱;依托 Web Worker 隔离线程与页面主 Realm 执行原生 JS |
| 存储后端 | 宿主本地沙盒文件系统 + SQLite (GRDB) | 虚拟文件系统 (Virtual File System, VFS) 运行于 IndexedDB (idb) |
| 网关与网络 | 直连模型 Provider / 远端代理 | 轻量 Go 转发网关 (gateway/) 负责藏 Key、限流与请求体裁剪 |
| 共有核心约束 | 极端受限的运行资源、电池/内存红线、脆弱的长上下文与严格的容错需求 |
OpenMinis 经过多次生产迭代,在 src/ios/Agent 与 NativeOffloads 中沉淀了极为严密且兼顾工程可靠性的 Agent Runtime 机制。本文提炼其核心设计,并给出 InPage Agent 落地改造的具体建议。
2. 核心借鉴要点 (Key Architectural Patterns to Adopt)
2.1 截断写入保护 (Truncated Write Protection)
OpenMinis 实现:位于
AIChatViewModel+ConcurrentTools.swift:186-240。- 痛点:在流式生成(SSE)工具参数(JSON)过程中,一旦达到模型单次输出 Token 上限或网络突发中断,JSON 修复逻辑(如补齐
"或})能使 JSON 变为合法对象,但其实际参数(如content)已被腰斩。若继续执行file_write或file_edit,会将残缺的代码写入文件,造成静默破坏(Silent Corruption)。 防御方案:OpenMinis 在参数修复层标记
truncationRepairTag。当针对写操作类工具 (file_write/file_edit) 检测到该标记时,直接拒绝落盘写入,并向模型反馈结构化拦截提示:"Error: This call was NOT executed. Its argument stream was truncated in transit... Nothing was written to disk — the target file is unchanged. Re-issue this write in smaller pieces."
- 痛点:在流式生成(SSE)工具参数(JSON)过程中,一旦达到模型单次输出 Token 上限或网络突发中断,JSON 修复逻辑(如补齐
InPage Agent 落地建议:
- 在
app/src/agent/runtime.ts的runLoop中,对file_ops(write)、write_file、edit_file加入流完整性校验。如果流解析在字符串未闭合前强制中断结束,严禁调用 VFS 写入,并回填截断警告。
- 在
2.2 工具死循环检测与断路器 (Tool Loop Detection & Circuit Breaker)
OpenMinis 实现:位于
ToolLoopDetector.swift。建立四层环形检测策略(Sliding Window History):
unknown_tool_repeat:检测模型反复幻觉调用未声明的工具,达到阈值直接切断。global_circuit_breaker:连续产生无进展输出(No-progress outcomes)达到上限,全局熔断。known_poll_no_progress:针对轮询类工具设定双阈值(警告阈值与硬中断阈值)。generic_repeat:基于(toolName, argsHash, resultHash)的哈希比对,拦截完全重复的参数请求。
InPage Agent 落地建议:
- InPage Agent 目前仅依靠
maxTurns = 8硬上限兜底。当模型在browser_use(如不断重复点击失效的选择器)或file_ops(反复读取不存在的文件)中打转时,会迅速烧完所有步数。 - 引入轻量级
ToolLoopDetector类,记录最近 10 次调用的参数 SHA-256,出现连续 3 次相同调用与报错时,主动注入引导性拦截信息([LOOP BLOCKED]),迫使模型更换解决思路。
- InPage Agent 目前仅依靠
2.3 上下文分层策略与动态压缩 (Tiered Context Policy & Compaction)
OpenMinis 实现:位于
ContextPolicy.swift与AIChatViewModel+Compaction.swift。- 按模型的上下文窗口尺寸划分等级(
<32K、32K-64K、64K-128K、≥128K)。 - 发送前执行
checkContextBeforeSend:评估当前已消耗 Token,当逼近阈值时触发自动压缩。 - 核心保序与锚点机制:压缩不会简单截断,而是调用小模型生成上下文摘要生成
CompactMarker,同时严格保留最近 N 轮用户对话(compactKeepRecentUserTurns = 3) 作为推理锚点(Verbatim Anchors),使模型仍可获取最近精准的代码片段与指令。
- 按模型的上下文窗口尺寸划分等级(
InPage Agent 落地建议:
- InPage Agent 包含大体积的 DOM 骨干树提取(
browser_use: get_backbone)与长代码读写,直接透传全量messages极易突破 Go 网关的 2MB 请求上限 (GATEWAY_MAX_BYTES) 或模型窗口。 - 需引入上下文预算检测:超过阈值时,自动将前半段历史折叠为
<compact_summary>,仅保留系统提示词、工作区文件列表与最近 2-3 轮交互。
- InPage Agent 包含大体积的 DOM 骨干树提取(
2.4 请求预算与超限转存机制 (Request Budget & Spillover Offloading)
OpenMinis 实现:位于
AIChatViewModel+RequestBudget.swift。规定单次请求的最大媒体/文本预算(如 25MB)。当图像或工具输出超限时,优先剔除较早的项,并将原始数据写入磁盘持久化路径(如
/attachments/spillover/<sha1>),在消息历史中替换为占位符:[image elided to fit request budget. Original at /var/minis/... — re-fetch with read_image if needed]
InPage Agent 落地建议:
- 当
browser_use抓取超大页面 DOM、或者用户在文件树中打开大文件时,无需将上万行文本直接存进对话上下文。 - 将大文本存入 IndexedDB 临时缓存(
/.cache/spillover/),上下文仅保留简要摘要与路径引用。
- 当
2.5 保序并发工具调度 (Order-Preserving Concurrent Tool Execution)
OpenMinis 实现:位于
AIChatViewModel+ConcurrentTools.swift。- 当模型在单轮回复中吐出多个
tool_use时(例如并发读取 3 个文件),使用TaskGroup启动并发执行,最大并发度限制为 10。 - 严格保序:收集结果后,按模型原始下发的工具调用索引重新排序装配,完全符合 OpenAI / Anthropic 规范对
tool_result顺序与tool_use严格一致的强要求。
- 当模型在单轮回复中吐出多个
InPage Agent 落地建议:
- 目前 InPage Agent 使用
for (const item of assistantMsg.toolDetails)串行await。 - 对于只读工具(
read_file,list_files, DOM 信息感知),可通过Promise.all并行加速,显著降低移动端首字等待时间。
- 目前 InPage Agent 使用
2.6 多模型分组降级与容错重试 (Model Group Fallback & Auto-Retry)
OpenMinis 实现:位于
AIChatViewModel+Fallback.swift与ModelGroupRouter.swift。streamWithAutoRetry:遇到网络抖动或 5xx 错误时,按照[3, 5, 10, 15, 30]秒退避重试,界面展示倒计时,允许用户手动跳过或中止。streamWithGroupFallback:在遇到 429 速率限制、余额耗尽或不可恢复的鉴权错误时,自动平滑降级至同组备选模型(例如 DeepSeek 故障时自动转接到备用 Provider)。
InPage Agent 落地建议:
- 目前 InPage Agent 一旦出错直接终止并呈现红字。增加轻量重试机制及 Provider 故障自动降级切换(如 Primary -> Backup),能极大提高可用性。
2.7 技能按需激活与元数据驻留 (On-Demand Skill Loading)
OpenMinis 实现:位于
SkillStore.swift。- 上下文中仅保留技能的元数据(名称、触发条件、摘要),当判定需要该技能时,再按需载入
SKILL.md正文及绑定的脚本资源。
- 上下文中仅保留技能的元数据(名称、触发条件、摘要),当判定需要该技能时,再按需载入
InPage Agent 落地建议:
- 目前 InPage Agent 将所有启用的技能正文全量拼接到
developerPrompt中,随着用户自定义技能增加,开销急剧上升。应改为只在 System Prompt 注入技能清单,模型通过调用内部动作或命中意图时才展开正文。
- 目前 InPage Agent 将所有启用的技能正文全量拼接到
2.8 浏览器生命周期与运行防冻 (Host Lifecycle Awareness)
- OpenMinis 实现:调用 iOS 系统后台任务接口
beginBackgroundTask,防止应用切到后台瞬间网络与进程被杀。 InPage Agent 落地建议:
- 针对移动端 Web 浏览器,利用 Screen Wake Lock API (
navigator.wakeLock.request('screen')) 在 Agent 执行任务流期间阻止手机休眠息屏。 - 监听
document.addEventListener('visibilitychange'),在切回前台时校验 SSE 流连接状态并进行断点续接。
- 针对移动端 Web 浏览器,利用 Screen Wake Lock API (
3. InPage Agent 改造实施路线图 (Implementation Roadmap)
第一优先级(防御性鲁棒性):
- 移植
ToolLoopDetector:拦截重复工具调用与不存在路径死循环。 - 增加截断写入拦截:防止流式异常造成 VFS 源码损坏。
- 移植
第二优先级(性能与吞吐):
- 并发工具调用(
Promise.all保序派发)。 - 上下文滑动窗口与超限压缩(Token Budgeting & Compaction)。
- 并发工具调用(
第三优先级(多模型与移动端体验):
- 网络错误指数退避重试(带倒计时 UI)。
- Provider 故障降级链。
- Screen Wake Lock 屏幕常亮保护。
本文归档于个人知识库 · 领域:CS & AI · 模块:04 Project_CS_AI/AI apps