cover

gpt-engineer 体验记录

本文记录了使用 gpt-engineer 开发一个简单的 Web 应用程序的经历,并在后文粗浅地解析了一下 gpt-engineer 的源码。

2024-02-15

gpt-engineer是一个使用大模型自动开发应用程序的 LLM 应用,其官方仓库中介绍的功能是:

  • 使用自然语言定义软件功能;
  • 由 AI 自动编写和执行代码;
  • 提供反馈让 AI 进行改进。

使用 gpt-engineer 创建一个应用程序

根据官方文档的说明,下面将使用 stable 版编 gpt-engineer 创建一个应用程序。Python 版本为 3.10,使用 venvgpt-engineer 创建一个虚拟环境并初始化相关文件。

mkdir gpt-engineer-sample
cd gpt-engineer-sample
python3 -m venv venv
source venv/bin/activate
python -m pip install gpt-engineer
mkdir app
touch app/prompt

完成初始化后,首先在 app/prompt 目录下编写对应用程序的要求:

使用 Next.js@14 实现一个 Web 应用程序,这个 Web 应用程序有以下 3 个页面:

1. 登录
2. 用户主页
3. 广场页

在“登录”页面中,用户需要:

1. 输入用户名
2. 输入密码
3. 点击登录
3.1 用户存在且密码匹配则跳转至“用户主页”
3.2 用户不存在或密码匹配失败则显示“登录失败”弹框

系统预置的用户为:

用户名:admin
密码:admin

在“用户主页”中,用户可以:

1. 上传新的图片
1.1 如果图片的名称中不包含“cat”,则弹框提示“图片名称中不包含 cat,请重新上传”
1.2 如果图片名称中包含“cat”则完成上传
2. 查看我上传的图片
2.1 以瀑布流的形式展示用户已经上传的图片,按照上传时间逆序排序
3. 退出登录

在“广场页”中,用户可以:

1. 查看所有用户上传的图片
1.1 以瀑布流的形式展示所有用户上传的图片,按照上传时间逆序排序

完成上述操作后,使用下面的脚本开始创建应用程序:

export OPENAI_API_KEY=<api-key>
gpte app

gpt-engineer 创建过程中,会输出其思考过程及需要执行的操作,同意操作后即可开始创建项目。测试项目是使用 Next.js 框架开发,因此初始化时需要等待一段时间。创建完成后项目文件会写入到 app 目录中,使用 npm run dev 启动应用程序。

生成的代码中可能会存在一些细微的语法错误,比如缺少 import 语句,进行简单的修复后打开应用,发现生成的应用中没有添加任何的样式,但是 prompt 中的要求基本上都完成了。对于许多细节可以继续使用 gpt-engineer improve 模式进行优化。

使用 gpt-engineer 优化已有项目

如上所述,gpt-engineer 能够生成可用的应用,但是仍有许多可以调整的地方。下面将说明使用 gpt-engineer 优化已有项目的方法。

首先创建一个文件夹用于保存用户 prompts:

mkdir app/.prompts
mv app/prompt app/.prompts/prompt.0_init

然后创建一个新的 prompt 用于指导 gpt-engineer 如何优化:

touch app/prompt
echo '在“用户主页”中,添加前往“广场”页的按钮' >> app/prompt

输入完成后使用下面的指令让 gpt-engineer 开始优化代码:

gpte app -i # -i 或 --improve

