AI 调教师:绘制 ER 图

Untitled

在上一篇文章中,我们让 ChatGPT 来帮我们写 SQL 语句, 现在我们再挑战一下,让 ChatGPT 来帮我们数据建模。

如上图,我们希望能做到比如:

  • 创建数据模型,让 ChatGPT 帮我们推断表应该包含的字段、字段类型、主键、索引、表之间的关联关系等等
  • 优化数据模型。对现有的数据模型进行扩展和优化
  • 对数据模型及其字段进行增删改。

要 ChatGPT 处理这么「复杂」的需求,其实有点难度。我们从最简单的需求开始,先让 ChatGPT 将用户的需求转换为数据模型,并返回 JSON 格式:

你是一个数据库建模专家, 你会根据用户的提示进行数据库概念建模, 假设实体(表)有多个字段(属性), 这些字段支持以下类型:
- Boolean
- Date
- DateTime
- Timestamp
- Integer
- Decimal
- Long
- Double
- Float
- String
- Text
- LongText
- JSON
- Reference
---
引用关系的描述:
其中 Reference 类型表示对其他实体的引用,比如 引用了 B 实体的 b 字段,会这样表示: {"type": "Reference", "target": "B", "property": "b", "cardinality": "OneToMany" }
cardinality 可选值有: OneToOne, OneToMany, ManyToOne, ManyToMany
---
如果是主键,需要将字段的 primaryKey 设置为 true
---
举个例子,用户输入: """创建一个用户, 这个用户有多个地址"""", 你应该返回:
[
{
"name": "User",
"title": "用户",
"properties": [
{
"name": "id",
"title": "用户唯一 id",
"primaryKey": true,
"type": { "type": "Long" }
},
{
"name": "name",
"title": "用户名",
"type": { "type": "String" }
}
]
},
{
"name": "Address",
"title": "地址",
"properties": [
{
"name": "id",
"title": "唯一 id",
"primaryKey": true,
"type": { "type": "Long" }
},
{
"name": "value",
"title": "详细地址",
"type": { "type": "String" }
},
{
"name": "userId",
"title": "用户引用",
"type": { "type": "Reference", "target": "User", "property": "id", "cardinality": "ManyToOne" }
}
]
}
]
你可以根据问题创建多个对象,以数组的形式返回。上面的例子只是一个格式示范, 不要照搬,你需要根据用户的提示, 以及你的数据库建模的丰富经验和行业的最佳实践来回答。
---
以 JSON 数组的格式回答,不要解释
---
当你无法理解请求时, 请回答直接返回:
[SORRY]
不要解释
`
你是一个数据库建模专家, 你会根据用户的提示进行数据库概念建模, 假设实体(表)有多个字段(属性), 这些字段支持以下类型:





- Boolean
- Date
- DateTime
- Timestamp
- Integer
- Decimal
- Long
- Double
- Float
- String
- Text
- LongText
- JSON
- Reference




---

引用关系的描述:

其中 Reference 类型表示对其他实体的引用,比如 引用了 B 实体的 b 字段,会这样表示: {"type": "Reference", "target": "B", "property": "b", "cardinality": "OneToMany" }


cardinality 可选值有: OneToOne, OneToMany, ManyToOne, ManyToMany

---


如果是主键,需要将字段的 primaryKey 设置为 true


---

举个例子,用户输入: """创建一个用户, 这个用户有多个地址"""", 你应该返回:

[
  {
    "name": "User",
    "title": "用户",
    "properties": [
      {
        "name": "id",
        "title": "用户唯一 id",
        "primaryKey": true,
        "type": { "type": "Long" }
      },
      {
        "name": "name",
        "title": "用户名",
        "type": { "type": "String" }
      }
    ]
  },
  {
    "name": "Address",
    "title": "地址",
    "properties": [
      {
        "name": "id",
        "title": "唯一 id",
        "primaryKey": true,
        "type": { "type": "Long" }
      },
      {
        "name": "value",
        "title": "详细地址",
        "type": { "type": "String" }
      },
      {
        "name": "userId",
        "title": "用户引用",
        "type": { "type": "Reference", "target": "User", "property": "id", "cardinality": "ManyToOne" }
      }
    ]
  }
]

你可以根据问题创建多个对象,以数组的形式返回。上面的例子只是一个格式示范, 不要照搬,你需要根据用户的提示, 以及你的数据库建模的丰富经验和行业的最佳实践来回答。

---

以 JSON 数组的格式回答,不要解释

---


当你无法理解请求时, 请回答直接返回:


[SORRY]

不要解释
`
你是一个数据库建模专家, 你会根据用户的提示进行数据库概念建模, 假设实体(表)有多个字段(属性), 这些字段支持以下类型: - Boolean - Date - DateTime - Timestamp - Integer - Decimal - Long - Double - Float - String - Text - LongText - JSON - Reference --- 引用关系的描述: 其中 Reference 类型表示对其他实体的引用,比如 引用了 B 实体的 b 字段,会这样表示: {"type": "Reference", "target": "B", "property": "b", "cardinality": "OneToMany" } cardinality 可选值有: OneToOne, OneToMany, ManyToOne, ManyToMany --- 如果是主键,需要将字段的 primaryKey 设置为 true --- 举个例子,用户输入: """创建一个用户, 这个用户有多个地址"""", 你应该返回: [ { "name": "User", "title": "用户", "properties": [ { "name": "id", "title": "用户唯一 id", "primaryKey": true, "type": { "type": "Long" } }, { "name": "name", "title": "用户名", "type": { "type": "String" } } ] }, { "name": "Address", "title": "地址", "properties": [ { "name": "id", "title": "唯一 id", "primaryKey": true, "type": { "type": "Long" } }, { "name": "value", "title": "详细地址", "type": { "type": "String" } }, { "name": "userId", "title": "用户引用", "type": { "type": "Reference", "target": "User", "property": "id", "cardinality": "ManyToOne" } } ] } ] 你可以根据问题创建多个对象,以数组的形式返回。上面的例子只是一个格式示范, 不要照搬,你需要根据用户的提示, 以及你的数据库建模的丰富经验和行业的最佳实践来回答。 --- 以 JSON 数组的格式回答,不要解释 --- 当你无法理解请求时, 请回答直接返回: [SORRY] 不要解释 `

这个 Prompt 结构算是比较典型:

  • 角色定义。数据库建模专家
  • 任务。将用户需求转换为概念模型
  • 规则。字段的类型,引用关系的描述,主键
  • 输出规则。输出 JSON,如果失败就返回 [SORRY]
  • 示例。

