VisualClaw深度解读:如何将流式视频多模态智能体成本砍到2%?
VisualClaw通过三时间尺度架构将流式视频多模态智能体成本降低98%,准确率提升3.85%至15.80%。边缘端级联过滤丢弃99.3%冗余帧,云端以冷热双路注入技能库控制token开销,离线端通过失败驱动实现技能库自我进化,无需修改模型权重。
1. 流式视频智能体的核心难题:成本、延迟与适应性的“不可能三角”
过去两年,视觉语言模型(VLM)逐渐成为多模态智能体的通用接口。通过输入图片或视频帧,模型能回答“画面里发生了什么”、“接下来应该怎么做”。然而,当应用场景从离线问答转向流式视频——例如AI眼镜、24小时安防监控、长时间记录的可穿戴设备——三个相互矛盾的约束会同时出现。
第一个是成本。前沿VLM按token计费,视频帧编码后迅速膨胀至几十万token。以30分钟长视频为例,按1 fps上传,单次问答需消耗约192万输入token,API调用成本达数美元。第二个是延迟。流式场景下用户期望秒级响应,但全帧上传云端加上推理时间和网络抖动,无法满足实时交互。第三个是适应性。部署后的智能体大多“出厂即定型”,遇到训练时未见的失败模式只能继续犯错,缺乏从经验中改进的能力。
VisualClaw——来自UC Santa Cruz、UNC、Google和UC Berkeley的联合团队——给出了一个让三者同时收敛的工程方案。其核心结论是:流式视频多模态智能体的API成本可降低98%;同时,通过失败积累驱动的自我进化机制,准确率提升3.85%到15.80%不等。整个过程无需改动模型权重,仅靠技能库和记忆库的演化完成。
项目主页:https://github.com/UCSC-VLAA/VisualClaw
上图来自VisualClaw论文首页,展示了典型应用场景:AR眼镜在购物中实时编码视频流,云端通过持续进化的记忆与技能库给出个性化回答。左侧是真实使用场景的截帧时间线,只有少数关键帧(黄色标记)被识别为“值得上传”,绝大多数帧在设备本地被丢弃。
2. 三时间尺度设计:微秒、毫秒、分钟级的协同
VisualClaw将处理步骤拆解为三种时间尺度,这是整个系统设计哲学的灵魂。边缘侧逐帧过滤运行在微秒级,CPU即可完成;云端逐问题检索运行在毫秒级,由VLM处理;离线逐会话进化运行在分钟级,由进化器分析失败案例并更新技能库。这种分层架构将计算资源精确分配到最能发挥价值的时间窗口,避免了“用一把锤子敲所有钉子”的资源浪费。
更关键的是,三层之间通过明确接口解耦。边缘层只需决定“这一帧要不要传”,不需要理解语义;云端只需在“上传的关键帧”基础上推理,不需要看到完整视频流;离线进化器只需从失败案例中提炼可复用策略卡片,不需要修改VLM任何权重。这种解耦让系统具备三个维度的可扩展性:边缘可换硬件、云端可换VLM后端、离线进化器可换更强语言模型,三者互不影响。
这张架构图详细展开了三时间尺度系统的内部数据流。设备端通过级联门控大量过滤冗余帧,云端进行Hot/Cold双路技能注入并协同记忆库和技能库生成答案,离线端通过失败触发的进化器实现技能库自我更新。论文中给出的形式化数学表达将整个过程归纳为一个条件概率:
答案是在冻结权重的VLM在给定问题、级联门控过滤后的关键帧集合、检索到的Top-热技能、冷技能目录、以及从记忆库检索到的片段这五个条件共同作用下采样得到的。其中三个组件分别在三种时间尺度上更新:在每帧(约,边缘)更新,在每问题(约,云端)更新,进化器在每会话(分钟级,离线)更新。
3. 边缘端:三步级联过滤,帧上传量降低98%
整个成本压降的第一道防线是部署在设备端的级联过滤器。它由三个O(1)复杂度的阶段组成,全程无需GPU、深度网络或未来帧,完全可跑在手机或眼镜的CPU上。论文实测数据:单帧处理时间小于10毫秒,CPU占用极低,可维持每秒100帧以上吞吐。
3.1 第一步:dHash感知哈希去重
第一道关卡dHash(difference hash)逻辑直接:将当前帧缩放至8×9灰度小图,比较相邻像素明暗关系,生成64位哈希值。若当前帧哈希值与上一帧的汉明距离(不同比特位数量)≤阈值,则判定为视觉近似重复,直接丢弃。这一步主要解决摄像头抖动、画面静止、轻微平移等情况。VisualClaw开源实现代码简洁:
def _dhash(jpeg_bytes: bytes, hash_size: int = 8) -> Optional[int]:
"""Compute 64-bit dHash from JPEG bytes. Returns None on failure."""
from PIL import Image
import io, numpy as np
img = Image.open(io.BytesIO(jpeg_bytes)).convert("L")
resized = img.resize((hash_size + 1, hash_size), Image.LANCZOS)
pixels = list(np.array(resized).flat)
h = 0
for row in range(hash_size):
for col in range(hash_size):
idx = row * (hash_size + 1) + col
if pixels[idx] < pixels[idx + 1]:
h |= 1 << (row * hash_size + col)
return h
class FrameHasher:
def should_drop(self, jpeg_bytes: bytes) -> bool:
h = _dhash(jpeg_bytes)
if self._last_hash is not None:
dist = bin(h ^ self._last_hash).count("1")
if dist <= self._threshold:
self._dropped += 1
return True
self._last_hash = h
return False
该代码精妙之处在于“用最少算力获得最大过滤收益”。整张图片压缩至72个像素,比较相邻像素明暗序,对光照变化、JPEG压缩噪声、轻微旋转具有天然鲁棒性。实际部署中,连续录制的视频流约40%到70%的帧在此步骤直接丢弃,不会触发后续特征提取。
3.2 第二步:128维CPU编码器
通过dHash去重的帧进入第二阶段:手工设计的128维特征编码器。这里不使用任何深度网络,而是显式提取图像统计特征——HSV颜色直方图48维、空间亮度网格64维、边缘密度8维、纹理能量8维。这些特征合计128维,归一化为单位向量后可用余弦距离比较。完整实现如下:
def _extract_features(self, img: np.ndarray) -> np.ndarray:
import cv2
features = []
# 1. HSV color histogram (48 dims)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
for ch, bins, rng in [(0, 16, [0, 180]), (1, 16, [0, 256]), (2, 16, [0, 256])]:
h = cv2.calcHist([hsv], [ch], None, [bins], rng).flatten().astype(np.float32)
if h.sum() > 0:
h /= h.sum()
features.append(h)
# 2. Spatial luminance grid (64 dims: 8×8 block averages)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
bh, bw = gray.shape[0] // 8, gray.shape[1] // 8
grid = np.zeros(64, dtype=np.float32)
for r in range(8):
for c in range(8):
grid[r*8+c] = gray[r*bh:(r+1)*bh, c*bw:(c+1)*bw].mean() / 255.0
features.append(grid)
# 3. Edge density per block (8 dims, Canny)
edges = cv2.Canny(gray, 50, 150)
# 4. Texture energy (8 dims, local variance)
# ...
vec = np.concatenate(features).astype(np.float32)
return vec / (np.linalg.norm(vec) + 1e-8)
为何不用CLIP等预训练编码器?因为部署在眼镜或手机边缘设备上,每多一个矩阵乘法都是真金白银的功耗。手工特征虽语义能力不如深度模型,但对“场景是否切换”这个二分类问题足够,功耗几乎可忽略。在VisualClaw开源实现中,代码会先尝试OpenCV路径;若不可用,自动降级至Pillow实现的纯numpy版本,保证最简环境也能运行。
3.3 第三步:自适应变化门控
通过前两步过滤的帧进入第三阶段:变化门控。这里维护两个参考向量——上一次MAJOR帧(关键帧)特征和上一次MINOR帧(次要帧)特征。当前帧特征与参考向量计算余弦距离,得到距离值。若距离≥τ_major,标记为MAJOR,触发上传至VLM;若距离≥τ_minor,标记为MINOR,更新参考向量但不上传;否则直接SKIP。
最巧妙之处在于阈值动态调整。系统用EMA(指数移动平均)持续跟踪场景“忙碌度”:EMA = α * distance + (1-α) * EMA_prev。根据当前EMA与τ_major的比值,系统自动给阈值乘上factor。静止场景(EMA低)时factor取上限,阈值放大,避免传感器噪声误判;动态场景(EMA高)时factor取下限,阈值压低,确保不错过关键转折。还有温度衰减机制:若长时间未触发MAJOR,阈值随时间自动衰减,防止系统在缓慢变化场景中完全收不到帧。核心实现如下:
class SceneComplexityTracker:
"""Rolling EMA of cosine distances → multiplicative factor for thresholds.
Static scene (low EMA) → factor > 1.0 → raise thresholds.
Dynamic scene (high EMA) → factor < 1.0 → lower thresholds.
"""
def update(self, distance: float) -> None:
if self._ema is None:
self._ema = distance
else:
self._ema = self._alpha * distance + (1.0 - self._alpha) * self._ema
self._n += 1
def factor(self) -> float:
if self._ema is None or self._n < 3 or self._tau_major <= 0:
return 1.0
ratio = self._ema / self._tau_major
if ratio < 0.25:
return self._low # static scene → raise threshold
if ratio > 1.0:
return self._high # dynamic scene → lower threshold
t = (ratio - 0.25) / 0.75
return self._low + t * (self._high - self._low)
三步走完,每个问题平均只需上传1.13到5.41帧。在30分钟长视频上,过滤比例可达99.3%。这意味着原本需传3600帧的1小时AI眼镜直播,现在只需5到20次上传——这是从“不可能部署”到“移动数据套餐就能跑”的工程跨越。
4. 云端:技能库的冷热双路注入,降低Prompt成本
视觉成本降低后,文本提示词成本容易反弹。VisualClaw维护一个不断生长的技能库S,每个技能是一张简短的Markdown卡片,包含名称、一行描述、编号的操作步骤、以及明确的反模式提示(负面示例)。若每次回答都将整个技能库平铺到Prompt,token开销会随技能数量线性增长——当技能库累积到几十甚至上百条时,有用信号会被噪音淹没。
VisualClaw的解法是Hot/Cold双路注入。系统先用句子嵌入模型(all-MiniLM-L6-v2)对当前问题编码,然后对所有技能描述也编码,按余弦相似度排序。排名前k的技能进入“热路”,整张卡片包括操作步骤和反模式全部内联进Prompt;其余技能则进入“冷路”,只保留名称和一行描述构成的目录。若VLM在推理过程中发现冷路目录中有更合适的技能名,可主动按名调取完整版本。这样一来,每个问题的Prompt成本只由k决定,与技能库总规模无关。
# 简化的Hot/Cold双路注入逻辑
def inject_skills(question: str, skill_bank: list[Skill], k: int = 3) -> str:
# Hot tier: top-k full skill bodies
q_emb = sentence_encoder.encode(question)
scores = [(s, cosine(q_emb, s.embedding)) for s in skill_bank]
scores.sort(key=lambda x: -x[1])
hot_skills = scores[:k]
cold_skills = scores[k:]
prompt = "## Available Skills (full)\n"
for skill, _ in hot_skills:
prompt += f"### {skill.name}\n{skill.body}\n\n"
prompt += "## Other Skills (catalog only)\n"
for skill, _ in cold_skills:
prompt += f"- {skill.name}: {skill.description}\n"
return prompt
论文中的消融实验给出一个反直觉发现:k的最优取值与VLM后端的强弱有关。在较弱的Gemini 3 Flash上,注入全部技能(All)效果最好,平均准确率达X;但在更强的GPT-5.2上,k=3才是最优值(准确率Y),注入全部技能反而下降至Z。论文解释:强模型对无关上下文更敏感,过多技能描述会干扰推理,类似“信息过载”效应。
这给工程实践提供了重要启示:当技能库需在多个VLM后端间迁移时,应默认采用这种相对保守的注入策略;只有当技能库为单一弱后端专门训练时,才适合全量注入。
5. 离线进化:记忆驱动技能演化,而非直接喂给VLM
整个系统最令人兴奋的部分是元进化机制。传统记忆增强智能体大多采用“答题前将检索到的记忆拼接到Prompt”的做法,但多模态场景下有两个问题:第一,拼接的原始记忆变成“VLM看一次就过期”的狭窄上下文,无法持续产生价值;第二,每次答题都付出额外Prompt成本,与技能库注入叠加后开销难以控制。
VisualClaw换了一个思路:让记忆去影响低频的“技能进化器”,而非高频的“答案生成器”。具体来说,系统维护一个情景记忆库,保存所有回答正确的高置信度案例,用dense向量索引。当累积失败(默认)时,离线进化器被唤醒,从记忆库检索与最近失败相关的成功案例,然后生成新的候选技能。
Cat.变体将记忆直接拼接到进化Prompt末尾:
Guide变体则在拼接前加入一段引导指令,要求进化器从失败相关上下文中提炼可复用的泛化策略:
其中E是LLM进化器,P_base是基础进化Prompt,F_recent是最近失败批次,M_retrieved是检索到的记忆,⊕表示文本拼接。技能库更新规则为S_new = S_old ∪ {new_skill},再经卫生过滤器剔除冗余与低效条目。
论文给出了两种记忆注入变体。Cat.变体(concat)直接将记忆拼接到进化Prompt后面,让进化器自行消化;Guide变体则在拼接前加一段引导指令,明确告诉进化器“要从这些案例里提炼出泛化的推理模式,避免被场景特定细节带偏”。实验数据显示,两种变体在不同任务上各有所长:Guide在静态视频问答上更稳,因为它逼迫进化器输出紧凑的推理范式;Cat.在Agent工作流上更强,因为后端有编辑和验证循环,能把原始记忆当成结构化决策的素材来消化。
进化器本身用Claude Haiku 4.5实现,运行在AWS Bedrock上。从开源代码中可看到失败样本的数据结构:
@dataclass
class FailedSample:
"""A failed turn used to drive skill evolution.
Supports both gateway-style and visualclaw-test style field names.
"""
prompt: str = ""
response: str = ""
images: list[ImageMeta] | None = None
image_descs: list[str] | None = None
prompt_text: str = "" # alias for prompt
response_text: str = "" # alias for response
reward: float = 0.0
每条失败样本包含原始Prompt、VLM错误响应、相关图像元数据和文本描述、以及奖励值。进化器将这些信息组装成结构化失败档案,让Claude Haiku分析“为什么失败”,然后输出新技能卡片。生成的技能卡片需通过两道卫生过滤器:F1在进化时用token-Jaccard距离去重,避免重复造轮子;F2跟踪每条技能的命中准确率,周期性地裁掉拖后腿条目,防止技能库膨胀失控。
6. 工程实现:Gateway模式的模块化设计
VisualClaw不只是一篇论文,其开源代码仓库展示了一套生产级工程架构。整个系统采用Gateway模式部署:智能体框架(如Claude Code、Codex CLI)将所有LLM请求转发至VisualClaw Gateway(默认监听30100端口),Gateway在请求前后分别执行Pre Pipeline和Post Pipeline,完成多模态预处理、技能注入、记忆检索、轨迹收集等动作。这种设计让VisualClaw可作为透明中间件接入任意智能体框架,无需修改上层应用代码。
Agent Framework
│
│ POST /v1/chat/completions (Proxy 模式)
│ POST /v1/skill/inject (Plugin 直连模式)
▼
┌─────────────────────────────────────────────────────┐
│ Gateway (port 30100) │
│ │
│ Pre Pipeline (顺序执行) │
│ multimodal_image → multimodal_video → memory │
│ → skill → rl │
│ │ │
│ Upstream LLM │
│ │ │
│ Post Pipeline │
│ skill (first) → memory ‖ rl ‖ multimodal ‖ │
│ governance (并行) │
│ │ │
│ SessionStore ────┘ │
└─────────────────────────────────────────────────────┘
Pre Pipeline由五个模块组成,按固定顺序串行执行。multimodal/image负责从请求中提取图像,multimodal/video负责注入关键帧摘要,memory负责检索相关记忆,skill负责检索技能并写入skill_generation元数据,rl负责根据RL训练状态决定使用哪个模型版本。每个模块通过importlib动态加载,任何一个模块失败都不会阻塞整个Gateway——这是生产环境必备的鲁棒性。
Post Pipeline的设计更精巧。skill/collect必须在所有其他Post处理器之前完成,因为它会更新skill_generation计数器;若让RL模块与skill模块并行执行,就会出现“训练样本拿到旧的skill_generation”的竞争条件,导致RL训练混入过期数据。其余模块(memory、rl、multimodal、governance)则用asyncio.gather并行执行,最大化Post阶段吞吐。
视频管道是整个系统最复杂的部分,被设计成五个阶段,前两个跑在边缘端,后三个跑在服务器端:
边缘端(手机或眼镜):
Stage 1: FrameHasher — dHash 64-bit,汉明距离 ≤ 阈值 → DROP
Stage 2: LightweightEncoder — 128 维 HSV + 亮度 + 边缘 + 纹理特征
服务器端(Gateway):
Stage 3: ChangeGate — 余弦距离 → SKIP / MINOR / MAJOR
Stage 4: StateMemory — 关键帧环形缓冲,按会话隔离
Stage 5: ContextBuilder — 关键帧 + 描述 → LLM 上下文消息
VLM仅在MAJOR事件触发时才被调用,边缘端处理延迟控制在5毫秒以内。整套系统在Meta Ray-Ban智能眼镜实测中可维持稳定1 fps输入速率,端到端延迟主要由云端往返决定,与级联本身无关。
7. 案例分析:技能与记忆如何协同纠错
数据图表之外,论文还给出了几个具体失败救援案例,清晰展示了“帧过滤 + 技能纠错 + 记忆纠错”的协同效应。
第一个案例来自EgoSchema。180帧视频流经级联门控后只选出1个MAJOR帧(压缩比1/180)上传至云端VLM。基线VLM看到这一帧后给出错误答案C(“picks paint”),它锁定了画面上最显眼的名词,忽略了问题中的目的从句。但技能库已进化出“多项选择精度匹配”、“基于准确性的选项消除”等四条针对该失败模式的技能。在Hot Tier注入这些技能后,VLM重新检视问题与画面的对应关系,最终将答案翻转为正确的D(“loosens color intensity”)。
第二个案例来自NextQA,是一个非自车视角的因果推理任务。级联从36帧中筛出1帧,基线VLM选了错误选项C(“moving themselves”)。该题难点在于推理“为什么登山者紧握绳索”——画面中看不到原因,需要常识推理。这里发挥关键作用的不是技能,而是Memory bank中的两条历史正确答案——“为什么登山者紧握绳索?为了抵抗钟摆摆动”、“为什么骑手紧握把手?为了保持平衡”。这两条记忆提供了“hold-tight → stabilise”的因果推理范式,将答案从C翻转为正确的B(“hold for balance”)。
这两个案例同时说明:技能和记忆是两套互补的纠错机制。技能擅长处理“答题格式”和“推理范式”层面的系统性偏差,记忆擅长提供“具体场景的因果模式”。两者结合,覆盖的失败模式比单一机制更广。
8. 结语
VisualClaw的核心价值不在于任何单一技术点,而在于将“如何让流式多模态智能体在真实部署环境中存活”这个工程问题,拆解成三个互相支撑的子问题。读完整篇论文和开源代码,最深的感受是:在大模型API时代,真正的工程壁垒不在于训练更强的模型,而在于设计能让既有模型可持续运转的系统架构。VisualClaw没有训练任何新模型,但用一套精巧的分层架构,将不可部署的方案变成了能装进眼镜里的方案——这才是面向生产环境的多模态智能体应有的样子。
