每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领域的领跑者。点击订阅,与未来同行! 订阅:https://rengongzhineng.io/
最近和同事讨论Tabby时,有人提到AI自动补全代码的潜在危害,比如因LLM(大型语言模型)的不可靠性导致代码质量下降,甚至滋生“意大利面条”代码,把像DRY这样的传统开发原则扔得一干二净。但本文的作者对此持不同意见:如果可以有一个框架,既能整合AI工具,又能让代码变得更可靠,会怎么样?这个想法让人瞬间联想到测试驱动开发(TDD)这种方法,尤其是结合LLM时的潜力。
TDD + LLM:从理想到现实的融合
TDD的核心思路是先写出覆盖全面的单元测试,再根据测试来实现主程序。理论上,测试本身就像完整的规范,所有测试通过则说明程序是正确的。然而,TDD在实践中被许多人认为拖慢了开发速度,甚至可能一无所获。LLM的出现,从经济效益上改变了这种状况。
在传统开发中,作者经常依赖像GitHub Copilot这样的工具来辅助编码。这些工具擅长识别模式并补全代码,但对深入理解需求、编写完整模块常常力不从心。为了让LLM高效工作,作者总结了一些经验:提出清晰的需求说明、逐步提供必要上下文、控制模型的注意力范围等。同时,LLM在调试方面表现优异——给出原始报错信息,它往往能猜出问题所在。
然而,频繁的切换窗口、复制粘贴上下文成了主要障碍。于是,作者尝试通过自动化脚本来简化整个流程。
自动化的TDD:工作流详解
作者写了一个简单的事件循环来自动化测试驱动开发:
- 定义需求与函数签名:第一步是向LLM提供明确的功能描述和函数签名,比如:
go run main.go --spec '开发一个函数,输入一段长文本,识别并解析其中的IPv4、IPv6地址和CIDR块(这些可能夹杂在其他符号或文本之间),并将结果返回为列表' --sig 'func ParseCidrs(input string) ([]*net.IPNet, error)'
模型会生成初版实现和对应的单元测试。 - 沙箱验证:将生成的代码和测试放入沙箱目录,执行一系列工具(如
go mod tidy
和go test
)进行语法修复和单元测试。 - 迭代优化:如果初版测试失败,作者会将测试输出和相关代码反馈给模型,让其分析问题并修复代码。这一循环持续进行,直到所有测试通过。
通过这种方式,可以降低模型上下文的长度,节省成本,同时提高迭代效率。
模型的局限与对策
尽管方法有效,但也存在局限。例如,模型可能生成质量不高的测试用例,甚至误导开发者。为了解决这个问题,作者建议引入人工补充测试,并使用“变异测试”进一步验证代码的鲁棒性。具体做法是让LLM对代码进行一些微妙但关键的修改,测试是否能够捕捉到这些改动。
优化代码结构以适配LLM
为了让LLM更好地融入实际项目,作者提出了以下几点建议:
- 模块化设计:将每个目录拆分为独立可测试的子模块,每个模块包含:
shared.go
:共享定义和全局变量;x.go
:单一功能的实现;x_test.go
:对应功能的测试。
- 提供上下文:为模型生成的代码提供必要的背景信息,如依赖文档和示例代码。
- 限制模型的工作范围:一次只让模型处理一个特定子目录,减少分心。
这种结构不仅能减少问题代码进入生产环境的风险,还鼓励代码解耦和单元测试优先的开发方式。最终,代码会趋于高内聚低耦合,既功能丰富,又易于维护。
结语:谨慎拥抱新工具
最后,作者提醒读者,AI技术更新日新月异,今天的优化方案可能很快被淘汰。因此,不必着急用这种方法重构已有的大型项目,但对于新项目来说,这是一种值得尝试的开发思路。