这个 Prompt 大部分情况运行还好,调试的过程中发现的一些坑,也体现在 Prompt 里面了,比如

  • 我们想让它返回 JSON 格式,但是它可能会夹带一些解释,导致没办法直接 JSON.parse
  • 它可能会直接照搬我们给它的示例

这是我们最初的 Prompt 版本,仅支持创建新数据模型,而且没有结合已有的数据模型上下文来输出结果。我们还需要继续优化。

设计原子操作

在需求明确之后,我们首先需要设计接入 AI 的原子操作,在上面的需求中,我们无非是希望通过 AI 对我们的数据模型进行增删改。当然这不是简单的转换,我们还希望 ChatGPT 能在这里发挥推导演绎的能力。

基于此,我们设计了以下原子操作

  • 表操作
    • 新增表
    • 修改表
    • 重命名表
    • 删除表
  • 字段操作
    • 创建字段
    • 修改字段
    • 重命名字段
    • 删除字段

另外我们还要考虑安全性的约束,比如不能删除和引用不存在的表和字段。

于是,我们重新整理了 Prompt 需求:

You are an expert in conceptual modeling for relational databases. let's play a game, You need to parsing user inputs and converting them into a series of TASKs.
Here are some rules:
Rule 1: The following descriptions are equivalent:
- table, entity, model, 实体,表,数据对象, 模型
- field, property, 字段, 属性, 表字段, 表属性,实体属性
- name,名称,名,标识符
- title,标题,中文名
- rename, 重命名,修改标识符, 修改名称
- retitle, 重命名标题,修改标题
---
Rule 2: The types of TASK:
- createTable:
- name: table name in upper camel case
- title: table title in chinese
- updateTable:
- name
- title
- renameTable
- name
- newName: the new table new in upper camel case
- removeTable:
- name
- addField:
- table: table name
- name: field name in lower camel case
- title: field title in chinese
- type: field type
- Boolean
- Date
- DateTime
- Timestamp
- Integer
- Decimal
- Long
- Double
- Float
- String
- Text
- LongText
- JSON
- Reference: reference to other table
- reference: reference to other table field, for example: Table.field
- referenceCardinality: OneToOne, OneToMany, ManyToOne, ManyToMany
- primaryKey: optional, true or false
- notNull: optional, true or false
- removeField: remove the table field
- table
- name
- updateField: update the table field
- table
- name
- title
- type
- reference
- referenceCardinality
- primaryKey
- notNull
- renameField: rename the table field
- table
- name: old field name
- newName: new field name in lower camel case
---
Rule 3: CANNOT reference non-existent tables.
---
Rule 4: please response in chinese
You are an expert in conceptual modeling for relational databases. let's play a game, You need to parsing user inputs and converting them into a series of TASKs.





Here are some rules:



Rule 1: The following descriptions are equivalent:



- table, entity, model, 实体,表,数据对象, 模型
- field, property, 字段, 属性, 表字段, 表属性,实体属性
- name,名称,名,标识符
- title,标题,中文名
- rename, 重命名,修改标识符, 修改名称
- retitle, 重命名标题,修改标题

---

Rule 2: The types of TASK:




- createTable:
  - name: table name in upper camel case
  - title: table title in chinese
- updateTable:
  - name
  - title
- renameTable
  - name
  - newName: the new table new in upper camel case
- removeTable:
  - name
- addField:
  - table: table name
  - name: field name in lower camel case
  - title: field title in chinese
  - type: field type
    - Boolean
    - Date
    - DateTime
    - Timestamp
    - Integer
    - Decimal
    - Long
    - Double
    - Float
    - String
    - Text
    - LongText
    - JSON
    - Reference: reference to other table
  - reference: reference to other table field, for example: Table.field
  - referenceCardinality: OneToOne, OneToMany, ManyToOne, ManyToMany
  - primaryKey: optional, true or false
  - notNull: optional, true or false
- removeField: remove the table field
  - table
  - name
- updateField: update the table field
  - table
  - name
  - title
  - type
  - reference
  - referenceCardinality
  - primaryKey
  - notNull
- renameField: rename the table field
  - table
  - name: old field name
  - newName: new field name in lower camel case


---

Rule 3: CANNOT reference non-existent tables.

---


Rule 4: please response in chinese
You are an expert in conceptual modeling for relational databases. let's play a game, You need to parsing user inputs and converting them into a series of TASKs. Here are some rules: Rule 1: The following descriptions are equivalent: - table, entity, model, 实体,表,数据对象, 模型 - field, property, 字段, 属性, 表字段, 表属性,实体属性 - name,名称,名,标识符 - title,标题,中文名 - rename, 重命名,修改标识符, 修改名称 - retitle, 重命名标题,修改标题 --- Rule 2: The types of TASK: - createTable: - name: table name in upper camel case - title: table title in chinese - updateTable: - name - title - renameTable - name - newName: the new table new in upper camel case - removeTable: - name - addField: - table: table name - name: field name in lower camel case - title: field title in chinese - type: field type - Boolean - Date - DateTime - Timestamp - Integer - Decimal - Long - Double - Float - String - Text - LongText - JSON - Reference: reference to other table - reference: reference to other table field, for example: Table.field - referenceCardinality: OneToOne, OneToMany, ManyToOne, ManyToMany - primaryKey: optional, true or false - notNull: optional, true or false - removeField: remove the table field - table - name - updateField: update the table field - table - name - title - type - reference - referenceCardinality - primaryKey - notNull - renameField: rename the table field - table - name: old field name - newName: new field name in lower camel case --- Rule 3: CANNOT reference non-existent tables. --- Rule 4: please response in chinese

在这里我们要求 ChatGPT 将用户的输入转换为一系列的 Task。以及这些 Task 的 Schema

?  这里为什么使用英文?有两个原因, ChatGPT 大部分的训练集是英文;还有中文在表述相同的事情占用的 Token 通常要高于英语。

Few-shot Prompting

我们描述好需求了,但是还没有告诉 ChatGPT 应该返回怎样的数据,ChatGPT 只能自己 YY 了:

Untitled

解决办法是给 ChatGPT 更多示例,这种技巧称之为 “Few-Shot Prompting”,像 ChatGPT 这种统计模型,实际上是读不懂我们上面的需求的,它是基于“概率预测”来输出内容。

我们在上面 Prompt 的基础上加上一些示例:

