什么样的操作系统适合 AI Agent:任务、接口与权限边界
导读:从一份 GPU 捕获开始
假设一个游戏的某一帧突然变慢,Agent 要调查原因。它需要找到耗时的 GPU 工作负载,查看相关资源和源码,修改后重新构建,再用新的运行结果判断问题是否得到改善。Apple 的 Metal 开发工具已经提供了图形界面和命令行入口,可以读取捕获并调查这类问题。[1]
这项任务会经过几种不同的环境:源码在仓库里,GPU 状态在捕获中,修改效果要在目标设备上观察。Shell 能启动这些工具、组织文件和处理输出;专业工具决定哪些状态可以被读取;操作系统和应用的权限设置决定调用能否执行。要评价 Agent 在某个平台上工作的体验,就得把这些环节连起来看。
前一篇关于 Snap 的文章讨论了工具选择背后的维护责任,《我们到底在争论什么》区分了技术事实与个人选择。本文沿用这两个问题,考察 Agent 完成任务时依赖的接口、工具与执行环境:它怎样取得足够的信息,怎样确认工作完成,又由谁约束它能做的事?
1 先确定任务,再比较运行环境
1.1 完成条件决定需要什么信息
修复编译错误时,Agent 可以从编译器诊断入手,定位并修改源码,再运行构建。diff 记录了代码改动,构建结果说明这组输入能否通过编译。如果用户报告的是“角色在运行时走错了分支”,调查还要继续进入实际执行过程,查看日志、断点和对象值。若要求把画面中的物体放到指定位置,渲染结果也要参与判断。
这几个例子需要不同种类的证据。源码描述程序可能怎样运行,运行时数据记录某次执行发生了什么,图像则呈现用户最终看到的结果。Agent 要取得哪一种信息,取决于用户要求它修复什么。工具选择也由此产生:现成的命令行程序能够提供所需信息时,可以直接调用;信息留在调试器或应用内部时,就需要相应的接入方式。
Coding Agent、应用 Agent 和 Computer Use 因此可以出现在同一项工作中。Agent 可能先编辑源码,再调用应用接口,最后通过截图观察结果,并用鼠标、键盘工具操作界面。自主运行多久、哪些步骤请求确认,则属于这套工作流的另一组设置。
1.2 模型的判断怎样变成实际操作
本文讨论的 Agent 由模型和组织工具调用的程序共同工作。模型依据上下文选择下一步,Agent 程序把请求交给工具执行,再将结果送回模型;这类程序也常被称为 harness。目标应用提供具体能力,例如调试器读取栈帧、图像编辑器修改图层。操作系统管理进程和本机资源,远端服务则使用自己的身份与权限处理请求。
一项能力要经过这条链才能被模型使用。IDE 里已有断点功能,Agent 还需要一个可调用的入口、正确的调试会话,以及能够解释返回值的上下文。连接失败、参数错误和断点没有命中,发生在不同环节:前两种问题涉及工具调用,后一种还可能与构建配置、符号或程序执行路径有关。
把这些环节分开,能让平台比较更准确。一次工具失败可能来自 Agent 程序的适配,也可能来自应用没有开放接口,或操作系统拒绝了访问。知道失败发生在哪里,才知道更换 Shell、升级插件或调整权限分别能解决什么。
1.3 从可行性到使用成本
我更愿意先确认一项工作能否完成,再比较完成它要花多少时间。某个平台缺少目标工具或设备时,首先要解决执行环境;几个平台都能完成任务以后,配置、调用和维护成本才成为主要差别。
| 条件 | 应当确认的问题 | 可以取得的证据 |
|---|---|---|
| 软件与设备 | 目标工具链、应用和硬件是否可用? | 支持范围、启动结果、设备连接状态 |
| 操作入口 | Agent 能否表达所需动作? | 命令参数、API 或工具定义及调用返回 |
| 状态与验证 | 能否读到足以判断成败的信息? | 诊断、对象值、测试结果或图像 |
| 执行权限 | 谁允许写文件、启动程序、访问网络? | 实际生效的策略、审批记录和服务端授权 |
| 使用成本 | 接入和运行需要谁投入时间? | 配置步骤、人工介入、延迟及故障恢复记录 |
同一套接口可能减少人工点击,也可能增加配置和故障排查。比较时,应尽量保持任务、模型和权限条件一致,观察完整过程里省下了哪些工作、又增加了哪些工作。Shell 是开发任务里常见的入口,可以先从这里看这种成本如何产生。
2 Shell 怎样帮助 Agent 完成开发工作
2.1 日常命令用到了多少 Shell 能力
在以检索源码、查看 diff 和运行构建为主的工作流中,Agent 主要调用的是 rg、Git 和编译器。换成 PowerShell 执行同一组命令,主要工作仍由这些外部程序完成。如果脚本很少使用 PowerShell 模块,也没有调用 .NET API,就很少用到对象管道与运行时集成所提供的能力。对这类简单文本与仓库操作,更直接的选择依据是现有脚本、参数传递和错误处理是否省事。
Bash 通过管道连接程序的输入输出,格式由程序约定;PowerShell 的 cmdlet 管道在进程内传递对象,按参数绑定规则接收。[2][3] 例如 Get-Process | Where-Object WorkingSet64 -gt 200MB 直接筛选对象属性,省去了识别显示列和单位的步骤。Bash 可以通过外部程序取得数据,再用 jq 等工具处理结构化输出。已有工具能提供什么,决定了两条路径各需多少额外处理。
而当任务需要 .NET 能力时,PowerShell 的优势就更具体了。它可以加载与当前运行时兼容的 .NET 程序集,构造对象、访问属性和调用方法,也能使用现成的 PowerShell 模块。[4] 相比为同一个类库另写包装程序,再让 Bash 启动并解析输出,直接调用通常更方便,也少了一层进程间的数据转换。
因此,已有 Bash 脚本和 Unix CLI 能顺畅完成的任务,值得继续复用;大量依赖 .NET 类库或管理模块的任务,则更能从 PowerShell 的集成中受益。Shell 的能力应当在它实际减少的工作中得到评价。附录 B 保留了进一步比较所需的示例和技术细节。
2.2 一条命令经过了哪些处理
命令看起来很短,执行时却可能经过多次解析。Agent 将命令文本交给执行工具,Shell 处理引号、展开和重定向,外部程序再解释收到的参数。程序结束以后,执行工具还可能截断输出,或将结果包装成文本、JSON 再交回模型。路径中的空格、编码差异和输出格式,都可能在这些步骤中影响结果。
这些规则与版本有关。PowerShell 7.3 改进了原生程序的参数传递,7.4 改进了部分原生命令重定向和管道中的字节流保留;Windows PowerShell 5.1 沿用较早的规则。输出经过 cmdlet 时,还需考虑该 cmdlet 的解析与转换。[5][6] 因此,一次失败值得保留的材料包括 Shell 版本、原命令、目标程序和实际错误。它们能帮助判断改动应落在哪一步。
返回值的设计同样影响后续工作。PowerShell 可以先筛选对象属性再输出 JSON,CLI 也可以自行生成 JSON。模型依据这些返回字段判断下一步:空结果、失败和部分成功若没有区别清楚,就可能需要额外调用才能确认发生了什么。附录 B.4 进一步讨论对象离开执行进程后如何表示。
2.3 接口设计的收益取决于任务
SWE-agent 的论文使用 ACI(Agent-Computer Interface)描述 Agent 与计算机交互的接口,并研究仓库浏览、文件编辑等操作的设计怎样影响软件工程任务。接口会影响模型获得什么反馈,以及怎样发现和纠正操作错误。[7] mini-SWE-agent 则采用以 Bash 为核心的简洁设计,复用现成命令来完成编程任务。[8]
在实际选型上,现成命令已经覆盖操作、诊断和验证时,我赞成先复用这套工具。专用接口值得引入的地方,是它能减少明确的工作:直接定位符号、提供应用内部状态,或让一次容易出错的编辑变成约束更明确的操作。这些收益足以说明接入的理由,也便于判断增加的维护是否值得。
因此,选择接口时可以追问一个具体问题:当前任务中,Agent 还缺哪项操作或哪条信息?答案如果在目标应用内部,就需要继续看应用开放了什么能力。
3 应用怎样把能力提供给 Agent
3.1 调用入口与它所提供的能力
CLI、应用 API、MCP 和图像输入分别参与调用过程的不同部分。CLI 通过命令及参数表达操作,应用 API 提供可编程能力;MCP(Model Context Protocol)约定客户端怎样发现工具、提交参数并取得结果;图像输入则让模型观察可见内容。一个 MCP 工具可以在服务端调用 CLI,一条 CLI 命令也可以通过应用 API 取得结构化数据。[9]
一个返回文件文本的工具,与一个返回断点处对象值的工具,向模型提供的信息不同。选用它们,要看当前问题需要哪一种信息,以及这些信息是否足以支持下一步判断。具体工具的输入和返回值,因而比接口名称更值得展开比较。
MCP 规范允许工具声明输入结构,并返回文本或结构化内容。这有助于客户端理解怎样发起调用,但具体操作、错误处理和访问控制仍由工具及其后端实现。[9:1] 下面三个案例分别考察 GPU 调查、游戏运行时调试和视觉结果检查,看看应用能力如何进入 Agent 的工作流。
3.2 Xcode 与 Metal:命令行也能提供专业状态
Apple 为 Metal 提供的命令行工具处理着具体的图形开发任务。gpucapture 用于捕获 GPU 工作负载,gpudebug 用于浏览捕获、检查资源和分析性能,metalperftrace 用于性能跟踪及摘要。Agent 可以通过命令取得这些领域信息,再结合源码继续调查。[1:1]
回到导读中的性能异常,源码检索可以找到某段着色器或资源准备代码,捕获则用于判断它在这次运行中的表现。找到耗时位置以后,Agent 还要解释它与源码或资源的关系,才能决定修改什么。专业 CLI 的价值正在于提供这一步所需的状态,让调查有实际运行数据可以依据。
Xcode 也通过 MCP 向外部 Agent 开放能力,包括项目构建等操作;使用时需按相应版本完成接入和授权。[10] 这使同一项调查可以组合命令行与 IDE 工具:读取捕获、修改工程、重新构建,再观察新的运行结果。接口如何分工,取决于每一步需要的数据和操作。
3.3 Rider 与 Unreal:把源码关系和运行状态接起来
假设 Unreal 项目中的角色在某个条件下走错了分支。Agent 可以从源码里找出相关函数和调用关系,再通过调试器查看这次执行的输入、对象和线程。前一种信息帮助形成解释,后一种信息用于核对解释是否符合实际运行。
Rider 2026.2 提供 ue-code-authoring、ue-live-debugging 和 ue-test-authoring 三项面向 UE C++ 的 Agent Skill,分别指导代码编写、运行时调查和测试编写。2026.2.1 公告又介绍了覆盖 C++ 和 Unreal 等项目的通用 debugging-code Skill。[11][12][13]
这些 Skill 为不同任务提供操作指引。执行调用时,Rider 的 MCP Server 提供入口,IDE 索引和调试器执行相应查询。Rider 与 Unreal Editor 之间还通过 UnrealLink、RiderLink 两侧插件实现蓝图导航、游戏启动设置和编辑器日志等集成。Agent 的工具调用由此能够使用工程信息,并在连接和调试条件满足时读取运行状态。[14][15]
ue-live-debugging 的文档还给出了 PIE(Play In Editor,即在编辑器内运行游戏)的调查路径:查询当前游戏状态,或者等待断点命中后读取栈帧与变量。对于项目 C++ 断点,这份技能要求先检查构建配置,使用 DebugGame Editor 或 Debug Editor,并确认断点已绑定后再触发问题。[13:1] 取得变量值后,Agent 要将断点命中时的输入和对象状态与用户报告的触发条件对照,确认观察到的是同一问题。
3.4 Blender:修改场景以后,怎样判断画面
运行时数据能够解释程序怎样执行;涉及构图和视觉效果时,还需要观察最终产物。Blender 的 Python API bpy 可以修改场景,命令行可以在无界面模式下执行脚本和渲染。依据这些能力,可以构造一条工作流:Agent 通过脚本移动物体、生成渲染,再将图片交给具备视觉输入的模型或用户检查。[16]
这里可以把完成条件说得很具体:目标物体是否出现在画面中,是否落在约定区域,是否被其他物体遮挡。脚本返回成功,说明这次调用按程序的规则完成;但画面是否符合要求,还要结合物体位置、摄像机朝向和遮挡关系检查渲染结果。“光照自然”之类要求则需要参考图或更明确的描述,才有一致的检查依据。
视觉输入负责观察,场景修改仍可通过 bpy 进行;需要处理界面状态时,GUI 控制也可以参与。由应用 API 完成操作、通过图像确认效果,是同一任务中可以配合的两种能力。
在这些专业任务中,应用与验证工具的接入,比命令采用哪套 Shell 语法更影响 Agent 能否完成工作。我认为,把专业软件已有的操作和状态开放给 Agent,是平台适配值得重点投入的方向。随着这些能力开放,Agent 能够修改的对象和调用的进程也会增加,执行环境还要对这些操作落实权限限制。
4 开发工具需要怎样的权限范围
4.1 让任务授权成为实际限制
开发任务需要访问的资源通常超出一个源码目录。Agent 在项目中写文件,编译器可能要读取安装在别处的工具链和依赖,构建工具还会启动子进程。执行环境既要容纳这些正常行为,也要把写入和网络访问限制在允许的范围内。Codex 的 Windows 沙箱工程文章描述的,正是这组需求。[17]
用户提出“修改这个项目”,给出了任务意图。产品还要把这个意图转成具体策略:哪些目录能写、哪些命令需要确认、是否允许联网,以及限制怎样传给子进程。例如,配置中的 writable_roots 描述可写范围,执行层再据此设置操作系统能够强制实施的限制。
这里的沙箱指受约束的执行环境。用户授权决定任务允许做什么,审批流程处理需要再次确认的操作,沙箱负责在进程执行时落实资源限制。三者相互配合,才使“允许修复项目”成为可以执行和检查的规则。
4.2 Codex on Windows:把现有机制组成沙箱
OpenAI 在 2026 年 5 月的工程文章中说明,团队需要让 Codex 使用用户已有的 Shell、Git、Python、包管理器和构建工具,同时限制文件写入和网络访问。团队评估了 AppContainer、Windows Sandbox 和完整性级别等方案。对于这种开放的工具调用,AppContainer 的能力配置难以直接适配;独立的 Windows Sandbox 桌面则需要额外衔接实际项目与开发环境。[17:1]
最终方案组合了专用 Windows 用户、安全标识符(SID)、访问控制列表(ACL)、受限令牌和防火墙规则。早期实现曾通过环境变量和代理地址抑制联网,但程序可以忽略这些设置,直接建立连接。后续实现改用针对专用用户的防火墙规则:设置阶段需要管理员权限,运行命令的进程则使用受限身份。[17:2]
这段实现过程说明了产品要承担哪些工作。它要准备用户和凭据,配置文件访问,建立并检查网络规则,还要让开发工具读到必要的路径。每项限制都需要落到实际调用上;某个依赖目录没有开放,正常构建就可能失败,某条网络路径没有受到约束,产品声明的规则就可能没有落实。
同文还讨论了 macOS 的 Seatbelt,以及 Linux 上的 seccomp、bubblewrap。[17:3] Linux 另有 Landlock,允许普通进程主动收紧自身及后代的部分资源访问,支持的操作随内核 ABI 变化。[18] 就这项 Codex 实践而言,Windows 的身份、文件权限与防火墙需要额外整合,这是原生 Windows 适配中实际增加的工作。因而,现成隔离工具和 Agent 产品的适配成熟度,应当作为平台选型的重要条件;用户最终要承担的安装、配置与排错成本也应计入其中。Win32 与 NT 的长期接口和资源管理设计见附录 A。
4.3 MXC 与 Windows MCP 分别解决哪一段
微软的 Microsoft eXecution Container(MXC)尝试用统一配置和 SDK 描述不可信代码的执行范围,再由 Windows、Linux、macOS 上的不同后端实施隔离。统一配置有助于开发者表达执行要求,实际限制则由所选后端和具体实现决定。不过,本文引用的仓库说明将它列为早期预览,并明确警示当前配置仍有过宽之处,不能作为安全边界。[19]
Windows MCP 文档关注工具的发现、连接和受限运行。On-device Agent Registry(ODR)帮助 Agent 发现并连接本机或远端 MCP 服务,并提供用户和管理员控制。符合相应打包、注册条件的受限服务可在独立的 Agent 会话中运行,访问用户文件还涉及额外授权。相关文档标为预发布信息。[20][21]
这两条路线分别试图减少执行环境配置和工具接入的工作。对一个实际任务,可以继续追踪:服务怎样被找到,客户端以什么身份连接,服务进程在哪里运行,最终访问由哪项策略限制。产品的发展状态及材料范围列在附录 C。
4.4 权限需要沿着调用继续追踪
假设 Agent 的本地命令只获准写一个项目目录,同时接入了能够修改远端仓库的 MCP 服务。一次本地写入由本机沙箱约束;一次远端提交使用的则是服务端身份和授权范围。两项操作即使由同一个模型发起,也可能经过不同的执行者。
MCP 工具定义描述调用形式,协议还规定 HTTP 传输中的授权职责。[9:2][22] 因此,在调查一次远端修改时,需要找到实际接收请求的服务及其凭据;在调查一次本地文件写入时,需要检查执行进程及其访问策略。调用链中的这些身份和限制,共同决定 Agent 最终能做什么。
这种追踪也适用于应用工具。Agent 获准连接 IDE 后,IDE 能执行哪些操作,取决于它暴露的工具、应用权限和项目状态。平台选择因而还涉及工具服务运行在哪里,以及用户能否理解、维护这条调用链。
5 怎样据此选择工作环境
5.1 把接口放进一次完整调查
现在可以把 Rider 与 Unreal 的案例连成一项工作:用户提供了可复现的运行时异常,Agent 先取得触发条件和日志,定位源码,再进入调试现场,最后修改并重新运行。下表依据前面的文档能力组织这条流程,说明每一步依赖什么,以及得到的结果用于判断什么。[13:2][14:1]
| 步骤 | 依赖的能力 | 得到的结果用于判断什么 |
|---|---|---|
| 重现并读取异常 | 引擎运行、输入条件与日志工具 | 问题能否在约定条件下再次出现 |
| 定位相关代码 | 文本搜索、IDE 符号和调用关系查询 | 哪条执行路径可能解释现象 |
| 检查运行时 | PIE 状态查询、断点、栈帧和变量读取 | 实际执行是否符合对源码的解释 |
| 修改并构建 | 文件编辑、构建工具及诊断 | 改动是否按预期完成,能否通过构建 |
| 再次运行 | 同样的触发条件及必要的画面检查 | 改动是否修复了用户报告的行为 |
通过 Rider MCP 执行这条 PIE 调查路径,需要 IDE 打开对应工程、MCP Server 已启用,并能连接 Unreal Editor;项目 C++ 断点还要确认已绑定。[14:2][13:3]
如果 Agent 找不到符号,可以从索引和工程状态查起;无法取得变量,就要检查调试会话;构建通过以后行为仍然异常,则要继续调查运行条件和修复思路。平台适配的收益也可以逐项观察,例如更容易连接调试器、少做一次文件传递,或更可靠地重现问题。它们最终影响的是完成这项工作的时间和人工介入。
5.2 目标软件先确定执行环境
专业工具给平台选择设定了具体条件。Metal 捕获和 Xcode 调查依赖相应的 Apple 开发环境;在 Windows 上用 PIX 调查 D3D12 工作负载,需要满足其 Windows、GPU 和图形 API 要求。[1:2][23] 一项需要在 Linux 目标环境重现的服务端故障,则可能把最终验证放在 Linux 主机或容器中。
对这些任务,专业软件和设备支持应当优先于通用命令执行的便利。一个平台能直接提供目标应用及其调试、构建接口,就是明确的适用性优势。Agent 的交互界面、命令执行端和最终验证设备可以位于不同位置,远程构建、容器和 WSL 都提供了组合环境的方式;组合以后,文件传递、凭据和设备连接也成为工作的一部分。
因此,“使用哪套桌面系统”和“让某项任务在哪个系统中执行”可以分别决定。对同时依赖几种环境的开发者,保留已有工具并连接它们,可能比迁移整个工作流更省事。Windows + WSL 就是其中一种实际可用的组合。
5.3 Windows + WSL:保留两侧已有的工作流
Windows + WSL 的适用场景及容器支持见 《Snap、Flatpak 与 Nix》3.4 节。对于同时依赖 Windows 应用和 Linux 开发环境的用户,我认为保留 Windows 桌面,再让 WSL 承担 Linux 侧开发工作,是务实的选择。Agent 也可以沿用这套分工:Windows 继续运行桌面应用,Codex CLI 与 Linux 工具链在 WSL2 中运行。OpenAI 的 WSL 文档给出了对应的安装和启动方法。[24]
这种组合让用户可以保留两侧已经熟悉的工具。不过,具体工程仍需确定放在哪里、由哪一侧编译和运行。微软与 OpenAI 都建议,将主要使用 Linux 命令处理的项目放在 WSL 文件系统中,以减少跨文件系统访问的开销及相关兼容问题。[25][24:1]
若要让 WSL2 中的 Agent 进一步调用 Windows IDE,工作流还需提供可达的工具入口,正确对应两侧路径,并安排最终构建和调试在哪一侧执行。设备、调试器与凭据的使用方式也要随之确定。这些接入工作会影响组合方案是否省事。
《我们到底在争论什么》1.1 节已经区分过技术事实与个人选择。Codex CLI 可以在 WSL2 中运行,是关于兼容性的事实;是否值得采用 Windows + WSL,则要结合个人的软件依赖和维护意愿。对已经在 Linux Desktop 上完成全部工作的用户,原有环境可能更直接;对依赖 Windows 专业应用、同时又需要 Linux 工具链的人,两侧配合可以保留各自的便利。YMMV 在这里有明确的含义:任务、已有投入和愿意承担的维护工作不同,合适的选择也会不同。
5.4 接口节省的工作,与接入后增加的工作
专用工具可以让 Agent 直接取得 IDE 的语义分析结果或调试状态,减少反复搜索与猜测。与此同时,工具需要配置和维护,定义及返回数据也会占用模型上下文。Anthropic 在讨论通过代码组合 MCP 调用时,展示了将部分中间处理留在执行环境中、只向模型返回必要结果的设计。[26] 调用方式会改变这些成本,工具提供的数据也需要适当选择。
评价一次接入,可以沿着 5.1 节的完整流程观察:它让哪一步更容易完成?减少了多少人工整理和重复调用?连接失败时,谁负责恢复?这些工作要与延迟、配置和版本维护一起计算。
我的取舍是优先复用成熟工具,把接入工作放在现有流程确实缺少的能力上。第 2 部分的 Shell 比较只是一个例子:日常调用同一组外部程序时,未使用的模块和运行时能力收益有限;需要直接调用类库时,集成优势才转化为更少的包装和转换。扩展到应用接口和执行环境,前者应当补足所需的操作与信息,后者应当落实执行限制并容纳正常工具。平台提供了哪些实际便利,仍需额外承担哪些工作,都应进入最终评价。
结语:从可调用的能力判断平台价值
这些案例让我更看重一个平台把已有软件能力交给 Agent 的程度。现成 CLI 已经能完成的仓库任务,继续复用成熟工具通常最省事;调查运行时问题、修改专业应用中的对象,则值得投入相应的工具接入。应用生态能提供什么、Agent 实际能调用什么,会直接影响一项完整任务能否完成。平台的优势应当体现在这些实际使用的能力上。
执行限制同样要按产品的实际实现评价。用户需要的是能落实授权、兼容正常工具、出错后可以定位原因的环境。现成隔离工具是否适用、Agent 产品需要补多少适配、用户还要承担多少维护,都是实在的成本。专业软件的便利与沙箱适配的困难可以同时存在于一个平台上,应当分别说清。
我因此主张,先选择能够复用目标软件和关键工具、落实执行限制的环境,再比较日常调用和维护的成本。对依赖 Windows 应用又需要 Linux 工具链的人,Windows + WSL 有明确的互补价值;对已经在 Linux Desktop 或 macOS 上建立完整工作流的人,保留现有环境也有充分理由。任务和已有投入不同,选择就会不同,但每项选择都应有具体的能力与成本作为依据。
附录 A:Windows 的长期接口与资源管理
正文中的 Windows 案例涉及应用接口和操作系统实现两个层次。Win32 向应用提供窗口、进程、文件和系统集成等 API;这里讨论的 NT 基础设施包括对象管理器、安全机制和 I/O 管理等内核态组件。它们影响软件能使用多久、资源由谁持有,以及应用如何落实访问限制。理解这些设计,有助于解释 4.2 节中沙箱实现的工程成本。
A.1 长期兼容如何保护既有投入
我看重 Win32 的一个原因,是 Windows 把旧软件继续可用当作平台维护的一项责任。源码兼容让旧代码仍能编译,二进制兼容让已经发布的程序继续运行,行为兼容则要求接口尽量维持调用方依赖的语义。对寿命很长的行业软件和内部工具,后两项直接影响用户能否升级操作系统。Raymond Chen 在讨论 Windows 兼容性的工程成本时指出,成本更多体现在新功能的设计上:平台必须考虑那些早于新功能发布、对它一无所知的应用会怎样运行。[27]
这意味着平台承担了一部分原本需要应用开发者和用户支付的迁移成本。停止维护的小工具仍有继续使用的机会,已有工作流也能逐步更新。与此同时,新接口的设计要照顾旧调用方式,开发者会遇到多个年代留下的函数、参数和行为。评价这样的接口,既要算今天写一段代码的成本,也要算已发布软件在今后几年继续工作的成本。
API Set 展示了 Windows 如何把公开契约与实现位置分开。应用可以依赖 API 契约名,由加载器将它映射到当前系统上的实现 DLL;平台调整内部组织时,调用方可以继续依赖同一契约。不过,使用具体契约前仍需查询它是否可用,并遵守接口文档中的版本要求。[28]
在 COM 组件体系中,QueryInterface 让调用方询问对象是否支持某个接口,成功后再使用;同一对象实例可查询到的接口集合须保持稳定。例如,宿主可以让旧插件继续提供基本读取功能,让实现了新接口的插件额外提供批量读取。这个例子说明,稳定的基础接口可以与逐步增加的能力并存,各组件因而能够按自己的节奏更新。[29]
A.2 对象、身份与一次访问获得的权限
NT 将文件、进程、线程、事件和注册表键等资源表示为不同类型的内核对象。对象管理器统一处理这类对象的命名和生命周期,具体类型保留各自的数据与操作。文件读取和进程终止因而可以共享身份、访问检查和引用管理的基本概念,同时按照各自的规则执行。[30][31]
| 概念 | 在访问控制中承担的工作 |
|---|---|
| SID | 标识用户、组等安全主体 |
| Access Token | 记录进程或模拟线程的身份、组、特权等安全上下文 |
| 安全描述符及 DACL | 描述对象的所有者和自主访问控制规则 |
| 句柄及已授予的访问权 | 让进程引用具体对象,并限定通过该句柄可请求的操作 |
例如,允许查询一个进程的信息、读取它的内存和终止它,可以对应不同的访问权。服务线程还可以模拟客户端身份,让资源访问接受客户端安全上下文的检查。[31:1] 服务据此选择以谁的身份访问;具体任务获准使用哪些资源,还要由宿主根据用户授权进一步限定。
对于按句柄接收输入的工作进程,宿主可以先打开文件,再传入具有所需访问权的句柄。DuplicateHandle 提供跨进程复制句柄的机制,结果受参数、对象类型和相应规则约束。设计者还要检查工作进程通过令牌、其他句柄或代理服务获得的访问路径:一个只读句柄只限定经它进行的操作,进程重新按路径打开文件时还会接受另一轮访问检查。[32][31:2]
这种把授权附着在具体资源引用上的思路,也可以与 FreeBSD 的 Capsicum 对照。进程进入 capability mode 后,访问全局命名空间受到限制,主要使用明确授予的文件描述符等资源,并能进一步收窄其操作权限。Linux capabilities 这个名称指向另一种机制:它把传统 root 特权拆成若干单元。比较这些设计时,需要分别说明授予的是某个对象的操作权,还是执行某类特权操作的资格。[33]
A.3 资源何时仍在使用,何时可以释放
程序取得句柄以后,还要遵守相应的生命周期契约。CloseHandle 用于关闭多类内核对象的句柄;注册表键和 socket 分别使用 RegCloseKey 和 closesocket。关闭一个进程句柄也不会终止那个进程。这些区别要求程序明确记录自己持有什么、谁负责释放,以及释放动作究竟结束了什么。[34]
这部分责任可以交给类型和封装来执行。微软的 Windows Implementation Library(WIL)提供 C++ RAII 包装,把 Windows 资源的释放与包装对象的生命周期绑定,并提供缓冲区和错误处理辅助。应用仍然调用原有 Windows API,同时用作用域管理减少遗漏清理的机会。稳定的底层接口由此可以继续使用,调用代码也能逐步改善。[35]
异步调用返回后,请求可能仍在进行。使用 I/O Completion Port 时,应用提交异步 I/O,工作线程从完成端口取得相应的完成通知。宿主要保存请求与任务的对应关系,并让相关内存在请求完成前保持有效。发出取消请求后,也要确认操作已经结束;微软的取消文档要求,相关 OVERLAPPED 结构要等相应 I/O 完成后才能重用。[36]
窗口消息提供了另一个具体例子。PostMessage 投递消息后返回,接收方稍后处理;SendMessage 等待窗口过程处理完成。同线程调用可以直接进入窗口过程,跨线程等待时发送方还可能处理传入的非队列消息。[37] 如果程序正在修改数据结构,此时调用的窗口过程又触发了回调,回调就可能看到尚未完成的状态。对提供 GUI 或插件接口的 Agent 宿主,需要明确什么时候允许回调观察状态,以及窗口关闭时怎样处理尚未完成的任务。
A.4 用任务组织进程、预算和退出规则
一次编译或文档转换可能启动多个辅助进程。Windows 的 Job Object 可以把相关进程作为一个单位管理,设置资源限制、收集统计,并整体终止其中的进程。设置 JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 后,关闭该 Job 的最后一个句柄会终止与它关联的进程。要让这条退出规则覆盖整项任务,还需检查子进程的创建方式,以及是否允许它们脱离 Job。[38]
假设 Agent 启动一个转换工具,工具又启动渲染器。宿主可以把它们纳入同一个 Job,为这次转换设置预算,并在任务结束时清理关联进程。用户取消这次转换时,宿主便能处理归入该任务的多个进程。实现时需要确认辅助进程确实被纳入管理;宿主可先请求正常退出,再按超时规则终止未退出的进程。
Linux 的 cgroup v2 同样能按层级组织进程、分配和限制资源。资源预算与访问控制各有职责:内存限额决定任务能使用多少内存,文件访问策略决定它能读取哪些文档。seccomp 限制系统调用,Landlock 则允许程序进一步收紧自身及后代的部分资源访问。[39][18:1] 对 Windows 也要逐项检查进程归组、身份、对象权限和网络策略,才能确定一次任务实际受到什么约束。
A.5 将基础机制变成用户可理解的行为
在自主访问检查中,NULL DACL 放行访问,存在但不含任何条目的空 DACL 则不授予访问。两个看起来相近的参数状态,产生了相反的效果。宿主需要把“未配置”“拒绝访问”“允许哪些操作”转换为准确的底层状态,并检查失败路径。[40]
审计也需要专门配置。文件访问审计依赖已启用的策略,以及系统访问控制列表(SACL)中与访问类型、主体匹配的条目。[41] 系统可以记录资源访问,Agent 产品还要将这些事件与任务、工具调用和用户授权关联起来。这些记录才能帮助用户查明某次修改由什么任务发起、当时允许了什么,以及任务取消以后是否仍有工作在运行。
Win32 的长期契约保护了已有应用和集成代码的投入,NT 的对象、安全与生命周期机制则为宿主提供了组织执行过程的基础。对本文讨论的 Agent,这些价值最终体现在旧工具能否继续使用、授权能否落实到具体操作、任务结束后能否正确收尾。4.2 节的 Windows 沙箱案例展示了把这些基础机制组合成产品的工作;5.3 节讨论的个人工作流,则决定这份投入对使用者是否划算。
附录 B:PowerShell 与 Bash 的能力边界
第 2 部分讨论 Shell 在工作流中的作用。本附录进一步区分解释器本身、运行时和外部程序提供的能力,并说明这些能力怎样变成 Agent 能使用的结果。
B.1 先限定比较对象
pwsh 通常指现代跨平台 PowerShell,运行在现代 .NET 上;Windows PowerShell 5.1 由 powershell.exe 启动,基于 .NET Framework。二者的模块兼容性、原生程序参数和编码行为有所不同。现代 PowerShell 可以在 Linux、macOS 上运行,但 Windows 专属模块、provider 或 API 仍需要相应的 Windows 环境。[42]
Bash 本身提供展开、数组、管道、重定向和进程替换等语言能力;GNU Coreutils、jq、Python 和 Git 是它可以调用的外部程序。脚本使用 Bash 的数组或进程替换时,部署环境也需要提供 Bash,不能只按 POSIX sh 的语法范围来准备。[43] 两种 Shell 的可移植性都涉及解释器、依赖库或命令,以及最终调用的操作系统接口。
| 维度 | PowerShell / pwsh | Bash |
|---|---|---|
| 数据与管道 | cmdlet 之间传递 .NET 对象,并按参数绑定规则处理 | 通过程序输入输出和文件描述符组织数据,格式由程序约定 |
| 库调用 | 可直接使用可加载的 .NET 类型与方法 | 通常通过命令、其他语言或单独的程序接入库 |
| 外部程序 | 能调用 Git、编译器等;参数和输出处理与版本有关 | 复用已有 Unix CLI 约定;外部命令选项可能随平台变化 |
| 错误处理 | 区分终止与非终止错误,并处理原生程序退出码 | 使用退出状态、条件判断与管道规则;set -e 受上下文影响 |
| 可移植性 | 取决于模块、.NET API 与操作系统支持范围 | 取决于 Bash 版本、GNU/BSD 工具参数与设备接口 |
B.2 PowerShell 怎样直接使用 .NET
下面的例子在 PowerShell 中构造一个 .NET System.Uri 对象,读取地址的主机名和查询字符串:
$uri = [System.Uri]::new('https://example.com/docs?id=7')
$uri.Host
$uri.Query脚本通过类型和成员直接取得结果。这条路径的便利来自 PowerShell 与 .NET 运行时的集成:已有类库中的对象可以继续保留属性和方法,供后续脚本使用。调用者可以用 Get-Member 查看成员,调用静态方法,也可以用 Add-Type 加载程序集或编译 C#。需要 Windows 原生函数时,还能经 .NET 的 P/Invoke 互操作路径调用,并按接口要求处理签名、数据布局和资源释放。[4:1]
对于已经依赖 .NET 类库或 PowerShell 管理模块的任务,直接使用这些类型可以省去一层包装程序。不过,程序集及其依赖需要适配当前运行时,Windows API 需要受支持的系统,进程访问也仍接受身份与沙箱检查。若任务需要读取某个应用的内部状态,应用还须提供相应接口,脚本才能调用。
B.3 Bash 怎样组合进程与文件描述符
下面的命令比较两份排序后的输入:
diff <(sort left.txt) <(sort right.txt)两次 sort 负责排序,diff 负责比较。Bash 的进程替换在系统支持时,将两条排序命令的输出呈现为 diff 可读取的路径。这里每个程序完成自己的操作,Shell 负责连接它们。管道、重定向和文件描述符使已有程序能够组合使用,展开和作业控制则帮助脚本组织输入与执行过程。[43:1]
这种组合方式适合已经围绕标准输入、标准输出和退出状态建立的工具链。要可靠地复用这些工具,脚本需要正确处理变量引用、分词与通配符展开,文件名和编码也要符合目标程序的约定;跨平台使用时,还可能遇到 GNU 与 BSD 工具选项不同。管道的默认退出状态和 pipefail 会影响前面某个命令的失败能否反映到整条管道。[2:1][43:2]
输入输出也可以采用结构化格式。例如,Bash 调用返回 JSON 的程序,再交给 jq 或 Python 处理,数据便能按约定字段继续传递。与 PowerShell 进程内的对象操作相比,这条路径把更多约定放在进程之间:谁生成数据、谁解析数据,以及怎样表达错误,都需要由工具和脚本共同确定。
B.4 数据返回 Agent 时发生了什么
PowerShell 可以先在执行进程内筛选对象、选择字段,再将结果编码:
Get-Process |
Where-Object WorkingSet64 -gt 200MB |
Select-Object Id, ProcessName, WorkingSet64 |
ConvertTo-Json200MB 是演示阈值。交给模型的是选定字段的 JSON。在这条调用中,对象处理由 PowerShell 完成,模型根据返回字段作判断。后续若需要读取更多属性或调用方法,Agent 还要发起相应的工具操作。接口也应约定返回值的形状,例如是否固定使用数组,空结果怎样表示,以及部分失败如何报告。
PowerShell 远程会话也会涉及类似的数据传递问题:输出通常经过序列化,接收端多是保留属性的表示,具体类型和方法行为由远程会话规则决定。[44] 因此,在一个进程里可直接调用的对象,跨过进程或工具边界以后,要按实际传输形式继续处理。
错误结果同样需要明确约定。PowerShell 的 try/catch 捕获终止错误,cmdlet 的非终止错误和原生程序的非零退出码需要按调用方式处理;Bash 则需要检查退出状态,以及管道中较早命令的失败。[45][43:3] MCP 的工具 schema 或 CLI 的 JSON 输出可以用字段表示这些结果,帮助 Agent 判断哪一步失败、是否还有可用数据,以及接下来能否继续。[9:3]
B.5 哪些任务能直接受益
系统管理任务如果已经使用 .NET 类库和 PowerShell 模块,直接调用对象与方法往往能减少包装和格式转换。已有大量 Bash 脚本和 Unix CLI 的项目,则可以沿用现成的进程、文件和退出状态约定。这些收益来自已有依赖与 Shell 能力的配合。
如果两边主要调用同一组跨平台程序,就应结合项目脚本比较参数传递、编码和错误处理。现有脚本的复用程度,以及团队是否需要维护额外包装,也会影响最终选择。
附录 C:文中产品材料的时间与范围
正文中的产品案例依据下列版本与材料。发布说明描述当时的实现,文档和仓库则可能继续更新;实际接入时,需要按使用的版本确认启用条件。
| 产品或机制 | 本文采用的材料 | 适用范围与限制 |
|---|---|---|
| Xcode / Metal | Apple 开发者文档;访问于 2026-09-28 | 说明文档所述的 Metal 工具和外部 Agent 接入方式,实际使用依赖 Xcode 版本与授权 |
| Rider / Unreal | Rider 2026.2、2026.2.1 公告,Unreal 技能及 MCP、UnrealLink 文档;访问于 2026-09-28 | Skill 指导调用;IDE 索引、调试器和运行中的 UE 项目提供状态,具体步骤依赖工具接入与调试配置 |
| Codex Windows 沙箱 | OpenAI 2026-05-13 工程文章 | 说明当时的设计与实现;当前行为按所用版本核对 |
| MXC | Microsoft GitHub README;访问于 2026-09-28 | 早期预览;仓库明确不允许将当前配置视作安全边界 |
| Windows MCP / ODR | Microsoft 预发布文档;访问于 2026-09-28 | 发现、授权和服务的受限运行各有前提,打包方式影响服务可使用的隔离方式 |
| Codex CLI in WSL2 | OpenAI WSL 文档;访问于 2026-09-28 | 支持在 WSL 内安装与运行 CLI;调用 Windows 应用还需相应的工具接入 |
Apple,Metal Developer Tools 与 Investigating GPU issues with AI agents,访问于 2026-09-28。说明 Metal 命令行工具的职责和文档化的调查路径。 ↩︎ ↩︎ ↩︎
GNU,Bash Reference Manual: Pipelines。定义管道的输入输出与退出状态规则。 ↩︎ ↩︎
Microsoft,about_Pipelines,PowerShell 7.4 文档视图,访问于 2026-09-28。说明 cmdlet 对象管道与原生程序边界。 ↩︎
Microsoft,Add-Type;Using Static Classes and Methods,访问于 2026-09-28。用于 .NET 类型、程序集及互操作路径。 ↩︎ ↩︎
Microsoft,What's new in PowerShell 7.3,访问于 2026-09-28。用于原生程序参数传递的版本说明。 ↩︎
Microsoft,What's new in PowerShell 7.4,访问于 2026-09-28。用于部分原生程序重定向和管道的字节流处理。 ↩︎
Yang 等,SWE-agent: Agent-Computer Interfaces Enable Automated Software Engineering,2024。论文讨论 ACI 设计与其软件工程实验结果,结论受实验条件限制。 ↩︎
mini-SWE-agent,官方项目文档,访问于 2026-09-28。用于说明以 Bash 为主的简洁工具设计。 ↩︎
Model Context Protocol,Tools 规范,协议版本 2026-07-28,访问于 2026-09-28。定义工具描述、调用与返回形式;具体工具实现负责处理正确性和访问权限。 ↩︎ ↩︎ ↩︎ ↩︎
Apple,Giving external agents access to Xcode;Xcode 26.3 Release Notes,访问于 2026-09-28。用于外部 Agent 接入及版本前提。 ↩︎
JetBrains,Rider 2026.2: IDE Intelligence for AI Agents, Faster Performance, and Spectacular Game Dev Updates,2026-07-22。公布面向 Unreal Engine C++ 编写、实时调试和测试的 Agent Skills。 ↩︎
JetBrains,Rider 2026.2.1 and ReSharper 2026.2.1 Are Here!,2026-08-19。说明通用
debugging-codeSkill 覆盖 C++ 与 Unreal Engine 等项目。 ↩︎JetBrains,Unreal Engine Agent Skills;ue-live-debugging 技能源码,访问于 2026-09-28。用于核对 Unreal 调试工作流的工具与前提。 ↩︎ ↩︎ ↩︎ ↩︎
JetBrains,Rider MCP Server,访问于 2026-09-28。说明外部 Agent 的连接、服务启用和 IDE 工具范围。 ↩︎ ↩︎ ↩︎
JetBrains,UnrealLink and RiderLink,访问于 2026-09-28。说明 Rider 插件、Unreal Editor 插件及两者提供的集成。 ↩︎
Blender,Python API 使用文档源码与后台脚本说明源码,访问于 2026-09-28。官方 GitHub 镜像中的前者展示通过
bpy修改对象位置,后者说明后台模式与脚本调用;视觉检查是本文组合示例。 ↩︎OpenAI,Building a safe, effective sandbox to enable Codex on Windows,2026-05-13。记载当时的目标、候选方案及受限用户、令牌、ACL、防火墙的组合实现。 ↩︎ ↩︎ ↩︎ ↩︎
Linux kernel,Landlock userspace API,访问于 2026-09-28。限制继承及支持的访问类别随内核 ABI 变化。 ↩︎ ↩︎
Microsoft,Microsoft eXecution Container README,访问于 2026-09-28。仓库自述为早期预览,警示现有配置过宽且当前不能作为安全边界。 ↩︎
Microsoft,MCP on Windows overview,访问于 2026-09-28。说明 ODR 的发现、连接与管理职责;页面标注预发布信息。 ↩︎
Microsoft,Securely containing MCP servers on Windows,访问于 2026-09-28。受限会话、打包前提、用户文件授权及例外需按具体配置核查。 ↩︎
Model Context Protocol,Authorization 规范,协议版本 2026-07-28,访问于 2026-09-28。用于 HTTP 传输的授权职责,不代替本地进程隔离。 ↩︎
Microsoft,PIX Requirements,访问于 2026-09-28。用于限定 PIX 的运行要求,不外推到所有游戏开发任务。 ↩︎
OpenAI,WSL: Run and troubleshoot Codex in Windows Subsystem for Linux,访问于 2026-09-28。提供 Codex CLI 在 WSL 中的安装运行说明及相关环境边界。 ↩︎ ↩︎
Microsoft,Working across Windows and Linux file systems,访问于 2026-09-28。建议根据主要使用的命令行环境选择项目存储位置。 ↩︎
Anthropic,Code execution with MCP: building more efficient AI agents,2025-11-04。分析工具定义与中间结果的上下文成本;示例数字不作为通用平均值。 ↩︎
Raymond Chen,The real cost of compatibility is not in the hacks; the hacks are small potatoes,2007-07-23。作者以 Windows 功能设计说明兼容旧应用的成本;本文据此讨论平台与调用方之间的维护责任。 ↩︎
Microsoft,Windows API sets,访问于 2026-10-03。说明契约名称、实现 DLL 的映射及可用性查询。 ↩︎
Microsoft,Rules for Implementing QueryInterface,访问于 2026-10-03。规定 COM 对象身份和可查询接口集合的稳定性;插件渐进扩展是本文构造的示例。 ↩︎
Microsoft,Windows kernel-mode object manager,访问于 2026-10-03。说明对象类型及对象管理职责。 ↩︎
Microsoft,Windows Security Model for Driver Developers,访问于 2026-10-03。用于身份、模拟、安全描述符与对象访问检查。 ↩︎ ↩︎ ↩︎
Microsoft,DuplicateHandle,访问于 2026-10-03。说明进程间句柄复制、访问权参数及对象类型的限制。 ↩︎
FreeBSD,capsicum(4);Linux man-pages,capabilities(7),访问于 2026-10-03。分别说明 capability mode、描述符权限限制与 Linux 对特权的拆分。 ↩︎
Microsoft,CloseHandle,访问于 2026-10-03。说明适用对象、注册表键和 socket 的关闭方式,以及关闭进程句柄与终止进程的区别。 ↩︎
Microsoft,Windows Implementation Library,访问于 2026-10-03。项目提供 Windows 资源的 RAII 包装、缓冲区及错误处理辅助。 ↩︎
Microsoft,I/O Completion Ports;Canceling Pending I/O Operations,访问于 2026-10-03。说明完成通知、请求取消及相关结构的使用寿命。 ↩︎
Microsoft,SendMessage,访问于 2026-10-03。说明同步消息处理、同线程调用、跨线程等待期间的非队列消息,以及投递消息的替代入口。 ↩︎
Microsoft,Job Objects;JOBOBJECT_BASIC_LIMIT_INFORMATION,访问于 2026-10-03。用于进程归组、资源限制、breakaway 和关闭最后一个 Job 句柄时的终止规则。 ↩︎
Linux kernel,Control Group v2;Seccomp BPF,访问于 2026-10-03。分别说明进程组织与资源控制,以及系统调用过滤的职责。 ↩︎
Microsoft,Null DACLs and Empty DACLs,访问于 2026-10-03。说明两种状态在自主访问控制中的含义;对象的最终可访问性还受其他适用检查影响。 ↩︎
Microsoft,Audit Policy CSP: ObjectAccess_AuditFileSystem,访问于 2026-10-03。说明文件访问审计策略与 SACL 匹配条件;事件与 Agent 任务的关联由本文提出为宿主的实现责任。 ↩︎
Microsoft,What is PowerShell?;Migrating from Windows PowerShell 5.1 to PowerShell 7;PowerShell differences on non-Windows platforms,访问于 2026-09-28。 ↩︎
GNU,Bash Reference Manual。用于 Bash 展开、重定向、进程替换、数组和退出状态规则。 ↩︎ ↩︎ ↩︎ ↩︎
Microsoft,about_Remote_Output,访问于 2026-09-28。说明远程会话输出的序列化及对象行为。 ↩︎
Microsoft,about_Try_Catch_Finally,访问于 2026-09-28。说明终止错误捕获;其他错误与原生退出码需另行处理。 ↩︎