首页
/ Omni-TARS Core 组合式多智能体架构:用 @omni-tars/core 插件系统拼装 MCP / GUI / Code 全模态 Agent

Omni-TARS Core 组合式多智能体架构:用 @omni-tars/core 插件系统拼装 MCP / GUI / Code 全模态 Agent

2026-09-08 15:05:33作者:贡沫苏Truman

这篇技术指南以 multimodal/omni-tars/core/README.md 为核心骨架,系统讲解 Omni-TARS 多模态 Agent 技术栈中 core 包的可组合(Composable)多智能体架构设计:如何基于 AgentPluginToolCallEngineProvider 两大扩展点,将 MCP(搜索/网页)、GUI(屏幕控制)与 Code(终端/文件)三种能力以“搭积木”方式拼装成一个 Agent,并理解其系统提示词生成与生命周期 Hook 组合机制。读完本文,你将掌握 @omni-tars/core 的装配 API、插件开发范式以及底层编排源码(ComposableAgentAgentComposerComposableToolCallEngine)的实现原理,可直接据此构建自己的组合式 Agent。

一、core 包在 Omni-TARS 中的定位

multimodal/omni-tars 目录下存放了一组面向多模态智能体场景的 npm 工作区包,其中:

  • @omni-tars/core(对应 multimodal/omni-tars/core/package.json,版本 0.3.0):提供可组合架构的基础设施——插件接口、组合式 Agent 主类、可组合 ToolCallEngine 工厂,以及三类模块化环境提示词;
  • @omni-tars/mcp-agent:提供 MCP 插件(负责 MCP_ENVIRONMENT,搜索与网页浏览能力);
  • @omni-tars/gui-agent:提供 GUI 插件(负责 COMPUTER_USE_ENVIRONMENT,GUI 交互与屏幕控制);
  • @omni-tars/code-agent:提供 Code 插件(负责 CODE_ENVIRONMENT,Bash 执行、文件编辑与 Jupyter Notebook)。

core 依赖 @tarko/agent@tarko/agent-interface@agent-infra/mcp-client@agent-infra/logger@tarko/model-provider(见 package.jsondependencies),其与各能力插件共同构成 Omni-TARS 开源多模态 AI Agent 技术栈中“一个 Agent 同时指挥代码、浏览器与桌面”的核心编排层。

二、架构两大设计收益:可组合性与可扩展性

🔧 Composability:按需混搭能力

README 设想的“全功能 Agent”是链式 API 形态:

// Full-featured agent
const agent = AgentBuilder.create()
  .addPlugin(mcpPlugin)
  .addPlugin(guiPlugin)
  .addPlugin(codePlugin)
  .build();

需要说明的是,从 core/src 的实际源码结构看,AgentBuilder.ts 尚未出现在核心包源码中(README 中“File Structure”一节所列的文件清单与真实目录存在出入)。当前 @omni-tars/core 的实际导出面(见 core/src/index.ts)采用的是另一套等价装配方式:ComposableAgent(构造器接收 plugins 数组)+ createComposableToolCallEngineFactory(组合多个引擎 Provider),详见下文第四节。这种“声明插件数组 → 生成组合系统提示 → 统一注册工具”的思路与 AgentBuilder 链式 API 完全同构,只是实现形态不同。如果你要按需混搭能力,请以实际导出的两个 API 为准。

📈 Extensibility:两条官方扩展路径

README 给出了两条二等公民级的扩展路径,二者分工清晰:插件负责“环境与钩子”,引擎 Provider 负责“模型输出解析策略”

路径一:实现一个新 Agent Plugin

import { AgentPlugin } from '@omni-tars/core';

export class MyCustomPlugin implements AgentPlugin {
  readonly name = 'my-custom-agent';
  readonly environmentSection = '<CUSTOM_ENVIRONMENT>...</CUSTOM_ENVIRONMENT>';

  async initialize(): Promise<void> {
    // Initialize your plugin
  }

