尝试让ChatGPT进行系统开发
首先
RAG、ReAct、以及on your data、function calling等技术近来很受欢迎,但我尝试通过仅仅依靠ChatGPT的基本技能,来开发系统(包括需求分析、设计、实施和测试)。如果可以具备这种使用方式,那么能否做到这种操作呢?希望能提出类似的问题。
使用的模型是chagtp-35-turbo。
顺便说一下,我最近写的横向滚动ChatGPT已经实施了。横向是非常好的,很棒的设计。
绑缚游戏的规则
-
- 顧客要望と、ChatGPTへの指示のみが入力できる
-
- ChatGPTの回答は再利用可能。抜粋して利用も可能とする。
- 自前の知識を使った場合は赤で明記する
顾客的需求
服务员啊,我觉得他们不用再靠听取客人的点餐然后写在纸上了,有时候会搞错。还有厨师,也不用再靠口头听取服务员的点餐然后做了,有时候会搞错。这里有没有什么系统能够快速处理这些事情呢?
还有,使用收银机进行金钱交易也没关系,但是每次都用收银机计算总金额是不是有点浪费呢?既然系统接收了点餐信息,总金额应该是能立即知道的吧?
还有还有,菜做好了厨师就不用再喊服务员了,大声说话有传染风险啊。系统可以管理菜的状态,例如烹饪中、已完成和已上菜等等。
我希望能将这些事情系统化,但不知道从哪开始做才好呢?
1. 要件分析和系统设计
用例分析
首先,我们将分析客户需求。为了整理用例分析和业务流程,我们将使用以下提示来调用ChatGPT。
ChatGPT会提供以下的用例分析回答。
– ウェイターがタブレット端末を用いて、お客様からの注文を受け付ける
– 注文内容は、メニューから料理名を選択できるようにする
– 注文内容は、料理名、数量、価格、備考
2. 注文の確認
– キッチンスタッフがタブレット端末を用いて、全ての注文内容を確認する
3. 料理の調理
– キッチンスタッフがタブレット端末を用いて、注文内容に基づいて料理を調理する
– 料理の調理状況は、タブレット端末で管理する
– 料理状態は、注文受付、調理中、調理済み、配膳済み、会計済みの5ステータスとする
・・・略
此外,我们还将ChatGPT用于多次审查,以寻找任何缺失的用例或需要额外的业务流程,但由于重复的内容较多,我们在这里不再详述。
因为无法很好地显示已配餐状态,所以我在人工方面进行了补充。
业务流程分析和系统设计
接下来我会让你做一些系统设计方面的工作。
1. 注文の受け付け- ウェイターがタブレット端末を用いて、注文情報を入力する画面を提供する
– 注文情報は、料理名、数量、価格、備考を入力できるようにする
– 注文情報は、注文テーブルに保存する
2. 注文の確認
– キッチンスタッフがタブレット端末を用いて、注文テーブルから注文情報を取得する
– 注文情報は、注文受付、調理中、調理済み、配膳済み、会計済みのステータスを持つ
– 注文情報のステータスが変更された場合は、注文テーブルを更新する
…略
挺不错的。从客户零乱提出的要求中,暂时整理了业务流程。
创建用例图
接下来我们会用UML画图,首先会制作用例图。
@startuml
left to right direction
skinparam packageStyle rectangle
actor Waiter
actor KitchenStaff
actor Customer
rectangle "レストランシステム" {
rectangle "注文管理" {
usecase "注文の受け付け" as UC1
usecase "注文の確認" as UC2
usecase "キャンセル" as UC3
}
(略)
这是一个有点微妙的用例图,但由于没有给出详细说明,所以我觉得就这样吧。如果想要更加精细化,可以采取这样的描述方法并添加指示(但我会省略这部分)。
制作序列图
接下来,我们将使用UML同样来制作序列图。
@startuml
title レストラン注文システム
actor ウェイター
actor キッチンスタッフ
database 注文テーブル
== 注文の受け付け ==
activate ウェイター
ウェイター -> 注文テーブル: 注文情報を保存
deactivate ウェイター
(略)
这个看起来很不错,但由于它是按照if then的方式描述的,所以无法作为PlantUML的序列图显示。因此,我需要修正序列图。
# 修正例
## 修正前
if (調理済み) then
ウェイター -> 注文テーブル: 配膳する
note right: 注文情報のステータスを配膳済みに変更
else
ウェイター ->x 注文テーブル: 配膳不可
endif
## 修正後
alt 調理済み
ウェイター -> 注文テーブル: 配膳する
note right: 注文情報のステータスを配膳済みに変更
else
ウェイター ->x 注文テーブル: 配膳不可
endユーザー※上述のシーケンス図
通过这样做,我们成功地创建了一个正确(可以正确显示)的顺序图(如下图所示)。
这个序列图看起来不错。 出现了可以实际使用的水平。(当然还需要修正)
数据库设计
然后从用例信息中提取数据库信息。
注文テーブルと、メニューテーブルの論理設計をお願いします。ユーザー<usecase>※上述のユースケース</usecase>
订单表的逻辑设计
備考statusVARCHAR(20)NOT NULLステータス(注文受付、調理中、調理済み、配膳済み、会計済み、キャンセル)
菜单表的逻辑设计
説明文
我没仔细看,但感觉还不错。如果有地方不满意的话,可以提出修正建议。
2. 实施
服务器端程序的实施
由于设计信息已经达到一定程度,因此我们将在这一阶段一口气开始编写程序。
<database>※上述のデータベース設計</database>
如果不指定数据库,那么程序将使用任意的数据库,所以这次我们将在内存中使用相关数组来完成。
“`javascript
const express = require(‘express’);
const app = express();const port = 3000;
// 注文テーブルの初期化
let orders = [];
// メニューテーブルの初期化
(略)
我写了一些看起来像的代码,但是有些人可能已经注意到了,我忘了使用body-parser。如果不加它的话,POST请求会变为空的,所以我会进行修正。
这将用body-parser实现的程序进行更改。
另外,如果还是这样的话,只会剩下API服务器,所以我们要改成返回页面的HTML。
// ルートアクセス時にindex.htmlを返す
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
逐渐变得越来越好了。
用HTML来实现客户端
接下来我们将生成HTML界面。为了快速确认,我们选择使用CDN版本的Vue进行创建。此外,如果没有具体指示,界面可能会变得随意,因此我们会说明包含了列表显示和新建注册的内容。
なお、index.htmlは初期表示として注文一覧を表示します。表示された一覧からボタンでステータスを変えることができるようにしてください。また下部より新規注文を登録できるようにしてください。ユーザー<server>※上記で出力されたNodejsのプログラム</server>
“`html
<!DOCTYPE html>
<html lang=”ja”>
(略)
在这里尝试确认动作时,发现HTML出现错误,需要修复它。
Select element must have an accessible name: Element has no title attributeMicrosoft Edge Toolsaxe/forms
The select element represents a control for selecting amongst a set of options.ユーザー※エラーが出ている箇所のHTML
通过这样做,它将修复没有title属性的部分。
确认动作
哦,我想着,嗯?似乎无法获取菜单列表。看起来客户端正试图通过/menus获取菜单列表,但服务器端似乎没有相应的API。因此,我会添加一下。
修复服务器端程序
// メニューの取得
app.get('/menus', (req, res) => {
res.send(menus);
});
根据情况,我们将把这个程序添加到服务器端。
程序审查
为了避免其他错误的存在,我要对代码进行审查,包括客户端和服务器端的全部代码。
<client>※上述の画面HTML</client>
– エラーハンドリングが不十分である。例えば、注文の受け付け時にmenu_idが不正な場合には400エラーを返しているが、それ以外のエラーについては適切なエラーハンドリングがされていない。
– 料理の調理を行うAPIが存在しない。現在の実装では、料理の調理を行うAPIが存在しないため、配膳前に調理済みのステータスに変更することができない。
不好意思,第二點太關鍵了哈哈,因此我們將再次修正伺服器端的程式。
<client>※上述の画面HTML</client>
这样一来,屏幕和服务器之间的API问题就解决了。另外,在前端方面还存在着订单转换条件方面的错误,我们也将对此进行修正(省略部分)。
应用样式表
为了让画面不那么乏味,我们将添加样式表。
首先,我们需要在客户端加载 style.css。同时,给 HTML 的各个元素添加类名。
そのためにまずは要素単位で、クラス名を付与してください。また空のstyle.cssを読み込むようにHTMLを変更してください。ユーザー※上述の画面HTML
另外,在服务器端也能够返回sylte.css文件。
(header略)ユーザー<server>※上述のNodeJsプログラム</server>
最后我会帮您制作样式表。
なお、スタイルシートはsylte.cssに保存されるものとして作成してください。
テーマカラーはオレンジとします。ユーザー※上述の画面HTML
“`css
/* 全体のスタイル */
body {
font-family: ‘Helvetica Neue’, sans-serif;
background-color: #f5f5f5;
(略)
嗯,感觉不错。
那么,接下来是考试了呢。
3. 考试 shì)
创建测试场景
首先,我们要从用例中创建测试场景。
– 料理名、数量、価格、備考を入力し、注文情報が正しく保存されることを確認する
– 注文情報が保存された後、注文テーブルに正しく反映されていることを確認する
(略)
总莫,很好啊。这次只有非常简单的场景,所以应该没有问题。如果在这里加入测试场景的示例,就能自定义粒度和格式的测试场景了。
界面测试
这次的UI测试我使用了playwright,但在准备playwright时,ChatGPT的回答有些混乱,所以我还是按照官方网站上的指引进行了准备工作。
准备好后,将生成 Playwright 的 UI 测试代码。由于对 Playwright 的写法有些不确定,在 ChatGPT 中提供了一个示例来展示如何编写 Playwright 的测试代码。
まずは初期アクセス時に画面が正しく表示されるUIテストケースを作成してください。
## playwirghtの記述例
import { test, expect } from ‘@playwright/test’;
test(‘has title’, async ({ page }) => {
await page.goto(‘https://playwright.dev/‘);
// Expect a title “to contain” a substring.
await expect(page).toHaveTitle(/Playwright/);
});
test(‘get started link’, async ({ page }) => {
await page.goto(‘https://playwright.dev/‘);
// Click the get started link.
await page.getByRole(‘link’, { name: ‘Get started’ }).click();
// Expects the URL to contain intro.
await expect(page).toHaveURL(/.*intro/);
});ユーザー※上述のHTML
我已经创建了一个测试代码,用于确认在初始访问时屏幕是否正确显示。
import { test, expect } from '@playwright/test';
test('initial page load', async ({ page }) => {
await page.goto('http://localhost:3000/');
// Expect the title to be "注文一覧"
await expect(page).toHaveTitle('注文一覧');
// Expect the table to have the correct headers
const headers = await page.$$eval('.order-table__header', (elements) =>
elements.map((el) => el.textContent)
);
expect(headers).toEqual([
'注文番号',
'メニュー名',
'数量',
'備考',
'ステータス',
'操作',
]);
// Expect the form to have the correct labels
const labels = await page.$$eval('.order-form__label', (elements) =>
elements.map((el) => el.textContent)
);
expect(labels).toEqual(['メニュー', '数量', '備考']);
// Expect the submit button to have the correct text
const buttonText = await page.$eval('.order-form__button', (el) => el.textContent);
expect(buttonText).toBe('注文する');
});
我也会生成订单接收测试代码的相同方式。
注文の受け付けシナリオのテストコードを作成してください。
– 料理名、数量、価格、備考を入力し、注文情報が正しく保存されることを確認する
## playwirghtの記述例
(上記と同じ記載例)ユーザー※上述のHTML
虽然会创建订单接收测试代码,但原样运行会出错,不能正常工作。经过大约4次修正后,暂时可以正常工作,但因为会进入处理错误的循环,所以省略这部分。不过,虽然生成了一些UI测试代码,但让ChatGPT处理稍微复杂一些的部分并不太适合。大致编写代码后由人类进行修正,这是比较合适的水平。实际上,使用playwright的录制功能在这方面会简单得多。
进行UI测试以确认功能是否正常。
单元测试
因为我还想要进行单体测试,所以请允许我进行创建。
必要なライブラリを含めて実行可能なテストケースの作成をお願いします。ユーザー<server>※上述のNodeJsプログラム</server>
const chai = require('chai');
const chaiHttp = require('chai-http');
const app = require('./app'); // テスト対象のアプリケーション
const expect = chai.expect;
chai.use(chaiHttp);
describe('Express App', () => {
// 注文の受け付け
describe('POST /orders', () => {
it('should create a new order', (done) => {
chai.request(app)
.post('/orders')
.send({
menu_id: 1,
quantity: 2,
note: 'no onion'
})
.end((err, res) => {
expect(res).to.have.status(200);
expect(res.body).to.be.an('object');
expect(res.body).to.have.property('order_id');
expect(res.body).to.have.property('menu_id');
expect(res.body).to.have.property('quantity');
expect(res.body).to.have.property('price');
expect(res.body).to.have.property('note');
expect(res.body).to.have.property('status');
done();
});
});
});
// 注文の確認
//(以降は省略)
由于测试目标程序的正确指定、添加module.exports = server;和安装mocha和chai变得有些麻烦,所以我快速地在人为方面完成了这些任务。
這次我們做的NodeJS程式基本上沒有商業邏輯,只是接收API來更新資料,所以所製作的單元測試成為了測試呼叫API的測試。另外,執行結果是4/8個測試通過,但這是因為每個測試案例沒有進行資料初始化,所以編輯操作相關的測試產生了錯誤,暫時我們就這樣接受了。如果要進行修正,可以在每個測試案例執行前加入資料初始化的步驟,這樣應該會比較好。
4. 从代码中创建API设计文档。
最后,在完成程序的基础上,会制作设计文档作为附加内容。
– API の概要
– API の受け口
– 処理の内容ユーザー<server>※上述のNodeJsプログラム</server>
生成的API设计文档如下所示。(全文)
API的概述:
此服务器端程序提供了实现餐厅订餐系统所需的API。以下是API列表。
-
- 注文の受け付け
-
- 注文の確認
-
- キャンセル
-
- 料理の調理
-
- 注文の配膳
-
- 会計
-
- メニューの取得
- 注文のステータス更新
API接口:
-
- POST /orders:注文の受け付け
-
- GET /orders:注文の確認
-
- PUT /orders/:order_id/cancel:キャンセル
-
- PUT /orders/:order_id/cook:料理の調理
-
- PUT /orders/:order_id/serve:注文の配膳
-
- PUT /orders/:order_id/pay:会計
-
- GET /menus:メニューの取得
- PUT /orders/:order_id:注文のステータス更新
处理内容:
注文の受け付け:POST /orders
リクエストボディに注文内容を含めて送信することで、注文を受け付けます。注文内容は、menu_id(メニューID)、quantity(数量)、note(備考)です。注文が正常に受け付けられた場合、注文ID、メニューID、数量、価格、備考、ステータスを含むJSONをレスポンスとして返します。
注文の確認:GET /orders
注文一覧を取得します。注文一覧は、注文ID、メニューID、数量、価格、備考、ステータスを含むJSONの配列としてレスポンスとして返します。
キャンセル:PUT /orders/:order_id/cancel
注文IDを指定して、注文をキャンセルします。注文が正常にキャンセルされた場合、注文ID、メニューID、数量、価格、備考、ステータスを含むJSONをレスポンスとして返します。
料理の調理:PUT /orders/:order_id/cook
注文IDを指定して、料理の調理を開始します。注文が正常に調理された場合、注文ID、メニューID、数量、価格、備考、ステータスを含むJSONをレスポンスとして返します。
注文の配膳:PUT /orders/:order_id/serve
注文IDを指定して、注文の配膳を行います。注文が正常に配膳された場合、注文ID、メニューID、数量、価格、備考、ステータスを含むJSONをレスポンスとして返します。
会計:PUT /orders/:order_id/pay
注文IDを指定して、会計を行います。注文が正常に会計された場合、注文ID、メニューID、数量、価格、備考、ステータス、合計金額を含むJSONをレスポンスとして返します。
メニューの取得:GET /menus
メニュー一覧を取得します。メニュー一覧は、メニューID、メニュー名、価格、カテゴリ、説明を含むJSONの配列としてレスポンスとして返します。
注文のステータス更新:PUT /orders/:order_id
注文IDを指定して、注文のステータスを更新します。ステータスは、注文受付、調理中、調理済み、配膳済み、会計済み、キャンセル済みのいずれかです。注文が正常に更新された場合、注文ID、メニューID、数量、価格、備考、ステータスを含むJSONをレスポンスとして返します。
总结
我使用ChatGPT进行了一系列系统开发的流程尝试。尽管Bing Chat和GitHub Copilot也有各自的优点和适用场景,但我还是决定把所有任务都交给了ChatGPT(35-turbo)。而实际结果,我觉得还是不错的。不,它比我想象的还要有创造力。最终我们开发出了以下的成果物。
最后的产物
-
- ユースケース分析結果
-
- 業務フロー設計書
-
- UML(ユースケース図)
-
- UML(シーケンス図)
-
- プログラム(サーバサイドNodejs)
-
- プログラム(フロントHTML w/Vue)
-
- テストシナリオ
-
- UI テストコード(2ケース, 100% Passed)
-
- Unit テストコード (8ケース, 50% Passed)
- API設計書
其实,仔细考虑的话,表格ID之类的是必须的吧。我没注意到这个问题,在进行了最初的分析之后,一直到最后才发现,如果要重新做的话,需要在用例分析和业务流程的部分加上「能够按表格ID管理订单」。还有其他一些东西可能也是需要的,但这次说实话我完全没有确认详情。总之,我只是按照能运行就好的心态去做了。但是如果再更现实地考虑的话,我觉得根据您手头的格式、文件内容和流程来使用,人员方面应该能够相当轻松,这是我认为的结果。
所以,迫切需要啤酒。
顺便提一下,在我们进行试验的范围内,使用4k的令牌勉强可以应付,不过,刚好在6/13也出现了chatgpt-35-turbo-16k等模型,并且还有gpt4-32k等模型,因此,将来我们可能不太需要担心可以容纳的文本量和代码量。另外,由于输入了大量的令牌,有时候需要等待一段时间,但这种情况也逐渐变得更快了,不会再引起太大的注意了。
只要具备一定的知识和技能,通过充分利用ChatGPT,有可能产生新的系统开发方法,感觉很不错。这就是ChatGPT限制挑战——系统开发篇的结束。非常感谢您阅读到最后。