来源说明:产品定位引自官方站点与技术介绍;实现机制全部来自对本机 ~/.marvis/ 的实测(目录、SQLite schema、表行数、统计分布)。 实测数据采集于 2026-10-27,反映的是"这台机器上真实跑出来"的形态,可能与官方白皮书表述有出入 —— 出入处我以实测为准并标注。


1. 定位:操作系统级的"手",不是"笔"

WorkBuddy 的落点是交付物(文档、表格、代码)。Marvis 的落点是操作本身(改系统设置、开软件、点网页、控制手机)。

这个差别决定了架构取向:

| | WorkBuddy | Marvis |
|---|---|---|
| 隐喻 | 一个能干的同事,最后给你文件 | 一双手,直接替你点、改、装 |
| 执行半径 | 工作目录为主 | 文件系统 + 注册表 + 进程 + 应用 UI + 手机 App |
| 风险模型 | 怕改错文件 | 怕改坏系统 |
| 状态载体 | 项目文件夹(jsonl / md / zip) | 三个 SQLite 库(业务 / 记忆 / 主数据) |

官方两个模式:效率模式(端云协同)、本地模式(端侧模型,文件 0 上传)。本机实测 llm_token_usage.is_local 全为 0 —— 说明当前跑在效率模式。


2. 多 Agent:不是"临时派生",是"常设编制"

官方说法是 1 主 + 5 副。实测 agent_activities 表按 agent_name 分组的真实调用次数:

file-agent       330
computer-agent    16
app-agent          9
browser            8

(search 没有独立活动记录,可能并入主控或被合并;主控在工具归属里标为 main。)

关键区别在这里:WorkBuddy 的子 Agent 是一次任务里临时派生的,任务结束就没了;Marvis 的领域 Agent 是常设编制,各自拥有固定工具集。证据是 mcp_tool_index.owner_agents 字段:

yyb-toolkit / click_observe      owner_agents = ["app-agent"]    always_on = 1
game_info   / list_game_capabilities  owner_agents = ["main"]     always_on = 0
androws_mcp / adb_debug          owner_agents = ["app-agent"]    always_on = 1

即:Agent 的边界是由"挂哪些工具"定义的,不是由 prompt 里的一段角色描述定义的。工具归属一变,Agent 能力就变,不用改代码。


3. 工具层:167 个可调用项,靠向量检索挑

实测工具规模:

  • mcp_tool_index 78 个工具,分布在 9 个 MCP server:
  androws_mcp 19 · commerce 18 · yyb-toolkit 16 · marvis_capabilities 14
  knowledge_base 4 · coupon_activity 2 · game_info 2 · wintools 2 · MarvisMCP 1
  • skill_index 89 个技能,category 全部为 builtin(内置;skills/custom 与 skills/market 目录为空,用户没装第三方的)

合计 167 项,不可能全塞进 prompt。解法在表结构里:

mcp_tool_index: server, tool_name, source, name, description, parameter_desc,
                owner_agents, added_at, last_used_at, enabled, always_on,
                embed_text, version, indexed_version

三个字段说明了一切:

  1. embed_text —— 工具存在向量化文本,选工具走语义检索("我想把手机上的截图拉过来"能命中 adb_pull),不是关键词匹配。length(embed_text)=0 的(如 click_observe)是常驻工具,不需要被检索。
  2. always_on —— 白名单式常驻。高频且必须随手可用的工具不参与检索,直接进上下文。
  3. indexed_version / version —— 索引和工具定义各自带版本。工具描述改了要重新嵌入,这两个字段负责判断索引是否过期。

对比 WorkBuddy:那边用的是"关键词/精确名检索 → 取 schema → 调用"的两级懒加载,纯文本匹配;Marvis 这层是向量检索。前者确定性高、成本低;后者泛化好,但要维护嵌入索引和版本一致性。

能力几乎全部 MCP 化是 Marvis 最值得注意的架构选择。连"点应用宝界面"(yyb-toolkit/click_observe)、"adb 调试"(androws_mcp/adb_debug)、"改 Windows 设置"(wintools)都是 MCP 工具。好处是能力可插拔、可灰度、可单独开关(enabled 字段);代价是每条能力都多一层协议开销。