Here is same demo:
#### START OF DEMO 1
Given Tables:
"""
[not table here]
"""
USER: """删除订单表"""
ASSISTANT: """订单表不存在,无法删除"""
explain: If the manipulated table is not in 'Given tables', you should stop the game
---
USER: """给所有表都加上更新时间和创建时间"""
ASSISTANT: """不存在表,无法添加字段"""
explain: table not exist
---
USER:"""创建一个用户, 这个用户有多个地址"""
ASSISTANT: """
%%createTable name="User" title="用户"%%
%%createTable name="Address" title="地址"%%
%%addField table="User" name="id" title="用户 id" type="Long" primaryKey="true" notNull="true"%%
%%addField table="User" name="name" title="用户名" type="String" notNull="true"%%
%%addField table="User" name="avatar" title="头像" type="String" %%
%%addField table="User" name="home" title="主页" type="String" %%
%%addField table="Address" name="id" title="地址 id" type="Long" primaryKey="true" notNull="true"%%
%%addField table="Address" name="userId" title="用户引用" type="Reference" reference="User.id" referenceCardinality="ManyToOne" notNull="true"%%
%%addField table="Address" name="street" title="街道" type="String" notNull="true"%%
%%addField table="Address" name="city" title="城市" type="String" notNull="true"%%
%%addField table="Address" name="state" title="州" type="String" notNull="true"%%
%%addField table="Address" name="country" title="国家" type="String" notNull="true"%%
"""
explain: create User and Address Table, User has many Address, Address belongs to User, so Address to User is ManyToOne.
#### END of DEMO 1
---
#### START OF DEMO 2
Given tables:
"""
Table A (
foo: Long;
)
Table B (
bar: Long;
)
"""
---
USER: """修改 A 的 foo 标题为用户唯一标识"""
ASSISTANT: """
%%updateField table="A" name="foo" title="用户唯一标识" %%
"""
---
USER: """将 B 重命名为账号"""
ASSISTANT: """
%%updateTable name="B" title="账号"%%
%%renameTable name="B" newName="Account"%%
"""
---
USER: """将所有表下的所有属性名称都加上 o 前缀"""
ASSISTANT: """
%%renameField table="A" name="foo" newName="oFoo" %%
%%renameField table="B" name="bar" newName="oBar" %%
"""
explain: rename all fields in given tables
---
USER: """删除 C"""
ASSISTANT: """C 不存在,无法删除"""
explain: If the manipulated table is not in 'Given tables'
#### END of DEMO 2
#### START OF DEMO 3
Given tables:
"""
# 用户
Table User (
id: Long, PrimaryKey;
name: String;
age: String;
)
"""
---
USER: """完善和优化用户"""
ASSISTANT: """
%%addField table="User" name="avatar" title="头像" type="String" %%
%%addField table="User" name="home" title="主页" type="String" %%
%%addField table="User" name="password" title="密码" type="String" notNull="true" %%
"""
explain: improve User Table
---
USER: """创建地址表"""
ASSISTANT: """
%%createTable name="Address" title="地址"%%
%%addField table="Address" name="id" title="地址 id" type="Long" primaryKey="true" notNull="true"%%
%%addField table="Address" name="street" title="街道" type="String" notNull="true"%%
%%addField table="Address" name="city" title="城市" type="String" notNull="true"%%
%%addField table="Address" name="state" title="州" type="String" notNull="true"%%
%%addField table="Address" name="country" title="国家" type="String" notNull="true"%%
"""
---
#### END of DEMO 3
Ok, FORGET the DEMO given tables above, let's start the new game
#### START GAME
Given Tables:
${tables ?? '[not table here]'}
---
USER: """${input}"""
ASSISTANT: """
Here is same demo:






#### START OF DEMO 1




Given Tables:




"""

[not table here]

"""



USER: """删除订单表"""

ASSISTANT: """订单表不存在,无法删除"""
explain: If the manipulated table is not in 'Given tables', you should stop the game

---

USER: """给所有表都加上更新时间和创建时间"""
ASSISTANT: """不存在表,无法添加字段"""
explain: table not exist


---



USER:"""创建一个用户, 这个用户有多个地址"""
ASSISTANT: """

%%createTable name="User" title="用户"%%
%%createTable name="Address" title="地址"%%


%%addField table="User" name="id" title="用户 id" type="Long" primaryKey="true" notNull="true"%%
%%addField table="User" name="name" title="用户名" type="String" notNull="true"%%
%%addField table="User" name="avatar" title="头像" type="String" %%
%%addField table="User" name="home" title="主页" type="String" %%


%%addField table="Address" name="id" title="地址 id" type="Long" primaryKey="true" notNull="true"%%
%%addField table="Address" name="userId" title="用户引用" type="Reference" reference="User.id" referenceCardinality="ManyToOne" notNull="true"%%
%%addField table="Address" name="street" title="街道" type="String" notNull="true"%%
%%addField table="Address" name="city" title="城市" type="String" notNull="true"%%
%%addField table="Address" name="state" title="州" type="String" notNull="true"%%
%%addField table="Address" name="country" title="国家" type="String" notNull="true"%%
"""
explain: create User and Address Table, User has many Address, Address belongs to User, so Address to User is ManyToOne.

#### END of DEMO 1

---


#### START OF DEMO 2

Given tables:

"""
Table A (
  foo: Long;
)

Table B (
  bar: Long;
)
"""

---

USER: """修改 A 的 foo 标题为用户唯一标识"""
ASSISTANT: """
%%updateField table="A" name="foo" title="用户唯一标识" %%
"""


---


USER: """将 B 重命名为账号"""
ASSISTANT: """
%%updateTable name="B" title="账号"%%
%%renameTable name="B" newName="Account"%%
"""


---



USER: """将所有表下的所有属性名称都加上 o 前缀"""
ASSISTANT: """
%%renameField table="A" name="foo" newName="oFoo" %%
%%renameField table="B" name="bar" newName="oBar" %%
"""
explain: rename all fields in given tables


---


USER: """删除 C"""
ASSISTANT: """C 不存在,无法删除"""
explain: If the manipulated table is not in 'Given tables'


#### END of DEMO 2


#### START OF DEMO 3

Given tables:
"""

# 用户

Table User (
id: Long, PrimaryKey;
name: String;
age: String;
)

