Windows Terminal 提权体验改进(1032):混合提权为何不可行,以及 elevate 配置、UAC 盾牌与 elevate-shim 的设计实现
本文基于 Windows Terminal 的官方设计文档(issue #1032,隶属 Process Model 2.0 系列规范)展开,讲解 Terminal 团队在放弃"同一窗口混合提权"方案后,围绕提权场景落地的一整套用户体验改进:elevate 配置项、UAC 盾牌指示器、跨提权级别的命令分发机制,以及安全模型中针对 settings.json 被篡改的防御设计。读完本文,你将理解"为什么不能在同一窗口里混开管理员和普通标签页"的安全本质,并能结合仓库源码读懂 _maybeElevate、elevate-shim.exe、elevated-state.json 等关键实现。
一、问题背景:为什么"混合提权"方案被否决
长期以来,团队研究过让 Windows Terminal 在同一窗口内同时运行普通(unelevated)和管理员(elevated)标签页,即"混合提权"(mixed elevation)。表面上看这并不困难:让普通级别的 Terminal 请求用户授权,弹出一个 UAC 提示,用户同意后就能在窗口里获得一个提权的 shell。
但文档明确指出,这会引入提权漏洞(escalation-of-privilege vector):一个普通级别的窗口直接连接着一个高完整性级别的进程。此时任何其他普通级别的应用都可以向该 Terminal 窗口的 HWND 发送输入,也就是说其他低权限进程可以"驱动"这个窗口,向提权客户端注入任意命令。
团队在调研中还逐一否决了几条绕行路径(这些分析出自 [Process Model 2.0 规范](https://gitcode.com/GitHub_Trending/term/terminal/blob/20588130d8ef2ba40eb56bdae88e04cce7fc5b5d/doc/specs/?utm_source=gitcode_repo_files#5000 - Process Model 2.0/#5000 - Process Model 2.0.md) 的背景章节):
- "迁移"方案:当用户从普通窗口请求提权标签页时,用 UAC 创建一个新的提权窗口进程,并把现有所有标签页"搬"过去,新窗口对外伪装成原窗口。问题在于:COM 不允许提权客户端连接到在运行时注册的普通级别服务,即使打包(packaged)环境下,操作系统也会拒绝
CoCreateInstance提权内容进程对象。 - RPC 隧道方案:在内容进程与窗口进程之间自建 RPC 通道来转移内容进程。但这要求 Terminal 自己负责保护 RPC 端点,团队对此缺乏信心。
- window-broker-content 架构:让 broker 进程拥有注册表中的静态 CLSID,由窗口与内容进程跨提权级别
CoCreateInstance该 broker——实测在打包环境下同样无法跨提权级别工作,可能是打包 COM 不支持混合完整性级别所致。文档还补充了一个细节:Terminal 此前曾被迫在 SxS manifest 中手工列举所有 WinRT 类,以便以非打包 WinRT 方式被激活(而不是依赖打包目录)。 - 反向混合提权:如果窗口一开始就是提权的,它可以启动新的普通进程。团队考虑过允许提权窗口创建普通连接,但这会偏离"提权窗口里默认全部提权"的既有行为,用户将需要手动追踪每个窗格的提权状态,或引入类似
"autoElevateEverythingInAnElevatedWindow"的设置。
由于"从普通窗口启动混合提权"不可行,反向支持也就失去了体验一致性上的意义,因此最终结论是:单窗口内所有连接保持同一提权级别。
二、替代方案:五项提权 QoL 特性
放弃混合提权后,文档(作者 Mike Griese,创建于 2020-11-20,最后更新于 2021-08-17)提出了一组提升提权工作体验的替代特性,对应社区 issue #1939、#632、#8311 等:
- 提权窗口的可视化指示器(#1939);
- 配置 Terminal 始终提权运行(#632);
- 配置指定 profile 始终提权打开(#632);
- 允许从普通窗口直接以提权方式打开新标签页/窗格;
- 根据提权状态动态变化的 profile 外观(#1939、#8311)。
2.1 提权窗口的可视化指示:UAC 盾牌
针对"一眼识别窗口是否提权"的需求,设计是在提权窗口的标签页左侧添加一个 UAC 盾牌图标。盾牌外观可经由主题(theming,见 issue #3327)配置,规划了三种状态:
- Colored(彩色):默认外观;
- Monochrome(单色):黑白盾牌;
- Hidden(隐藏):即使提权也不显示,即当时的现状行为。
文档还给出了演进策略:可以先简化为布尔设置(true 表示默认外观、false 表示隐藏),再逐步演进为 enum 驱动——这体现了 Terminal 开发中"从没有设置,到布尔设置,再到 enum 设置"的迭代习惯。
2.2 配置 profile 始终提权运行:"elevate" 属性
某些工具链只在提权状态下才能工作。为此,Terminal 增加了逐 profile 的 "elevate": true|false 设置,默认值为 false:
- 设为
true时,每次启动该 profile 都会尝试自动提权。实现逻辑是先检查当前窗口是否已提权,若未提权,则创建一个新窗口(以所请求的提权级别)来承载该连接; "elevate": false不做任何事:如果当前窗口已经是提权的,profile 不会打开一个降权的窗口;- 若用户在已提权的窗口中打开一个
"elevate": true的 profile,则直接在现有窗口内新建标签页/分屏,而不是再弹一个提权窗口。
2.3 让 Terminal 整体"始终提权"
elevate 是逐 profile 属性而非全局属性。如果用户希望所有 Terminal 实例都提权运行,可以在 profiles.defaults 中设置 "elevate": true,这样启动的任何 profile 都会以提权窗口形式打开——这是通过 profile 继承机制获得的"全局"效果。
2.4 Actions 中的 elevate 属性与可迭代命令
除了 profile 层面,elevate 也被加入了 NewTerminalArgs,因此 newTab、splitPane、newWindow 等 action 都可以在启动时覆盖 profile 的提权属性。这与 profile 其他属性"启动时覆盖"的机制一致。elevate 是一个可选布尔值,行为如下:
| 值 | 行为 |
|---|---|
null(默认) |
不修改该 profile 的 elevate 属性 |
true |
本次启动视同 profile 具有 "elevate": true |
false |
本次启动视同 profile 具有 "elevate": false |
同时文档给出了"打开提权标签页"的可迭代命令示例(iterate-on 命令,遍历 profiles 生成菜单项):
{
// New elevated tab...
"name": { "key": "NewElevatedTabParentCommandName", "icon": "UAC-Shield.png" },
"commands": [
{
"iterateOn": "profiles",
"icon": "${profile.icon}",
"name": "${profile.name}",
"command": { "action": "newTab", "profile": "${profile.name}", "elevated": true }
}
]
},
注:原文示例 JSON 中写作
"elevated": true;而在当前仓库的实现里,NewTerminalArgs序列化的属性名是elevate,见后文源码分析。
2.5 下拉菜单中的提权快捷方式
新标签页下拉菜单原本支持通过 Alt+click 以新窗格方式打开 profile。文档提议类似地支持 Ctrl+click 直接以提权方式打开标签页——这一交互与 Windows 任务栏对"以管理员身份运行"的处理方式(在任务栏图标上 Ctrl+click)保持一致。
三、跨提权级别的命令行流转
当创建新终端实例(新标签页、新分屏、新窗口)时,如果目标 profile 需要提权而当前窗口未提权,Terminal 需要把动作转换成 wt 命令行参数交给一个新进程。wt 的命令行子命令与这些动作之间已经可以互相转换,因此反向转换并不困难。
假设用户当前处于一个未提权的 Terminal 窗口:
新提权标签页——需要创建一个提权新进程,命令行形如:
wt new-tab [args...]
这个新的 wt 实例会遵循 [会话管理规范](https://gitcode.com/GitHub_Trending/term/terminal/blob/20588130d8ef2ba40eb56bdae88e04cce7fc5b5d/doc/specs/?utm_source=gitcode_repo_files#5000 - Process Model 2.0/#4472 - Windows Terminal Session Management.md) 中定义的 glomming(自动合并)规则:它可能合并到该提权级别下已有的某个窗口,也可能自己创建新窗口。
新提权窗口——通过 -w new 参数强制忽略 glomming 设置,确保命令一定在新窗口执行:
wt -w new new-tab [args...]
新提权窗格(split-pane)——这里最棘手:wt split-pane [args...] 本身好办,但如果命令最终 glomm 到一个提权窗口,用户可能本意是在当前普通窗口的标签页里分屏,而不是在提权窗口里分屏;另外,如果提权窗口空间不足无法分屏,操作会"看起来什么都没发生"。文档最终与团队讨论后决定:跨提权级别的 split-pane 最合理的处理是在提权窗口中新建一个标签页(该决定已在 issue #8514 的 PR 中按此实现),用户之后可以用 move-pane 命令把新窗格重新挂回分屏。
四、源码级实现:从 action 到 elevate-shim.exe
以下结合当前仓库的源码,验证设计文档中的方案如何落地。
4.1 NewTerminalArgs 中的 elevate 可选布尔属性
elevate 作为 NewTerminalArgs 的一部分定义在 ActionArgs.h 中,类型为 IReference<bool>(即可选布尔):
X(Windows::Foundation::IReference<bool>, Elevate, "elevate", false, ArgTypeHint::None, nullptr)
当值为空(null)时不覆盖 profile 属性,这与文档中"三态"语义完全对应。序列化为命令行参数时,ActionArgs.cpp 仅在 Elevate() 非空时输出 elevate: true/false 片段,即 null 不产生任何命令行输出。
4.2 _maybeElevate:新标签页/窗格的提权拦截点
在 TerminalPage.cpp 中,TerminalPage::_maybeElevate 是自动提权的核心判断逻辑,注释写明其语义:"如果被请求的设置希望这个新终端实例提权、而当前未提权,则用 _OpenElevatedWT 以提权实例打开新终端;如果已经提权或设置不要求提权,则什么都不做"。其实现要点:
// 如果都不需要提权可以直接返回。
// 如果已经提权也可以返回,因为不可能比这更提权了。
if (!defaultSettings->Elevate() || IsRunningElevated())
{
return false;
}
// 手动把 NewTerminalArgs 的 Profile 设置为解析出来的 guid
newTerminalArgs.Profile(::Microsoft::Console::Utils::GuidToString(profile.Guid()));
newTerminalArgs.StartingDirectory(_evaluatePathForCwd(defaultSettings->StartingDirectory()));
_OpenElevatedWT(newTerminalArgs);
return true;
可以看到它精确实现了文档语义:elevate 非 true 或窗口已提权时直接返回;否则解析出 profile GUID 与工作目录后转交 _OpenElevatedWT,并向调用方返回 true 表示"请求已移交给提权窗口",调用方可提前结束。该拦截点同时存在于新标签页路径(TabManagement.cpp 中先调用 _maybeElevate 再创建窗格)和窗格/连接创建路径(TerminalPage.cpp)。
TabManagement.cpp 中的注释还印证了文档"取消降级"的结论:// We can't go in the other direction (elevated->unelevated) unfortunately. This seems to be due to Centennial quirks. It works unpackaged, but not packaged.——从提权降级到非提权因打包应用(Centennial)的怪癖而无法工作,仅非打包构建可行。
4.3 为什么需要一个独立的 elevate-shim.exe
文档"Implementation Details"给出的基本机制是给 ShellExecute 传 "runas" 动词来触发 UAC 提权:
ShellExecute(nullptr,
L"runas",
L"wt.exe",
L"-w new new-tab [args...]",
nullptr,
SW_SHOWNORMAL);
但实际实现比这多了一层。ShellExecute 要求调用进程存活到子进程成功生成,而像 wt -p AlwaysElevateMe 这种场景下,原始 WT 实例发起提权后就会立即退出,导致 ShellExecute 无法完成,Terminal 还会在 XAML 层神秘崩溃。因此仓库引入了一个与 Terminal 同目录的小工具 elevate-shim.exe,由 Terminal 以 CreateProcessW 拉起,并把要提权执行的命令行原样传给它。
elevate-shim.cpp 顶部的注释(原文标注 BODGY)直白地解释了这一点:
// BODGY
//
// If we try to do this in the Terminal itself, then there's a bunch of weird
// things that can go wrong and prevent the elevated Terminal window from
// getting created. Specifically, if the origin Terminal exits right away after
// spawning the elevated WT, then ShellExecute might not successfully complete
// the elevation. ...
// To mitigate this, the Terminal will call into us with the commandline it
// wants elevated. We'll hang around until ShellExecute is finished, so that
// the process can successfully elevate.
elevate-shim.exe 自身的处理逻辑(elevate-shim.cpp)则用 ShellExecuteExW 替代了文档示意中的 ShellExecute,并针对"已提权状态下对打包应用调用 ShellExecuteExW 会失败"的问题(见其代码注释引用的 GH#14501)提供了两条目标发现路径:
- 打包路径:通过
GetCurrentApplicationUserModelId拿到包身份,用shell:AppsFolder\{package}!{app}形式拉起应用本体,参数为原始命令行; - 非打包兜底:取 shim 自身的模块目录,把文件名替换为相邻的
WindowsTerminal.exe直接执行。
随后以 lpVerb = L"runas" 调用 ShellExecuteExW,由 shell 弹 UAC 提示并生成提权进程——这正是文档设想的"让 shell 在生成 wt.exe 之前执行 UAC 提示"。
调用方一侧,TerminalPage.cpp 的 _OpenElevatedWT 负责组装命令行并拉起 shim:
// We're going to construct the commandline we want, then toss it to a
// helper process called `elevate-shim.exe` that happens to live next to us.
...
auto cmdline{ fmt::format(FMT_COMPILE(L"new-tab {}"), newTerminalArgs.ToCommandline()) };
wil::unique_process_information pi;
...
LOG_IF_WIN32_BOOL_FALSE(CreateProcessW(exePath.c_str(), cmdline.data(), ...));
注意它固定把动作构造成 new-tab {args} 形式交给 shim——这对应文档中"跨提权 split-pane 统一转为新建标签页"的决议:shim 拉起的是提权 wt 进程,而 glomming 行为交由该提权进程按会话管理规范自行决定。
4.4 启动阶段的"直接移交"逃生通道
还有一个微妙场景:用户执行 wt 时所有启动动作都要求提权。如果让普通 WT 先建窗、再走 XAML dispatcher 异步处理动作,会闪出一个无意义的普通窗口。为此 TerminalPage.cpp 提供了两个配套方法:
ShouldImmediatelyHandoffToElevated:在窗口尚未创建、XAML 尚未启动时检查——若当前未提权、存在启动动作、且所有newTab/splitPane动作解析出的 profile 都要求Elevate(),则返回true(newTab/splitPane无参数时不排除,因为默认 profile 可能要求提权);HandoffToElevated:挂接 keybinding 后仅把NewTab与SplitPane动作分发给 action dispatch,让每个动作各自走_maybeElevate→_OpenElevatedWT流程,把启动命令行"原样丢弃"给提权窗口,而不实际创建普通窗口。
TerminalWindow.cpp 则以注释形式声明了使用纪律:HandoffToElevated 是"尚未创建窗口时立即把请求分发给提权窗口"的逃生通道,且必须先调用 ShouldImmediatelyHandoffToElevated 确认才可使用。
4.5 elevated-state.json:提权专属状态文件的落地
文档安全章节提出:用户确认某条命令行安全后,应把确认结果写入一个"仅提权 Terminal 可访问的 state.json 变体",防止攻击者在用户已有提权窗口时篡改 settings.json 劫持 profile。当前仓库的 ApplicationState.cpp 正体现了这一设计:
static constexpr std::wstring_view stateFileName{ L"state.json" };
static constexpr std::wstring_view elevatedStateFileName{ L"elevated-state.json" };
其读写策略(_read 与 _write 的注释)是:提权实例只从共享 state.json 加载 Shared 属性,Local 属性(窗口状态、已确认命令行等)从 elevated-state.json 加载;写回时先把共享状态读入、把自身视图的共享属性叠加其上再写回 state.json,从而原样保留普通实例的 Local 属性,随后把自身 Local 属性单独写入 elevated-state.json。这套双文件机制正是文档中"提权版 state.json 只有提权 Terminal 可访问"的工程实现。
五、安全模型:为什么必须防"settings.json 劫持"
文档的 Security 章节是本设计中信息量最大的一部分,值得完整继承。
威胁模型:settings.json 当前是一个完全没有保护的、任何中等完整性级别(medium-IL)进程都可写任意修改的文件。恶意程序可以定位用户的"Elevated PowerShell" profile,把它的 commandline 改成 malicious.exe。用户以为打开的是提权 PowerShell,实际是提权执行了攻击者程序。如果 UAC 对话框中只展示 profile 名称,用户根本无法确认即将启动的究竟是什么。
缓解手段(按文档逐条列出):
- 始终把求值后的完整
commandline传给ShellExecute调用。ShellExecute接收的参数对用户可见(需点开"更多详细信息"下拉框),让 UAC 对话框至少暴露真实命令; - 在任何提权终端实例创建前显示确认对话框,展示将要执行的 commandline,让用户显式确认。该风险与自动提权功能无关——即使用户从 Windows 11 的 Win+X 菜单直接提权启动 Terminal,恶意程序覆盖默认 profile 的
commandline也会让用户"以为在开 Terminal 实际在跑恶意程序"。对提权 Terminal 窗口而言,这意味着每一次新建 profile 连接/命令行都需要先确认; - 确认结果缓存进提权专属 state 文件(即 4.5 节的
elevated-state.json),让"不舒服"的提示只出现在某条命令行的首次提权启动,后续未修改commandline的启动恢复无感; - 确认对话框应提供"了解更多"文档链接,以透明度换取用户接受度(文档以 VSCode 的 Workspace Trust 特性首次发布时的用户反弹为先例,认为在应用信任面前这是可接受的 UX 退化);
- 无 split token 时不显示对话框:若用户系统未启用 UAC,其本身就以管理员身份运行、所做一切皆提权,则不应打扰;
- Settings UI 应提供查看/清除这些缓存条目的入口,且该页面只在提权版 Terminal 中有数据。
其余维度:可访问性(用户本来就能手动创建提权窗口,降低创建门槛不改变可访问性现状)、可靠性(无预期变化)、性能与功耗(无预期变化)。兼容性方面,elevate 属性默认未设置,用户需显式选择(opt-in)新的自动提权行为;唯一的小顾虑是 UAC 盾牌经由主题配置,意味着必须先发布主题用户才能再次隐藏盾牌。
六、已知限制与平台边界
6.1 Centennial 打包应用的提权问题
文档直言历史上 Terminal 与 Centennial 打包基础设施在提权场景下"相处得很糟糕":必须把所有 WinRT 类列举进 SxS manifest 才能在提权时以非打包 WinRT 方式激活;在"过肩提权"(over-the-shoulder, OTS)场景下问题尤为突出——
- 当前用户账户安装了 Terminal,
- 但当前用户不是管理员,
- 管理员账户没有安装 Terminal。
此时即使用户在 UAC 提示中输入了管理员凭据,提权上下文中的 Terminal 也可能启动失败。文档承认这些问题是 OS 层的 bug,基本不在 Terminal 团队控制之内,并指出本 spec 不做新的缓解,甚至可能因提权场景更易到达而让这些 bug 更常见。从源码侧看,4.3 节 elevate-shim 的双路径发现机制(shell:AppsFolder 与非打包 WindowsTerminal.exe)正是为打包/非打包两种提权路径打的补丁。
6.2 Default Terminal 与自动提权互斥
文档在 2021-08-17 的修订中补充:由于"默认终端"(defterm)已发布,团队更清楚地认识到打包 COM 与提权边界的限制——defterm 目前完全无法用于提权进程(对应 issue #10276)。提权命令行应用启动时总是落在 conhost.exe 中;而"未提权的 peasant 无法与提权的 monarch 通信"(monarch/peasant 架构见 [会话管理规范](https://gitcode.com/GitHub_Trending/term/terminal/blob/20588130d8ef2ba40eb56bdae88e04cce7fc5b5d/doc/specs/?utm_source=gitcode_repo_files#5000 - Process Model 2.0/#4472 - Windows Terminal Session Management.md)),因此无法把连接转交给提权 monarch 处理。最简方案是:对传入的 defterm 连接始终忽略 elevate 属性,待相关 COM 限制修复后再重议。
6.3 OneCore(非桌面)SKU 上的提权
ShellExecute 并非在所有 Windows SKU 上可用,非桌面("OneCore")SKU 尤其如此,某些 SKU 甚至可能根本不存在多提权级别或多用户概念。文档认为这目前是"基本假设性的担忧"(桌面是当前唯一公开支持的 SKU),并预置了两条缓解思路:
- 若该 SKU 支持提权,必然存在某种提权机制,可改用它;
- 若不支持提权(文档以 Windows 10X 为例),可在用户尝试打开提权 profile 时弹出警告对话框,甚至加一层配置校验:当用户尝试把 profile 或 action 标记为
"elevate": true时即给出警告。
七、未来考虑:降级、提权主题与提权外观
文档最后保留了若干未落地的设计种子:
elevatedTheme:进一步走"视觉差异化"路线,允许按提权状态整体切换主题(例如强制提权窗口使用红色标题栏);- 提权专属 profile 外观:在外观对象(appearance object)讨论(issue #8345、#3062)中,团队认为为 profile 单独定义"提权外观"过于复杂——简单叠加就会导出 [
appearance、unfocusedAppearance、elevatedAppearance、elevatedUnfocusedAppearance] 四态组合爆炸,因此推迟到有人想出更干净的定义方式为止; - 提权/非提权使用不同 profile(issue #3637)同样留待未来,且与"自定义新标签页下拉菜单"(issue #1571)的设计互相纠缠,超出本版本范围;
- 带盾牌的独立 Terminal 图标:尤其用于托盘图标——提权与未提权窗口的托盘实例将各自独立,独特图标有助于用户区分;
- 降级(De-elevation)的保留设计:早期版本曾提议
"elevated": false从提权窗口创建新的未提权实例(机制即"从提权进程启动未提权进程"的经典做法)。但降级与打包 Centennial 应用不兼容:请求 OS 在提权上下文中运行打包应用时,子进程仍然是提权的——App model 会拦截CreateProcess调用并重定向到某个 COM 服务,子进程的父进程并非发起方,因此"父进程降级"类技巧全部失效。文档保留了原始三态语义以备将来重新引入(以取代elevate):null(默认):不修改提权级别;true:当前窗口未提权时,尝试新建提权窗口承载连接;false:当前窗口已提权时,尝试新建未提权窗口承载连接。
八、小结
#1032 的价值不仅在于几个具体特性,而在于它展示了一个安全驱动的设计否决流程:混合提权因为"普通进程可向提权窗口的 HWND 注入输入"这一根本问题被整体放弃,转而在窗口级别隔离提权边界的前提下,用 elevate 属性、wt 命令行转发生成、elevate-shim.exe 独立提权代理、UAC 盾牌、elevated-state.json 双状态文件这一整套机制重建提权体验。从 elevate-shim.cpp、TerminalPage.cpp、ActionArgs.h 到 ApplicationState.cpp 的当前实现,均与设计文档一一呼应,可作为理解 Windows Terminal 进程模型与安全边界的完整样本。
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