4. 事件流:2579 万行事件,UI 是"回放"出来的

data.db 有 12.4GB,主要来自一张表:

agui_events   行数 ≈ 25,790,649

字段:event_id, conversation_id, response_id, seq, event_type, data, metadata, timestamp

event_type 的实测分布(采样最近 3000 条):

REASONING_CONTENT      1396      TEXT_MESSAGE_CONTENT   1065
TOOL_CALL_ARGS          481      CUSTOM                   12
TEXT_MESSAGE_START        7      REASONING_END             7
REASONING_START           6      TEXT_MESSAGE_END          6
RUN_STARTED               4      HUMAN_MESSAGE             4
RUN_FINISHED              4      TOOL_CALL_RESULT          4
TOOL_CALL_END             2      TOOL_CALL_START           2

这是一套标准的 AG-UI 事件协议(Agent–User Interaction):RUN_STARTED → REASONING_ / TEXT_MESSAGE_ / TOOL_CALL_* → RUN_FINISHED,带 seq 序号。

架构含义有三层:

  1. UI 不是"等最终答案",而是订阅事件流逐帧渲染。 思考过程(REASONING_CONTENT)、正文流、工具调用参数生成(TOOL_CALL_ARGS)都能实时显示 —— 这就是"执行日志里能看到六个人分工"的实现基础。
  2. seq + 全量落库 = 可回放、可断线续传。 关掉客户端再打开,会话能恢复到逐条事件级,不是恢复到"最后一句话"。
  3. 代价是写放大约两个数量级:9.5 万条消息对应 2579 万条事件(约 272 倍)。这是用存储换体验的典型交易,必须配套归档/分区策略,否则单库无限膨胀(本机已经 12.4GB,WAL 还有 1.6GB)。

5. 人在环与可恢复:两张表撑起"敢让它动手"

approvals(审批) —— 1024 条,状态分布:

approved 790 · cancelled 6 · pending 2 · rejected 2

字段:approval_id, conversation_id, tool_call_id, tool_name, arguments, status, reason, metadata, created_at, decided_at

设计要点:审批是持久化实体,不是弹窗即弃。arguments 存了当时要执行的具体参数 —— 事后能回答"它当时想干什么、我批的是什么"。reason 让拒绝有据可查。约 1% 的消息会触发审批,说明分级做得比较克制:常规操作不问,只有越界才拦。

agent_checkpoints(61 万条…准确说是 60,644 条) —— 字段 conversation_id, response_id, checkpoint_data。

一个 response_id 一个检查点,意味着长任务中断后可从中途续跑,而不是从头再来。对"我要它连续装三个软件再配环境"这类任务,这是必备项。

对比 WorkBuddy:那边是 orderedRules 三类规则的事前拦截 + 哈希链审计 + 文件回滚;Marvis 是 approvals 事前确认 + checkpoints 事后续跑。前者偏"系统级策略",后者偏"交互级确认"。两者其实是互补的两套思路,谁也没覆盖对方。


6. 模型层:每个 Agent 一个模型别名 + 94% 缓存命中

llm_token_usage 字段(注意 is_local 这一列):

usage_date, conversation_id, response_id, model_id, is_local,
input_tokens, output_tokens, thinking_tokens, cached_tokens, total_tokens

实测分布(这是最能说明工程水位的表):

| model_id | 调用次数 | 输入 token | 输出 token | 缓存 token |
|---|---|---|---|---|
| file-auto | 24,303 | 1439.1M | 17.5M | 1351.3M |
| main-auto | 19,821 | 1074.0M | 11.8M | 996.4M |
| deepseek-v4-pro-external | 2,382 | 46.8M | 1.7M | 21.6M |
| venus-vision-llm | 1,245 | 1.1M | 0.3M | 0 |
| hy3-preview-agent-real | 1,238 | 11.1M | 0.1M | 1.1M |
| browser-auto | 1,136 | 61.9M | 0.4M | 59.4M |
| computer-auto | 691 | 29.4M | 0.5M | 27.7M |
| app-auto | 288 | 10.8M | 0.1M | 10.3M |

