一个被低估的AI Agent核心竞争力

0 评论 464 浏览 2 收藏 36 分钟

当所有人都在追逐更强大的模型时,顶尖开发者们却在悄悄优化脚手架。实测数据显示:同一模型在不同 harness 下性能可相差一倍,Claude Opus 4.5 从 42% 飙升至 78% 的关键变量并非模型本身。本文深入解析 harness 与 framework 的本质区别,揭示 Progressive Disclosure 等被严重低估的设计模式,以及为何"给模型删工具"反而能让任务成功率大幅提升。

所有人都在追逐更强大的模型,但几乎没人谈论脚手架。

这是我最近观察到的一个奇怪现象。

每当有新模型发布,科技圈就会沸腾,大家讨论参数量、基准测试分数、上下文长度。但当我深入研究那些真正成功的 AI agent 产品时,我发现了一个被严重忽视的真相:决定 AI agent 性能的,不是你用哪个模型,而是你如何使用这个模型。

同一个模型,在不同的系统架构下,性能可以相差一倍。Claude Opus 4.5 在一个脚手架下得分 42%,换另一个脚手架后得分 78%。这不是模型的问题,而是围绕模型构建的系统的问题。

最近我读到三位开发者——Himanshu、Viv 和 Tony Kipkemboi——分别从不同角度深入分析了 agent harness 这个概念。他们的观点相互补充,让我对 AI agent 的构建有了全新的理解。

  1. Himanshu 通过分析顶尖公司的实践证明了 harness 比模型更重要;
  2. Viv 从第一性原理出发,解释了为什么我们需要 harness 以及它应该包含什么;
  3. Tony 则清晰区分了 harness 和 framework 的概念,帮助我们理解它们各自的适用场景。

这三个视角结合起来,构成了一幅关于 AI agent 构建的完整图景。

Harness 到底是什么

在深入讨论之前,我们需要先搞清楚 harness 这个概念。Tony Kipkemboi 曾在 CrewAI(一个 agent framework)工作,他对这个概念有很清晰的定义。他把 agent 开发比作一个光谱:最左边是原始代码,你直接调用 API,自己管理状态,从零开始构建一切。中间是 agent framework(代理框架),给你提供结构和抽象,但你仍然需要做很多决定。最右边是 agent harness(代理脚手架),这是最有观点的方案,一切都已经内置好了。

Viv 则从更技术的角度给出了定义:Agent = Model + Harness。如果不是模型本身,那就是 harness。换句话说,harness 是所有不属于模型的代码、配置和执行逻辑。一个原始模型不是 agent,但当 harness 给它提供状态、工具执行、反馈循环和可执行约束时,它就变成了 agent。我很认同这个定义,因为它迫使我们从系统的角度思考,而不仅仅是从模型的角度。

具体来说,harness 包括系统提示、工具和技能及其描述、捆绑的基础设施(文件系统、沙盒、浏览器)、编排逻辑(子 agent 生成、交接、模型路由)、以及用于确定性执行的钩子和中间件(压缩、续传、语法检查)。这个列表乍看之下很技术化,但每一项都对应着 agent 在实际工作中会遇到的具体问题。

Framework vs Harness:关键区别

Tony 对 framework 和 harness 的区分让我豁然开朗。Framework 给你提供构建 agent 的抽象。你定义角色、任务、工具。你指定 agent 如何协作,是顺序工作还是层次化工作。Framework 处理管道工作——调用 LLM、路由工具输出、管理执行循环。但你仍在做架构决策。

Framework 对构建块的样子有观点,它有内存抽象、工具接口、任务结构。但这些部分是可交换的。如果你不喜欢默认的内存实现,可以插入自己的。如果想使用不同的 LLM 提供商,可以配置它。Framework 给你标准接口,但你仍在组装系统。这种模块化正是重点。Framework 是为想要构建 agent 的人设计的,不仅仅是使用它们。你需要理解各部分如何组合,因为你是决定使用哪些部分的人。

相比之下,harness 不给你构建块,它给你一个完整的系统。Tony 举的例子是 OpenClaw,几周前在网上很火。这是一个 harness。你下载它,添加 API 密钥,突然就有了一个可以在 WhatsApp、Telegram 和其他平台上聊天的 agent。内存已处理。上下文管理已处理。Agent 循环已处理。工具调用、权限、状态持久化,全都内置了。

