首页
/ UI-TARS Desktop 设置系统全解:VLM 接入、报告分享存储与 UTIO 遥测配置

UI-TARS Desktop 设置系统全解:VLM 接入、报告分享存储与 UTIO 遥测配置

2026-09-05 14:29:36作者:胡唯隽

本文基于 UI-TARS Desktop 归档的设置配置指南(docs/archive-1.0/setting.md),系统讲解桌面端设置系统中各配置项的作用、取值与默认值,并结合仓库源码剖析 Language、VLM 接入(Base URL / Model Name / Provider)、Report Storage Base URL 与 UTIO Base URL 四类设置的存储、校验与运行期调用链路。读完本文,你将能够独立完成 VLM 接入配置、自建报告存储服务器与 UTIO 事件接收服务器,并理解每个设置项在 Electron 主进程中的落地方式。

UI-TARS Desktop 主设置界面

设置系统的整体设计:ElectronStore + Zod 校验

UI-TARS Desktop 通过一套细粒度的设置系统控制应用行为。设置项的默认值与持久化逻辑集中在主进程的 setting.ts,其中 DEFAULT_SETTING 给出了全部默认值:

export const DEFAULT_SETTING: LocalStore = {
  language: 'en',
  vlmProvider: (env.vlmProvider as VLMProviderV2) || '',
  vlmBaseUrl: env.vlmBaseUrl || '',
  vlmApiKey: env.vlmApiKey || '',
  vlmModelName: env.vlmModelName || '',
  useResponsesApi: false,
  maxLoopCount: 100,
  loopIntervalInMs: 1000,
  searchEngineForBrowser: SearchEngineForSettings.GOOGLE,
  operator: Operator.LocalComputer,
  reportStorageBaseUrl: '',
  utioBaseUrl: '',
};

从源码结构看,设置采用 electron-storeui_tars.setting 文件名持久化,任何一项变化都会通过 BrowserWindow.getAllWindows() 向所有渲染进程窗口广播 setting-updated 事件,从而实现主/渲染进程间设置的实时同步。此外,SettingStore 还内置了 Preset(预置配置)导入能力:importPresetFromUrlimportPresetFromText 会先经 validatePreset 校验再整体写入,这为后续的预置管理提供了基础。

所有写入前都会经过 validate.ts 中的 Zod Schema 校验,关键约束包括:

配置项 Zod 校验规则 含义
vlmBaseUrl z.string().url() 必填,必须是合法 URL
vlmApiKey z.string().min(1) 必填,非空字符串
vlmModelName z.string().min(1) 必填,非空字符串
language z.enum(['zh', 'en']).optional() 可选,仅允许 zh/en
maxLoopCount z.number().min(25).max(200).optional() 可选,25~200
loopIntervalInMs z.number().min(0).max(3000).optional() 可选,0~3000ms
reportStorageBaseUrl z.string().url().optional() 可选,必须是合法 URL
utioBaseUrl z.string().url().optional() 可选,必须是合法 URL

这解释了设置界面中「URL 类配置项必须填合法 URL 才能保存」的行为:校验不通过时表单会阻止 updateSetting 落盘。

Language:只影响 VLM 输出,不影响应用界面语言

Language 控制视觉语言模型(VLM)输出内容的本地化语言。

属性 详情
Type string
Options en(English)、zh(Chinese)
Default en

注意:修改该设置只会影响 VLM 的输出语言,不会改变桌面应用自身的界面语言。从 validate.tsz.enum(['zh', 'en']).optional()setting.ts 的默认值 'en' 可以印证这一取值边界。

在渲染端的设置分类组件 chat.tsx 中,语言切换通过表单触发校验后调用 updateSetting({ ...settings, language: newLanguage }) 完成写入,随后经 SettingStoreonDidAnyChange 回调广播给各窗口。

VLM 接入配置:Base URL、Model Name 与 Provider

VLM Base URL

指定待请求的 VLM 服务的基础 URL。

属性 详情
Type string
Required true

VLM Base URL 必须是 OpenAI 兼容的 API 端点(OpenAI 兼容协议中支持 base64 编码图像的视觉接口)。

自部署 UI-TARS 模型时可参考归档的部署文档:其推荐方式为使用 vLLM(vllm>=0.6.1)启动 OpenAI 兼容服务,例如:

python -m vllm.entrypoints.openai.api_server --served-model-name ui-tars --model <path to your model>