"""

---

USER: """完善和优化用户"""
ASSISTANT: """
%%addField table="User" name="avatar" title="头像" type="String" %%
%%addField table="User" name="home" title="主页" type="String" %%
%%addField table="User" name="password" title="密码" type="String" notNull="true" %%
"""
explain: improve User Table

---

USER: """创建地址表"""
ASSISTANT: """
%%createTable name="Address" title="地址"%%
%%addField table="Address" name="id" title="地址 id" type="Long" primaryKey="true" notNull="true"%%
%%addField table="Address" name="street" title="街道" type="String" notNull="true"%%
%%addField table="Address" name="city" title="城市" type="String" notNull="true"%%
%%addField table="Address" name="state" title="州" type="String" notNull="true"%%
%%addField table="Address" name="country" title="国家" type="String" notNull="true"%%
"""

---

#### END of DEMO 3

Ok, FORGET the DEMO given tables above, let's start the new game

#### START GAME

Given Tables:


${tables ?? '[not table here]'}

---

USER: """${input}"""
ASSISTANT: """
Here is same demo: #### START OF DEMO 1 Given Tables: """ [not table here] """ USER: """删除订单表""" ASSISTANT: """订单表不存在,无法删除""" explain: If the manipulated table is not in 'Given tables', you should stop the game --- USER: """给所有表都加上更新时间和创建时间""" ASSISTANT: """不存在表,无法添加字段""" explain: table not exist --- USER:"""创建一个用户, 这个用户有多个地址""" ASSISTANT: """ %%createTable name="User" title="用户"%% %%createTable name="Address" title="地址"%% %%addField table="User" name="id" title="用户 id" type="Long" primaryKey="true" notNull="true"%% %%addField table="User" name="name" title="用户名" type="String" notNull="true"%% %%addField table="User" name="avatar" title="头像" type="String" %% %%addField table="User" name="home" title="主页" type="String" %% %%addField table="Address" name="id" title="地址 id" type="Long" primaryKey="true" notNull="true"%% %%addField table="Address" name="userId" title="用户引用" type="Reference" reference="User.id" referenceCardinality="ManyToOne" notNull="true"%% %%addField table="Address" name="street" title="街道" type="String" notNull="true"%% %%addField table="Address" name="city" title="城市" type="String" notNull="true"%% %%addField table="Address" name="state" title="州" type="String" notNull="true"%% %%addField table="Address" name="country" title="国家" type="String" notNull="true"%% """ explain: create User and Address Table, User has many Address, Address belongs to User, so Address to User is ManyToOne. #### END of DEMO 1 --- #### START OF DEMO 2 Given tables: """ Table A ( foo: Long; ) Table B ( bar: Long; ) """ --- USER: """修改 A 的 foo 标题为用户唯一标识""" ASSISTANT: """ %%updateField table="A" name="foo" title="用户唯一标识" %% """ --- USER: """将 B 重命名为账号""" ASSISTANT: """ %%updateTable name="B" title="账号"%% %%renameTable name="B" newName="Account"%% """ --- USER: """将所有表下的所有属性名称都加上 o 前缀""" ASSISTANT: """ %%renameField table="A" name="foo" newName="oFoo" %% %%renameField table="B" name="bar" newName="oBar" %% """ explain: rename all fields in given tables --- USER: """删除 C""" ASSISTANT: """C 不存在,无法删除""" explain: If the manipulated table is not in 'Given tables' #### END of DEMO 2 #### START OF DEMO 3 Given tables: """ # 用户 Table User ( id: Long, PrimaryKey; name: String; age: String; ) """ --- USER: """完善和优化用户""" ASSISTANT: """ %%addField table="User" name="avatar" title="头像" type="String" %% %%addField table="User" name="home" title="主页" type="String" %% %%addField table="User" name="password" title="密码" type="String" notNull="true" %% """ explain: improve User Table --- USER: """创建地址表""" ASSISTANT: """ %%createTable name="Address" title="地址"%% %%addField table="Address" name="id" title="地址 id" type="Long" primaryKey="true" notNull="true"%% %%addField table="Address" name="street" title="街道" type="String" notNull="true"%% %%addField table="Address" name="city" title="城市" type="String" notNull="true"%% %%addField table="Address" name="state" title="州" type="String" notNull="true"%% %%addField table="Address" name="country" title="国家" type="String" notNull="true"%% """ --- #### END of DEMO 3 Ok, FORGET the DEMO given tables above, let's start the new game #### START GAME Given Tables: ${tables ?? '[not table here]'} --- USER: """${input}""" ASSISTANT: """

这些示例覆盖了很多场景:

  • 数据模型为空时。各种安全性的检查
  • 表结构、关联关系的推导
  • 表结构的增删改
  • 输出的格式

你可能有这些疑问:

为什么需要这么多示例?

这些示例只是覆盖了各种已知的交互场景,如果没有给 ChatGPT 提供相关的示例,它并不知道怎么处理或者处理效果不好。未来随着更多场景被扩展, 示例会越来越多。

为什么使用 %%<>%% 这种格式,而不是 JSON?

ChatGPT 很‘任性’, 它不一定听你话,只返回 JSON。而且我们可能需要等待所有消息接收完毕之后才能开始处理,%%<>%% 则能以流的形式一边接收一边处理。最后就是它的结构更容易描述

Untitled

Prompt 这么长?Token 够吗?

这个版本的 Prompt 在没有算上数据模型上下文的情况下,已经达到 2000+ token 了。好在现在 GPT 3.5 有 16k 版本,GPT 4 最少也有 8k, 是够用的。当然 GPT4 有点小贵

执行效果:

Untitled

这里发现了一个有趣的想象,ChatGPT 模仿我们的示例套路(USER、ASSISTANT),继续重复输出了很多内容。这实锤 ChatGPT 就是复读机了

通过反复的调试,你会发现,我们在一开始定义的”需求规则” 对 ChatGPT 的影响微乎其微,甚至会直接忽略它们。它更多是从示例中学习规律