你不是在配置内存系统,不是在决定工具如何注册或 agent 如何从错误中恢复。这些决定已经由构建 harness 的人做出。你的工作是把它指向一个任务并让它运行。这就是权衡:你得到了立即可用的东西,但不能改变它内部的工作方式。Harness 对一切都有观点,使用它时你就是在接受这些观点。

我的理解是,这个区别很像买家具和买宜家家具的区别。定制家具(framework)让你选择材料、尺寸、风格,但你需要花时间设计和等待制作。宜家家具(harness)已经设计好了,你买回家按说明书组装就能用,但你不能改变它的基本设计。两者都有价值,取决于你的需求和能力。

从模型的视角理解:为什么需要 Harness

Viv 的文章有一个很有意思的角度:从模型的视角出发,推导出我们为什么需要 harness。这种自底向上的思考方式让我对 harness 的必要性有了更深的理解。

模型本身能做什么?它们接收文本、图像、音频、视频等数据,输出文本。就这样。开箱即用,它们无法维持跨交互的持久状态,无法执行代码,无法访问实时知识,无法设置环境和安装包来完成工作。这些都是 harness 层面的功能。LLM 的结构决定了需要某种机制来包装它们,才能做有用的工作。

举个例子,要实现”聊天”这样的产品体验,我们需要把模型包装在一个 while 循环中,跟踪之前的消息并添加新的用户消息。读这篇文章的每个人都已经使用过这种 harness。关键思想是,我们想把期望的 agent 行为转化为 harness 中的实际功能。这个观点让我意识到,harness 工程本质上是在弥合”模型能力”和”实际需求”之间的鸿沟。

Harness 的核心组件

基于 Viv 的分析,我总结了 harness 必须包含的几个核心组件,以及每个组件存在的理由。

文件系统是最基础的 harness 原语。我们希望 agent 有持久存储来处理真实数据、卸载上下文窗口装不下的信息、并在会话间持久化工作。模型只能直接操作上下文窗口内的知识。在有文件系统之前,用户必须复制粘贴内容给模型,这体验很糟糕,而且对自主 agent 不起作用。世界已经在使用文件系统工作,所以模型自然在数十亿个 token 上训练了如何使用它们。自然的解决方案是:harness 配备文件系统抽象和文件操作工具。

文件系统的重要性怎么强调都不为过。它让 agent 有了工作空间来读取数据、代码和文档。工作可以增量添加和卸载,而不是把所有东西都放在上下文中。Agent 可以存储中间输出并维护超越单个会话的状态。文件系统还是自然的协作界面,多个 agent 和人类可以通过共享文件协调。Git 为文件系统添加版本控制,这样 agent 可以跟踪工作、回滚错误、分支实验。

Bash 和代码执行则是通用工具。我们希望 agent 自主解决问题,而不需要人类预先设计每个工具。今天主流的 agent 执行模式是 ReAct 循环,模型推理、通过工具调用采取行动、观察结果、在 while 循环中重复。但 harness 只能执行它有逻辑的工具。与其强迫用户为每个可能的动作构建工具,更好的解决方案是给 agent 一个通用工具,比如 bash。

Bash 加代码执行是朝着”给模型一台计算机,让它自己搞定其余部分”迈出的一大步。模型可以通过代码即时设计自己的工具,而不是被限制在固定的预配置工具集中。Harness 仍然配备其他工具,但代码执行已经成为自主问题解决的默认通用策略。我认为这是一个重要的设计哲学转变:从”提供足够的工具”转向”提供创建工具的能力”。

沙盒和执行环境也必不可少。Agent 需要一个有正确默认设置的环境,这样它们可以安全行动、观察结果并取得进展。我们已经给了模型存储和执行代码的能力,但这一切都需要在某个地方发生。在本地运行 agent 生成的代码有风险,而且单个本地环境无法扩展到大量 agent 工作负载。

沙盒给 agent 提供安全的操作环境。Harness 可以连接到沙盒来运行代码、检查文件、安装依赖并完成任务,而不是在本地执行。这创造了代码的安全隔离执行。为了更高安全性,harness 可以白名单命令并强制网络隔离。沙盒还能实现规模化,因为环境可以按需创建、分散到多个任务,工作完成后销毁。