服务起来后,将 VLM Base URL 指向该服务(如 http://localhost:8000/v1),即可在设置中接入自部署模型。Zod 层对 vlmBaseUrlz.string().url() 约束(见 validate.ts)保证只有合法 URL 才会被写入设置。

VLM Model Name

指定请求的模型名称。

属性 详情
Type string
Required true

校验规则为 z.string().min(1),即非空字符串即可;实际取值取决于你的 VLM 服务以什么名字对外提供模型(如上文 vLLM 命令中的 --served-model-name ui-tars)。

VLM Provider

选择为 GUI 动作决策提供后端能力的 VLM 供应商。

属性 详情
Type string
Options Hugging FacevLLM
Default Hugging Face

该选项是一个为不同 VLM 供应商预留的接口。

在 1.0 设置体系中,供应商枚举定义于 types.ts

export enum VlmProvider {
  // Ollama = 'ollama',
  Huggingface = 'Hugging Face',
  vLLM = 'vLLM',
}

可以推断,VlmProvider 保留了 1.0 文档所列的 Hugging FacevLLM 两个选项(Ollama 已被注释停用);而当前仓库中另有一个扩展的 VLMProviderV2 枚举,在默认值层面引入了更多云侧模型选项(如 Hugging Face for UI-TARS-1.5VolcEngine Ark for Doubao-1.5-UI-TARS 等)。对 1.0 设置文档所描述的版本而言,界面呈现的即为 Hugging FacevLLM 二选一。

Report Storage Base URL:从本地下载到云端报告链接

Report Storage Base URL 用于定义报告文件的上传地址。其核心行为分支在于:未配置时点击「Export as HTML」(即 Share)会自动触发报告文件的本地下载

未配置存储地址时下载报告

一旦配置了该地址,点击「Export as HTML」时报告文件会先上传到 Report Storage Server,服务端返回一个可公开访问的持久化 URL。

这一行为在渲染端 ShareOptions.tsx 中有完整实现:

  1. 生成报告 HTML(reportHTMLContent)后,若 settings?.reportStorageBaseUrl 非空,则调用 uploadReport(htmlContent, settings.reportStorageBaseUrl) 上传,成功后将返回的 url 复制到剪贴板并弹出 Report link copied to clipboard! 提示;
  2. 若未配置该地址或上传失败,则回退为创建 Blob、生成本地 <a download> 链接下载 report-YYYY-MM-DD-HH-mm-ss.html 文件。

也就是说,「下载回退」是源码中明确的兜底路径,上传成功与否(uploadSuccess 标志)直接决定是否走本地下载分支。

Report Storage Server 接口规范

Report Storage Server 应实现如下 HTTP API 端点:

属性 详情
Endpoint POST /your-storage-endpoint
Headers Content-Type: multipart/form-data

请求体

请求应以 multipart/form-data 发送,包含如下字段:

Field Type Required Description Constraints
file File Yes HTML report file 格式:HTML;最大大小:30MB

响应

成功响应(200 OK)

{
  "url": "https://example.com/reports/xxx.html"
}

响应必须返回一个包含报告可公开访问地址的 JSON 对象。

注意:Report Storage Server 目前未设计任何鉴权机制。如有此需求,建议向项目提交 issue 讨论。

对应地,Zod 层对 reportStorageBaseUrl 的约束是 z.string().url().optional()(见 validate.ts),即留空合法(走本地下载),填写则必须是合法 URL。

UTIO Base URL:应用洞察与观测的数据通道

UTIOUI-TARS Insights and Observation)是 UI-TARS Desktop 的遥测数据采集机制,其设计也与「分享」场景相关联。UTIO Base URL 定义了处理应用事件与指令的 UTIO 服务器基础地址。

UTIO 数据流

服务端接口规范

UTIO 服务器通过 HTTP POST 请求接收事件:

属性 详情
Endpoint POST /your-utio-endpoint
Headers Content-Type: application/json

事件类型

服务器需处理三种事件:

1. 应用启动(Application Launch)

interface AppLaunchedEvent {
  type: 'appLaunched';
  /** 平台类型 */
  platform: string;
  /** 操作系统版本,形如 "major.minor.patch" */
  osVersion: string;
  /** 屏幕宽度(像素) */
  screenWidth: number;
  /** 屏幕高度(像素) */
  screenHeight: number;
}

2. 发送指令(Send Instruction)

interface SendInstructionEvent {
  type: 'sendInstruction';
  /** 用户提交的指令内容 */
  instruction: string;
}

3. 分享报告(Share Report)

interface ShareReportEvent {
  type: 'shareReport';
  /** 可选:最后一张截图的 url 或 base64 内容 */
  lastScreenshot?: string;
  /** 可选:报告 url */
  report?: string;
  /** 关联的指令 */
  instruction: string;
}

请求示例

{
  "type": "appLaunched",
  "platform": "iOS",
  "osVersion": "16.0.0",
  "screenWidth": 390,
  "screenHeight": 844
}

响应

成功响应(200 OK)

{
  "success": true
}

所有事件均按异步方式处理。服务器应尽快响应以确认事件已接收。

客户端实现:UTIO 包的静默失败设计