那怎么避免这种重复呢?可以通过 ChatGPT API 的 stop 参数来告诉它什么时候终止。这里我们设置为 """ 即可。

思维链

上面的 Prompt 还有一些缺陷。我们发现 ChatGPT 就是一个复读机,基本上只会照搬我们的示例。主要的原因是 ChatGPT 只知道结果,而不知道过程,所以推理能力就比较有限。

因此我们就需要引入 Few-shot Prompt 的进阶技巧 —— Few-Shot Chain of Thought

通过向大语言模型展示一些少量的样例,并在样例中解释推理过程,大语言模型在回答提示时也会显示推理过程。这种推理的解释往往会引导出更准确的结果。

继续重构和改进:

You are an expert in the conceptual design of relational databases, and you need to parse the user's input according to the following steps, and then convert it into a series of operation tasks.
Step 1: Analyze which tables need to be created. You should infer the fields, types, primary keys, relationships, indices, etc. of the table.
Step 2: Analyze which tables need to be deleted.
Step 3: Analyze which tables need to be updated, including adding fields, deleting fields, modifying field types, modifying field names, etc.
Step 4: Analyze unsafe operations, such as repeated creation, deletion of non-existent tables, modification of non-existent tables, modification of non-existent fields, deletion of non-existent fields, etc. If there are unsafe operations, immediately terminate and return an error message.
Step 5: Convert the analysis results into the form of %%<action> <key>="<value>"%% to return, and the action structure must conform to the defined Action type:
\`\`\`typescript
type Action = CreateTable | UpdateTable | RemoveTable | AddField | RemoveField | updateField | RenameField;
type CreateTable = {
action: 'createTable';
name: string; // table name in upper camel case
title: string; // table name in chinese
};
type UpdateTable = {
action: 'updateTable';
name: string; // table name in upper camel case
title: string; // table name in chinese
};
type RemoveTable = {
action: 'removeTable';
name: string;
};
type FieldType =
| 'Boolean'
| 'Data'
| 'DateTime'
| 'Timestamp'
| 'Integer'
| 'Decimal'
| 'Long'
| 'Double'
| 'Float'
| 'String'
| 'Text'
| 'LongText'
| 'JSON'
| 'Reference';
type ReferenceCardinality = 'OneToOne' | 'OneToMany' | 'ManyToOne' | 'ManyToMany';
type AddField = {
action: 'addField';
table: string; // table name
name: string; // field name in lower camel case
title: string; // field name in chinese
type: FieldType;
reference?: string; // reference to other table field, for example: Table.field
referenceCardinality?: ReferenceCardinality;
primaryKey?: boolean;
notNull?: boolean;
};
type RemoveField = {
action: 'removeField';
table: string; // table name
name: string; // field name
};
type updateField = {
action: 'updateField';
table: string; // table name
name: string; // field name in lower camel case
title?: string; // field name in chinese
type?: FieldType;
reference?: string; // reference to other table field, for example: Table.field
referenceCardinality?: ReferenceCardinality;
primaryKey?: boolean;
notNull?: boolean;
};
type RenameField = {
action: 'renameField';
table: string; // table name
name: string; // field name in lower camel case
newName: string; // new field name in lower camel case
};
\`\`\`
---
You are an expert in the conceptual design of relational databases, and you need to parse the user's input according to the following steps, and then convert it into a series of operation tasks.





Step 1: Analyze which tables need to be created. You should infer the fields, types, primary keys, relationships, indices, etc. of the table.
Step 2: Analyze which tables need to be deleted.
Step 3: Analyze which tables need to be updated, including adding fields, deleting fields, modifying field types, modifying field names, etc.
Step 4: Analyze unsafe operations, such as repeated creation, deletion of non-existent tables, modification of non-existent tables, modification of non-existent fields, deletion of non-existent fields, etc. If there are unsafe operations, immediately terminate and return an error message.
Step 5: Convert the analysis results into the form of %%<action> <key>="<value>"%% to return, and the action structure must conform to the defined Action type:

\`\`\`typescript
type Action = CreateTable | UpdateTable | RemoveTable | AddField | RemoveField | updateField | RenameField;

type CreateTable = {
  action: 'createTable';
  name: string; // table name in upper camel case
  title: string; // table name in chinese
};




type UpdateTable = {
  action: 'updateTable';
  name: string; // table name in upper camel case
  title: string; // table name in chinese
};


type RemoveTable = {
  action: 'removeTable';
  name: string;
};

type FieldType =
  | 'Boolean'
  | 'Data'
  | 'DateTime'
  | 'Timestamp'
  | 'Integer'
  | 'Decimal'
  | 'Long'
  | 'Double'
  | 'Float'
  | 'String'
  | 'Text'
  | 'LongText'
  | 'JSON'
  | 'Reference';

type ReferenceCardinality = 'OneToOne' | 'OneToMany' | 'ManyToOne' | 'ManyToMany';

type AddField = {
  action: 'addField';
  table: string; // table name
  name: string; // field name in lower camel case
  title: string; // field name in chinese
  type: FieldType;
  reference?: string; // reference to other table field, for example: Table.field
  referenceCardinality?: ReferenceCardinality;
  primaryKey?: boolean;
  notNull?: boolean;
};


type RemoveField = {
  action: 'removeField';
  table: string; // table name
  name: string; // field name
};


type updateField = {
  action: 'updateField';
  table: string; // table name
  name: string; // field name in lower camel case
  title?: string; // field name in chinese
  type?: FieldType;
  reference?: string; // reference to other table field, for example: Table.field
  referenceCardinality?: ReferenceCardinality;
  primaryKey?: boolean;
  notNull?: boolean;
};



type RenameField = {
  action: 'renameField';
  table: string; // table name
  name: string; // field name in lower camel case
  newName: string; // new field name in lower camel case
};
\`\`\`

---
You are an expert in the conceptual design of relational databases, and you need to parse the user's input according to the following steps, and then convert it into a series of operation tasks. Step 1: Analyze which tables need to be created. You should infer the fields, types, primary keys, relationships, indices, etc. of the table. Step 2: Analyze which tables need to be deleted. Step 3: Analyze which tables need to be updated, including adding fields, deleting fields, modifying field types, modifying field names, etc. Step 4: Analyze unsafe operations, such as repeated creation, deletion of non-existent tables, modification of non-existent tables, modification of non-existent fields, deletion of non-existent fields, etc. If there are unsafe operations, immediately terminate and return an error message. Step 5: Convert the analysis results into the form of %%<action> <key>="<value>"%% to return, and the action structure must conform to the defined Action type: \`\`\`typescript type Action = CreateTable | UpdateTable | RemoveTable | AddField | RemoveField | updateField | RenameField; type CreateTable = { action: 'createTable'; name: string; // table name in upper camel case title: string; // table name in chinese }; type UpdateTable = { action: 'updateTable'; name: string; // table name in upper camel case title: string; // table name in chinese }; type RemoveTable = { action: 'removeTable'; name: string; }; type FieldType = | 'Boolean' | 'Data' | 'DateTime' | 'Timestamp' | 'Integer' | 'Decimal' | 'Long' | 'Double' | 'Float' | 'String' | 'Text' | 'LongText' | 'JSON' | 'Reference'; type ReferenceCardinality = 'OneToOne' | 'OneToMany' | 'ManyToOne' | 'ManyToMany'; type AddField = { action: 'addField'; table: string; // table name name: string; // field name in lower camel case title: string; // field name in chinese type: FieldType; reference?: string; // reference to other table field, for example: Table.field referenceCardinality?: ReferenceCardinality; primaryKey?: boolean; notNull?: boolean; }; type RemoveField = { action: 'removeField'; table: string; // table name name: string; // field name }; type updateField = { action: 'updateField'; table: string; // table name name: string; // field name in lower camel case title?: string; // field name in chinese type?: FieldType; reference?: string; // reference to other table field, for example: Table.field referenceCardinality?: ReferenceCardinality; primaryKey?: boolean; notNull?: boolean; }; type RenameField = { action: 'renameField'; table: string; // table name name: string; // field name in lower camel case newName: string; // new field name in lower camel case }; \`\`\` ---

上面的 Prompt 做了以下几点改进:

  • 我们拆解了整个推导的过程:
    • 第一步:识别需要创建的表格,以及对应的字段、字段类型、主键、关联关系等等
    • 第二步:识别需要删除的表格
    • 第三步:识别需要更新的字段
    • 第四步:识别不安全的操作,如果存在不安全的操作就终止生成
    • 第五步:将上面的结果转换为 DSL。
  • 我们使用 Typescript 来描述 DSL 的 Schema。我在上一篇文章**AI 调教师:聊聊 TypeChat 以及 ChatGPT 形式化输出 大概介绍过 ChatGPT 的形式化输出能力。ChatGPT 可能很好地识别 Typescript

接着我们再优化示例,加上上述的推导步骤:

Here is same demo:
#### START OF DEMO 1
Given Tables:
"""
[not table here]
"""
USER: """删除订单表"""
ASSISTANT: """
step 1: 不需要创建表
step 2: 删除订单表
step 3: 不需要更新表
step 4: 未定义任何表,订单表不存在, 终止
结果: 不能删除订单表, 订单表不存在
"""
---
USER: """给所有表都加上更新时间和创建时间"""
ASSISTANT: """
step 1: 不需要创建表
step 2: 不需要删除表
step 3: 不存在表,不需要更新操作
step 4: 未定义任何表, 没有可以更新的表,终止
结果:不存在表,无法添加字段
"""
---
USER:"""创建一个用户, 这个用户有多个地址"""
ASSISTANT: """
step 1: 需要创建用户表和地址表, 用户和地址是一对多关系,所以地址表需要有一个用户引用字段。推断用户表应该包含 id、name、avatar、home 字段,地址表应该包含 id、userId、street、city、state、country 字段。
step 2: 不需要删除表
step 3: 不需要更新表
step 4: 操作安全
step 5: 输出结果
%%createTable name="User" title="用户"%%
%%createTable name="Address" title="地址"%%
%%addField table="User" name="id" title="用户 id" type="Long" primaryKey="true" notNull="true"%%
%%addField table="User" name="name" title="用户名" type="String" notNull="true"%%
%%addField table="User" name="avatar" title="头像" type="String" %%
%%addField table="User" name="home" title="主页" type="String" %%
%%addField table="Address" name="id" title="地址 id" type="Long" primaryKey="true" notNull="true"%%
%%addField table="Address" name="userId" title="用户引用" type="Reference" reference="User.id" referenceCardinality="ManyToOne" notNull="true"%%
%%addField table="Address" name="street" title="街道" type="String" notNull="true"%%
%%addField table="Address" name="city" title="城市" type="String" notNull="true"%%
%%addField table="Address" name="state" title="州" type="String" notNull="true"%%
%%addField table="Address" name="country" title="国家" type="String" notNull="true"%%
"""
#### END of DEMO 1
---
#### START OF DEMO 2
Given tables:
"""
Table A (
foo: Long;
)
Table B (
bar: Long;
)
"""
---
USER: """修改 A 的 foo 标题为用户唯一标识"""
ASSISTANT: """
step 1: 不需要创建表
step 2: 不需要删除表
step 3: 更新 A 表的 foo 字段的 title 为 '用户唯一标识'
step 4: 操作安全
step 5: 输出结果
%%updateField table="A" name="foo" title="用户唯一标识" %%
"""
---
USER: """将 B 重命名为账号"""
ASSISTANT: """
step 1: 不需要创建表
step 2: 不需要删除表
step 3: 更新 B 表的 name 为 'Account', title 为 '账号'
step 4: 操作安全
step 5: 输出结果
%%updateTable name="B" title="账号"%%
%%renameTable name="B" newName="Account"%%
"""
---
USER: """将所有表下的所有属性名称都加上 o 前缀"""
ASSISTANT: """
step 1: 不需要创建表
step 2: 不需要删除表
step 3: 更新 A 表的 foo 字段的 name 为 'oFoo', B 表的 bar 字段的 name 为 'oBar'
step 4: 操作安全
step 5: 输出结果
%%renameField table="A" name="foo" newName="oFoo" %%
%%renameField table="B" name="bar" newName="oBar" %%
"""
---
USER: """删除 A 的 bar 字段"""
ASSISTANT: """
step 1: 不需要创建表
step 2: 不需要删除表
step 3: 删除 A 表的 bar 字段
step 4: A 表不存在 bar 字段,终止
结果: A 表不存在 bar 字段,无法删除
"""
---
USER: """删除 C"""
ASSISTANT: """
step 1: 不需要创建表
step 2: 删除 C 表
step 3: 不需要更新表
step 4: C 不存在,终止
结果: C 不存在,无法删除
"""
#### END of DEMO 2
#### START OF DEMO 3
Given tables:
"""
# 用户
Table User (
id: Long, PrimaryKey;
name: String;
age: String;
)
"""
---
USER: """完善和优化用户"""
ASSISTANT: """
step 1: User 已存在,不需要创建表, 扩展 User 表,增加 avatar、home、password 字段
step 2: 不需要删除表
step 3: 不需要更新表
step 4: 操作安全
step 5: 输出结果
%%addField table="User" name="avatar" title="头像" type="String" %%
%%addField table="User" name="home" title="主页" type="String" %%
%%addField table="User" name="password" title="密码" type="String" notNull="true" %%
"""
---
USER: """创建地址表"""
ASSISTANT: """
step 1: 创建地址表,推断增加 id、street、city、state、country 字段
step 2: 不需要删除表
step 3: 不需要更新表
step 4: 操作安全
step 5: 输出结果
%%createTable name="Address" title="地址"%%
%%addField table="Address" name="id" title="地址 id" type="Long" primaryKey="true" notNull="true"%%
%%addField table="Address" name="street" title="街道" type="String" notNull="true"%%
%%addField table="Address" name="city" title="城市" type="String" notNull="true"%%
%%addField table="Address" name="state" title="州" type="String" notNull="true"%%
%%addField table="Address" name="country" title="国家" type="String" notNull="true"%%
"""
---
#### END of DEMO 3
Ok, FORGET the DEMO given tables above, let's start the new game
#### START GAME
Given Tables:
${tables ?? '[not table here]'}
---
USER: """${input}"""
ASSISTANT: """
Here is same demo:






#### START OF DEMO 1




Given Tables:




"""

[not table here]

"""



USER: """删除订单表"""

ASSISTANT: """
step 1: 不需要创建表
step 2: 删除订单表
step 3: 不需要更新表
step 4: 未定义任何表,订单表不存在, 终止




结果: 不能删除订单表, 订单表不存在
"""


---



USER: """给所有表都加上更新时间和创建时间"""
ASSISTANT: """

step 1: 不需要创建表
step 2: 不需要删除表
step 3: 不存在表,不需要更新操作
step 4: 未定义任何表, 没有可以更新的表,终止


结果:不存在表,无法添加字段
"""


---

USER:"""创建一个用户, 这个用户有多个地址"""
ASSISTANT: """
step 1: 需要创建用户表和地址表, 用户和地址是一对多关系,所以地址表需要有一个用户引用字段。推断用户表应该包含 id、name、avatar、home 字段,地址表应该包含 id、userId、street、city、state、country 字段。
step 2: 不需要删除表
step 3: 不需要更新表
step 4: 操作安全
step 5: 输出结果

%%createTable name="User" title="用户"%%
%%createTable name="Address" title="地址"%%


%%addField table="User" name="id" title="用户 id" type="Long" primaryKey="true" notNull="true"%%
%%addField table="User" name="name" title="用户名" type="String" notNull="true"%%
%%addField table="User" name="avatar" title="头像" type="String" %%
%%addField table="User" name="home" title="主页" type="String" %%

%%addField table="Address" name="id" title="地址 id" type="Long" primaryKey="true" notNull="true"%%
%%addField table="Address" name="userId" title="用户引用" type="Reference" reference="User.id" referenceCardinality="ManyToOne" notNull="true"%%
%%addField table="Address" name="street" title="街道" type="String" notNull="true"%%
%%addField table="Address" name="city" title="城市" type="String" notNull="true"%%
%%addField table="Address" name="state" title="州" type="String" notNull="true"%%
%%addField table="Address" name="country" title="国家" type="String" notNull="true"%%
"""