三个观察:

  1. -auto 后缀 = 路由别名,不是具体模型。file-auto / main-auto / browser-auto / computer-auto / app-auto 一一对应领域 Agent —— 每个 Agent 有自己的选型策略(简单判据用便宜模型,复杂规划切强模型)。这是"按角色分模型",比"全局一个模型"省得多。
  2. 缓存命中率 93–94%(1351/1439、996/1074)。这是硬指标:说明 prompt 前缀极其稳定 —— 系统提示、工具定义、历史前缀固定在前,只让末尾变化。前缀设计一旦抖动,这个数字会立刻掉下来。这是衡量 Agent 工程成熟度最直接的一个数。
  3. venus-vision-llm 缓存为 0 —— 视觉模型输入是截图,天然无法前缀复用。也反过来说明其他模型的缓存是"设计出来的",不是白捡的。

model_configs(business.db)显示支持 BYOK + 第三方模型:

deepseek-v4-flash      DeepSeek   https://api.deepseek.com/chat/...
GLM-5.3-Flash          智谱       https://open.bigmodel.cn/api/...

密钥处理是规范的:api_key_ciphertext(密文)+ salt + api_key_fingerprint + key_tail(只回显尾号)。没用明文列存 key。


7. 三个库的分工(这是与 WorkBuddy 最大的形态差异)

| 库 | 大小 | 表 | 职责 |
|---|---|---|---|
| business.db | 2.9 MB | 10 | 模型配置、会话-模型绑定、任务日统计、Office 行为埋点、schema 迁移 |
| memory.db | 570 MB | 6 | conversations / conversation_detail / memory_entries / user_profile / kv_store |
| data.db | 12.4 GB | 16 | 消息、事件流、活动、检查点、审批、工具索引、产物、token 计量、画像 |

为什么拆三个:写入频率与生命周期不同。事件流是高频写(2579 万行),业务统计是低频读(3MB),记忆是读多写少的长期资产。混在一个库里,一次 WAL checkpoint 就要拖动 12GB —— 拆开后各自独立 VACUUM / 归档。

memory_entries 的字段值得单独看:

memory_id, conversation_id, agent_name, uid, source, type,
title, summary, full, display_title, display_summary, display_full,
origin, status, metadata, created_at, updated_at,
last_accessed_at, accessed_times, migrated_from
  • 双层存储 summary / full:检索走摘要,命中才拉全文。
  • **display_ 三件套*:另存一份展示用版本 —— 说明"给模型看的"和"给人看的"是两套文本(可能是脱敏或格式化后的)。
  • accessed_times / last_accessed_at:记忆有热度,可做 LRU 淘汰。记忆库只增不减是常见坑,这两个字段是解药。
  • migrated_from:记忆格式迁移的溯源,说明这套记忆体系已经改过版。

user_personas 则是画像层:style / persona_keyword / scenario / hobby / raw_prompt / cloud_last_modified。cloud_last_modified 说明画像会跟云端同步 —— 这跟"文件 0 上传"的本地模式并不矛盾:画像同步的是偏好,不是文件内容。


8. 入口层:三个,且都不是屏幕模拟

浏览器扩展 + Native Messaging Host(这才是"Browser Agent"的真相)

AppData/Local/Marvis/nmh/ 下有:

com.marvis.extension.chrome.json
com.marvis.extension.edge.json
com.marvis.extension.qq_browser.json
com.marvis.extension.360_se.json
com.marvis.extension.360_speed.json
com.marvis.extension.json

Native Messaging Host 是浏览器官方支持的"扩展 ↔ 本地程序"通道。配合 marvis-browser-edge.json:

{ "port": 50315, "token": "...", "pid": 17564, "browser": "edge",
  "host_version": "0.1.0", "started_at_ms": ... }

即:本地起一个带 token 校验的端口,扩展连过来。取 DOM、执行点击都不需要看像素 —— 这就是官方说"不靠视觉看屏幕"的实现路径:能走协议就不走视觉。

手机远程:mobile_address.json 存 mobile_open_id / mobile_guid / session_id / access_token / login_type。手机通过 token 连本机,看执行画面并接管。

