最近我在四川稻城的一个商业远程天文台租了一个机位，用于[天文摄影](/astrophoto-tutorial-0.html)。商业远程天文台是指一个企业在无光污染的地方租地，提供稳定的电源和维护服务。天文爱好者将自己的设备寄过去，由公司托管。用户可以远程控制自己的设备进行摄影。天文台的基本结构是顶部可移动的大房子，白天关闭（关顶），晚上打开（开顶）以进行摄影。和国内的很多其他远程台一样，这个天文台的主要沟通方式是通过[微信群](/wechat-bot.html)。我在群里潜水一段时间后发现，很多讨论都是关于天文台有没有开顶，是不是起云了等状态咨询。这些问题占用了台长很多时间。此外，台长的另一个重要职责是在房顶打开时@所有人来提醒微信群里的所有台友，但这条信息作为一条普通提醒，往往会淹没在微信群中，导致很多人错过拍摄机会。

作为一个码农，我对这种可以自动化的事情都是很感兴趣的。为什么我们不实现一个AI系统来解析监控画面，自动回答这些问题，甚至主动提醒用户天文台已经开顶了呢？对于一个有经验的工程师来说，构建这个系统并不特别困难。经过一番思考之后我们可以意识到，如图一所示，这个系统可以分为四个主要模块。在远程天文台，可以部署一个监控端，它利用相机的SDK读取天文相机的监控画面。这个监控画面一方面会被发送到服务器端进行分析和存储传输，另一方面，在经过采样和标注后，会用于构建AI模型的训练和测试数据集。这个数据集将在我们自己的GPU集群上进行训练，以得到一个优化后的神经网络模型，并部署到服务器端。在服务器端，我们运行一个FastAPI应用层来执行三个主要任务：第一，存储和转发监控端传来的图像，以便移动客户端可以查看；第二，使用之前训练好的神经网络对监控图像进行分析，判断是否开顶；第三，与移动客户端和苹果推送服务通信，实现开顶的推送通知服务。