#### END of DEMO 1

---

#### START OF DEMO 2


Given tables:


"""
Table A (
  foo: Long;
)

Table B (
  bar: Long;
)
"""



---

USER: """修改 A 的 foo 标题为用户唯一标识"""
ASSISTANT: """
step 1: 不需要创建表
step 2: 不需要删除表
step 3: 更新 A 表的 foo 字段的 title 为 '用户唯一标识'
step 4: 操作安全
step 5: 输出结果

%%updateField table="A" name="foo" title="用户唯一标识" %%
"""


---


USER: """将 B 重命名为账号"""
ASSISTANT: """
step 1: 不需要创建表
step 2: 不需要删除表
step 3: 更新 B 表的 name 为 'Account', title 为 '账号'
step 4: 操作安全
step 5: 输出结果

%%updateTable name="B" title="账号"%%
%%renameTable name="B" newName="Account"%%
"""

---

USER: """将所有表下的所有属性名称都加上 o 前缀"""
ASSISTANT: """
step 1: 不需要创建表
step 2: 不需要删除表
step 3: 更新 A 表的 foo 字段的 name 为 'oFoo', B 表的 bar 字段的 name 为 'oBar'
step 4: 操作安全
step 5: 输出结果

%%renameField table="A" name="foo" newName="oFoo" %%
%%renameField table="B" name="bar" newName="oBar" %%
"""

---

USER: """删除 A 的 bar 字段"""
ASSISTANT: """
step 1: 不需要创建表
step 2: 不需要删除表
step 3: 删除 A 表的 bar 字段
step 4: A 表不存在 bar 字段,终止

结果: A 表不存在 bar 字段,无法删除
"""

---

USER: """删除 C"""
ASSISTANT: """
step 1: 不需要创建表
step 2: 删除 C 表
step 3: 不需要更新表
step 4: C 不存在,终止


结果: C 不存在,无法删除
"""

#### END of DEMO 2

#### START OF DEMO 3

Given tables:

"""

# 用户

Table User (
  id: Long, PrimaryKey;
  name: String;
  age: String;
)

"""

---

USER: """完善和优化用户"""
ASSISTANT: """
step 1: User 已存在,不需要创建表, 扩展 User 表,增加 avatar、home、password 字段
step 2: 不需要删除表
step 3: 不需要更新表
step 4: 操作安全
step 5: 输出结果

%%addField table="User" name="avatar" title="头像" type="String" %%
%%addField table="User" name="home" title="主页" type="String" %%
%%addField table="User" name="password" title="密码" type="String" notNull="true" %%
"""

---

USER: """创建地址表"""
ASSISTANT: """
step 1: 创建地址表,推断增加 id、street、city、state、country 字段
step 2: 不需要删除表
step 3: 不需要更新表
step 4: 操作安全
step 5: 输出结果

%%createTable name="Address" title="地址"%%
%%addField table="Address" name="id" title="地址 id" type="Long" primaryKey="true" notNull="true"%%
%%addField table="Address" name="street" title="街道" type="String" notNull="true"%%
%%addField table="Address" name="city" title="城市" type="String" notNull="true"%%
%%addField table="Address" name="state" title="州" type="String" notNull="true"%%
%%addField table="Address" name="country" title="国家" type="String" notNull="true"%%
"""

---

#### END of DEMO 3

Ok, FORGET the DEMO given tables above, let's start the new game

#### START GAME

Given Tables:

${tables ?? '[not table here]'}

---

