来自:DALLE-3
如果你和我一样,通过大学或者无数在线课程踏入了数据科学的领域,你可能怀揣着这样的梦想:创建一个像我们计算机科学朋友似乎轻而易举就能写出来的那种AI或机器学习软件产品。毕竟,就像我们计算机科学朋友似乎轻而易举就能写出来的那种产品。
但如果你曾经尝试过全栈 web 开发的话,你很快就会遇到配置、部署、终端命令等等方面的看似难以克服的问题。
这是我大学时候和室友在刚开始写我这个应用程序时经历的许多挫败对话之一。图片由我制作。
我对此再清楚不过了,曾经花了无数个小时挣扎却无能为力,这只会加深我那种永远无法制作出能正常运行的软件的挫败感。
但是恰好一年前,在1月21日,一个因护照问题和取消的旅行而意外空出的周末,我开始制作AI应用程序的旅程。这趟旅程带我去了意想不到的地方——与远在地球另一边的联合创始人合作,加入了旧金山的一个创业加速器,最终我们拥有了数千用户,每年收入也很不错(快来试试我的应用Podsmart! 我们总结播客)。
我在Buildspace上的应用演示页面。出处:https://buildspace.so/s3/demoday/Podsmart
但最重要的是,这是一段充满挫折、回头、错误和返工的旅程。它关乎在没有正式的计算机科学或软件工程背景的情况下,摸爬滚打在这个让人摸不着头脑的软件开发世界。
所以,回顾过去一年构建我第一个软件产品,我整理了一些技术小贴士——这适用于给任何想要构建一个功能齐全的、服务于数千用户的网络应用的对数据科学感兴趣的朋友们。
这份指南是我一年来的挣扎和学习经历的结晶,代表了我希望告诉一年前我的建议。
请留意:以下是一些建议,基于我个人的具体经历,可能对其他人不太适用。这里提到的工具与我没有任何关系或利益关联。
目录· 你想要打造的应用
· YouTube 上的网页开发教程的风险
∘ 小贴士 #1:用 Next.js 替换 React
∘ 小贴士 #2:用 Tailwind CSS 替代 Bootstrap 进行样式设计
· 数据科学思维的误区
∘ 小贴士 #3:为后端选择 FastAPI 而不是 Flask,并严格定义响应模型
∘ 小贴士 #4:用 TypeScript 替代 JavaScript
· 关于部署…
∘ 小贴士 #5:使用 Modal 作为 GPU 后端
∘ 小贴士 #6:用 AWS Lambda 部署后端,并用 Vercel 部署前端
· 让生活更简单
∘ 小贴士 #7:不要自己用 React 建立着陆页
∘ 小贴士 #8:使用 Firebase + Stripe 进行用户认证和支付
∘ 小贴士 #9:使用 Sentry 进行错误监控
· 结论
你想构建的东西
要开发这样的功能型网页应用,你需要一个前端界面(前端或客户端应用),让用户可以互动,以及一个服务器(后端),处理数据、存储数据并调用机器学习或AI模型。
(你可能听说过Streamlit。它非常适合简单的演示,但确实缺乏足够的定制化来制作一个产品级别的应用)
作为一名数据科学家,我感到不安的是,担心会因为配置问题浪费好几天时间。没有什么比看到某样东西坏了,却不知道它为什么会坏,也不知道如何修复它更让人感到沮丧的了。
因此,我拼命依赖于一步一步的教学视频,特别是我在YouTube上找到的那些,它们从头到尾详细展示了整个过程,比如如何从头到尾设置一个React项目,部署后端或网站等。
回过头来看,主要就是两个问题:
首先,由于多个可能已过时且相互冲突的教程(例如,随着React新版本的发布),我常常按照教程进行直到发现教程不再适用。
其次,大多数教程的目标是构建适合初学者的酷炫课堂演示,因此它们使用了框架并强化了一些编码模式,这些模式性能较低,在实际生产和扩展时会显得不够。后来发现,我从YouTube教程中学到了不少不好的编程习惯,这些习惯现在成为了要将我的应用发展成服务数千用户的实时产品的障碍。
既然你最擅长从失败中学习,虽然这个过程令人沮丧,但对我来说是整整一年来非常宝贵的学习经历。希望你可以从我的失败中学到东西,省下很多时间。
在 YouTube 上搜索“前端和后端应用教程”或“full stack app tutorial”,你会发现很多关于 React 的教程。来源:https://www.youtube.com/results?search_query=full+stack+app+tutorial
许多 YouTube 教程都推荐使用 React,我最初也尝试了。
然而,最终我还是想提高我的网站的SEO优化效果——这对吸引更多的用户至关重要。React的一些限制性特性,例如无法动态修改meta标签和没有服务器端渲染,让我感到头疼,不得不切换到Next.js。切换后,性能上的差异简直是天壤之别。
Vercel 提供了许多 Next.js(一种基于 JavaScript 的 Web 框架)模板,帮助你快速开始 web 开发。详情请见:https://vercel.com/templates/next.js
有些人认为 React 更适合初学者,但网上有很多 Next.js 模板,比如 Vercel (Next.js 创建者) 网站上就有很多,尤其是 AI 相关的应用。Next.js 确实是现代 Web 框架中的佼佼者,几乎每个 AI 应用都在用它。
刚开始我的前端界面之旅时,我有点天真地跟着大流,选择了前端教程中推荐的方向,转向了Bootstrap。Bootstrap的魅力在于,使用现成的组件,比如下拉菜单和折叠面板,带来便捷的体验。
“Bootstrap风格的外观”——我网站在2023年2月20日看起来有多难看。图片由作者提供。
然而,过了一段时间后,我意识到我的网站看起来……真的很难看,特别是和那些时尚的AI演示页面相比就更明显了。我的网站有着显而易见的“Bootstrap风格的样子”——一种审美上的死板,纠结于一堆混乱的CSS类名。最终,我再次硬着头皮,用Tailwind CSS重新设计了整个前端,一共用了三天的时间。
这个AI演示页面绝对没有使用Bootstrap构建。来源网址:restorephotos.io
如果你曾经看过一个现代且简洁的AI演示页面,他们很可能使用了这个Tailwind CSS工具来构建他们的UI。
Tailwind CSS及其实用类让自定义每个元素变得非常简单。图片由作者提供。
最初,我对Tailwind感到有点害怕——它的长组件定义充满了看起来像晦涩的实用类,一点也不适合初学者……我还以为Tailwind没有预构建的组件,并且记住这些实用类会很困难。然而,事实并非如此!有许多优秀的UI组件库是基于Tailwind CSS的——我用了Flowbite React(它包含了我需要的所有组件)。
作为一名数据科学的学生,我渐渐喜欢上了Python及其简洁而强大的代码语法。Python的自动推断类型免去了我为每个变量定义类型的繁琐,这对我来说太繁琐了,特别是在我入门计算机课程中初次接触的Java语言中。
我用JavaScript作为前端,用Python作为后端,除非必要,否则不会给API端点定义数据类型。
然而,随着我的应用程序变得越来越复杂,前端和后端之间出现了大量意外的类型错误,这影响了我的编码效率。我终于理解了朋友们为何坚持明确类型的重要性。原来,详细的类型定义不仅不是多余的——而是必不可少的。
如果你在YouTube上搜索Python后端开发教程,大多数视频会推荐你使用Flask。就像一个坏钟一天也有两次是正确的,我意外选择了FastAPI来进行我的Python后端开发,现在回想起来,这显然是一个正确的选择。
(然而搞笑的是,我完全没注意到FastAPI带来的好处。直到最近,我才明白为什么要在POST请求中使用Pydantic类,之前我一直觉得这样做更麻烦。)
FastAPI 具有几个突破性的好处:
使用 Pydantic 来构建数据模型,你可以用它来定义 FastAPI 服务中的路由的响应类型,使它们更加明确。图片由作者提供。
但最重要的是FastAPI的类型提示功能。
这确保了每个路由都有一个一致的数据结构输出格式。但要真正发挥此功能的全部潜力,我们还需要做……
一直以来,我一直手动编写前端数据抓取方法(再次从全栈教程中学习),所以在我应用中添加新的路由总是变得又长又容易出错。
你可以想象当我那位在大科技公司工作的朋友,他是一名软件工程师,告诉我听到你可以根据API规范自动生成Typescript客户端代码时,我有多么惊讶。FastAPI的相关文档可以在这里找到更多详情(参见这里)。其中一个可用的工具是openapi-typescript-codegen。
使用客户端代码自动生成的TypeScript,您的fetcher方法会自动完成并带有文档,这些功能都是基于您的FastAPI端点响应模型。图片由作者制作。
瞬间,我意识到这将同时解决两个主要问题:消除手动编写且容易出错的客户端抓取器,确保前后端类型的一致性。这大大减少了持续困扰我应用可靠性的类型错误。
当然,只有前端也强制执行这些类型限制时,为后端路由设置类型限制才有帮助——自然需要TypeScript。
因此,我目前正在经历定义FastAPI后端响应模型的艰难过程,并将前端从JavaScript转为TypeScript,这样做的话,如果你从一开始就使用FastAPI和TypeScript,这个过程就可以避免了。
在我的数据科学和机器学习课程中,我已经习惯了跳到Google Colab,点击播放按钮,代码就运行了。因此,一想到部署就让我感到害怕,这也不足为奇。但是正如Buildspace加速器的创始人所说,你需要“脱离本地主机”(GTFOL)才能让你的软件应用为全世界所访问。因此,我希望部署过程尽可能简单无痛。
如果你想要部署自己的模型(例如机器学习模型、图像识别、Whisper 语音转文字,或者最近的开源大型语言模型如 Llama),你需要一个提供 GPU 支持的云服务提供商来托管你的模型。
我的建议就是选了Modal之后就别回头。
Modal因为其出色的文档和学习资源而脱颖而出,这些资源为最新应用提供最新的样例代码,从微调开源大规模语言模型到提供大规模语言模型聊天机器人服务,不一而足。
我实际上是从 Modal 的样例 音频转录代码 借鉴开始创建了我的整个播客转写应用,所以毫不夸张地说,没有 Modal,我就不会开发出这个应用了。
Modal的仪表板在进行监控和追踪错误时非常易于用户操作。来源:modal.com。图片来源:作者。
Modal 的易用性尤其突出(对于一个讨厌部署的人来说,这简直太重要了)。只需在本地代码编辑器中编写云函数,并通过一个命令部署。它的仪表盘非常用户友好(特别是与 AWS 相比),让我能轻松跟踪使用情况、分析性能并追踪错误。
最后,当 Lambda 没有这些功能或实现起来很麻烦时,Modal 就成了我的一个出口,例如,文件存储(这在下文会提到的点中会用到),例如调度功能。
当我运行我的Python后端时,我困惑于是否选择Amazon EC2或AWS Lambda。我的应用需要存储音频文件(这些文件可能会很大,占用大量存储空间),由于Lambda的无服务器架构不适合存储文件(它只有2GB的临时存储空间,且不是持久化的),我原以为我别无选择只能使用Amazon EC2。然而,EC2的配置要复杂得多,并且它作为一个始终运行的专用实例,它的成本会更高,且更难扩展。
这时 Modal 的免费文件存储就派上了用场,我便能将后端设计得与 Lambda 兼容,并在需要时将文件下载和存储到 Modal。
幸好,這個視頻 非常好,跟著他們的指示做讓我順利部署了後端。
对于我的前端来说,Vercel(https://vercel.com/guides/deploying-react-with-vercel)就足够了。过程简单轻松,除了域名费用外,完全是免费的。
最后三项提示,这些提示能帮你避免在开发过程中浪费时间。
我再次犯了错误,是因为所有那些全栈教程误导了我,让我以为我需要自己用React编写着陆页。当然你可以这样做(我也这样做了),但是性能和美观却有限——而这恰恰是你成功着陆页所必需的重要特质。
React 更适合用于像实际 AI 应用界面这样的自定义功能。对于仅包含静态内容的首页或着陆页,你应该使用无需编写代码的网站构建工具,如 Webflow 或 Framer 快速构建着陆页(例如使用 Webflow 或 Framer),并将着陆页的设计和构建外包给你的设计师,这样你就可以专注于其他任务了。
说到用户认证时,各种选择和教程多到让人眼花缭乱。我需要一个解决方案来处理认证需求,还能与支付系统集成,从而根据用户的订阅状态控制访问。
尝试了几天不同的认证解决方案,如 auth0,但都没有成功。我发现 Stripe 和 Firebase 配合得很好。Firebase 与 Stripe 集成,会在用户成功付款后更新其订阅状态,React 客户端可以做客户端认证,而 Python 客户端可以很好地做服务器端访问控制。按照这两个视频(这里 和 这里)的操作,我成功在我的应用中完成了这个实现。
几个月来,我对用户在我的应用程序中遇到的问题一无所知。只有当我或用户发现bug时,我才会查看AWS Cloudwatch,试图找出后端的bug。
Sentry 在您的应用(前端和后端)的生产环境中追踪错误。更多详情请访问 sentry.io。
这一直持续到我的另一位创始人也向我介绍了Sentry,一个用于云应用程序性能监控和错误跟踪的工具,比如Sentry。它在初始化你的前端和后端时非常方便,并且可以和Slack无缝集成,让你实时接收错误通知。但要小心别让一些微小但频繁的错误(如认证超时)耗尽你的免费计划的每个月错误配额。这就是我遇到的情况——我不得不转为付费计划,才能找到并解决真正重要的问题。
Bonus Tip #10: 不要试图使用 Spotify 的 API 构建 web 应用!我花了两个月的时间白费力气,以为可以将 Spotify 的 API 集成到我的应用中,让用户加载他们保存的播客。但为了将此功能投入生产环境,你需要申请配额扩展请求,Spotify 需要一个月以上的时间来审核申请。即使我的应用没有使用任何 Spotify 数据来训练模型,他们可能还会因为你的申请中的描述违反了他们的开发者政策而拒绝。
我希望这份技术指南能帮助各位数据科学爱好者揭开一些 web 应用开发的神秘面纱,使它们不再神秘。
如果你觉得这篇帖子有用:
谢谢你的阅读!