安全提醒(重要):mobile_address.json 和 marvis-browser-edge.json 里的 token 是明文落盘的。这两个文件等于"你电脑的遥控器"。异常场景(共享机器、备份上传网盘、恶意软件扫盘)下这是明确的风险面,比 WorkBuddy 那种纯本地会话文件敏感得多。建议自己确认下这两个文件的权限。

产物面:products 表 1223 条,按扩展名分布:

.exe 141 · .py 116 · .md 86 · .png 73 · .apk 53 · .pdf 40
.html 27 · .txt 26 · .kt 21 · .js 21

不只输出文档,还能产出可执行程序(.exe / .py / .js)、写 Kotlin(.kt)、下载安装 APK(.apk)。这解释了 12GB 库的体积,也说明它的执行面确实比"办公助手"大一圈。


9. 与 WorkBuddy 的架构对比(同一类产品,两种哲学)

| 维度 | WorkBuddy | Marvis |
|---|---|---|
| 核心抽象 | 项目 = 文件夹 | 会话 = 数据库行 |
| Agent 编制 | 单主循环 + 临时派生子 Agent | 常设主控 + 5 个固定领域 Agent |
| Agent 边界由什么定义 | prompt + 可用工具集 | owner_agents 字段(数据驱动) |
| 工具发现 | 关键词/精确名检索(确定性) | 向量检索 embed_text + always_on(语义) |
| 扩展方式 | 内置 + Skill + MCP + 专家包(四种) | 几乎全 MCP 化(一种) |
| UI 驱动 | 消息 + 产物双区 | AG-UI 事件流(2579 万条,可回放) |
| 事前控制 | orderedRules file/command/network 三类有序规则 | approvals 审批表(1% 消息触发) |
| 事后追溯 | 哈希链审计(prevHash→hash,防篡改) | 事件全量 + 检查点(可回放) |
| 撤销能力 | 会话级文件回滚 | 检查点续跑(不是回滚) |
| 模型策略 | 云端路由 + 本地 llama.cpp | 每 Agent 别名 + BYOK + is_local 双轨 |
| 状态规模 | 与项目大小同阶 | 单机 13GB 起 |

最本质的差异:WorkBuddy 把状态放在文件系统里(人类可读、可 git、可打包带走);Marvis 把状态放在数据库里(查询快、可统计、可回放,但不可读、不可移植)。

对应两种产品观:

  • 文件系统 → 产物导向,一切为了让用户拿到能用的文件
  • 数据库 → 过程导向,一切为了让执行可观测、可干预、可恢复

10. 这套方案的风险点(实测看到的问题)

  1. 单库 12.4GB + 1.6GB WAL:事件全量持久化的代价。没有分区归档的话,长期使用会撞上 SQLite 的实际管理上限(备份、VACUUM、迁移都会变成大工程)。
  2. token 明文落盘:mobile_address.json / marvis-browser-edge.json。这是设计上省了事、安全上留了口子。
  3. 能力半径过大:注册表编辑、进程管理、adb、装 APK。审批表能拦,但审批疲劳(790 次 approved)会让人逐渐无脑点"允许" —— 这是所有 HITL(人在环)系统的通病。
  4. is_local=0 全量:本地模式在本机没跑起来(官方门槛 ≥8GB 内存 / Apple Silicon M1)。端侧模型的实际体验仍是未知数。
  5. 事件模型对磁盘的持续压力:2579 万条 / 97 个会话 ≈ 每个会话 26 万条事件。会话数一多,写放大很可观。

11. 一句话总结

WorkBuddy 是"把活干完,文件给你";Marvis 是"把机器接管,过程给你看"。

前者靠文件系统 + 有序规则 + 哈希链审计,追求确定性交付;
后者靠多 Agent 编制 + 向量工具检索 + 事件溯源,追求可观测执行。

要抄的话:Marvis 的 owner_agents(工具归属定义 Agent 边界)和 embed_text(工具向量检索)值得直接借鉴 —— 前者让 Agent 编排变成数据配置,后者在工具过百时几乎必需。至于事件全量落库,先想清楚 12GB 之后怎么办再动手。