好的环境配备好的默认工具。Harness 负责配置工具,这样 agent 可以做有用的工作。这包括预安装语言运行时和包、用于 git 和测试的 CLI、用于网页交互和验证的浏览器。浏览器、日志、截图和测试运行器等工具给 agent 提供了观察和分析工作的方法。这帮助它们创建自我验证循环,在那里它们可以编写应用代码、运行测试、检查日志并修复错误。

内存和搜索用于持续学习。Agent 应该记住它们见过的东西,并访问训练时不存在的信息。模型除了权重和当前上下文中的内容外,没有额外知识。在无法编辑模型权重的情况下,”添加知识”的唯一方法是通过上下文注入。

对于内存,文件系统再次成为核心原语。Harness 支持像 AGENTS.md 这样的内存文件标准,在 agent 启动时注入上下文。随着 agent 添加和编辑此文件,harness 将更新后的文件加载到上下文中。这是一种持续学习形式,agent 从一个会话持久存储知识,并将该知识注入未来会话。

知识截止日期意味着模型无法直接访问新数据,比如更新的库版本,除非用户直接提供。对于最新知识,Web Search 和像 Context7 这样的 MCP 工具帮助 agent 访问超出知识截止日期的信息,比如新库版本或训练停止时不存在的当前数据。

对抗上下文腐烂也是关键挑战。Agent 性能不应该在工作过程中降低。上下文腐烂描述的是模型在上下文窗口填满时推理和完成任务的能力变差的现象。上下文是宝贵而稀缺的资源,所以 harness 需要策略来管理它。今天的 harness 在很大程度上是良好上下文工程的交付机制。

压缩解决的是当上下文窗口接近填满时该怎么办。没有压缩,当对话超过上下文窗口会发生什么?一个选项是 API 报错,这不好。Harness 必须为这种情况使用某种策略。所以压缩智能地卸载和总结现有上下文窗口,这样 agent 可以继续工作。

工具调用卸载帮助减少大型工具输出的影响,这些输出可能会嘈杂地堆满上下文窗口而不提供有用信息。Harness 保留超过阈值 token 数的工具输出的头部和尾部 token,并将完整输出卸载到文件系统,这样模型可以在需要时访问它。

数据说话:为什么 Harness 比模型更重要

说到这里,我想回到 Himanshu 提供的那些令人震撼的数据。这些数字最有说服力地证明了 harness 的重要性。

CORE-Bench 的测试结果非常直接。Claude Opus 4.5 在一个脚手架下得分 42%,换另一个脚手架后得分 78%。同样的模型,性能几乎翻倍。Sonnet 4 的表现是 33% vs 47%。Sonnet 4.5 是 44% vs 62%。这不是小幅改进,这是质的飞跃。唯一的变量是 harness,模型完全相同,基准测试完全相同。

Cursor 的懒工具加载将 token 使用量削减了 46.9%。这是一个具有统计显著性的数字。同样的任务,同样的模型,只是改变了工具的加载方式,就能节省近一半的 token。考虑到 token 成本和处理速度,这种优化的商业价值是巨大的。

更极端的案例来自 Vercel。他们删除了 agent 80% 的工具,结果 agent 从失败任务变成了完成任务。这个案例特别有意思,因为它挑战了我们的直觉。我们通常认为给 agent 更多工具会让它更强大,但事实证明,工具太多反而会降低性能。Token 从 145463 降到 67483,步骤从 100 降到 19,延迟从 724 秒降到 141 秒。这是全方位的改进,而改变的只是 harness 设计。

LangChain 的 deepagents-cli 在 TerminalBench 2.0 上的表现也很说明问题。仅通过改变 harness,分数从 52.8% 提升到 66.5%,提高了 13.7 个百分点。我反复强调这一点:模型完全没变,只是改变了围绕模型的脚手架。

这些数据让我重新思考了 AI 行业的投资方向。我们看到无数公司花费数百万甚至数十亿美元训练更大更强的模型,但可能只需要花一小部分精力优化 harness,就能获得同等甚至更好的性能提升。这不是说模型不重要,而是说我们严重低估了 harness 的价值。

顶尖公司的 Harness 实践

Himanshu 详细分析了几家顶尖公司的 harness 实现,每家都有独特的设计哲学。

Claude Code 采用”模型控制循环”的理念。它是一个简单的 while(tool_call) 循环,没有复杂的 DAG 编排,没有竞争的 agent 角色。模型接收消息和工具,返回文本结束循环,返回工具调用继续循环。Anthropic 明确称之为”模型控制循环”而不是”代码控制模型”。这个微妙的措辞差异体现了设计哲学:给模型更大的自主权。

