生成模型:Claude Opus 4.6 (anthropic/claude-opus-4-6) Token 消耗:输入 ~82k tokens,输出 ~9k tokens(本节)
当用户在聊天中发送一个 YouTube 链接,或者转发一段语音消息、一张照片,纯文本 Agent 是无法"看到"或"听到"这些内容的。OpenClaw 通过两个理解系统弥补这一鸿沟:链接理解(Link Understanding)将 URL 背后的内容提取为文本摘要,媒体理解(Media Understanding)将图片、音频、视频转换为文字描述或转录文本,最终将这些附加信息注入到消息上下文中,使 Agent 能够"理解"多媒体内容。
26.3.1 链接理解(src/link-understanding/)
链接理解模块是一个轻量级的管道,核心流程如下:
用户消息 → extractLinksFromMessage (URL 提取)
→ resolveScopeDecision (作用域检查)
→ runLinkEntries (CLI 工具链执行)
→ formatLinkUnderstandingBody (结果注入消息体)
extractLinksFromMessage 从用户消息中提取裸 URL(即非 Markdown 链接语法内的 URL):
// src/link-understanding/detect.ts
const MARKDOWN_LINK_RE = /\[[^\]]*]\((https?:\/\/\S+?)\)/gi;
const BARE_LINK_RE = /https?:\/\/\S+/gi;
export function extractLinksFromMessage(message: string, opts?: { maxLinks?: number }): string[] {
// 1. 先移除 Markdown 链接 [text](url),避免重复提取
const sanitized = stripMarkdownLinks(message);
// 2. 用正则匹配所有裸 URL
const seen = new Set<string>(); // 去重
const results: string[] = [];
for (const match of sanitized.matchAll(BARE_LINK_RE)) {
if (!isAllowedUrl(match[0])) continue; // 过滤 127.0.0.1 等内部地址
if (seen.has(match[0])) continue;
results.push(match[0]);
if (results.length >= maxLinks) break; // 默认最多 3 个
}
return results;
}
设计要点:先去除 Markdown 链接语法的原因是,[点击这里](https://example.com) 中的 URL 是用户有意隐藏在文本背后的引用,不应被当作需要理解的独立链接;而 请看 https://example.com 中的裸 URL 才是用户希望 Agent 理解的内容。
链接理解不内置任何网页解析逻辑,而是通过配置的外部 CLI 工具来执行。每个工具条目(LinkModelConfig)定义了命令和参数模板:
runCliEntry 将 URL 注入模板变量 {{LinkUrl}},然后通过 runExec 执行子进程。模板引擎复用了第 10 章介绍的 applyTemplate 函数,支持消息上下文中的所有变量。
多个工具条目按顺序尝试(fallback 链):
链接理解复用了媒体理解模块的作用域系统(resolveMediaUnderstandingScope),支持按通道(channel)、聊天类型(chatType)、会话前缀(keyPrefix)来控制启用/禁用:
当 CLI 工具返回了链接内容摘要,applyLinkUnderstanding 将结果追加到消息体末尾:
这样 Agent 收到的消息变为:
媒体理解模块的规模和复杂度远超链接理解。它处理三种媒体能力:图像描述(image.description)、音频转录(audio.transcription)、视频描述(video.description),以及附带的文件内容提取。整体架构可以分为四层:
每个 Provider 可以实现一个或多个能力接口。例如 OpenAI 同时支持音频转录(Whisper API)和图像描述(GPT-4o Vision),而 Deepgram 只支持音频转录。
六个内置 Provider 在 providers/index.ts 中注册:
当用户没有在配置文件中显式指定媒体理解模型时,系统通过 resolveAutoEntries 自动发现可用的模型,搜索顺序为:
衍生解释 — Whisper
Whisper 是 OpenAI 开源的自动语音识别(ASR)模型,支持多语言转录和翻译。whisper-cli 是其 C++ 移植版(whisper.cpp),运行在本地 CPU 上无需 GPU。OpenClaw 优先探测本地 Whisper 安装,避免 API 调用开销。
一个巧妙的优化:当 Agent 使用的主模型(如 GPT-4o)本身支持视觉能力时,runCapability 会跳过图像描述——因为图像会直接作为多模态输入传递给主模型,无需额外的描述步骤:
MediaAttachmentCache 类缓存了每个附件的下载结果,避免同一附件被多个能力重复下载:
CLI 工具需要文件路径(getPath),API Provider 需要 Buffer(getBuffer)。缓存层统一处理了这两种访问模式,并在最后统一清理临时文件。
媒体理解涉及网络 I/O(下载附件、调用 API),耗时可能较长。runWithConcurrency 实现了一个简单但有效的工人池模型:
默认并发度为 2(DEFAULT_MEDIA_CONCURRENCY),确保图像、音频、视频三种能力最多有两个并发执行。
媒体理解通过规则链控制不同场景下的启用状态:
当使用 CLI 工具(如 whisper-cli、gemini、sherpa-onnx-offline)时,不同工具的输出格式各异。resolveCliOutput 实现了多策略的输出解析:
读取 {outputDir}/{basename}.txt 文件
从 JSON 标准输出中提取 response 字段
applyMediaUnderstanding 是整个模块的入口,编排了完整的媒体理解流程:
除图像/音频/视频外,用户发送的文本类附件(PDF、CSV、JSON、Markdown 等)通过 extractFileBlocks 提取内容。该函数的处理逻辑包含大量编码检测:
UTF-16 BOM 检测:通过字节序标记(BOM)识别 UTF-16LE/BE 编码
统计检测:对没有 BOM 的文件,通过统计零字节的奇偶位置分布推断 UTF-16 编码
Legacy 编码回退:对非 UTF-8 的西文文件,通过 CP1252 映射表解码(Windows 默认编码)
CSV/TSV 猜测:根据第一行的逗号和制表符数量推断分隔符格式
提取后的内容包装为 XML 块注入消息体:
文件名和 MIME 类型经过 XML 转义处理,防止属性值注入攻击。
每次媒体理解都会生成一个 MediaUnderstandingDecision 结构,记录每个附件尝试了哪些模型、成功/跳过/失败的原因。这些决策信息存储在消息上下文的 MediaUnderstandingDecisions 字段中,用于调试和监控:
链接理解从消息中提取裸 URL,通过可配置的 CLI 工具链获取内容摘要,并将结果追加到消息体中。
媒体理解支持图像描述、音频转录、视频描述三种能力,通过 Provider 接口层统一六个内置后端(Groq、OpenAI、Google、Anthropic、MiniMax、Deepgram)。
自动模型发现在无显式配置时,按优先级探测本地 CLI 工具和云端 API Key,选择最佳可用模型。
智能跳过在主模型已支持视觉时跳过图像描述,避免冗余处理。
附件缓存统一管理 Buffer 和文件路径的获取,CLI 和 API 两种消费模式共享下载结果。
作用域规则支持按通道、聊天类型、会话前缀三维度控制启用策略。
文件内容提取处理 PDF、CSV、文本等非媒体附件,包含 UTF-16、CP1252 等复杂编码检测。
决策追踪完整记录每次理解的模型选择、成功/失败原因,便于调试和监控。