如果你是一名建筑设计师、室内设计师或3D建模爱好者,最近是否感觉AI工具层出不穷,但真正能“理解”你的设计意图,并直接在熟悉的建模软件(比如SketchUp)里帮你把想法变成模型的工具,却少之又少?
你或许听说过一些AI生成3D模型的网站,但它们往往操作繁琐、格式不通用,或者生成的模型细节粗糙,无法直接用于你的工作流。真正的痛点在于:想法与落地之间存在一道“操作鸿沟”。你需要一个能听懂自然语言指令,并能在SketchUp中实时、精准地创建和修改模型的智能助手。
这就是“Codex + SketchUp 实时建模MCP插件”系列课程要解决的核心问题。本系列第一课,我们将彻底打通这条从“想法”到“模型”的智能流水线。这不是一个简单的工具介绍,而是一套完整的、可落地的工程化解决方案。通过本文,你将能独立完成从零开始的环境搭建,理解MCP(Model Context Protocol)协议如何成为AI与SketchUp对话的桥梁,并亲手运行第一个由AI驱动的建模指令。
本文的判断是:基于MCP协议的Codex插件,代表了AI辅助设计工具从“玩具”走向“生产力”的关键一步。它不再仅仅是生成一个孤立的模型文件,而是实现了与SketchUp这个行业标准工具的深度、实时交互。对于设计师和开发者而言,掌握这套工作流,意味着能将重复性、规范性的建模工作自动化,从而将更多精力集中于创意和决策本身。
下面,我们就从最基础也是最重要的一步开始:软件安装及环境配置。一个稳定、正确的环境是后续所有神奇功能的基础。
1. 这篇文章真正要解决的问题
在深入代码和配置之前,我们必须先厘清一个根本问题:我们到底在搭建一个什么样的系统?以及,为什么传统的“AI生成模型+手动导入”流程不够好?
核心痛点:工作流的断裂与低效传统流程下,你需要在AI生成平台描述需求 -> 等待生成 -> 下载模型文件(可能是.obj, .fbx等格式)-> 打开SketchUp -> 导入文件 -> 调整比例、位置、材质 -> 处理可能存在的模型错误(如破面、法线反转)。这个过程不仅耗时,而且AI生成的模型往往与你的具体场景尺寸、风格难以完美匹配,二次调整的工作量巨大。
我们的解决方案:实时、上下文感知的建模助手本课程构建的系统,其核心是MCP (Model Context Protocol) 协议。你可以把它想象成AI大脑(Codex)和建模软件(SketchUp)之间的一套“标准通信语言”。通过这套协议:
- AI理解场景:AI不仅能听懂你的指令(如“在房间中央添加一个长2米宽0.8米的餐桌”),还能通过MCP实时获取SketchUp当前模型中的上下文信息(如房间的尺寸、现有家具的位置)。
- 精准执行:AI根据指令和上下文,生成精确的SketchUp Ruby API调用命令。
- 实时反馈:命令通过插件发送给SketchUp,模型被立即创建或修改,结果可视。如有问题,你可以即时给出修正指令。
这篇文章的目标读者:
- SketchUp中高级用户:希望用AI提升建模效率的设计师、建筑师。
- 技术背景的设计师:对编程有基本了解,愿意尝试自动化工具。
- 开发者/技术爱好者:希望了解如何将AI能力集成到传统桌面软件中,MCP是一个绝佳的实践案例。
通过第一课,你将搭建起整个系统的骨架,为后续学习更复杂的建模技能和自定义功能打下坚实基础。
2. 基础概念与核心原理拆解
要玩转这个系统,你需要理解三个核心组件的关系,它们共同构成了一个完整的“AI智能体(Agent)”工作流。
| 组件 | 角色 | 类比 |
|---|---|---|
| SketchUp | 执行终端 | 就像工人的手和工具。它负责最终的实际建模操作,拥有强大的几何图形处理能力。 |
| SketchUp Ruby API | 控制接口 | 就像工人能听懂的一套详细指令集。我们可以通过编写Ruby脚本,告诉SketchUp精确地画线、推拉、旋转。 |
| MCP (Model Context Protocol) 协议 | 通信协议与翻译官 | 就像项目经理的沟通标准。它定义了一套AI工具(如Codex)与外部资源(如SketchUp)之间如何交换信息的规则。MCP Server负责将AI的“自然语言”翻译成SketchUp Ruby API的“机器指令”。 |
| Codex (或兼容MCP的AI模型) | 智能决策中心 | 就像富有经验的设计师或项目经理。它理解你的自然语言需求,结合从MCP获取的模型上下文,规划出需要执行的一系列Ruby API命令。 |
核心工作流程(原理图):
你的自然语言指令(“建一个窗户”) ↓ Codex (AI模型) 思考 ↓ Codex 通过MCP协议查询/操作 ↓ MCP Server (SketchUp插件) 接收请求 ↓ MCP Server 调用 SketchUp Ruby API ↓ SketchUp 执行API,模型被创建/修改 ↓ 结果通过MCP Server返回给Codex ↓ Codex 将结果反馈给你这个闭环使得AI能够进行“感知-思考-行动”的循环,而不仅仅是单次生成。
为什么是MCP?MCP协议的核心价值在于标准化。它让不同的AI模型(不仅仅是Codex,未来可能是Claude、GPT等)能够以统一的方式与SketchUp(乃至其他任何支持MCP的软件)对话。你不需要为每个AI、每个软件都写一套适配代码,大大降低了集成复杂度。
3. 环境准备与前置条件
我们的目标是搭建一个本地开发与测试环境。请确保你拥有以下资源的下载和安装权限。
操作系统:Windows 10/11 或 macOS (本文以Windows为例进行演示,macOS步骤类似)。硬件建议:独立显卡有助于SketchUp流畅运行,但对AI推理部分(如果本地运行Codex)要求较高。初期建议使用云端AI API。
需要准备的软件清单:
SketchUp Pro 2022 或更高版本
- 原因:只有Pro版才支持完整的Ruby API功能,这是插件运行的基石。Make版(免费版)功能受限。
- 来源:请从Trimble官网下载正版试用版或购买正式版。
- 注意:安装路径请避免中文和特殊字符,例如
C:\Program Files\SketchUp\SketchUp 2023\。
文本编辑器或集成开发环境 (IDE)
- 推荐VSCode:轻量、插件丰富,非常适合编写和调试Ruby脚本及配置文件。
- 安装:从官网下载安装即可。
Node.js 运行环境
- 原因:许多现代的MCP Server实现基于Node.js。它是运行JavaScript/TypeScript编写的服务端程序所必需。
- 版本:建议安装最新的LTS(长期支持)版本,如
18.x或20.x。 - 验证安装:安装后打开命令提示符(CMD)或PowerShell,输入
node --version和npm --version,应能显示版本号。
一个兼容MCP的AI服务/工具
- 选项A(推荐,最简单):使用Claude Desktop或Cursor IDE。它们内置了MCP客户端支持,配置简单。
- 选项B(更灵活):使用MCP SDK自行开发客户端。这需要更多编程知识。
- 本文选择:我们将以Claude Desktop为例进行配置,因为它对用户最友好。
4. 核心流程拆解:四步搭建智能建模环境
整个安装配置过程可以清晰地分为四个步骤,每一步都为下一步打下基础。
4.1 第一步:安装并验证SketchUp Pro
这一步是基石。确保SketchUp Pro已正确安装并能正常启动。
- 关键操作:启动SketchUp,创建一个新模型,随意画一个长方体并保存。目的是确认软件基础功能完好,并能找到插件安装目录。
- 找到插件目录:在SketchUp中,点击菜单
窗口->Ruby控制台。在控制台中输入以下命令并回车,这会显示你的SketchUp插件目录路径,记下它,后面会用到。puts Sketchup.find_support_file("Plugins")- 典型路径:
- Windows:
C:\Users\[你的用户名]\AppData\Roaming\SketchUp\SketchUp 2023\SketchUp\Plugins - macOS:
~/Library/Application Support/SketchUp 2023/SketchUp/Plugins
- Windows:
- 典型路径:
4.2 第二步:获取并部署SketchUp MCP Server插件
MCP Server是运行在SketchUp内部的“翻译服务”,它以后台方式运行,监听来自外部的AI指令。
- 来源:你需要找到为SketchUp开发的MCP Server插件。这通常是一个
.rb文件或一个包含.rb文件的文件夹。 - 部署方法:
- 将下载的插件文件(例如
sketchup_mcp_server.rb)或整个插件文件夹。 - 复制到上一步找到的
Plugins目录中。 - 重启SketchUp。重启后,插件会自动加载。
- 将下载的插件文件(例如
- 验证插件是否运行:再次打开
Ruby控制台。如果插件加载成功,控制台在启动时通常不会报错(某些插件可能会打印一行加载成功的日志)。更直接的验证将在下一步与Claude连接时进行。
4.3 第三步:安装并配置Claude Desktop(MCP客户端)
Claude Desktop将作为我们与AI对话的界面,并通过MCP协议与SketchUp插件通信。
- 下载安装:从Anthropic官网下载Claude Desktop并安装。
- 关键配置:Claude Desktop需要通过配置文件来告知它有哪些可用的MCP Server。
- 定位配置目录:
- Windows:
C:\Users\[你的用户名]\AppData\Roaming\Claude\claude_desktop_config.json - macOS:
~/Library/Application Support/Claude/claude_desktop_config.json如果文件或目录不存在,可以手动创建。
- Windows:
- 编辑配置文件:用文本编辑器(如VSCode)打开
claude_desktop_config.json文件。
4.4 第四步:编写MCP连接配置并测试连通性
这是连接AI与SketchUp的最后一步,也是最关键的一步。
配置内容:在
claude_desktop_config.json中,你需要添加一个mcpServers配置项,指向SketchUp的MCP Server。由于SketchUp插件通常作为本地进程间通信(IPC)服务器,配置可能如下所示(具体配置需根据你获取的插件文档调整):{ "mcpServers": { "sketchup": { "command": "node", "args": [ "C:\\PATH\\TO\\YOUR\\MCP_SERVER\\index.js" // 示例:如果插件是Node.js脚本 ], "env": { "SKETCHUP_PLUGIN_PORT": "8729" // 示例端口,需与插件设置一致 } } } }重要:更常见的情况是,SketchUp Ruby插件自身作为服务器,需要通过
stdio方式连接。如果插件提供的是Ruby脚本,配置可能完全不同,甚至Claude Desktop可能需要通过一个本地中转脚本连接。请务必以你所获取插件的官方文档为准。这里提供一个概念性示例,假设有一个本地Python中转脚本:{ "mcpServers": { "sketchup": { "command": "python", "args": [ "C:\\mcp_bridge\\sketchup_bridge.py" ] } } }重启Claude Desktop:保存配置文件后,完全关闭并重新打开Claude Desktop。
测试连接:在Claude Desktop的聊天框中,你可以尝试询问Claude它有哪些可用的工具。例如输入:“/list_tools” 或 “你现在可以使用哪些工具?”。如果配置成功,Claude应该会回复它已连接到
sketchup服务器,并列出可用的工具,例如create_rectangle,push_pull,select_entity等。
5. 完整示例:一个简单的配置与测试案例
由于具体的SketchUp MCP插件实现各异,我无法提供确切的插件文件。但我会以一个高度模拟的真实场景为例,展示从配置到运行第一个指令的完整流程。假设我们有一个名为sketchup_mcp_bridge的Node.js项目作为MCP Server。
项目结构假设:
C:\ai_modeling\ ├── sketchup_mcp_bridge\ # MCP Server 项目 │ ├── index.js # 主入口文件 │ ├── package.json │ └── ...其他依赖 └── claude_desktop_config.json步骤1:准备MCP Server项目假设index.js是一个简单的MCP Server,它通过本地网络套接字与SketchUp插件通信。
// 文件:C:\ai_modeling\sketchup_mcp_bridge\index.js const { Server } = require('@modelcontextprotocol/sdk/server/index.js'); const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js'); const net = require('net'); // 1. 创建MCP Server实例 const server = new Server( { name: 'sketchup-mcp-server', version: '0.1.0' }, { capabilities: { tools: {} } } ); // 2. 定义一个工具:在原点创建立方体 server.setRequestHandler('tools/call', async (request) => { const { name, arguments: args } = request.params; if (name === 'create_cube') { const size = args.size || 1.0; // 这里应该是与SketchUp插件通信的代码 // 例如,通过TCP socket发送Ruby命令 const command = `Sketchup.active_model.entities.add_group.add_face([0,0,0], [${size},0,0], [${size},${size},0], [0,${size},0]).pushpull(${size})`; // 模拟调用SketchUp Ruby API(实际应通过socket发送) console.error(`[MCP->SketchUp] Executing: ${command}`); // 假设调用成功 return { content: [ { type: 'text', text: `已成功在原点创建了一个边长为 ${size} 米的立方体。` } ] }; } throw new Error(`Unknown tool: ${name}`); }); // 3. 启动Server,使用Stdio传输(供Claude Desktop连接) async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error('SketchUp MCP Server running on stdio...'); } main().catch(console.error);你需要在此目录下运行npm install @modelcontextprotocol/sdk来安装MCP SDK依赖。
步骤2:配置Claude Desktop编辑claude_desktop_config.json:
{ "mcpServers": { "sketchup": { "command": "node", "args": [ "C:\\ai_modeling\\sketchup_mcp_bridge\\index.js" ], "env": {} } } }步骤3:在SketchUp中启动配套的Ruby插件(假设)在SketchUp的Plugins目录下,放置一个Ruby插件sketchup_mcp_listener.rb,其核心是启动一个TCP服务器,接收来自上述Node.js服务器的命令并执行。
# 文件:sketchup_mcp_listener.rb (简化概念版) require 'socket' require 'sketchup.rb' module SketchupMCP class Listener def start @server = TCPServer.new('localhost', 8729) puts "SketchUp MCP Listener started on port 8729" Thread.new do loop do client = @server.accept handle_client(client) client.close end end end def handle_client(client) command = client.gets.chomp puts "Received command: #{command}" begin # 警告:在实际应用中,直接eval用户输入是极端危险的! # 这里仅为演示,生产环境必须使用严格的白名单或解析器。 Sketchup.active_model.start_operation('MCP Op', true) eval(command) # 执行从MCP Server传来的Ruby代码 Sketchup.active_model.commit_operation client.puts "SUCCESS" rescue => e Sketchup.active_model.abort_operation client.puts "ERROR: #{e.message}" end end end end # 启动监听器 listener = SketchupMCP::Listener.new listener.start- 安全警告:上述Ruby代码中的
eval是极度危险的,仅用于演示原理。真实插件必须采用更安全的方式,如预定义命令映射、参数化调用等。
步骤4:进行端到端测试
- 启动SketchUp,确保
sketchup_mcp_listener.rb插件已加载。 - 启动Claude Desktop。
- 在Claude Desktop中,向Claude发送消息:“请使用sketchup工具,在原点创建一个边长为2米的立方体。”
- Claude会识别到可用的
create_cube工具,并调用它。 - Node.js MCP Server (
index.js) 收到请求,生成Ruby命令字符串。 - Node.js Server 通过Socket将命令发送到
localhost:8729。 - SketchUp中的Ruby插件接收到命令,在确保安全的前提下执行
eval(或安全调用)。 - SketchUp中瞬间出现一个2米边长的立方体。
- 执行结果通过原路返回,Claude将成功信息呈现给你。
6. 运行结果与效果验证
成功配置后,你的工作流将发生根本性变化。验证是否成功,可以通过以下几个层次进行:
层次一:基础连接验证
- 现象:在Claude Desktop中询问工具列表,Claude能明确回复已连接
sketchup服务器,并列出如create_rectangle、push_pull、move_entity等具体工具名称。 - 成功标志:Claude的回复中包含了来自SketchUp插件的特定工具,而不是通用的“我无法操作外部软件”。
层次二:简单指令执行验证
- 操作:在Claude中输入一个明确的、简单的建模指令。例如:“在SketchUp当前模型的坐标原点,创建一个长3米、宽2米的矩形面。”
- 预期结果:
- Claude理解指令,并表明将使用某个工具。
- 切换到SketchUp窗口,你会立刻看到指定的矩形面被创建出来。
- Claude在聊天窗口反馈执行成功。
- 验证点:实时性和准确性。模型是否按精确尺寸在正确位置生成?
层次三:上下文感知指令验证
- 操作:先在SketchUp中手动画一面墙。然后对Claude说:“在我刚刚画的那面墙的正中央,开一个宽1米、高2米的窗洞。”
- 预期结果:
- Claude需要先“知道”哪面墙是“刚刚画的”。这依赖于MCP Server是否能提供当前模型的选择集(selection)或实体列表。
- Claude计算出墙的中心点,并生成创建窗洞的指令(可能涉及面的布尔运算)。
- SketchUp中,指定的墙上出现一个精确的窗洞。
- 验证点:AI是否能结合已有模型上下文进行智能操作。这是本系统超越简单脚本的关键。
如果以上验证均通过,恭喜你,你已经成功搭建了一个AI实时辅助建模的雏形系统!
7. 常见问题与排查思路
在配置过程中,你几乎一定会遇到一些问题。下表列出了最常见的问题及其解决方法。
| 问题现象 | 可能原因 | 排查步骤 | 解决方案 |
|---|---|---|---|
| Claude Desktop启动时报错或配置不生效 | 1.claude_desktop_config.json格式错误。2. 配置文件路径不正确。 3. Claude Desktop未以读取该配置的权限运行。 | 1. 使用JSON验证工具检查配置文件语法。 2. 确认配置文件在正确的用户目录下。 3. 尝试以管理员身份运行Claude Desktop。 | 1. 修正JSON格式,确保引号、括号配对。 2. 检查Claude Desktop的日志文件(通常在同级目录),看是否有加载配置的错误信息。 |
| Claude无法识别Sketchup工具(/list_tools无响应) | 1. MCP Server进程启动失败。 2. Claude Desktop配置中 command路径错误。3. MCP Server本身有bug,崩溃退出。 4. 防火墙/安全软件阻止进程间通信。 | 1. 手动在命令行运行配置中指定的command和args,看能否成功启动Server。2. 查看系统任务管理器,确认Server进程是否存在。 3. 检查Server代码的日志输出(如果它有输出到stderr)。 | 1. 确保Node.js/python已安装且版本合适。 2. 修正配置文件中的路径,使用绝对路径。 3. 暂时关闭防火墙或安全软件进行测试。 4. 查阅MCP Server插件的具体文档,确认启动方式。 |
| Claude显示工具但执行指令后SketchUp无反应 | 1. SketchUp插件未正确加载。 2. MCP Server与SketchUp插件之间的通信失败(端口、协议不一致)。 3. 生成的Ruby API命令有语法错误或无效。 | 1. 检查SketchUp的Ruby控制台,查看插件加载时有无报错。 2. 在MCP Server和SketchUp插件中增加详细的通信日志。 3. 让Claude执行一个最简单的命令(如 create_cube),并在Ruby控制台手动执行MCP Server试图发送的命令,看是否报错。 | 1. 确保插件文件在正确的Plugins目录,并重启SketchUp。 2. 核对双方使用的通信端口、主机地址是否一致。 3. 检查Ruby API命令的格式,确保在SketchUp的当前上下文中有效(例如,是否有活动的模型)。 |
| SketchUp中模型被创建在错误的位置或比例不对 | 1. 坐标系统理解错误(世界坐标 vs. 组件内部坐标)。 2. 单位不统一(AI默认可能是米,但SketchUp模板可能是毫米)。 | 1. 检查MCP Server生成的命令中使用的坐标值。 2. 确认SketchUp当前模型的单位设置(窗口 -> 模型信息 -> 单位)。 | 1. 在MCP Server逻辑中,明确坐标转换规则。通常以SketchUp的世界坐标系原点为参考。 2. 在AI指令或MCP Server配置中强制指定单位,或在生成命令时进行单位换算。 |
| 执行复杂指令时SketchUp卡死或无响应 | 1. 单次操作过于复杂,生成面数过多。 2. Ruby API调用未包裹在 start_operation/commit_operation中,导致无法撤销。3. 陷入了死循环或递归。 | 1. 尝试执行更简单的指令测试。 2. 检查SketchUp插件代码,确保每个由外部触发的修改操作都包含在事务中。 | 1. 优化AI指令,或让AI将复杂任务分解为多个简单步骤依次执行。 2. 在插件代码中务必使用 model.start_operation和model.commit_operation。3. 为MCP Server调用设置超时机制。 |
8. 最佳实践与工程建议
当你成功运行起第一个Demo后,若想将其用于实际工作或进一步开发,请务必遵循以下建议:
1. 安全第一:永远不要在生产环境使用eval
- 风险:直接执行来自AI的字符串代码,相当于给了AI在你自己电脑上运行任意Ruby代码的权限,极其危险。
- 正确做法:在SketchUp插件端,实现一个安全的命令分发器。预定义一组安全的操作函数(白名单),AI只能通过参数调用这些函数。
# 安全示例 def handle_safe_command(command_name, args) case command_name when 'create_rectangle' point, width, length = args # 调用安全的内部方法创建矩形 when 'push_pull' face_id, distance = args # 通过ID找到面并进行推拉 else raise "Unsupported command: #{command_name}" end end
2. 环境隔离与版本管理
- Node.js环境:建议使用
nvm(Windows下是nvm-windows) 管理Node.js版本,为项目创建独立的环境。 - Ruby依赖:如果SketchUp插件依赖额外的Ruby gem,需在插件中妥善处理加载逻辑,避免与用户其他插件冲突。
- 配置文件版本化:将
claude_desktop_config.json等配置文件纳入版本控制系统(如Git),方便迁移和回滚。
3. 设计健壮的通信与错误处理
- 心跳机制:MCP Server与SketchUp插件之间应定期发送心跳包,检测连接是否存活。
- 超时与重试:网络调用必须设置超时,对于可重试的错误应有重试逻辑。
- 结构化错误返回:错误信息应清晰、结构化地返回给AI,以便AI能理解并尝试修复指令。例如,
{"error": "INVALID_PARAMETER", "message": "长度参数必须为正数"}。
4. 为AI提供丰富的上下文
- 场景信息:除了执行命令,MCP Server应能向AI提供当前模型的摘要信息,如“当前模型包含5个组件,主要是一个房间的墙体,最近一次操作是选择了东面的墙”。
- 操作反馈:每次操作后,不仅返回成功/失败,最好能返回操作结果的描述,如“已在坐标(10,5,0)创建了一个名为‘桌子’的组件”。这有助于AI进行后续决策。
5. 性能与用户体验优化
- 批量操作:对于AI生成的一系列连续操作,可以考虑在SketchUp端合并为一个事务 (
start_operation),使它们可以一次撤销。 - 进度反馈:长时间操作时,应通过MCP协议向客户端反馈进度,避免用户以为卡死。
- 指令历史:在插件中记录AI执行过的指令历史,便于调试和重现问题。
9. 总结与后续学习方向
至此,你已经完成了“Codex+SketchUp实时建模MCP插件”环境搭建的全部核心步骤。回顾一下,你不仅安装了几个软件,更重要的是理解了一个由AI、通信协议、专业软件API构成的协同系统是如何运作的。你解决了环境变量、进程通信、配置对接等一系列工程问题。
本课的核心收获:
- 理解了MCP协议的角色:它是连接AI大脑与专业软件手臂的“神经”。
- 掌握了本地AI助手的配置方法:通过Claude Desktop和自定义配置,让通用AI具备了操作特定软件的能力。
- 建立了问题排查的基本框架:从连接、权限、命令到执行的层层递进排查思路。
接下来的学习方向:
- 深化SketchUp Ruby API知识:AI的能力上限取决于你能通过API操控SketchUp做什么。深入学习实体(Entities)、组件(ComponentInstance)、材质(Materials)、图层(Layers)等高级API。
- 开发更强大的MCP工具:将常用的复杂建模流程(如生成楼梯、屋顶、门窗族库)封装成一个个独立的MCP工具,让AI可以像搭积木一样调用。
- 探索其他AI模型与客户端:除了Claude,可以尝试配置Cursor IDE、或使用MCP SDK自行开发客户端,接入GPT、DeepSeek等不同模型,比较其在本场景下的表现。
- 实现真正的上下文感知:让MCP Server能够向AI更智能地描述当前模型状态,例如通过图像识别截图,或提取模型的属性树,使AI的指令更具针对性。
环境配置只是起点,它为你打开了一扇门。门后的世界,是如何让AI从一个“听话的执行者”成长为一名“懂你的设计伙伴”。在接下来的课程中,我们将深入如何设计高效的MCP工具、如何处理复杂建模逻辑、以及如何优化人机交互的体验。建议你将本文收藏,在后续实践中遇到环境问题时,可以快速回溯排查。现在,打开你的SketchUp,开始向AI发出第一个建模指令吧。