Claude Code 只提供约 18 个原始工具,分四类:命令行发现、文件交互、网页访问和编排。设计哲学是原始工具优于集成。更有意思的是,Anthropic 选择正则表达式(ripgrep)而不是向量数据库进行代码搜索,理由是 Claude 的代码理解能力足够强,可以构建复杂正则表达式而不需要搜索索引。

Claude Code 还有一个巧妙设计:TodoWrite 工具。从功能上讲它什么都不做,纯粹是 harness 层面的技巧——一个无操作工具,强制 agent 明确表达和跟踪计划,让它在长时间运行中保持正轨。这种设计让我想到,有时候最有效的工具不是执行复杂操作的,而是帮助 agent 保持清晰思路的简单机制。

Cursor 的核心决策是”文件作为基本原语”。为什么?因为文件支持强大搜索、可自然分组、可版本化。他们针对每个前沿模型专门调优 harness。不同模型得到不同工具名称、提示指令和行为指导。这种精细化调优让我意识到,通用方案往往不是最优方案。

Cursor 的自定义语义搜索特别值得一提。他们的嵌入模型使用 agent 会话轨迹作为训练数据。当 agent 完成任务时,Cursor 分析哪些文件本应更早被检索,然后训练嵌入模型匹配这些模式。结果是搜索准确率平均提高 12.5%,在大型代码库上的代码保留率提高 2.6%。这种从实际使用中学习的方法比任何理论优化都更有效。

Manus 则走了另一个极端,从推出以来已经重写了五次框架。他们最独特的做法是使用 logit masking 而不是动态移除工具。任何对上下文前端工具定义的更改都会使所有后续 token 的 KV-cache 失效。所以所有约 29 个工具永久加载,每步可用性通过约束输出 token 概率控制。

Manus 团队得出的最大教训是:最大性能提升来自删除东西。复杂工具定义被 shell 执行替代,”管理 agent”被简单交接替代。如果你的 agent harness 在模型变好的同时变复杂,那就出问题了。这个观点让我深有感触,真正的进步往往来自简化和精简。

Progressive Disclosure:关键但被忽视的模式

Himanshu 特别强调了 progressive disclosure(渐进式披露)这个概念,我认为这是整个 harness 设计中最被低估的模式。

Progressive disclosure 借鉴自 UI/UX 设计,1980 年代起源于 IBM Research 的 John Carroll,1990 年代由 Jakob Nielsen 推广。核心原则:只显示现在需要的内容,按需揭示复杂性。这直接映射到 agent 设计。就像可折叠菜单减少人类认知负荷,分层上下文加载减少 LLM 注意力分散。

数据非常有说服力。Claude-Mem 文档显示,静态加载注入 25000 个 token,效率只有 0.8%。Progressive disclosure 只需 955 个 token,效率 100%。这是约 26 倍改进。Cursor 的懒加载实现 46.9% token 削减。Vercel 删除 80% 工具后,token 从 145463 降到 67483,步骤从 100 降到 19,延迟从 724 秒降到 141 秒,agent 从失败变成功。

各家公司实现方式不同但思路一致。Claude Code 的 SKILL.md 模式:技能存储为 .claude/skills/ 文件,不预加载到每次对话。与每次加载的 CLAUDE.md 不同,技能只在 Claude 检测到相关性时加载。当项目有几十个技能时,这防止上下文膨胀。

为什么 progressive disclosure 如此重要?Liu 等人在 TACL 2024 的论文证明,LLM 性能遵循 U 型曲线——相关信息在输入开头或结尾时性能最高,在中间时下降。即使长上下文模型也是如此。这就是为什么 harness 重要:progressive disclosure 保持输入较小,并将新检索信息放在末尾。

我的理解是,这从根本上挑战了”给模型更多上下文总是更好”的假设。上下文组织方式比数量更重要。这也解释了为什么同一模型在不同 harness 下性能差异如此巨大。

Framework 与 Harness 的模糊边界

Tony 指出,framework 和 harness 的界限并不总是清晰的,而且我认为它也不应该清晰。

一些 framework 正在添加类似 harness 的功能。LangChain 是个好例子。他们发布了 Deep Agents,明确称之为”agent harness”,位于框架之上。它配备内置规划工具、用于上下文管理的文件系统访问、子 agent 生成和内存持久化。你仍在底层使用 LangChain,但 Deep Agents 给你开箱即用的默认设置,这样你不必自己把所有东西连接起来。