  getTools(): ToolInterface[] {
    // Return tools provided by this plugin
  }

  // Optional lifecycle hooks
  onLLMRequest?(id: string, payload: any): void | Promise<void> {}
  onLLMResponse?(id: string, payload: any): void | Promise<void> {}
  onEachAgentLoopStart?(): void | Promise<void> {}
  onAgentLoopEnd?(): void | Promise<void> {}
}

对照真实的基类源码 core/src/AgentPlugin.tsAgentPlugin 其实是一个带默认空实现的 TypeScript 类而非纯接口,每个字段与钩子都有确定的运行时语义:

成员 类型/签名 语义
name? readonly string 插件唯一标识,会被 AgentComposer 用来做环境探测(见第五节)
environmentSection? readonly string 该插件贡献的环境能力描述段,组合时会被拼接进系统提示词
setAgent(agent) 方法 在组合装配阶段把 Agent 实例注入插件,插件随后可通过 get agent 读取(未注入时访问会抛出 The current plugin does not associate any agent instance
protected tools Tool[] 插件持有的工具列表
getTools() 返回 Tool[] 供组合器收集并注册到 Agent 上
async initialize?() 可选 插件初始化,组合设置期间调用
onLLMRequest(id, payload) 可选 每次 LLM 请求发送前触发
onLLMResponse(id, payload) 可选 每次 LLM 响应返回后触发
onEachAgentLoopStart() 可选 每个 Agent 循环开始时触发
onEachAgentLoopEnd() 可选 每个 Agent 循环结束时触发
onAgentLoopEnd() 可选 整个 Agent 循环结束时触发
onAfterToolCall(id, toolCall, result) 可选 每次工具调用结束后触发,返回 result

也就是说,README 中标注为可选的钩子,在基类里都以空实现方法存在,子类只需覆写关心的钩子即可,不必处理“方法不存在”的判空问题——这正是其“可叠加组合”的工程基础。

路径二:实现一个新的 ToolCallEngineProvider

export class MyCustomToolCallEngineProvider extends ToolCallEngineProvider<MyCustomToolCallEngine> {
  readonly name = 'my-custom-engine';
  readonly priority = 70;
  readonly description = 'My custom tool call engine for specific tasks';

  protected createEngine(): MyCustomToolCallEngine {
    return new MyCustomToolCallEngine();
  }

  canHandle(context: ToolCallEngineContext): boolean {
    return context.tools.some(tool =>
      tool.function.name.includes('my_special_tool')
    );
  }
}

基类定义见 core/src/types.ts:Provider 是抽象类,通过 abstract name / priority / description 描述自己,通过 abstract createEngine() 创建引擎实例;getEngine() 内部使用单例缓存private engineInstance)保证同一个 Provider 在组合生命周期内只实例化一个引擎。canHandle(context: ToolCallEngineContext)可选的路由判定函数,决定该引擎何时被选中。路由上下文 ToolCallEngineContext 包含:tools(当前可用工具)、toolCalls(模型本次输出的工具调用)、messageHistory(历史消息)与 latestAssistantMessage(本循环最新模型文本输出)。

三、工具调用引擎的组合机制

引擎选择与优先级调度

组合器核心在 core/src/ComposableToolCallEngine.ts

  • 构造函数按 priority 降序排序引擎数组,engines = [...config.engines].sort((a, b) => b.priority - a.priority)defaultEngine 缺省时取排序后的第一个引擎,并 assert 保证至少有一个可用引擎;
  • selectEngine(context) 依优先级遍历 Provider:若 Provider 未定义 canHandle 则直接选用;否则只有 canHandle(context) 返回 true 才选用。没有任何引擎命中时回退到 defaultEngine
  • 注意一个实现细节:preparePromptprepareRequestfinalizeStreamProcessingselectEngine 动态路由prepareRequest 会根据 toolsmessageHistory 选引擎),而 initStreamProcessingStateprocessStreamingChunkbuildHistoricalAssistantMessagebuildHistoricalToolCallResultMessages 固定使用 defaultEngine。也就是说,流式中间态解析统一由默认引擎负责,而“给模型发什么请求、如何收尾解释最终结果”按场景动态切换;
  • getEngineInfo() 返回各引擎 { name, priority, description } 清单;getActiveEngineName() 通过比对单例实例找到当前活动引擎名。

