从 2022 年 AI 编程助手刚起步,到如今各种“Agent 编程”话题刷屏,开发者工具领域有一个变化非常明显:越来越多讨论不再聚焦“某个模型写代码有多强”,而是聚焦“代码到底应该在哪里被生成、在哪里被执行”。最近看到讨论区里有人提起 Charlie Holtz 的一个判断——他认同多人云端开发环境将取代本地 harness 的观点。这个话题看似是工具党之间的争论,但背后其实关系到团队协作方式、Agent 权限边界、环境一致性乃至安全问题。这篇博客不想只聊“谁说了什么”,而是先用通俗方式把“harness”这一概念讲清楚,再拆一拆为什么云端多人开发环境会有取代本地 harness 的趋势,最后给团队一份可落地的迁移参考方案。
如果你是正在用 Cursor、Codex 或 DeepSeek API 改 bug 的开发者,如果你在本地维护过一堆模型调用脚本,或者你所在团队正在考虑如何让多个人共享同一个 AI Agent 工作流,这篇文章适合你。读完你会明白:本地 harness 的“消失”不等于功能消失,而是这一层能力正在从个人配置升级成云端环境的内建服务。
1. 先看懂讨论背景:本地 harness 和云端开发环境的正面碰撞
1.1 这个判断为什么值得关注
Charlie Holtz 一直活跃在 AI 应用开发工具的前沿,也经常和大量使用云端模型 API 的开发者交流。在他看来,开发者在本地折腾 harness 所解决的问题,本质上是开发环境、工具链、模型上下文和团队协作之间的问题。如果把这一整套能力继续交给每位开发者本地维护,每个人都会重复踩同一个坑;而多人云端开发环境天然就适合把这些资源集中起来。
需要提醒的是,这里说的“取代”不是明天一觉醒来所有本地 IDE 都消失,而是指开发工具的使用重心会从个人电脑的进程,迁移到团队共享的云工作区。换句话讲,本地仍然可以有编辑器、有终端、有 Git 客户端,但承载 Agent 运行的“工作现场”不再只是你这一台电脑。
1.2 这个判断可以拆成三个可验证命题
为了不把技术讨论变成口号,我们可以把“多人云端开发环境将取代本地 harness”拆成三个更具体的命题:
- 本地 harness 解决的许多问题,会被云端开发环境以更标准的方式解决。
- Agent 的工作流会逐渐从“个人单机操作”变成“多人共享操作”,这要求环境本身就支持并发与共享。
- harness 仍会存在,但它不再是开发者本地私藏的一套配置,而是云开发平台默认提供的一项能力。
后面几节会分别讨论上面的命题。只要有一条成立,这条判断就已经非常有参考价值。
1.3 为什么这个话题不只是“工具之争”
很多后端团队在接触 AI 编程时,最先遇到的并不是模型能力不足,而是工具链不统一:张三用本地脚本调模型、李四用 IDE 插件、王五把 prompt 写在 Jupyter 里。真正进入开发时,Agent 需要读代码、执行测试、查看 Git 状态,这时候每个人本地的环境差异会被放大。多人云端开发环境的价值在于,它让“开发环境”本身成为可以被版本管理和复制的东西,也因此让 Agent 有了一个稳定的运行基座。这是这个话题值得技术团队认真对待的核心原因。
2. 先厘清概念:AI 编程中的 harness 到底是什么
2.1 harness 原本的含义
在软件工程里,harness 这个词最早常见于“test harness”,也就是测试脚手架。它负责准备运行环境、加载被测对象、收集测试结果。很多工程师也会把混沌工程里用来注入故障的工具叫作 chaos harness。总之,它指的是为了支撑某个自动化过程而建立的辅助层,并不是业务代码本身。
当这句话落到 AI 编程场景时,意思就变得很清晰:为了让大模型真正操作代码仓库、执行命令、读取文件,开发者需要在模型与本地环境之间铺一层“胶水”。这层胶水负责管理 API Key、收集上下文、定义工具函数、执行 shell 命令,并把执行结果反馈给模型。这一整套胶水,就是社区里常说的 harness。
2.2 “DeepSeek harness”“Codex harness” 是同一类东西
如果你关注模型开发圈,会看到越来越多类似“DeepSeek harness”“Codex harness”的说法。它们不是某个厂商官方的唯一产品名,而是开发者对“给特定模型开发一套本地编排工具”这件事的通俗称呼。常见的形态包括:
- 命令行工具,比如让模型能够从一个终端里调用文件读写、代码搜索、Git 命令。
- IDE 插件,把模型能力嵌入编辑器侧边栏或对话框。
- 桌面端工具,把多个模型 API 整合到一个可视化面板里。
- 自研框架,团队在内部把 prompt 模板、工具函数、上下文处理封装成一个 Python/Node 服务。
这些 harness 都有一个共同点:它们承担了模型与实际开发环境之间的连接器功能。没有 harness,模型只能“建议代码”;有了 harness,模型才能“修改代码”或“运行命令”。
2.3 一个最小本地 harness 通常包含哪些部分
无论是用 OpenAI Codex、DeepSeek 还是 Claude API,自己想搭一个能操作仓库的最小 harness,通常需要以下模块:
| 模块 | 作用 | 常见的本地实现 |
|---|---|---|
| 模型访问层 | 统一调用模型 API,处理流式输出 | OpenAI SDK / DeepSeek API |
| 上下文收集层 | 把项目结构、目标文件、Git 状态组装成 prompt | 文件读取、rg 搜索 |
| 工具注册层 | 让模型可以选择调用哪些操作 | 函数注册表 / JSON Schema |
| 执行反馈层 | 执行工具并读取输出 | subprocess、文件系统 API |
| 安全边界 | 限制 agent 能访问的路径和命令 | 白名单、权限检查 |
| 会话管理 | 保存多轮对话与中间结果 | JSONL 或 SQLite 存储 |
为什么本地 harness 在过去一段时间特别流行?因为早期模型官方工具往往并不完善,个人开发者为了追求效率,最快的方式就是自己写一个 Python 脚本包一层 API,再注册几个函数。但问题也在这里:这种 harness 与开发者的个人电脑强绑定,上下文在个人终端里,执行日志在个人终端里,Agent 用的 API Key 也在个人终端里。它能支撑单人的高效开发,却很难支撑团队的协同。
3. 多人云端开发环境究竟强在哪里
3.1 它并不只是“把网页版 IDE 搬进浏览器”
很多人听到“云端开发环境”时会下意识觉得它就是网页版 VS Code。这其实低估了新一代多人云端开发环境的能力。真正的差异在于环境模型从“以个人电脑为中心”变成了“以云工作区为中心”。
在传统模式中,代码放在 Git 远端,但运行代码的环境长在每个人电脑上。云端开发环境则把“环境”本身变成了一个可创建、可共享、可销毁的实体。你打开一个 workspace,里面已经包含操作系统、运行时、依赖、工具链、甚至数据库模拟器。多人加入同一个 workspace 后,看到的是同一个文件系统,操作的是同一套环境。它不是“把界面云化”,而是“把现场云化”。
3.2 多人共享 Agent 上下文:这才是最核心的变化
如果只是多人同时编辑同一个文件,不少本地工具已经能实现。但真正让“多人 + Agent”产生质变的,是上下文共享。在本地方案里,Agent 的对话历史、工具调用结果、终端输出都绑定在某一个开发者的进程里,别人看不到,也接管不了。
在云端多人开发环境中,情况不同。Agent 可以运行在共享的后台服务中,它执行过的命令、生成的 diff、读取过的错误信息都会落在同一个 workspace。新加入的开发者不需要从零开始读聊天记录,而是可以直接查看 Agent 留下的会话、文件和执行日志。这种“共享上下文”能力让 AI 编程第一次真正具备了团队协作属性。
3.3 权限、审计与安全边界更容易统一
本地 harness 的一个隐患在于:为了让 Agent 工作,开发者往往需要给它较大的本地权限,比如读取整个用户目录、执行 shell 命令、修改任意文件。在个人电脑上,这是个人选择;但在团队或企业环境里,这种“无边界 Agent”很难被审计。
云端开发环境提供了统一治理的可能。团队可以规定 Agent 只能访问某个仓库目录,只能执行白名单命令,不能在测试环境以外修改配置,所有调用记录都会写入审计日志。它还把密钥从“本地 .env 文件”收拢到统一的 Secret 管理服务中,降低密钥泄露风险。对技术负责人来说,这是非常有吸引力的价值点。
3.4 计算资源的池化带来更多可能性
本地跑 Agent 还有一个隐形限制:模型推理、代码检索、单元测试这些任务都在抢占个人电脑资源。遇到大型代码库索引时,笔记本风扇狂转是常态。
多人云端开发环境把大量计算资源放在云端,开发者的终端只负责展示和输入。需要跑测试时,可以在云上并行执行多个任务;需要做模型评测时,也可以在云端直接调用 GPU 实例;这些都不是普通的本地 harness 能轻松完成的。资源池化意味着 Agent 能承担更重的任务,而不是只在一个 16GB 内存的笔记本上做小规模重构。
4. 为什么说多人云端环境会取代本地 harness
4.1 本地 harness 正在撞上四堵墙
第一堵墙是协作。本地 harness 天然是单人的。当一个 Agent 正在跑一套“查找问题 → 修改代码 → 跑测试”的循环时,其他开发者看不到过程,也无法中途介入。团队合作中,频繁出现一个人用 Agent 改完代码,另一个人完全不知道改动理由的情况。云端共享环境则可以解决这个问题,因为每个 Agent 动作都发生在公共工作区中。
第二堵墙是环境一致性。本地 harness 依赖的开发环境是“各自为政”的。你本地的 Python 版本、Node 版本、依赖缓存和同事不一致时,同一段 Agent 指令会产生不同的执行结果。很多人把时间花在“为什么你那边能跑、我这边跑不了”上,而没有花在业务逻辑上。
第三堵墙是权限边界。为了调用工具,本地 harness 往往直接在开发者的用户权限下运行。一旦 prompt 注入或工具调用错误,Agent 可能读取本机敏感文件,甚至执行危险命令。这个问题在单机开发中就已经存在,在多人协作中更加不可控。
第四堵墙是运行连续性。长时间运行的 Agent 任务如果绑定在某个开发者的笔记本上,一旦电脑休眠、网络切换或 IDE 重启,任务就中断了。云端环境可以让 Agent 作为后台服务运行,即使开发者关掉浏览器,任务也仍然能继续跑完。
4.2 本地 harness 会“死亡”还是“下沉”
更准确的说法是“下沉”。本地 harness 作为一种显性的个人配置会越来越少见,但它所承担的能力——模型访问、工具注册、上下文管理、执行反馈——不会消失,而是被并入云端开发平台。
这很像早期前端工程化的演进:过去每个项目都要自己手写 Webpack 配置,后来新一代框架把配置收敛为约定;配置并没有消失,但开发者不再需要从零维护。本地 harness 同样会从“使用者要自己搭的脚手架”,变成“云平台开箱即用的默认能力”。
从这个角度理解,Charlie Holtz 认同的判断并不是“以后不需要 harness 了”,而是“以后 harness 不再是初级开发者的个人负担,而是云平台工程师要内建的系统能力”。
4.3 一个简化对比:个人工具变成多人服务
| 对比维度 | 本地 harness | 多人云端开发环境 |
|---|---|---|
| 环境位置 | 单台个人电脑 | 云端共享工作区 |
| Agent 会话 | 单人私有 | 多人可见、可接管 |
| 工具注册 | 个人维护 | 团队配置统一 |
| 权限控制 | 基于本机用户权限 | 可做细粒度策略 |
| 审计日志 | 通常没有 | 默认记录 |
| 运行连续性 | 依赖本机在线 | 可后台服务化 |
| 资源扩展 | 受单机限制 | 可按需扩容 |
| 环境一致性 | 难以保证 | devcontainer/Nix 声明式重建 |
这张表并不意味着本地 harness 没有价值。对于个人练手、快速原型、私人脚本来说,本地 harness 仍然轻量高效。但如果是多人参与的产品研发,云端模式的优势会随着团队规模扩大而被放大。
5. 实战视角:从本地 harness 迁移到共享云端开发环境
如果你认同上面的趋势,接下来最现实的问题是:团队怎么落地?下面给一个可操作的迁移路径,从“把环境代码化”到“把 Agent runtime 服务化”逐步展开。注意,这里给的是思路和骨架,具体镜像、包版本请结合项目实际调整。
5.1 用 devcontainer 固化团队开发环境
迁移的第一步,是把当前每个开发者的“本地环境差异”收拢成一份环境定义。推荐使用 devcontainer.json,它能够统一描述镜像、扩展、挂载卷、启动命令。团队成员只要打开同一个工作区,就会自动进入同一套环境。
{ "name": "team-ai-agent-dev", "image": "mcr.microsoft.com/devcontainers/python:3.12", "features": { "ghcr.io/devcontainers/features/docker-in-docker:2": {} }, "customizations": { "vscode": { "extensions": [ "ms-python.python", "github.copilot" ] } }, "mounts": [ "source=harness-agent-cache,target=/home/vscode/.cache,type=volume" ], "postCreateCommand": "pip install --no-cache-dir -r requirements.txt", "remoteUser": "vscode" }这份配置里值得解释的几点:
- image 指定基础镜像,示例使用官方 Python 开发容器,实际项目需要按 Python/Node/Go 版本替换。
- features 可以给容器附加 Docker 能力,方便 Agent 在隔离容器里执行构建或测试。
- mounts 把缓存目录放到独立卷,避免每次重建环境都要下载依赖。
- postCreateCommand 在环境创建后自动安装 Python 依赖。
对团队的收益是:任何新成员加入,不再需要花两天配置环境;Agent 看到的代码和依赖也和你完全一致。
5.2 把 Agent 工具定义提升为团队级 Manifest
很多本地 harness 的问题在于工具函数写死在个人脚本里,别人不知道这个 Agent 有哪些能力,也无法审查。建议把工具定义抽出来,做成团队可见的 YAML 清单,例如保存为.harness/tools.yaml:
version: 1 tools: - name: read_file description: 读取项目内文本文件 permission: read_only - name: list_dir description: 列出目录内容 permission: read_only - name: run_pytest description: 运行测试用例 permission: test commands: - "pytest {path}" - name: git_diff description: 查看当前改动 permission: read_only commands: - "git diff" security: allow_secrets: false audit_log: true allowed_domains: - api.github.com这份清单把工具权限分为只读和测试两类,默认不允许 Agent 执行无限制的 shell 命令,也不允许读取密钥。团队在做代码评审时,可以直接 review 这份 YAML,而不用去读一堆晦涩的 Python handler。它相当于把 Agent 的“可行动范围”变成显式配置。
5.3 把 Agent runtime 从编辑器进程解耦为服务
本地 harness 通常以插件形式存在,其生命周期和编辑器绑定。为了让多人共享同一个 Agent,更合理的做法是让 harness runtime 成为一个独立服务。下面用一个最小 Python 例子展示这个思路。
先实现最基础的工具注册与调用骨架,保存为agent_harness.py:
# 文件:agent_harness.py """演示用 Agent Harness:先定义工具注册表,再把入口暴露为服务。""" from __future__ import annotations import os import subprocess from dataclasses import dataclass from typing import Callable @dataclass class Tool: name: str description: str handler: Callable[[str], str] class HarnessRuntime: def __init__(self) -> None: self._tools: dict[str, Tool] = {} self.register(Tool("read_file", "读取指定文本文件", self._read_file)) self.register(Tool("run_shell", "执行白名单内的 shell 命令", self._run_shell)) def register(self, tool: Tool) -> None: self._tools[tool.name] = tool def list_tools(self) -> list[Tool]: return list(self._tools.values()) def call(self, name: str, args: str) -> str: if name not in self._tools: return f"未找到工具: {name}" return self._tools[name].handler(args) def _read_file(self, path: str) -> str: if not os.path.exists(path): return f"文件不存在: {path}" with open(path, "r", encoding="utf-8") as f: return f.read() def _run_shell(self, command: str) -> str: # 安全示例:只放行只读命令,真实场景建议用更严格的解析而非 startswith allowed_prefix = ["echo", "ls", "pwd", "git status"] if not any(command.startswith(prefix) for prefix in allowed_prefix): return "命令不在白名单中,拒绝执行" result = subprocess.run( command, shell=True, capture_output=True, text=True, check=False, ) return result.stdout or result.stderr这个类本身没有任何界面逻辑。本地使用时,它可以被 IDE 插件加载;云端运行时,它被一个 Web 服务加载。这样,同样一套工具逻辑可以被不同前端复用。
接着使用 FastAPI 把运行时暴露为 HTTP 接口,保存为server.py:
# 文件:server.py """把 HarnessRuntime 暴露成 HTTP 服务,方便多人共享同一个工具执行环境。""" from fastapi import FastAPI, HTTPException from pydantic import BaseModel from agent_harness import HarnessRuntime app = FastAPI() runtime = HarnessRuntime() class ToolCallRequest(BaseModel): tool_name: str args: str class ToolInfo(BaseModel): name: str description: str @app.get("/tools", response_model=list[ToolInfo]) def list_tools(): return [ ToolInfo(name=tool.name, description=tool.description) for tool in runtime.list_tools() ] @app.post("/call") def call_tool(request: ToolCallRequest): try: result = runtime.call(request.tool_name, request.args) return {"ok": True, "result": result} except Exception as exc: # 实际项目应精确捕获异常 raise HTTPException(status_code=500, detail=str(exc)) from exc这段代码背后的迁移含义是重要的:本地 harness 是“进程内模块”,云端多人 harness 是“进程外服务”。两者共享同一套工具定义和调用逻辑,只是部署在云端工作区之后,所有团队成员可以通过接口访问,而不是在各自电脑里各跑一份。
5.4 多人共享 Agent 会话的工作流
当 runtime 变成 HTTP 服务后,多人工作流可以设计成下面这样:
- 开发者在云工作区启动 agent server 服务。
- 团队其他成员通过统一服务地址查看可用工具列表。
- 需要执行代码操作时,按
/tools返回的工具清单发起/call请求。 - Agent 的实际执行发生在共享容器内,结果写入共享日志。
这种设计带来的直接好处是:即使发起请求的开发者不在电脑前,任务依然运行在云端容器中。换一个人加入协作时,他也可以立刻看到前面操作留下的痕迹。
5.5 运行与验证
本地启动服务验证也很简单:
pip install fastapi uvicorn uvicorn server:app --host 0.0.0.0 --port 8000服务启动后,先查看工具清单:
curl http://localhost:8000/tools预期返回类似下面的 JSON,工具列表以接口数据而不是个人脚本形式存在:
[ { "name": "read_file", "description": "读取指定文本文件" }, { "name": "run_shell", "description": "执行白名单内的 shell 命令" } ]再调用一次只读工具:
curl -X POST http://localhost:8000/call \ -H "Content-Type: application/json" \ -d '{"tool_name": "run_shell", "args": "pwd"}'返回结果里会带上当前工作目录路径,代表 harness runtime 已经在云容器内正常执行。团队成员可以把同一个服务地址配置到共享的 IDE 工作流中,完成从单机 Agent 到共享 Agent 的第一步。
6. 迁移中常见问题与排查思路
从本地模式切换到云端多人环境,并不会一帆风顺。下面整理几个经常出现的问题,以及相应的排查顺序。
| 问题现象 | 常见原因 | 排查与解决思路 |
|---|---|---|
| devcontainer 构建很慢 | 基础镜像体积大,依赖安装步骤没有利用缓存 | 优先使用带缓存的包管理、把依赖安装指令放在文件变更频率低的位置 |
| 多人同时编辑时出现改动覆盖 | 会话没有按工作区或分支隔离 | 建立“一人一分支、一个任务一个工作区”的约定 |
| Agent 工具调不到本地数据库 | 数据库只允许本机访问,没有对云环境放开网络策略 | 检查数据源白名单和连接串,确认云工作区 IP 或内网域名被允许访问 |
| 容器内无法访问私有 NPM/Python 仓库 | 缺少内部源配置或认证信息 | 将仓库凭据放进 Secret 管理服务,在环境初始化时注入 |
| 服务能启动但 Agent 读不到业务文件 | 挂载卷路径与仓库路径不一致 | 统一工作目录,并在 HarnessRuntime 中限制只允许访问指定根目录 |
| 工具返回权限错误 | Agent 在容器内运行但命令需要 sudo | 为容器内用户补齐必要权限,同时限制敏感命令白名单 |
| 审计日志里只有成功调用,没有拒绝记录 | 安全拦截逻辑在工具 handler 内部提前 return | 把拒绝路径也写入日志,便于复盘 prompt 注入风险 |
另外,很多团队在迁移时容易忽略密钥管理。如果 Agent 服务需要在生产环境里访问数据库或对象存储,不要直接把连接串放在环境变量里写死。推荐先使用团队的 Secret 管理能力注入到运行环境,并遵循最小权限原则:只给 Agent 它完成任务所需的读权限和测试权限。迁移过程中如果出现“本地能跑、云端不能跑”的问题,按下面步骤定位:
- 先对比环境变量:两端是否加载了同一套配置。
- 再检查工具白名单:云端是否存在 read 权限以外的命令被拦截。
- 随后检查网络策略:连接目标服务时是否有域名/IP 限制。
- 最后看 Agent 日志:是模型请求失败、工具调用失败,还是结果回传失败。
这四项检查覆盖了多数迁移问题。
7. 工程落地的最佳实践
7.1 先把环境代码化,再谈多人协作
如果团队还没用过 devcontainer 或 Nix,不要急着让所有人切换到云端。可以先选择一两个项目,把依赖锁文件、容器镜像、启动脚本全部收进仓库。当“环境”能被 Git 管理和评审时,多人协作才有共同前提。否则,即使把工具搬到云端,团队内部的环境差异仍然会存在。
7.2 不要一开始就自研复杂 Harness
很多人听说 harness 之后,第一反应是自己写一套复杂的 Agent 调度框架,覆盖 prompt 路由、任务队列、插件机制。但更稳妥的做法是先梳理团队真实需求。多数情况下,只需要一个“能读仓库、能查 diff、能跑测试”的轻量服务。等使用场景变多后,再把公共能力抽成工具,而不是在第一天设计一个大而全的“云原生 Agent 中台”。
7.3 工具权限要显式声明,并默认最小化
Agent 工具调用能力越强,意味着风险上限越高。我建议团队把工具权限以 YAML 或 JSON 形式声明,而不是散落在代码里。每个工具都必须有清晰的权限级别,如只读、测试、受控写入、生产变更等。默认情况下,高危操作应先用“计划模式”输出将要执行的命令,等待有权限的人确认后再真正执行。生产环境变更则需要额外的审批流和可回滚方案,不建议直接把 Agent 权限对接到生产数据库。
7.4 建立审计日志和可追溯性
多人共享 Agent 后,要建立“谁在什么时候让 Agent 执行了什么命令”的审计链路。至少需要记录三类信息:
- 原始请求:发起者、工具名、参数。
- 执行结果:返回码、标准输出、错误信息。
- 策略命中:是否被白名单拦截、是否被权限系统拒绝。
有了这些日志,团队才能在 Agent 做了异常操作时快速定位根因,而不是靠成员回忆。
7.5 成本与资源也需要纳入考量
本地 harness 看起来“免费”,因为它消耗的是个人电脑的闲置资源。云端环境则会把 CPU、磁盘、网络、存储费用集中体现出来。建议团队在迁移初期就为每个 workspace 设置资源上限,并定期清理不再使用的环境和数据卷。长期空闲的 agent server 也要设置自动休眠策略,否则即使没有调用,服务进程依然占用内存。
7.6 借助开放标准避免被单一厂商锁定
最后,无论选择哪一家云端 IDE 或云开发平台,都建议关注它是否支持开放标准。支持 devcontainer 格式的平台能让你在不同服务商之间迁移环境定义;支持 MCP 或类似协议的工具层能让你把 Agent 工具能力标准化。这样即使平台更换,团队积累的环境定义和工具清单也不会作废。
8. 写在最后
回到开头那个判断:Charlie Holtz 认同多人云端开发环境将取代本地 harness。这个话题如果只停留在争论中,意义有限;但它对开发者的实际启示却很明确——未来的开发重心会从“我的电脑怎么跑 Agent”变成“我们的团队环境如何承载 Agent”。开发环境从个人配置演进为共享基础设施,这正是多人云端开发环境越来越有吸引力的原因。
对当下最有价值的行动不是立刻推翻所有本地工具,而是向前走两步:把环境用代码定义起来,把 Agent 工具能力从个人脚本中抽出来。如果这两件事做成了,你并不需要刻意“抛弃”本地 harness——你会自然而然发现,团队的 Agent 协作已经运行在一个更可靠、更透明、更可维护的云端底座上了。
如果这篇文章对你理解本地 harness 与多人云端开发环境的差异有帮助,可以收藏备用,也欢迎在实际迁移过程中对照验证。技术趋势会一直变化,但让代码、Agent 和团队在同一个正确环境里协同这件事,值得长期投入。