LangChain 实际上在自己的技术栈中区分了三层。LangChain(原始库)是 framework。LangGraph 是他们称为”agent runtime”(代理运行时)的东西,处理执行、状态管理和持久性。Deep Agents 是位于两者之上的 harness。这是一家公司跨越整个光谱。用于组合 agent 的 framework,用于可靠执行的 runtime,用于开箱即用的 harness。

这是一家 framework 公司向光谱右侧移动。Deep Agents 仍然是模块化的。你可以交换后端、配置工具、调整提示。但它给你一个工作系统,不需要你组装每一块。

另一方面,harness 也没有听起来那么锁定。拿 OpenClaw 来说,开箱即用时最有观点,但如果你下载源代码,可以交换实现。你可以改变内存工作方式、调整 agent 循环、修改工具处理。只是大多数人不会这样做,因为默认已经工作了。

区别在于开始时已经决定了什么。Harness 配备内置决策。Framework 暴露选项。如果使用 harness,你接受大多数决策并在边缘配置。如果使用 framework,你自己做决策并组装系统。

长时程自主执行的挑战

Viv 特别强调了长时程自主执行的重要性和挑战。自主软件创建是编码 agent 的圣杯,但今天的模型存在早期停止、复杂问题分解困难、以及工作跨越多个上下文窗口时的不连贯问题。好的 harness 必须围绕所有这些设计。

这正是早期 harness 原语开始复合的地方。长时程工作需要持久状态、规划、观察和验证,以在多个上下文窗口间持续工作。文件系统和 git 用于跨会话跟踪工作。Agent 在长任务中产生数百万 token,文件系统持久捕获工作以随时间跟踪进展。添加 git 允许新 agent 快速了解最新工作和项目历史。对于多个 agent 协作,文件系统也充当共享工作账本。

Ralph Loop 是一个有意思的 harness 模式,用于继续工作。它通过钩子拦截模型的退出尝试,在干净的上下文窗口中重新注入原始提示,强制 agent 针对完成目标继续工作。文件系统使这成为可能,因为每次迭代从新上下文开始但从上一次迭代读取状态。

规划和自我验证让 agent 保持正轨。规划是模型将目标分解为一系列步骤。Harness 通过良好提示和注入如何使用文件系统中计划文件的提醒来支持这一点。完成每一步后,agent 从通过自我验证检查工作正确性中受益。Harness 中的钩子可以运行预定义测试套件,在失败时循环回模型并带上错误消息,或者可以提示模型独立自我评估代码。验证将解决方案建立在测试上,并为自我改进创建反馈信号。

Harness 的未来

三位作者都对 harness 的未来有自己的看法,我觉得他们的观点很有启发性。

Himanshu 注意到模型训练和 harness 设计的耦合。今天的 agent 产品如 Claude Code 和 Codex 在模型后训练时将 harness 纳入循环。这帮助模型在 harness 设计者认为它们应该原生擅长的动作上改进,如文件系统操作、bash 执行、规划或与子 agent 并行工作。

这创造了一个反馈循环。有用的原语被发现、添加到 harness,然后在训练下一代模型时使用。随着这个循环重复,模型在训练时所在的 harness 中变得更有能力。但这种共同演化对泛化有有趣的副作用。它以改变工具逻辑导致模型性能下降的方式表现出来。一个真正智能的模型应该不难在补丁方法间切换,但在循环中训练会创造这种过拟合。

但这并不意味着对你任务最好的 harness 就是模型后训练时用的那个。Terminal Bench 2.0 排行榜是个好例子。Opus 4.6 在 Claude Code 中的得分远低于在其他 harness 中的 Opus 4.6。通过只改变 harness 可以榨取很多价值。

Viv 认为随着模型变得更有能力,今天存在于 harness 中的一些东西会被吸收到模型中。模型会在规划、自我验证和长时程连贯性上原生变好,因此需要更少的上下文注入。这表明 harness 随时间会变得不那么重要。但就像提示工程今天继续有价值一样,harness 工程可能会继续对构建好的 agent 有用。

Harness 今天确实在修补模型缺陷,但它们也围绕模型智能构建系统以使其更有效。配置良好的环境、正确的工具、持久状态和验证循环让任何模型更高效,无论其基础智能如何。