ComposableToolCallEngineFactorycore/src/ComposableToolCallEngineFactory.ts)将上述组合引擎包装成与 @tarko/agent 期望的 ToolCallEngine 接口兼容的子类;而 createComposableToolCallEngineFactory(config) 是一个高阶帮助函数,它返回一个“把 config 固化进构造器”的 ToolCallEngine 构造器,从而可以直接作为 AgentOptions.toolCallEngine 传入。

原生思考控制

ComposableToolCallEngine.ts 中还有一个值得注意的开关:当 bypass_native_thinking(来自环境变量 NATIVE_THINKING === 'bypass',见 environments/prompt_t5.ts)为真时,prepareRequest 会向 messages 末尾推入一条空 assistant 消息,用于规避模型服务商的“自动推理”行为,保证外部可见的思维链由 Agent 端自主生成。

四、装配一个组合式 Agent

README 给出的标准装配示例:

import { codePlugin, CodeToolCallEngineProvider } from '@omni-tars/code-agent';
import { mcpPlugin, McpToolCallEngineProvider } from '@omni-tars/mcp-agent';
import { guiPlugin, GuiToolCallEngineProvider } from '@omni-tars/gui-agent';
import { ComposableAgent, createComposableToolCallEngineFactory } from '@omni-tars/core';

const toolCallEngine = createComposableToolCallEngineFactory({
  engines: [
    new GuiToolCallEngineProvider(),
    new McpToolCallEngineProvider(),
    new CodeToolCallEngineProvider(),
  ],
});

const agent = new ComposableAgent({
  name: 'Omni Agent',
  plugins: [mcpPlugin, guiPlugin, codePlugin],
  toolCallEngine,
});

对照源码给出三点实操澄清(避免读者照抄示例时踩坑):

  1. 关于导入的细节:三个插件包的导出面已在各自 src/index.ts 中得到确认——mcp-agent/src/index.ts 导出了 McpAgentPluginMcpToolCallEngineProvidergui-agent/src/index.ts 导出了 GuiAgentPluginGuiToolCallEngineProviderOperatorManagercode-agent/src/index.ts 导出了 CodeAgentPluginCodeToolCallEngineProvider。各包并未直接以具名常量 codePlugin / mcpPlugin / guiPlugin 导出现成插件,而是提供工厂函数或导出插件类:codePluginBuilder({ sandboxUrl, ignoreSandboxCheck })mcpPluginBuilder({ googleMcpUrl, googleApiKey, ... })。实际写法应类似 plugins: [codePluginBuilder({ sandboxUrl }), new McpAgentPlugin({...}), new GuiAgentPlugin({...})](注意 Provider 与 Plugin 需成对搭配使用,例如 GUI 场景引擎应选 GUI 专属的 GUIAgentToolCallEngine)。
  2. ComposableAgent 的构造时序(见 core/src/ComposableAgent.ts):构造器先以 plugins 数组创建 AgentComposer,再把剩余 options(...optionsWithoutPlugins)传给父类 Agent,最后 composer.setAgent(this) 把自身注入每个插件——源码注释明确提示这样做的原因:“Remove plugins to prevent circular reference from reporting errors”(避免 options 里带插件形成循环引用)。构造完成后会打印 load plugins success: [插件名列表] 日志。
  3. initialize() 阶段ComposableAgent.ts):依次执行 composer.initialize()(逐插件初始化)、getAllTools() 收集全部插件工具并逐一 registerTool,最后调用父类 initialize() 完成模型层就绪。

ComposableAgentOptionsAgentOptions & { plugins: AgentPlugin[] }ComposableAgent.ts)。

