最近把主力开发环境从 Claude Code 切到了 opencode,折腾了小两周,踩了不少坑,也把它的配置逻辑摸了个七七八八。这工具在 GitHub 上势头挺猛,社区里讨论度一直在涨,但网上中文资料普遍停留在"装个 npm 包跑起来"的层面,真正涉及模型配置、Skill 编写、LSP 联动、Playwright 调试的深度内容很少。我打算把这段时间的实践整理出来,从安装、配置到实战排查,尽量写成一套可以直接照着操作的流程。这篇内容主要面向两类人:一类是已经被 Claude Code 或 Codex 的模型绑定搞得有点烦、想换一个更灵活方案的人;另一类是刚听说 opencode、想从零开始上手但被各种术语劝退的新手。前100字里先给个结论:opencode 是一个开源、终端优先、模型无关的 AI 编程助手,靠一个统一的配置层同时对接多家模型服务,配合 Skill、LSP、Memory 这些机制,能在很大程度上替代 IDE 里的传统 AI 插件,也能跟 Claude Code 形成互补。
1. opencode 到底是个啥,凭什么在一堆 AI 编程工具里杀出来
1.1 先搞清楚定位:opencode、Claude Code、Codex、Cursor 这几兄弟的差别
AI 编程助手这个赛道已经挤满了选手,但它们的定位其实差得挺远。Cursor 是 IDE 形态,把 AI 能力缝进一个编辑器里,打开即用,适合不折腾环境的人。Claude Code 是 Anthropic 官方出的 CLI 工具,终端里跑,主打 Agent 自主执行任务,但模型只能用 Anthropic 自家那几款。Codex 是 OpenAI 体系的,同样偏 Agent 形态,但模型和平台绑定。
opencode 的定位和它们都不同,它走的是"前端工具 + 后端模型解耦"的路线。你可以把 opencode 理解成一个标准的、开源的"AI 编程终端客户端",它自己不训练模型,而是通过统一的接口对接多种模型后端。官方默认配置支持 OpenAI 系、Anthropic 系、Google Gemini、本地 Ollama 等,用户也可以通过自定义 Provider 接入任意兼容接口的服务。这个设计直接解决了 Claude Code 用户的痛点:Anthropic 的订阅价格不低,而想换个模型还得换工具。
这就像是你平时开发用的代码编辑器。你写 JavaScript 可以用 VS Code,也可以用 WebStorm,但真正干活的是 Node.js 这个运行时。opencode 在 AI 编程工具里的角色就是那个前端编辑器,模型后端则是运行时,两者解耦,意味着模型价格变动、新模型发布、服务商切换,都不会影响你的操作习惯。社区里有人已经拿 opencode 同时管理五六个模型服务,按任务类型分派,这个灵活性是封闭工具给不了的。
1.2 我为什么把主力切到 opencode
切换主力工具有成本,尤其是我这种已经习惯 Claude Code 的人。但有两个因素让我下决心搬家。第一是模型选择的自由度。我在实际开发里发现,不同任务下不同模型的差距非常明显:Anthropic 的 Claude 在代码理解上表现稳定,但某些大规模重构场景下,Gemini 的上下文处理更从容;而一些简单的格式化、补全任务,用便宜的小模型就够了。opencode 允许我在一个会话里随时换模型,不用重启工具。
第二是 Agent 能力的可扩展性。opencode 的 Agent 不是死的,它支持通过 Skill 来扩展工作流。我最早是在 Twitter 上看到有人用它处理"按已有代码风格补全 API 实现"这种半自动任务,当时就意识到这不是简单的对话式补全,而是真正能被"调教"的工作流工具。后来我把自己常用的代码审查规则、提交信息规范、测试生成模板都写成了 Skill,当多个项目都开始复用这套配置时,效率提升就非常明显了。
还有一点很实在:opencode 是开源项目,没有账号体系的隐形成本。CLI 从安装到跑通不需要注册任何账号,模型接入全凭你自己的 key,这对我这种需要同时维护多个项目、多个环境的开发者来说,省了不少管理上的麻烦。
2. 安装 opencode:三种装法实测,以及 Windows 上最常见的那个报错
2.1 安装方式怎么选:npm、Homebrew、go install、桌面版
opencode 的官方文档提供了几种安装途径,我全部实测过,简单给个对比结论:
| 安装方式 | 命令 | 适用场景 | 备注 |
|---|---|---|---|
| npm 全局安装 | npm install -g opencode-ai | 最常见的安装方式,跨平台一致 | 需要先装 Node.js 环境 |
| Homebrew | brew install opencode | macOS 用户 | 方便后续 brew upgrade 统一升级 |
| go install | go install github.com/sst/opencode@latest | 想直接体验最新开发版 | 会安装到 GOPATH/bin,需确认 PATH |
| 桌面版 | 官网/Release 下载 | 不习惯终端的用户 | 底层仍会调用本地 CLI,建议同时装 CLI |
我自己的选择是 npm 全局安装,原因很简单:我在多台机器上开发,npm 是跨平台最一致的方案,Windows、macOS、Linux 上行为差异最小。Homebrew 在 macOS 上体验很好,但 Windows 下的朋友基本不用考虑。go install 适合那些想尝鲜 main 分支功能的开发者,但我实测发现它的更新频率太高,有些时候刚装完就提示有新版本,而 npm 稳定版反而更安稳。
桌面版我单独说一句。很多人以为装了桌面版就万事大吉,其实桌面版的核心逻辑还是包了一个终端会话,只是加了 GUI 外壳和可视化配置入口。它的好处是配置面板直观,模型列表一看就懂,不需要手改 JSON;缺点是它依赖本地 CLI,所以如果你命令行里opencode没跑通,桌面版一样会报错。建议无论如何先装一个 CLI,桌面版当成配置文件的可视化工具来用。
2.2 Windows 下"无法将 opencode 识别为 cmdlet"报错怎么破
这个报错几乎可以排到 opencode 热搜词前几名,原话是:
opencode : 无法将“opencode”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。这句话翻译成人话就是:PowerShell 在当前目录和 PATH 环境变量里找不到opencode这个可执行文件。这有两种常见原因,一种是没装成功,一种装成功了但 PATH 没生效。
先说排查路径。你在 PowerShell 里先跑一句:
npm list -g opencode-ai如果返回空或者报错,说明 npm 全局包里根本没有它,那就重装一次:
npm install -g opencode-ai装完后,关键是确认 npm 全局包目录是不是在 PATH 里。很多 Windows 用户遇到的问题是 npm 全局安装目录在C:\Users\你的用户名\AppData\Roaming\npm,但这个目录没有加入 PATH。用这个命令查一下:
npm config get prefix拿到输出目录后,手动把它加到系统环境变量 PATH 里,然后重开一个 PowerShell 窗口。这里有个细节坑:很多人改完环境变量不重启终端,或者直接复用原来的会话,结果 PATH 根本没刷新,就误以为重装没用。
还有一种情况是 Node.js 安装时没有把 npm 全局目录写入 PATH。我建议在系统环境变量里确认下面这条路径存在,如果用的是 nvm-windows 管理 Node 版本,还要注意 npm 全局目录实际上是跟随当前 Node 版本的,切换版本后经常出现"某个全局命令突然不见了"的问题。
注意:改完 PATH 后,务必重启 PowerShell 或直接重启电脑再测试,
opencode --version能输出版本号才算安装通过。
2.3 第一次启动:目录结构与环境初始化
安装成功后,第一次在终端运行opencode,它会自动创建配置目录。Linux 和 macOS 下是~/.config/opencode/,Windows 下是C:\Users\你的用户名\.config\opencode\。这个目录下的结构非常清晰,我列一下核心文件:
opencode.json:全局配置文件,负责模型、Provider、Agent 行为等全局设置。skills/目录:存放自定义 Skill 的目录,每个 Skill 一个子目录。- 日志文件:运行过程中会自动生成,排查问题时很有用。
第一次启动会进入 TUI 界面(终端交互界面),界面顶部显示当前会话状态,中间是对话区,底部是输入框。它会默认尝试读取你本机已有的环境变量来找模型 API key,比如ANTHROPIC_API_KEY、OPENAI_API_KEY。如果你过去用过 Claude Code 或者 Codex,环境变量里很可能已经有 key 了,opencode 会直接识别出来,这点值得点赞,迁移成本很低。
我第一次启动时因为没配任何 key,工具会提示当前没有可用模型,需要先配置。这时可以按Ctrl+C退出,然后在项目根目录下创建一个项目级的opencode.json,或者直接编辑全局配置文件,把模型服务填上。
3. 配置 opencode:模型接入、套餐选择与配置文件的正确玩法
3.1 opencode.json 配置结构详解
opencode 的配置采用 JSON 格式,全局配置文件在~/.config/opencode/opencode.json,项目级配置文件在项目根目录下也叫opencode.json。两者合并时,项目级配置会覆盖全局的同名配置项。一个最基本的配置结构长这样:
{ "$schema": "https://opencode.ai/config.json", "provider": { "anthropic": { "options": { "api_key": "{env:ANTHROPIC_API_KEY}" }, "models": { "claude-sonnet-4-20250514": { "name": "Claude Sonnet 4" } } } }, "model": "claude-sonnet-4-20250514", "theme": "opencode" }这里有几个关键点需要展开说明。
第一是provider配置段。opencode 的多 Provider 设计非常灵活,每个 Provider 可以定义自己的 API 地址、密钥读取方式、模型列表。api_key既支持明文写入,也支持用{env:变量名}的方式从环境变量读取,我强烈建议用环境变量方式,避免 API key 被提交到 Git 仓库。
第二是models段的声明。在 Provider 下面可以显式声明该 Provider 下有哪些模型可用。这个设计有点类似"登记制",你用哪些模型就声明哪些,不需要把服务商的所有模型都拉出来。
第三是model顶层字段,它决定当前会话默认使用哪个模型。
如果你的需求更复杂,比如想根据项目类型自动切换模型,可以在项目级配置里覆盖model字段。我在一个 Java 后端项目和一个小程序前端项目里就分别配置了不同模型,项目根目录各放一个opencode.json,互相不影响。
3.2 模型服务怎么选:API、订阅、免费模型的取舍
这是 opencode 用户最关心也最容易疑惑的地方。我在实际使用中发现,模型服务商大致分三类:官方 API 按量付费、订阅制套餐、以及各种中转或免费额度服务。先说结论,按量付费的官方 API 稳定性最好,写代码场景下我最推荐,但是成本高;订阅制适合重度使用且有预算的用户,但通常有模型锁定问题;免费额度模型适合尝鲜、学习、跑量大的测试脚本,但稳定性参差不齐。
官方 API 的优点是响应快、上下文窗口大、限流规则明确。缺点是贵。我记得有段时间用 Sonnet 模型跑长任务,一个下午点掉十几美元,之后我就变得非常谨慎,开始为不同任务分配不同模型:日常对话和简单补全用小模型,重大重构和代码审查才开强模型。
订阅制方面,Anthropic 的 Claude 订阅无法直接绑定到 opencode 的官方 API,这是个老话题了。社区里的主流做法是通过 Anthropic Console 申请 API key,或者使用支持订阅转 API 的服务商平台。这个我不展开具体推荐,因为涉及的服务商和政策一直在变,我只说筛选标准:看它是否支持openai兼容接口格式,响应是否快,是否有明确的使用政策,以及是否有便捷的充值管理后台。
免费模型我单独提醒一点:确实有渠道可以零成本接入模型,但大部分免费服务的并发限制和稳定性都一般。用来学习 opencode 的配置玩法可以,放在生产环境要慎重。我见过有人把免费模型接入后发现之前能用的 Skill 突然失灵了,排查半天发现是模型服务端切换了模型版本,能力分布发生了变化。
3.3 用 ccswitch 做多配置切换
多模型服务接入后,一个现实问题就来了:日常开发、写技术方案、处理客户紧急 bug,不同场景想用不同模型,来回改配置文件和重启太费劲。社区里解决这个问题用的比较多的是一个叫 ccswitch 的配置切换工具,它本质上是一个轻量的配置管理脚本,通过修改 opencode 的配置文件来快速切换当前默认模型。
ccswitch 在我的工作流里的用法是这样:我在配置文件里预先定义三档模型组合,写一个ccswitch 对话就切到便宜快速的小模型,ccswitch 重构就切到强模型,ccswitch 审查就切到指定审查模型。这个工具很轻,没有 GUI,纯命令行切换,还支持配置文件模板。
需要额外说明的是,ccswitch 是社区工具,不是 opencode 官方出品,版本兼容性可能跟 opencode 的主版本有关。我建议先试一下更新日志,确认当前 opencode 版本下它能正常工作再部署,避免版本不一致导致误改配置。
3.4 接入 superpowers 和 skills,让 Agent 真正能干细活
如果说模型是 Agent 的大脑,那 Skill 就是 Agent 的手和工具库。opencode 的 Skill 机制非常像 IDE 里的扩展包:一个 Skill 本质上是一组指令,告诉 Agent"遇到这个任务时该怎么一步步执行"。
我推荐的入门方法是安装社区热门的 superpowers 系列 Skill,这是个集合包,里面包含了很多打磨过的技能,比如代码审查、Bug 复现、测试生成等。安装方式通常是克隆对应仓库到~/.config/opencode/skills/目录,或者通过 opencode 的插件机制导入。装好后在对话里输入对应的 Skill 关键词,模型就会按照 Skill 定义的工作流来执行任务。
我自己写 Skill 的体会是,一个合格的 Skill 必须做到三点。第一是角色定义清晰,告诉模型它现在扮演什么角色;第二是步骤明确,把任务拆成一个接一个的可执行步骤,而不是一句"帮我做个代码审查"然后指望模型自由发挥;第三是输出格式确定,要求模型以特定格式返回结果,比如 Markdown 表格、特定日志格式,这样后续处理才好自动化。
举个例子。我给自己的团队写过一个"前端页面走查"的 Skill,核心指令就是让模型按既定清单逐项检查页面布局、交互异常、数据展示问题,每检查一项输出一个结论。用了这个 Skill 之后,让 opencode 跑前端页面查 bug 的效率比以前高得多,因为它不会跳过步骤,也不会只泛泛地给个总结。
4. 实战:用 opencode 处理一个真实前端 Bug(Skill+LSP+Playwright 联动)
4.1 挂上 LSP,让 Agent 真正"看懂"代码
很多人在终端里用 AI 工具时会发现一个问题:Agent 虽然能读代码文本,但对"类型定义在哪"、"函数调用链是怎样的"这类语义信息理解得不够。opencode 对这个问题给出的解法是内置 LSP(Language Server Protocol)支持,也就是让 Agent 通过语言服务器来获取代码的符号信息。
我在一个真实项目里测试过这个能力。当时有个 React 组件报了一个诡异的状态更新 bug,现象是列表拖动排序后,某几个条目的数据错乱。如果只把代码丢给模型,它很难定位到状态管理的问题,因为问题出在多个组件之间的数据流上。但在启用了 TypeScript 的 LSP 之后,opencode 可以直接查询类型定义、引用关系,顺着双向绑定的链路找到问题源头。它最后定位到是一个useEffect的依赖数组漏了字段,导致排序后的数组没有触发联动更新。
配置 LSP 也比较简单。在 opencode.json 里,为支持的语言指定对应的语言服务命令,比如 TypeScript 配置为typescript-language-server,需提前通过 npm 全局安装。具体配置字段可以看官方文档,这里只提醒一点:LSP 服务会消耗一定内存,机器配置不够的话,建议只对主力工作目录开启,不要全局无脑启用。
4.2 用 Playwright 驱动浏览器复现前端 Bug
定位到问题后,很多前端 Bug 还需要"复现验证"。以前我是在终端里跑 AI 工具,发现 Bug 后再切到浏览器手动验证,来回切换很费神。opencode 社区的做法是给 Agent 装上 Playwright 工具,让 Agent 本身具备操作浏览器的能力。
我在 opencode 里配置 Playwright 后,让 Agent 自动打开本地开发服务器,执行排序操作然后截图对比。它的调用流程大致是这样:Agent 根据任务决定使用 Playwright 工具,传入目标 URL 和操作脚本,Playwright 实际驱动浏览器执行,并把页面 DOM、截图、console 报错信息回传给 Agent。Agent 根据这些反馈继续调整操作或者定位问题。
这个流程在前端测试场景里非常有用。有一个热搜词是"opencode playwright 怎么测试前端 bug",我猜大家真正的痛点不是怎么装工具,而是怎么让模型自主决定"什么时候该打开浏览器"。我建议在 Skill 里明确告诉 Agent:当用户要求验证交互效果或者复现页面问题时,自动调用浏览器工具;当只是修改纯逻辑代码时,不要启动浏览器。有了这个约束,模型不会动不动就打开浏览器,浪费时间和资源。
4.3 Memory 记忆功能:让 Agent 记住项目上下文
AI 编程助手一个常被吐槽的点是"没有记忆"——明明上次已经安排好了项目结构和编码规范,下次开新会话又忘了。opencode 的 Memory 机制就是解决这个问题的。
它的做法是把项目相关的"长期记忆"写在一个约定的目录里,Agent 在每次会话开始时自动加载。你可以往里写项目架构说明、代码规范、部署流程、已知坑位等。一个可参考的做法是,在项目根目录创建.opencode/memory.md,然后在 opencode.json 里把 Memory 功能打开。之后每次对话,模型会自动读取这个文件作为上下文的一部分。
我对 Memory 的建议是:它是一个"组织记忆",不是"对话日志"。不用记流水账,而是提炼那些对整个项目有长期价值的信息。比如"这个服务登录态用的是 JWT,localStorage 里的 token 在请求拦截器里会自动带上"就值得记,比每次让 Agent 从代码里猜高效得多。另一个价值是团队协作:新人拉到项目后用 opencode,只要 Memory 写得足够好,Agent 给出的建议就能直接对齐团队的技术选型和历史决策,不用反复沟通。
5. 开发环境集成:VSCode、IDEA、桌面版怎么配合用
5.1 VSCode 插件实测
虽然 opencode 的默认形态是终端应用,但对习惯了 IDE 的人来说,编辑器里直接对话往往更顺手。opencode 官方提供 VSCode 扩展,安装方式是直接在扩展市场搜索opencode,或者用扩展面板里的"从 VSIX 安装"。装好后侧边栏会出现一个 opencode 面板,可以聊代码、看 diff、执行 Agent 任务。
我实测下来,VSCode 插件的体验和 CLI 共用一套配置和模型,不会出现两边各自为政的情况。它有两个比较实用的点。第一是选中代码后可以直接"发送到 opencode",这会自动把选中代码以及当前文件路径作为上下文传给 Agent,省去了手动复制粘贴和描述文件位置的麻烦。第二是在面板里点击修改建议时,插件可以直接生成 diff 预览,你确认后再应用,比直接让 Agent 改文件安全很多。
有一个值得注意的坑:VSCode 插件依赖本地 CLI,如果你的终端里opencode命令都跑不通,插件一样会报错。所以集成 VSCode 前,请先确认 CLI 安装完成、配置好模型、能正常对话,然后再回到编辑器。
5.2 JetBrains IDEA 插件
如果你主要在 IDEA 或者 PyCharm 里写 Java、Python,也有对应插件。JetBrains 插件的官方名称就叫opencode,从插件市场搜索就能找到。它的交互逻辑和 VSCode 版类似,在右侧工具窗口里嵌入了对话面板,选中代码右键也能直接发送给 Agent。
不过坦白讲,JetBrains 插件目前的成熟度不如 VSCode 版。我遇到过一个现象:插件连接本地 CLI 的初始化时间比较长,有时需要手动点击重新连接。还有一次模型返回的代码片段里的缩进被插件格式化坏了,导致我不得不在编辑器里手动调整。如果你是重度 JetBrains 用户,可以把插件当作"查看工具"来用——也就是用 opencode 做深度分析和解释,最终代码修改还是在 IDEA 里手动完成。等插件版本迭代成熟了,再考虑把改动直接落到编辑器里。
5.3 桌面版和 TUI 模式,怎么选
桌面版和 TUI 模式的选择,本质上是对"界面形态"的选择。opencode 桌面版提供了图形化窗口、聊天列表、模型切换下拉框、配置编辑面板,对不熟悉终端的新手更友好。TUI 模式则是传统的终端交互方式,界面虽然不花哨,但胜在速度快、资源占用低,而且和脚本、快捷键配合起来更加顺畅。
我个人的工作节奏是:日常在终端里用 TUI 模式干活,因为它不打断我的命令行工作流;遇到需要可视化查看变更文件列表或者多个会话并行管理的时候,再切到桌面版。如果你的项目已经大量依赖 VSCode 或 IDEA,桌面版其实有些鸡肋,因为编辑器插件已经补足了图形界面需求,再用桌面版反而多开了一个窗口。
无论如何,桌面版和 TUI 模式都共用同一套配置目录和模型服务,切换无痛,所以不用纠结"选哪个",两者可以同时装。
6. 高频报错与排查实录
6.1 报错速查表
这两周我整理了一份 opencode 的高频报错速查表,把社区里常见的问题和解决办法汇总一下:
| 报错现象 | 可能原因 | 快速排查思路 |
|---|---|---|
无法将“opencode”项识别为... | PATH 未配置或安装失败 | 确认 npm 全局目录在 PATH,重启终端 |
this model is not available in your country | 模型服务商区域限制 | 查询官方支持区域,更换可用模型或服务商 |
unexpected server error. check server logs | 服务端异常或请求参数错误 | 打开详细日志,确认 API 地址和密钥有效性 |
model not found | 配置文件里模型名拼写错误 | 检查对应 Provider 里声明的模型 ID 是否准确 |
connection timeout | 网络连不上模型服务 | 检查网络连通性,加大超时时间 |
token limit exceeded | 请求上下文超长 | 精简上下文,或切换更大上下文的模型 |
这个表格只是索引,下面挑两个我印象最深的报错详细讲。
6.2 this model is not available in your country
这个报错是模型服务商基于区域合规要求做的访问控制,并不是 opencode 本身的问题。现象是运行opencode后,模型返回英文提示this model is not available in your country,对话无法继续。
遇到这种情况,我的建议是先从合规和使用的角度处理,而不是想办法绕过区域限制。首先确认你当前所在区域是不是服务商官方支持的区域;其次,在 opencode 配置里切换可用的替代模型或服务商。如果项目的业务场景确实需要某个特定模型,那么更稳妥的做法是使用该服务商在你所在区域合法提供的产品线。这里要特别提醒:不要用任何未经授权的手段去绕过区域限制,一方面是合规风险,另一方面稳定性也完全不可控,跑着跑着断联是家常便饭。
6.3 unexpected server error 和日志查看
unexpected server error是个很让人头疼的模糊报错,因为信息量太少,根本不知道是哪一端出了问题。我的排查套路是三步走。
第一步,确认日志。opencode 会把本地日志写到配置目录的 logs 文件夹里,查看最后几行日志,重点看请求发出后服务端返回了什么状态码。如果是 401/403,基本就是 key 失效或者没有权限;如果是 429,说明限流了,需要降速或等待;如果是 5xx,就是模型服务端异常,可以稍后重试或换个服务商。
第二步,验证 API key 本身是否可用。最直接的方式是用 curl 手动请求一次该模型的 API,看返回是否正常。这不调 opencode,能快速把问题隔离到"opencode 配置问题"还是"模型服务商问题"。
第三步,检查配置文件里的模型名是否准确。opencode 的模型名是强校验的,模型 ID 拼错一个字母就会导致请求失败。我在配置自定义 Provider 时犯过错,把模型名写成了展示用的别名,服务端自然不认识。
这几步做完,大部分unexpected server error都能定位到具体原因。
7. 个人使用体会与扩展建议
最后分享一点这段时间用下来的体会。opencode 最打动我的地方不是某个单点功能,而是它的"组合能力"——模型自由切换、LSP 语义理解、Skill 工作流、Playwright 自动化、Memory 长期记忆,这些要素可以像乐高一样自由拼装。同样是做代码审查,我可以让一个模型配合审查 Skill 做逻辑审查,再让另一个模型只关注安全风险,它们在同一个 opencode 会话里各司其职,这是封闭工具很难做到的。
给想入手的读者一个建议:不要一上来就追求"完美配置",先把最简单的一条链路跑通,也就是一个模型加一个项目目录,能对话、能改代码;然后逐步叠加 LSP、Memory、一个 Skill;如果某个环节不顺手,先降级再排查。我见过太多人一开始就把市面上所有 Skill 和插件全装上,最后界面花哨但崩溃不断,反而劝退了。
后续我打算进一步探索两个方向:一个是基于 opencode 的自定义脚本构建团队内部的工作流模板,让新成员拉下来就能跑;另一个是把 opencode 和更多实用工具组合起来,在自动化测试方向上继续深挖。如果你也在折腾 opencode,遇到具体的报错或者有想实现的场景,欢迎在评论区一起讨论,我踩过的坑能帮你省不少时间。