Viv 提到 harness 工程是 LangChain 用来改进其 harness 构建库 deepagents 的一个非常活跃的研究领域。一些开放和有趣的问题包括:编排数百个 agent 在共享代码库上并行工作;分析自己轨迹以识别和修复 harness 级别失败模式的 agent;根据给定任务即时动态组装正确工具和上下文而不是预配置的 harness。

我对 Harness 未来的思考

读完这三位作者的分析后,我有一些自己的深度思考。

我认为 harness 工程正在成为一门独立的学科。就像软件工程从计算机科学中分离出来,成为一个有自己方法论、最佳实践和工具链的领域一样,harness 工程也在经历类似的过程。我们已经看到了一些早期信号:专门的 harness 构建库(如 LangChain 的 Deep Agents)、harness 设计模式的总结(如 12 Factor Agents)、以及用于评估 harness 质量的基准测试(如 CORE-Bench、Terminal Bench)。

这种专业化很重要,因为它降低了构建高质量 AI agent 的门槛。当 harness 工程成为一门成熟的学科时,开发者不需要从零开始摸索,可以借鉴已验证的模式和最佳实践。这会加速整个行业的创新速度。

我也注意到一个有趣的悖论:虽然模型在变得更强大,但对 harness 的需求不会消失,只是会转变形式。早期的 harness 主要是在弥补模型的不足,比如给模型添加文件系统访问、代码执行能力等基础功能。但随着这些能力逐渐被模型原生支持,harness 的角色会从”能力补充”转向”性能优化”和”可靠性保证”。

就像现代编程语言已经有了垃圾回收、类型系统等高级特性,但我们仍然需要框架和库来构建复杂应用一样,未来即使模型本身变得非常强大,我们仍然需要 harness 来优化性能、管理复杂性、确保可靠性。Progressive disclosure、上下文管理、错误恢复这些问题不会因为模型变强而消失。

从商业角度看,我认为 harness 工程能力将成为 AI 公司的核心竞争力之一。模型本身正在快速商品化,任何公司都可以通过 API 访问最先进的模型。但如何有效利用这些模型、如何设计出让模型发挥最大效能的系统,这才是真正的护城河。这就像云计算时代,底层基础设施(AWS、Azure、GCP)是商品,但在这些基础设施上构建的应用和平台才是真正的价值所在。

我还思考了 harness 设计的一个哲学问题:应该给模型多大的自主权?Claude Code 的”模型控制循环”代表了一个极端,给模型最大的自由度。而更传统的方法则倾向于用代码严格控制 agent 的每一步。我认为最佳平衡点会随着模型能力的提升而移动。当模型还比较弱时,需要更多的 harness 级别控制和约束。但随着模型变强,给它们更多自主权会带来更好的结果。这个平衡点的把握,需要深刻理解模型的能力边界和任务的复杂度。

Tony 提出的”你解决什么问题决定你需要 framework 还是 harness”这个观点让我想到,也许我们需要一个更细粒度的分类。在 framework 和 harness 之间,可能还有很多中间状态。比如”可配置的 harness”、”模块化的 harness”、”领域特定的 harness”等等。未来可能会出现更多这样的中间形态,让开发者可以根据具体需求选择合适的抽象层次。

最后,我想强调 Himanshu 提到的一个关键洞察:最好的团队一直在简化。Manus 五次重写,每次都删除东西。Anthropic 设计 Claude Code 是为了随模型改进而缩小。这个趋势告诉我们,harness 工程的终极目标不是构建一个功能齐全、无所不包的系统,而是找到最小必要集——那些真正不可或缺、无法被模型原生能力替代的部分。这需要持续的迭代、测试和勇于删除的决心。

Agent = Model + Harness。这个简单的等式背后,是关于如何构建真正有用的 AI 系统的深刻洞察。模型提供智能,harness 让智能有用。在追逐更强大模型的同时,我们不应该忽视 harness 工程的价值。因为最终,没有人购买引擎,大家购买的是完整的汽车。

本文由人人都是产品经理作者【深思圈】,微信公众号:【深思圈】,原创/授权 发布于人人都是产品经理,未经许可,禁止转载。

题图来自Unsplash,基于 CC0 协议。

更多精彩内容,请关注人人都是产品经理微信公众号或下载App
评论
评论请登录
  1. 目前还没评论,等你发挥!