五、模块化 Environment 与系统提示词自动生成

三个环境能力段

原文档说明:将原先单块的 environments/prompt.ts 拆分成了三个模块化环境段,各自独立导出(对应 core/src/environments 下的 code.tsmcp.tscomputer.ts),并由 core/src/index.ts 统一 re-export:

  • CODE_ENVIRONMENTcode.ts)——Bash 执行、文件编辑与 Jupyter Notebook 能力。环境段内以“---- BEGIN FUNCTION / ---- END FUNCTION”方式逐条声明工具:execute_bash(一次只允许执行一条命令,长驻进程需后台运行并重定向输出到日志文件,如 python3 app.py > server.log 2>&1 &;可用空命令读取额外日志、用 C-c 中断进程)、JupyterCI(保留状态的 Python 代码沙盒)、str_replace_editorview / create / str_replace / insert / undo_edit 五种命令,str_replace 要求 old_str 在文件中唯一匹配)。该文件还额外导出 HOME_INSTRUCTION(一切 bash/文件操作必须以 /home/gem 为根目录、完整项目需先 mkdir -p)、PROXY_INSTRUCTION(启动服务禁止占用 8080/8888/9222 等端口)与 STOP_INSTRUCTION(输出 </code_env> 后必须立即停止,等待下一轮工具结果);
  • MCP_ENVIRONMENTmcp.ts)——搜索与网页浏览能力,通过 MCP 工具 Search(联网搜索,复杂问题应拆解逐步搜索)、LinkReader(打开网页/PDF 等链接并按需求汇总内容)实现;
  • COMPUTER_USE_ENVIRONMENTcomputer.ts)——GUI 交互与屏幕控制能力,用于以坐标/按键/拖拽等方式操作屏幕完成界面类任务。

另外 prompt_t5.ts 面向 T5 系列 UI-TARS / Doubao 模型维护了配套的系统提示分组 SYSTEM_PROMPT_GROUPcreateSystemPromptGroup 以及 think_token(默认 thinkt,可用环境变量 THINK_TOKEN 覆盖);code_functions / mcp_functions / gui_functions 三组变量以 JSON 格式声明了对应工具集。

组合器如何拼接系统提示词

AgentComposercore/src/AgentComposer.ts)是“把 N 个插件变成一份系统提示词”的关键:

  • generateSystemPrompt()L44-L64)输出 = 基础提示(“You are a general AI agent … can interact with the following environments: {envs} … 推理过程需包裹在 <think></think> 中”)+ 拼接所有插件提供的 environmentSection(过滤空段后以空行连接)+ 由 generateUsageInstructions() 生成的使用指令;
  • getAvailableEnvironments() 通过 hasPlugin('code' / 'mcp' / 'computer' / 'gui') 判断当前可用环境,并在 hasPlugin 中用 plugin.name.toLowerCase().includes(type) 按插件名字符串子串匹配(源码中留有 TODO 注释,说明该方案后续需优化);
  • generateUsageInstructions()L169-L221)会基于可用插件动态渲染一段 <IMPORTANT_NOTE>:要求模型推理结束 </think> 后用 <环境名>…</环境名> 标签声明下一步要使用的环境,并分别给出三类环境的输出范本——代码环境用 <code_env> + <function=…>/<parameter=…> 的 XML 式调用;MCP 环境用 <mcp_env> + <|FunctionCallBegin|>[…]<|FunctionCallEnd|> 的 JSON 调用;计算机环境用 <computer_env> + Action: click(point='<point>100 200</point>') 之类的动作指令;完成任务则以 <answer>…</answer> 提交最终答案。也就是说,“能力是否出现在系统提示词里,完全取决于你拼装了哪些插件”,这正是模块化架构的直观体现。

六、Hook 组合系统:跨插件叠加的生命周期