客户端事件类型定义在独立包 packages/ui-tars/utio 中,与上述文档的三种 EventTypeappLaunched / sendInstruction / shareReport)一一对应,并以 EventPayloadMap 做类型到载荷的映射。核心发送逻辑见 utio/src/index.ts

export class UTIO {
  constructor(private readonly endpoint: string) {}

  async send<T extends EventType>(data: EventPayload<T>): Promise<void> {
    if (!this.endpoint) return;

    try {
      const response = await fetch(this.endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(data),
      });
      if (!response.ok) {
        throw new Error(`UTIO upload failed with status: ${response.status}`);
      }
    } catch (error) {
      // Silent fail
    }
  }
}

两个关键设计值得注意:其一,endpoint 为空时直接返回,这解释了「UTIO Base URL 留空则完全不上报」;其二,网络异常与 HTTP 非 2xx 均被静默吞掉(Silent fail),确保遥测故障永远不影响主功能。

主进程中的 UTIOService 以单例模式封装了三个事件的触发点:

  • getEndpoint() 每次从 SettingStore.getStore().utioBaseUrl 读取端点,只有非空时才构造 UTIO 实例(ensureUTIO);
  • appLaunched() 通过 screen.getPrimaryDisplay().size 获取主屏分辨率,配合 process.platformos.release() 组装载荷——这与文档中 platform / osVersion / screenWidth / screenHeight 字段完全对应;
  • sendInstruction(instruction)shareReport(params) 分别上报用户指令与分享事件。

三处调用点的接线见 main.ts(应用启动时执行 UTIOService.getInstance().appLaunched(),并注册 ipcMain.handle('utio:shareReport', ...))与 runAgent.ts(执行任务前上报指令)。分享链路则经由 preload/index.ts 暴露的 window.electron.utio.shareReport 由渲染进程调用——在 ShareOptions.tsx 中,仅当 settings?.utioBaseUrl 已配置时,才会携带 lastScreenshot(最后一条含截图的消息的 base64)、instruction 与可选的报告 URL 发出 shareReport 事件。这与文档中「UTIO 设计与分享相关联」的描述一致:报告上传成功后,报告 URL 会一并进入 UTIO 的 shareReport 事件。

服务端示例

Node.js

const express = require('express');
const cors = require('cors');
const app = express();
const port = 3000;

app.use(cors());
app.use(express.json());

app.post('/your-utio-endpoint', (req, res) => {
  const event = req.body;

  if (!event || !event.type) {
    return res.status(400).json({ error: 'Missing event type' });
  }

  switch (event.type) {
    case 'appLaunched':
      return handleAppLaunch(event, res);
    case 'sendInstruction':
      return handleSendInstruction(event, res);
    case 'shareReport':
      return handleShareReport(event, res);
    default:
      return res.status(400).json({ error: 'Unsupported event type' });
  }
});

app.listen(port, () => {
  console.log(`Server listening on port ${port}`);
});

Python

from flask import Flask, request, jsonify
from flask_cors import CORS
import re

app = Flask(__name__)
CORS(app)

@app.route('/events', methods=['POST'])
def handle_event():
    data = request.get_json()

    if not data or 'type' not in data:
        return jsonify({'error': 'Missing event type'}), 400

    event_type = data['type']

    if event_type == 'appLaunched':
        return handle_app_launch(data)
    elif event_type == 'sendInstruction':
        return handle_send_instruction(data)
    elif event_type == 'shareReport':
        return handle_share_report(data)
    else:
        return jsonify({'error': 'Unsupported event type'}), 400

if __name__ == '__main__':
    app.run(port=3000)

小结:配置项与落地位置速查

配置项 默认值 校验约束 作用与代码落点
language en zh/en 枚举 控制 VLM 输出语言,不影响界面语言
vlmBaseUrl 空(可由 env 注入) 必填 URL OpenAI 兼容端点地址,见部署文档
vlmModelName 空(可由 env 注入) 必填非空 请求的模型名
vlmProvider Hugging Face 枚举 1.0 版提供 Hugging FacevLLM 两选项
reportStorageBaseUrl '' 可选 URL 配置后报告上传换链接,未配置则本地下载
utioBaseUrl '' 可选 URL 配置后上报 appLaunched/sendInstruction/shareReport 三类事件,失败静默

需要说明的是,该文档位于 docs/archive-1.0/ 归档目录,描述的是 1.0 版本的设置体系;但如上所述,languagevlmBaseUrlreportStorageBaseUrlutioBaseUrl 等核心字段在当前的 setting.tsvalidate.tspackages/ui-tars/utio 中仍然保留,本文所述的存储、校验与上报链路依然有效。配置自部署服务时,只需保证 Report Storage Server 与 UTIO Server 分别实现各自的小接口规范,即可获得完整的「报告云端分享 + 使用洞察采集」能力,且两者均未启用鉴权,仅适合可信网络环境使用。

登录后查看全文
热门项目推荐
相关项目推荐