Published on

和 AI 一起写代码,应该注意的两件事?

Authors
  • avatar
    Name
    浩森 Hansen
    Twitter

AI 确实正在一点一点肉眼可见地变强,编程能力也越来越厉害了!

当前 AI 编程存在的问题

然而,AI 的局限性还是挺大的,主要有以下几个方面:

首先,是老朋友幻觉问题,说到幻觉,就要提到 Transformer 架构的底层逻辑,它的底层算法就就决定了模型的目标是:“输出看起来最合理的内容”。所以,一旦模型缺乏某些特定领域的知识,它就会找一些“合理的替代内容”来输出,于是从结果上来看,幻觉就出现了。

另外,有上下文不足的问题。就好像即时战略游戏里每个单位都有“视野范围”,上下文不足意思是就是它的“视野范围”有限,仅能根据我的提示词中提到的内容,进行一些有限范围内的处理。如果我没有在提示词中将关联的文件指出来,那么再加上点幻觉,AI 就会开始胡编乱造。

而我们知道 AI 理解力的来源是注意力机制,它通过比较词汇和词汇之间的关联程度来找到理解文章,然而,越长的上下文就需要更多的计算时间和内存空间。其中,自注意力的复杂度为 O(n^2),呈平方增长。即使使用了某些稀疏注意力,也仅能在边际上减少一些计算资源的需求。

所以,越长的上下文越难处理,在没有算法复杂度进步的情况下,长文本的处理是非常耗费资源的。

怪不得我有很多同事说,用 AI 编程要先写提示词,再阅读代码,然后测试,还不如自己手敲代码来得更快一些。

应该如何有效使用 AI 编程?

针对以上两个问题,我提出两个在编程实践中的建议,分别是数据驱动、测试验证和提示词工程:

数据驱动

我不太建议直接在 AI 提示词中直接写需求,这样有时 AI 可能会写出可运行的代码,但是实际的操作规范和我们的想法可能差很多。

为了让 AI 按照我们的要求编码,我的建议是,在写函数前规定好参数和返回值的数据模型,让 AI 根据数据模型编码。

以下是一个例子:

from pydantic import BaseModel

class Paramter(BaseModel):
  name: str #用户名称
  age: int #用户年龄

class Result(BaseModel):
  desciption: str #用户描述:模版为:"我叫{name},今年{age}岁"

def get_user_info(parameter: Paramter) -> Result:
  """此函数由AI生成"""
  return Result(desciption="我叫{name},今年{age}岁".format(name=parameter.name, age=parameter.age))

以上代码中,我们定义了输入和输出数据的模型,并加上了对其中字段的说明,由 AI 来生成函数中具体的代码。

我们定义的模型和说明,类似于软件的需求说明,同时用代码固定的函数的输入输出接口。这样能保证函数的生成逻辑至少不会偏离需求太远。

测试验证

在生成代码之后,我一般会让 AI 写一个测试用例。运行测试用例来检查代码逻辑是否存在错误。另外,如果使用 Windsurf 或者 Cursor ,它们的 Agent 也许会自动帮你生成好一个测试用例然后执行。

在软件开发领域有一个重要的开发模式就是“测试驱动开发”,但这在之前只是一个美好的梦想,因为我想应该没有什么程序员会先写很多测试用例然后再写代码逻辑吧,这样的时间成本太高了。

但是在 AI 编程时代,这却成了一个不错的最佳实践。哈,果然是技术改变命运啊。

一些提示词工程

除了需求之外,至少在提示词中额外注明:

  • 对应数据模型在哪里?
  • 要调用哪些方法?
  • 可能被哪些方法调用?
  • 参考哪些类似的模块?

以上指向越明确越好,缩减 AI 要处理的上下文范围。

举个例子:

在 src/service 目录中生成一个 ParameterService.py 用于处理来自上游传递来的 xml 参数。你需要将这些参数翻译成为 ffmpeg 参数。xml 文件示例位于 @api_demo.xml ,其中参数说明位于 @common_api_spec.csv 和 @spec_api_spec.csv 。你需要自定义 pydantic datamodel 用于定义参数字段。该模块的下游是 @ffmpeg_service.py ,上游是 @ffmpeg_route.py。

总结

以上三个方法,可以保证在当前 AI 能力尚不完善的情况下,部分规避 AI 的幻觉和上下文不足的问题。

附录

附上我用 Windsurf 的全局提示词文件 .windsurfrules

请使用中文

项目介绍:
{{这个项目是做什么用的}}?

代码生成规则:
- 除非我明确要求,不要在写完代码之后立即执行脚本,也不要自动执行测试用例
- 使用数据模型驱动的开发,除非我明确要求,否则不要轻易修改数据模型
- 在写代码时,注意参考数据模型

测试用例生成规则:
- 请使用 pytest 生成测试用例
- 除非我明确要求,否则不要自动生成测试用例。
- 如果生成测试用例,仅生成集成测试,无需对功能的 mock 做测试,我只需要联调
- 注意在编写测试用例时,尽量避免单次大量产生请求,避免对对方的网站造成过量负载