UI-TARS Desktop 设置系统全解:VLM 接入、报告分享存储与 UTIO 遥测配置
本文基于 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 主进程中的落地方式。
设置系统的整体设计: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-store 以 ui_tars.setting 文件名持久化,任何一项变化都会通过 BrowserWindow.getAllWindows() 向所有渲染进程窗口广播 setting-updated 事件,从而实现主/渲染进程间设置的实时同步。此外,SettingStore 还内置了 Preset(预置配置)导入能力:importPresetFromUrl 与 importPresetFromText 会先经 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.ts 的
z.enum(['zh', 'en']).optional()与 setting.ts 的默认值'en'可以印证这一取值边界。
在渲染端的设置分类组件 chat.tsx 中,语言切换通过表单触发校验后调用 updateSetting({ ...settings, language: newLanguage }) 完成写入,随后经 SettingStore 的 onDidAnyChange 回调广播给各窗口。
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 层对 vlmBaseUrl 的 z.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 Face、vLLM |
| Default | Hugging Face |
该选项是一个为不同 VLM 供应商预留的接口。
在 1.0 设置体系中,供应商枚举定义于 types.ts:
export enum VlmProvider {
// Ollama = 'ollama',
Huggingface = 'Hugging Face',
vLLM = 'vLLM',
}
可以推断,VlmProvider 保留了 1.0 文档所列的 Hugging Face 与 vLLM 两个选项(Ollama 已被注释停用);而当前仓库中另有一个扩展的 VLMProviderV2 枚举,在默认值层面引入了更多云侧模型选项(如 Hugging Face for UI-TARS-1.5、VolcEngine Ark for Doubao-1.5-UI-TARS 等)。对 1.0 设置文档所描述的版本而言,界面呈现的即为 Hugging Face 与 vLLM 二选一。
Report Storage Base URL:从本地下载到云端报告链接
Report Storage Base URL 用于定义报告文件的上传地址。其核心行为分支在于:未配置时点击「Export as HTML」(即 Share)会自动触发报告文件的本地下载。
一旦配置了该地址,点击「Export as HTML」时报告文件会先上传到 Report Storage Server,服务端返回一个可公开访问的持久化 URL。
这一行为在渲染端 ShareOptions.tsx 中有完整实现:
- 生成报告 HTML(
reportHTMLContent)后,若settings?.reportStorageBaseUrl非空,则调用uploadReport(htmlContent, settings.reportStorageBaseUrl)上传,成功后将返回的url复制到剪贴板并弹出Report link copied to clipboard!提示; - 若未配置该地址或上传失败,则回退为创建 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:应用洞察与观测的数据通道
UTIO(UI-TARS Insights and Observation)是 UI-TARS Desktop 的遥测数据采集机制,其设计也与「分享」场景相关联。UTIO Base URL 定义了处理应用事件与指令的 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 中,与上述文档的三种 EventType(appLaunched / 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.platform与os.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 Face、vLLM 两选项 |
reportStorageBaseUrl |
'' |
可选 URL | 配置后报告上传换链接,未配置则本地下载 |
utioBaseUrl |
'' |
可选 URL | 配置后上报 appLaunched/sendInstruction/shareReport 三类事件,失败静默 |
需要说明的是,该文档位于 docs/archive-1.0/ 归档目录,描述的是 1.0 版本的设置体系;但如上所述,language、vlmBaseUrl、reportStorageBaseUrl、utioBaseUrl 等核心字段在当前的 setting.ts、validate.ts 与 packages/ui-tars/utio 中仍然保留,本文所述的存储、校验与上报链路依然有效。配置自部署服务时,只需保证 Report Storage Server 与 UTIO Server 分别实现各自的小接口规范,即可获得完整的「报告云端分享 + 使用洞察采集」能力,且两者均未启用鉴权,仅适合可信网络环境使用。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00