gpt-engineer 在开始优化前会在 shell 中使用 vim 显示一个文件选择器,在这个文件中会列出项目目录中的文件列表,需要通过修改此文件(取消文件前的注释 #)来选择需要优化的文件。完成后使用 :wq 保存并退出,然后 gpt-engineer 就会开始优化相关文件中的代码。

gpt-engineer 优化的结果中可能存在错误,在完成后需要检查并修复文件中的问题。由于 gpt-engineer 在修改文件前并不会进行备份,为了避免错误的修改导致的问题,在进行优化前最好还是手动将创建一次 git commit

示例项目迭代了 15 次 improve,虽然依旧不能算得上是一个完备的应用程序,但是基本功能也算是 OK。

生成效果

在简单使用了一段时间后(约莫两个小时,模型是 gpt-4-1106-preview,开销 0.9$),总的来说 gpt-engineer 的生成的应用程序的代码质量还算不错,至少没有明显的错误,并且要求的需求也完成了。结合 improve 模式进行迭代,开发体验尚可。只是依旧有以下几个问题需要注意:

  • 没有使用网络请求的能力,因此能够使用的知识完全依赖于 LLM,无法使用较新的技术;
  • 输出的代码大概率可用,但是还是会出现一些问题(缺少 import 语句、语法错误等),使用者还是需要具备一定的开发能力;
  • improve 前需要手动选择相关的文件,没有办法识别 import 语句并自动读取,因此如果项目复杂的话,还是需要手动确定需要调整的文件。

gpt-engineer 源码分析

gpt-engineer 的源码算不上复杂,主流程非常简单:

  1. 解析参数;
  2. 初始化 LLM(model、azure_endpoint);
  3. 读取用户 prompt;
  4. 确定代码生成函数
  5. 确定代码执行函数
  6. 初始化 preprompts;
  7. 初始化 DiskMemoryDiskExecutionEnvCliAgent
  8. 执行 agent.init(生成应用程序代码)或 agent.improve(优化已有代码)
  9. 更新文件。

下面是一些核心概念的说明。

代码生成函数

用于生成项目代码。根据启动时的参数,有以下三种生成方法:

应用 ENTRYPOINT 文件

项目代码的入口文件。

生成方法:调用 gen_entrypoint方法生成,在该方法中使用 preprompts/entrypoint 和代码文件调用 LLM 生成入口文件。

执行方法:调用 execute_entrypoint执行代码入口文件。

代码执行函数

该方法用于执行应用 ENTRYPOINT 文件。根据使用的参数不同有以下两种方式:

  • self_heal:使用 -sh 选项时使用此方法。该方法会读取 ENTRYPOINT 文件并尝试执行,如果执行失败则会将文件内容、执行的输出内容以及 preprompts/file_format_fix 整合为一条消息发送给 AI 以获取修复结果,并返回修复后的 FilesDict
  • execute_entrypoint:直接执行 ENTRYPOINT 文件。

代码优化函数

improve 方法用于优化已有项目的代码的方法,在使用 -i 选项时会使用此方法。

该方法的执行步骤是使用 setup_sys_prompt_existing_code 方法拼接 improve PROMPT 和 philosophy PROMPT 以生成系统 PROMPT,然后将使用 FileSelector 选中的文件的内容和用户 prompt 作为消息调用 LLM 获取优化意见,最后通过 overwrite_code_with_edits 方法覆写源文件。

代码执行环境 DiskExecutionEnv

DiskExecutionEnv 是一个在本地文件系统上运行代码并捕获执行输出的执行环境。其主要职责是通过子进程执行磁盘中的代码(ENTRYPOINT),并处理用户中断。

上下文记忆 DiskMemory

DiskMemory 时一个基于文件的键值存储,其中键对应于文件名,值对应于文件内容。该类实现了一个简易的支持 CRUD 的数据库。

Preprompts 容器 PrepromptsHolder

PrepromptsHolder 用于加载并读取存储在磁盘上的预提示文本的容器。之所以需要该方法是为了方便通过 --use-custom-preprompts 使用自定义的 Preprompts

临时文件存储 FileStore

FileStore 用于管理临时目录中文件存储的模块。

文件选择器 FileSelector

FileSelector 用于管理项目目录内文件选择和交互,提供了从终端交互式选择文件、保存选择以供以后使用,并与系统编辑器集成以直接修改文件的方法。

CliAgent 智能体

CliAgent 管理使用 AI 模型进行代码生成和改进的生命周期。根据给定的提示协调生成新代码和改进现有代码,并利用记忆系统和执行环境进行处理。

在 Agent 实例中主要使用两个方法:

  • init 方法:根据用户 prompt 创建一个项目。具体来说是使用代码生成函数生成项目代码,然后为项目创建 ENTRYPOINT 文件并执行 ENTRYPOINT。
  • improve 方法:优化已有项目代码,内部操作仅为调用代码优化函数 improve 方法。