![Framework](https://yage.ai/images/ai-code-framework.png)

图一. 系统基本架构

这样的服务既不算难，也不算简单，因为它涉及到使用不同技术栈来设计、实现和维护四个在不同位置运行的模块。一个现实的估计是可能需要三四个人（MLE，后端，iOS）用一两天的时间全职开发来完成这个项目。但我想分享的是，最近我确实实现了这个项目。并且在[AI的帮助](/ai-it-impact.html)下，我作为一个熟手MLE，半吊子后端，和完全的iOS新手，只用了八个小时就完成了一个完整的工程系统。在这个过程中，我还遵循了良好的工程实践，比如编写单元测试、提供完备的文档，并且通过了苹果的TestFlight平台的审核，让台里的群友们都能使用（界面如图二所示）。即使到半年前我都无法想象这样的效率，但在2023年AI技术的发展下，八小时内完成过去一个团队几天的所有工作变得相当现实。在这篇文章中，我会首先介绍我是如何使用不同的AI技术来构建不同模块的，以及我在利用AI高效完成软件工程开发任务方面的一些心得体会。

![UI](https://yage.ai/images/ai-code-ui.jpg)

图二. 系统示例界面

整个项目构建的过程可以分为两个阶段。第一个阶段主要是人工完成的，包括几个关键步骤。首先是进行opportunity sizing，评估项目的可行性和潜在收益，确保所投入的时间能够为远程台公司或台友用户带来足够的回报。这个决策非常重要，甚至可能比技术细节更为关键。如果估计错误，可能会导致工作量大大超出预期，就像预想的闪电战变成了陷入莫斯科的冬天一样，这种误判的损失远大于代码优化不当的损失。目前AI还无法帮助做出这样的决策或为人类背锅。

第二步是设计架构。我尝试过使用AI来设计一个基本框架，但发现AI虽然能提供一些正确的方案，却缺乏深刻的见解。它就像一个[知识渊博的小实习生](/AI-thoughts.html)，记忆力好，但在需要提供深刻见解或启发思考时表现不佳。因此，对于具体的模块规划，我们还是必须依靠人工制定。不过，AI可以在这个过程中提供文书辅助，例如使用口述重整工具快速得到整洁的文档。尽管如此，框架图还是需要人工制作。有了框架图和文档，无论是沟通还是未来回顾项目，都非常有帮助。

第三步是选择技术栈。这一选择非常个性化，因为每个人对不同技术的熟悉程度不同。目前AI还不能代替人类进行这一步骤。但如果将来有一个AI，它了解你的所有信息，包括历史和偏好，那么它或许能在这一步替代人类帮助我们完成工作。

在完成了三项关键决策之后，项目的具体编码和实现主要是由AI来完成的，这一点在五个方面尤为明显。首先，对于监控端，尽管我已经有了可以复用的现成代码，我还是尝试使用AI来编写代码，并且取得了很好的效果。具体来说，我使用的是ZWO的天文相机，它的一个优点是提供了基于Python的SDK，可以用Python直接控制相机的多项功能，如自动白平衡、自动曝光和读取RAW格式等。我所做的就是将这个API的Python接口和示例作为提示输入给GPT-4 Turbo，询问如何实现一个Python后台服务，以连接相机，调整自动平衡和自动曝光，接着每30秒读取一帧RAW格式的图像，并以特定的命名方式保存到硬盘的某个文件夹。尽管这个prompt很长，因为贴进去的SDK Python代码可能有七八百行，但GPT-4 Turbo的上下文窗口很大，它轻松处理了整个提示，并给出了很好的结果。它生成的代码与我手头的代码非常相似，我很快就让它运行起来了。

第二，对于服务器端，我完全依赖GPT来编写代码。我使用[明确的prompt](/prompt-engineering-guide.html)告诉它需要使用fast API来实现特定的功能，它接下来就能根据我们的提示写出框架。在此基础上，我使用了Github的Copilot来微调一些功能。例如，我的数据库使用的是MongoDB，GPT假设这个MongoDB没有密码，但我不希望用户信息暴露在互联网服务器上。因此，我还是需要修改一些连接字符串和其他细节。当然，MongoDB的配置工作也是在GPT的指导下完成的，我所做的只是询问如何添加密码，并将其指令在命令行中复制粘贴执行。

第三，对于神经网络的训练，我选择了EfficientNet架构。并且因为我对PyTorch非常熟悉，我使用了非常详细的Prompt指导AI编写了数据加载、训练和测试的代码。我还使用TensorBoard来监控模型的训练过程，并进行超参数的调整。得益于详细的Prompt，AI很快就编写出了高质量的代码。在Copilot的协助下，我只需做了微小的修改，就能在我的GPU机器上运行程序，并成功导出了模型文件和部署代码。

第四，至于iOS客户端，这是我较弱的一环，而且大部分时间也都花在了这上面。我的代码几乎全部是从GPT抄来的，尤其是SwiftUI的实现，基本上复制粘贴后就能直接使用。有时会有一些语法或运行时错误，这时候只要把错误信息贴到GPT里面，两三轮以后也基本可以解决。有个硬骨头是推送通知在iOS中的实现特别复杂，因为它涉及到向苹果申请证书，然后使用OpenSSL命令行将其转换为Python库能读取的格式，最后在FastAPI中使用Python库与苹果的推送服务器通信，触发推送通知。GPT详细地指导了我整个过程，包括申请和转换证书，还帮我写了触发通知的代码。我最初没有意识到开发阶段和产品阶段所需证书的不同，导致用户最初无法收到推送通知。但在询问GPT后，它准确地指出了问题所在，并帮我申请了正确的证书和更新代码。

第五，作为一个码农，我明显没有图像设计方面的天赋。每次提交app时，最让我头疼的一步是设计logo或者app图标。为了解决这个问题，我使用了Mid Journey来进行设计。但问题是，我因为没有相关经验，也不擅长编写mid journey的prompt。最终，我写了一个基于GPT的bot，它可以根据用户的简单指令生成适合Mid Journey的prompt。在这个GPT bot的帮助下，我成功生成了如图三所示的app图标。可以看到，它非常专业，我觉得这样的app图标如果在淘宝上定制，可能要花费几百到上千元。此外，包括这篇文章在内，也是我口述后使用GPT重整语言完成的。它在各种文书和艺术方面为我节省了大量时间，让不可能变成了可能。

![app icon](https://yage.ai/images/ai-code-logo.jpg)

图三. app的图标。海豚是南方天文的吉祥物，狐狸是因为这个远程台旁边有个狐狸老来找吃的。

在整个开发过程中，我的代码都有详尽的注释。这主要是因为，第一AI生成的代码都带有详尽的注释和DocStrings；第二为了让Copilot生成准确的代码，我会先写注释，然后依赖它的自动补全功能来完成代码；第三，Copilot还帮我方便地自动生成了DocStrings。此外，AI还帮我快速生成了一些复杂的单元测试，并真正帮我发现了一个bug。由于AI帮我完成了许多繁重的工作，我能够将更多精力投入到最佳的软件工程实践中，加速了开发进程，减少了走弯路的时间成本。

总的来说，当前的AI技术已经能够显著加速软件工程的开发速度，效率提升了数倍，而且效率提升的幅度与工程师的能力成正比。不同用户利用AI的方式确实各不相同。首先，对于小白用户，即那些没有任何基础的人来说，AI可以作为一个个性化的学习工具。这个"老师"非常耐心和博学，能够理解复杂的问题并提供适当的解决方案。但是，如果用户没有任何编程基础或者基础非常薄弱，即使在AI的帮助下，他们也很难达到实际构建一个软件工程产品的水平。其次，对于有一定基础的用户，比如那些会编程但不懂Swift的人，他们从AI中得到的回报最大，往往能够实现以前无法达到的从零到一的工程构建。这主要是因为在现有的工作框架上修改代码比从头编写代码要容易，而且在AI的帮助下，我们还能有余力去践行更好的软件工程实践。最后，对于[高手](/system-design-interview.html)来说，他们对各种技术细节都非常熟悉，可以将繁琐的编码工作交给AI。就像我们之前提到的模型训练一样，通过非常具体的提示，AI能够生成非常接近成品的代码。而我们人类则可以专注于需求分析和架构设计，这样我们就能将精力和创造力集中在最关键的地方，从而在软件开发方面走得更远。

总的来说，目前AI还无法取代人类，但它是一个倍增器，能够显著提升人的工作效率。我觉得这一轮AI和蒸汽革命，电力革命大体上是可以相提并论的。我们可以预见，在未来，低端软件开发工作可能会被AI取代，就像纯体力劳动被电动机和蒸汽机取代一样。那些能够利用蒸汽和电力的人，他们的工作效率会成倍提升，甚至可能实现阶级跃升。

具体来说，我们应该如何使用AI呢？我的建议是：首先，要理解AI的功能限制和能力边界，知道何时该使用它，何时不该使用它。例如，目前我们不能期望把这篇文章扔给AI，然后它立刻就能输出完美无Bug能运行的整个项目代码。其次，在决定使用AI时，要能够提出正确的问题。换句话说，我们可以将更多精力放在提出正确的问题上，尤其是当我们知道这个问题完全在AI的能力范围内时，就不必再花费大量精力去做底层的思维工作，比如将想法翻译成代码。第三，我们在整个过程中需要避免过度依赖AI，因为目前的AI仍在快速发展，可能存在各种偏见。就像过度使用抖音可能会陷入信息茧房一样，过度依赖AI可能会让我们陷入思维定势，这对于在这个快速发展的领域中生存是不利的。第四，我们应该针对AI优化我们的开发和产品流程。例如，以前构建软件开发库时，通常只需要为人类编写一套详尽的文档。但现在，如果我们想让AI更有效地帮助人类使用这个库编程，我们可能需要为AI准备另一套文档，比如OpenAPI Specification或者是更适应AI有限的上下文窗口的精简版本。对于用户而言，我们的软件开发流程当然也可以针对AI进行优化和简化。

这是一个令人激动不已的时代。以前，如果说能在8小时内完成上面说的整个项目，我甚至不敢想象，但现在这已经成为现实。我对所有读者的建议是，请立刻学习如何使用AI。我们正处在一个类似蒸汽或电力革命的十字路口。使用AI就能立即实现效率的数倍提升，对那些不懂AI的人形成压倒性的优势。

<script async data-uid="49b08a3e73" src="https://yage-ai.kit.com/49b08a3e73/index.js"></script>