README 将其列为组合系统的核心特性——生命周期钩子可以在多个插件间可加性地分层叠加。其分发实现位于 ComposableAgentAgentComposer 的配合:

  • ComposableAgent 覆写了父类的全部钩子(ComposableAgent.ts):onLLMRequestonLLMResponseonEachAgentLoopStartonEachAgentLoopEndonAgentLoopEndonAfterToolCall,每个覆写方法内部只做一件事——把控制权转交给 composer.executeXxx(),最后 onAgentLoopEnd 仍会调用父类实现以确保 Agent 循环正常终结;
  • AgentComposer 对每种钩子提供 executeXxx() 批处理方法,内部按 plugins 数组顺序 for...of 依次 await(例如 executeOnLLMRequest),executeOnAfterToolCall 在全部执行后返回原始 resultL131-L143),使插件可以“先看后改/透传结果”;initialize() 在逐个插件初始化时会统计并打印每个插件的耗时日志。

一句话总结运行时序:Agent 主循环每触发一次生命周期事件 → ComposableAgent 钩子 → AgentComposer.executeXxx → 顺序遍历所有插件钩子。每个插件只需关心自己的钩子逻辑,多个插件对同一事件的观察与副作用天然叠加。

七、官方内置插件包速览

README 的“What Was Implemented”部分描述了三个官方插件与一个复合形态,结合源码可进一步补充其实用配置:

@omni-tars/mcp-agent(搜索/网页能力)

McpAgentPlugin 基于新核心架构接管 MCP_ENVIRONMENT支持通过配置挂载 mcpServers。从 mcp-agent/src/index.tsmcpPluginBuilder 可见其典型服务描述格式:

{
  type: 'streamable-http',
  name: McpManager.McpClientType.Google,
  description: 'google search tool',
  url: option.googleMcpUrl,
  headers: { 'x-serper-api-key': option.googleApiKey },
  enable: true,
}

需要传入的 MCPTarsExtraOption 包括:googleMcpUrlgoogleApiKey(必填)与 tavilyApiKeylinkReaderMcpUrllinkReaderAK(可选,enable 字段随 key 是否存在而置位),MCP 客户端能力来自 @agent-infra/mcp-client 依赖。

@omni-tars/gui-agent(GUI / 屏幕能力)

GuiAgentPlugin 接管 COMPUTER_USE_ENVIRONMENT可配置屏幕尺寸与动作预算,面向 computer-use 工具就绪。GUIAgentConfig<TOperator>gui-agent/src/index.ts)要求提供 operator(如经 OperatorManager.create(agentMode, sandboxUrl) 创建,源码位置 gui-agent/src/OperatorManager.ts)与模型配置 model.baseURL / id / apiKey / uiTarsVersion;可选 systemPromptsignal(AbortSignal,用于取消)、maxLoopCountloopIntervalInMsuiTarsVersion 支持 'ui-tars-1.0' | 'ui-tars-1.5' | 'doubao-1.5-ui-tars-15b' | 'doubao-1.5-ui-tars-20b'。核心 AgentMode 类型(core/src/types.ts)规定 id 取值为 'omni' | 'gui' | 'game',并带可选的 browserMode: 'dom' | 'visual-grounding' | 'hybrid'

@omni-tars/code-agent(代码执行能力)

CodeAgentPlugin 接管 CODE_ENVIRONMENT可配置工作目录与执行限制,面向 bash、文件编辑与 Jupyter 工具就绪。CodeAgentExtraOptioncode-agent/src/index.ts)包含 sandboxUrl(必填的代码沙箱地址)与 ignoreSandboxCheck(可选,跳过沙箱连通性校验)。

@omni-tars/agent(MCP + GUI + Code 复合体)

三者之上还存在一个将 MCP、GUI、Code 能力合一的聚合形态,即开篇 ComposableAgent({ name: 'Omni Agent', plugins: [mcpPlugin, guiPlugin, codePlugin], toolCallEngine }) 描述的组合体——README 仅以一句收尾,而其工程化落地正是第四节“三种能力拼装进一个 Agent”的完整示例。

八、工程结构地图与阅读指引