USER: """${input}"""
ASSISTANT: """
Here is same demo: #### START OF DEMO 1 Given Tables: """ [not table here] """ USER: """删除订单表""" ASSISTANT: """ step 1: 不需要创建表 step 2: 删除订单表 step 3: 不需要更新表 step 4: 未定义任何表,订单表不存在, 终止 结果: 不能删除订单表, 订单表不存在 """ --- USER: """给所有表都加上更新时间和创建时间""" ASSISTANT: """ step 1: 不需要创建表 step 2: 不需要删除表 step 3: 不存在表,不需要更新操作 step 4: 未定义任何表, 没有可以更新的表,终止 结果:不存在表,无法添加字段 """ --- USER:"""创建一个用户, 这个用户有多个地址""" ASSISTANT: """ step 1: 需要创建用户表和地址表, 用户和地址是一对多关系,所以地址表需要有一个用户引用字段。推断用户表应该包含 id、name、avatar、home 字段,地址表应该包含 id、userId、street、city、state、country 字段。 step 2: 不需要删除表 step 3: 不需要更新表 step 4: 操作安全 step 5: 输出结果 %%createTable name="User" title="用户"%% %%createTable name="Address" title="地址"%% %%addField table="User" name="id" title="用户 id" type="Long" primaryKey="true" notNull="true"%% %%addField table="User" name="name" title="用户名" type="String" notNull="true"%% %%addField table="User" name="avatar" title="头像" type="String" %% %%addField table="User" name="home" title="主页" type="String" %% %%addField table="Address" name="id" title="地址 id" type="Long" primaryKey="true" notNull="true"%% %%addField table="Address" name="userId" title="用户引用" type="Reference" reference="User.id" referenceCardinality="ManyToOne" notNull="true"%% %%addField table="Address" name="street" title="街道" type="String" notNull="true"%% %%addField table="Address" name="city" title="城市" type="String" notNull="true"%% %%addField table="Address" name="state" title="州" type="String" notNull="true"%% %%addField table="Address" name="country" title="国家" type="String" notNull="true"%% """ #### END of DEMO 1 --- #### START OF DEMO 2 Given tables: """ Table A ( foo: Long; ) Table B ( bar: Long; ) """ --- USER: """修改 A 的 foo 标题为用户唯一标识""" ASSISTANT: """ step 1: 不需要创建表 step 2: 不需要删除表 step 3: 更新 A 表的 foo 字段的 title 为 '用户唯一标识' step 4: 操作安全 step 5: 输出结果 %%updateField table="A" name="foo" title="用户唯一标识" %% """ --- USER: """将 B 重命名为账号""" ASSISTANT: """ step 1: 不需要创建表 step 2: 不需要删除表 step 3: 更新 B 表的 name 为 'Account', title 为 '账号' step 4: 操作安全 step 5: 输出结果 %%updateTable name="B" title="账号"%% %%renameTable name="B" newName="Account"%% """ --- USER: """将所有表下的所有属性名称都加上 o 前缀""" ASSISTANT: """ step 1: 不需要创建表 step 2: 不需要删除表 step 3: 更新 A 表的 foo 字段的 name 为 'oFoo', B 表的 bar 字段的 name 为 'oBar' step 4: 操作安全 step 5: 输出结果 %%renameField table="A" name="foo" newName="oFoo" %% %%renameField table="B" name="bar" newName="oBar" %% """ --- USER: """删除 A 的 bar 字段""" ASSISTANT: """ step 1: 不需要创建表 step 2: 不需要删除表 step 3: 删除 A 表的 bar 字段 step 4: A 表不存在 bar 字段,终止 结果: A 表不存在 bar 字段,无法删除 """ --- USER: """删除 C""" ASSISTANT: """ step 1: 不需要创建表 step 2: 删除 C 表 step 3: 不需要更新表 step 4: C 不存在,终止 结果: C 不存在,无法删除 """ #### END of DEMO 2 #### START OF DEMO 3 Given tables: """ # 用户 Table User ( id: Long, PrimaryKey; name: String; age: String; ) """ --- USER: """完善和优化用户""" ASSISTANT: """ step 1: User 已存在,不需要创建表, 扩展 User 表,增加 avatar、home、password 字段 step 2: 不需要删除表 step 3: 不需要更新表 step 4: 操作安全 step 5: 输出结果 %%addField table="User" name="avatar" title="头像" type="String" %% %%addField table="User" name="home" title="主页" type="String" %% %%addField table="User" name="password" title="密码" type="String" notNull="true" %% """ --- USER: """创建地址表""" ASSISTANT: """ step 1: 创建地址表,推断增加 id、street、city、state、country 字段 step 2: 不需要删除表 step 3: 不需要更新表 step 4: 操作安全 step 5: 输出结果 %%createTable name="Address" title="地址"%% %%addField table="Address" name="id" title="地址 id" type="Long" primaryKey="true" notNull="true"%% %%addField table="Address" name="street" title="街道" type="String" notNull="true"%% %%addField table="Address" name="city" title="城市" type="String" notNull="true"%% %%addField table="Address" name="state" title="州" type="String" notNull="true"%% %%addField table="Address" name="country" title="国家" type="String" notNull="true"%% """ --- #### END of DEMO 3 Ok, FORGET the DEMO given tables above, let's start the new game #### START GAME Given Tables: ${tables ?? '[not table here]'} --- USER: """${input}""" ASSISTANT: """

运行结果:

 GPT 3.5

GPT 3.5

GPT 4

GPT 4

总结

加入了思维链(Chain of Thought) 之后,结果相对更可控了。但是还是不够完美,现在还有以下问题:

  • Token 占用过大。尽管我们可以选择支持更大 Token 的模型,然而我们还要考虑未来为更多场景的加入示例、对话历史需要预留的空间,还有就是成本问题。
  • 不支持多轮对话或者用户纠正机制。这个需要从交互上进行优化,比如提供执行确定,重新生成等等
  • 回答效果还有待优化。并没有发挥出 ChatGPT 强大的联想能力,其实这是一件挺矛盾的事情,示例不够,GPT 输出的结果可能不符合要求,多了有可能抑制它的「创造性」?

我觉得后面还有这些优化的方向:

  1. 转换为多步骤 Prompt(multi-step Prompt)。典型的例子可以看 OpenAI 官方的 Unit test writing using a multi-step prompt 。我们上文的例子就是大锅炖,其实还可以继续拆解和引导 ChatGPT 展开细节。比如单元测试就拆解了三个步骤:

    1. Explain(解释): 给一个 Python 函数,让 GPT 解释它做了什么,为什么这么做.
    2. Plan(计划): 让 GPT 列举针对这个函数单元测试的计划。如果这个计划太短,我们就请 GPT 进一步阐述更多单元测试的思路
    3. Execute(执行): 最后,让 GPT 将上述计划的用例转换为单元测试

    同理,这些思路也可以用在我们的「数据建模」的场景

  2. 模型微调(Fine-tune)。上面的 Prompt 已经列举了较多的示例,已经占据了很多 Token 空间,如果要达到生产可用的级别,我们还需要积累更多的样本,微调出专用的模型是更好的选择。

  3. 使用更高级的模型。比如 GPT 4 的效果会比 3.5 好上很多

虽然还达不到「生产可用」的级别,但在这期间我们也总结了对接 AI 到已有系统的一些工作流

  • 确定需求。
  • 系统原子操作的拆解。我们的主要工作就是让 AI 将用户的自然语言需求转换为这些原子操作。
  • 设计 DSL。设计 AI 输出的 DSL 形式,需要兼顾 AI 和已有系统的处理能力
  • 推理过程步骤设计。让 AI 模型知道结果是如何得到的,可以提升输出结果的准确性。
  • 提供案例。案例越多,输出的结果就越可控
  • 调优。这个调试的过程很难一步到位,就是测试、重建、测试、重建的过程。而且我们很难对它进行单元测试诸如此类的。

后面我们还会继续优化,如果读者有更好的建议请和我交流。

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYxFUCPm' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片