README 自带的目录结构(multimodal/omni-tars/README.md 的同目录文档树)与实际仓库核对后基本吻合,但需注意两处差异:core/src并未实际存在 AgentBuilder.ts,取而代之的是 AgentPlugin.tsComposableToolCallEngine.tsComposableToolCallEngineFactory.tsplugins/snapshot.ts 等文件(后者通过 core/src/index.ts 导出的 SnapshotPlugin 提供快照能力)。建议按下面的“真实结构 + 阅读顺序”逐层深入:

multimodal/omni-tars/
├── core/                          # 可组合架构(本文核心)
│   ├── src/
│   │   ├── index.ts               # 公共导出面(推荐入口)
│   │   ├── AgentPlugin.ts         # 插件基类:环境段 + 生命周期钩子 + 工具
│   │   ├── ComposableAgent.ts     # 组合式 Agent:初始化、钩子分发、工具注册
│   │   ├── AgentComposer.ts       # 系统提示词组合器 + execute* 钩子批处理
│   │   ├── ComposableToolCallEngine.ts       # 引擎选择与优先级路由
│   │   ├── ComposableToolCallEngineFactory.ts # 兼容 @tarko/agent 的构造器包装
│   │   ├── types.ts               # ToolCallEngineProvider / AgentMode 等类型
│   │   ├── environments/          # code.ts / mcp.ts / computer.ts / prompt_t5.ts
│   │   ├── plugins/snapshot.ts    # SnapshotPlugin
│   │   └── utils/parser.ts + streamingParser*/ # 流式结果与内容解析器
│   ├── examples/openai.ts         # 使用示例
│   └── test/                      # ComposableToolCallEngine.test.ts / parser 测试
├── mcp-agent/src/                 # McpAgentPlugin、McpToolCallEngine(Provider)、mcpServers 挂载
├── gui-agent/src/                 # GuiAgentPlugin、GUIAgentToolCallEngine、OperatorManager
└── code-agent/src/                # CodeAgentPlugin、CodeToolCallEngine(Provider)

深入验证建议优先阅读这几处:想看“组合引擎如何路由”,读 test/ComposableToolCallEngine.test.ts;想看“模型输出如何被解析成工具调用/内容”,读 core/src/utils/parser.ts 及其 parseCodeContent / parseComputerContent / parseMcpContent 三个导出(分别面向三类环境的输出格式,配套 test/parseRealCode.test.tstest/parser.test.ts);想跑通构建与测试,可在包目录执行 rslib buildvitest(脚本定义见 core/package.json)。

九、小结

Omni-TARS core 包通过一套“插件声明能力、Provider 声明解析策略、组合器负责拼接”的三层设计,把多模态 Agent 拆成了高度内聚、可独立演进的积木:AgentPlugin 提供环境说明与生命周期钩子,ToolCallEngineProvider 提供按优先级与上下文选择的工具调用解析引擎,ComposableToolCallEngine/工厂把多个 Provider 编排为一个整体,而 AgentComposer 则把任意插件集合实时编译成一套自洽的系统提示词。MCP、GUI、Code 三个官方插件包正是这套架构的第一批落地案例——理解 core 的组合规则,你既能直接拼装出“全模态 Omni Agent”,也能以同样模式扩展出自己的环境插件与解析引擎。

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

项目优选

收起
kernelkernel
deepin linux kernel
C
34
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.21 K
2.81 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
945
1.86 K
docsdocs
暂无描述
Markdown
906
5.84 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
537
607
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
864
1.36 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
4.28 K
1.03 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.39 K
1.48 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
550
401
flutter_flutterflutter_flutter
本仓库是 Flutter SDK 与 Flutter Engine 的 OpenHarmony 适配版本,由 CPF-Flutter 团队维护。开发者可使用熟悉的 Flutter 技术栈开发 OpenHarmony 应用,3.35.7 及以后的适配版本可基于本仓库源码构建支持 OpenHarmony 的 Flutter Engine。
Dart
1.19 K
347