你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
Codex 模型和 Azure OpenAI 服务
重要
本文是针对旧代码生成模型创作和测试的。 这些模型使用完成 API 及其交互提示/完成样式。 如果要测试本文中所述的技术,建议使用允许访问完成 API 的 gpt-35-turbo-instruct
模型。 但是,对于代码生成,聊天完成 API 和最新的 GPT-4o 模型会产生最佳结果,但需要将提示转换为与这些模型交互时的特定对话样式。
Codex 模型系列是 GPT-3 系列的后代,它经过了自然语言和数十亿行代码的训练。 该模型系列精通十几种语言,包括 C#、 JavaScript、Go、Perl、PHP、Ruby、Swift、TypeScript、SQL,甚至 Shell,但最擅长 Python。
你可以使用 Codex 完成各种任务,包括:
- 将注释转换为代码
- 在上下文中补全下一行代码或函数
- 为你提供一些知识,例如为应用程序查找有用的库或 API 调用
- 添加注释
- 重写代码以提高效率
如何将完成模型与代码结合使用
下面是一些使用 Codex 的示例,可以在部署了 code-davinci-002
等 Codex 系列模型的 Azure AI Studio 的操场中进行测试。
说“Hello”(Python)
"""
Ask the user for their name and say "Hello"
"""
创建随机名称 (Python)
"""
1. Create a list of first names
2. Create a list of last names
3. Combine them randomly into a list of 100 full names
"""
创建 MySQL 查询 (Python)
"""
Table customers, columns = [CustomerId, FirstName, LastName, Company, Address, City, State, Country, PostalCode, Phone, Fax, Email, SupportRepId]
Create a MySQL query for all customers in Texas named Jane
"""
query =
解释代码 (JavaScript)
// Function 1
var fullNames = [];
for (var i = 0; i < 50; i++) {
fullNames.push(names[Math.floor(Math.random() * names.length)]
+ " " + lastNames[Math.floor(Math.random() * lastNames.length)]);
}
// What does Function 1 do?
最佳实践
从注释、数据或代码开始
可以在操场中使用其中一个 Codex 模型进行试验(根据需要将样式说明设置为注释)。
若要让 Codex 创建有用的补全内容,思考程序员执行任务时需要哪些信息将很有帮助。 这些信息有可能只是一个明确的注释或编写有用函数所需的数据,例如变量的名称或函数处理的类型。
在此示例中,我们将告诉 Codex 调用什么函数,以及它将执行哪些任务。
# Create a function called 'nameImporter' to add a first and last name to the database
甚至可以这样做:为 Codex 提供注释和数据库架构示例,以便为各种数据库编写有用的查询请求。 以下示例为查询提供列和表名称。
# Table albums, columns = [AlbumId, Title, ArtistId]
# Table artists, columns = [ArtistId, Name]
# Table media_types, columns = [MediaTypeId, Name]
# Table playlists, columns = [PlaylistId, Name]
# Table playlist_track, columns = [PlaylistId, TrackId]
# Table tracks, columns = [TrackId, Name, AlbumId, MediaTypeId, GenreId, Composer, Milliseconds, Bytes, UnitPrice]
# Create a query for all albums with more than 10 tracks
向 Codex 展示数据库架构时,它便能够就如何设置查询格式做出明智的猜测。
指定编程语言
Codex 理解数十种不同的编程语言。 许多语言对注释、函数和其他编程语法使用类似的约定。 通过在注释中指定语言和版本,Codex 能够更好地提供你所需要的补全内容。 也就是说,Codex 在风格和语法方面相当灵活。 下面是 R 和 Python 的示例。
# R language
# Calculate the mean distance between an array of points
# Python 3
# Calculate the mean distance between an array of points
提示 Codex 你想让它执行的操作
如果想让 Codex 创建网页,请在注释告知 Codex 接下来应执行哪些操作后,初始代码放在 HTML 文档中 (<!DOCTYPE html>
)。 同样的方法也适用于从注释创建函数(注释后面是以 func 或 def 开头的新行)。
<!-- Create a web page with the title 'Kat Katman attorney at paw' -->
<!DOCTYPE html>
将 <!DOCTYPE html>
放在注释之后可使 Codex 非常清楚我们希望它执行哪些操作。
或者,如果要编写函数,可以按如下所示启动提示,Codex 将了解接下来需要执行的操作。
# Create a function to count to 100
def counter
指定库有助于 Codex 了解你需要它执行的操作
Codex 了解大量的库、API 和模块。 通过告诉 Codex 要使用哪些资源,无论是从注释还是将其导入到代码中,Codex 都将根据这些内容而不是替代内容提出建议。
<!-- Use A-Frame version 1.2.0 to create a 3D website -->
<!-- https://aframe.io/releases/1.2.0/aframe.min.js -->
通过指定版本,可以确保 Codex 使用最新的库。
注意
Codex 会建议有用的库和 API,但请你务必自己做些调查,确保它们对应用程序是安全的。
注释样式会影响代码质量
对于某些语言,注释的样式可以提高输出的质量。 例如,使用 Python 时,在某些情况下,使用 doc 字符串(三引号括起来的注释)比使用井号 (#
) 得到的结果质量更高。
"""
Create an array of users and email addresses
"""
在函数中添加注释很有用
推荐的编码标准通常建议将函数的说明放在函数中。 使用此格式有助于 Codex 更清楚地了解你希望函数执行的操作。
def getUserBalance(id):
"""
Look up the user in the database ‘UserData' and return their current account balance.
"""
提供更精确的结果的示例
如果需要 Codex 使用特定的样式或格式,在请求的第一部分提供示例或演示将有助于 Codex 更准确地满足你的需求。
"""
Create a list of random animals and species
"""
animals = [ {"name": "Chomper", "species": "Hamster"}, {"name":
温度越低,得到的结果越精确
在大多数情况下,将 API 温度设置为 0 或接近 0(如 0.1 或 0.2)往往会得到更好的结果。 在 GPT-3 模型中,较高的温度可以提供有用的创意结果和随机结果,Codex 模型则不同,较高温度可能会产生随机或难以预测的响应。
如果需要 Codex 提供不同的潜在结果,请从 0 开始,然后向上递增 0.1,直到找到合适的变体。
将任务组织成函数
可以在注释中尽可能精确地指定函数应该执行哪些操作,以便让 Codex 编写函数。 例如,通过编写以下注释,Codex 创建了一个 JavaScript 计时器函数,该函数在用户按下按钮时触发:
简单的 JavaScript 计时器
// Create a timer that creates an alert in 10 seconds
创建示例数据
测试应用程序通常需要使用示例数据。 由于 Codex 是一种能够理解如何编写和理解自然语言的语言模型,因此可以指示 Codex 创建数据,如虚构名称、产品和其他变量的数组。 例如,此处我们要求 Codex 创建天气温度数组。
/* Create an array of weather temperatures for San Francisco */
要求 Codex 执行此任务将生成如下所示的表:
var weather = [
{ month: 'January', high: 58, low: 48 },
{ month: 'February', high: 61, low: 50 },
{ month: 'March', high: 64, low: 53 },
{ month: 'April', high: 67, low: 55 },
{ month: 'May', high: 70, low: 58 },
{ month: 'June', high: 73, low: 61 },
{ month: 'July', high: 76, low: 63 },
{ month: 'August', high: 77, low: 64 },
{ month: 'September', high: 76, low: 63 },
{ month: 'October', high: 73, low: 61 },
{ month: 'November', high: 68, low: 57 },
{ month: 'December', high: 64, low: 54 }
];
复合函数和小型应用程序
可以为 Codex 提供包含复杂请求的注释,例如创建随机姓名生成器或使用用户输入执行任务,然后 Codex 就可以生成剩余内容,前提是有足够的令牌。
/*
Create a list of animals
Create a list of cities
Use the lists to generate stories about what I saw at the zoo in each city
*/
限制补全内容的大小,以便获得更精确的结果或更低的延迟
在 Codex 中请求较长的补全内容可能会导致答案不精确和出现重复。 通过减少 max_tokens 和设置停止令牌来限制查询的大小。 例如,添加 \n
作为停止序列,以将补全内容限制为一行代码。 较小的补全内容也会产生少量延迟。
使用流式处理降低延迟
大型 Codex 查询可能需要数十秒才能完成。 若要生成需要较低延迟的应用程序,例如执行自动完成的编码助手,请考虑使用流式处理。 在模型生成完整的补全内容之前,系统将返回响应。 只需要部分补全内容的应用程序可以通过编程方式或使用 stop
的创意值来切断补全内容,从而减少延迟。
用户可以通过从 API 请求多个解决方案并使用返回的第一个响应将流式处理和复制相结合,从而减少延迟。 可通过设置 n > 1
实现此目的。 此方法需要使用更多的令牌配额,因此请谨慎使用(例如,对 max_tokens
和 stop
使用合理的设置)。
使用 Codex 解释代码
Codex 能够创建和理解代码,因此可以使用它来执行任务,例如解释文件中的代码的用途。 实现此目的的一种方法是在以“此函数”或“此应用程序是”开头的函数之后添加注释。Codex 通常会将此理解为说明的开始,并补全文本的其余部分。
/* Explain what the previous function is doing: It
解释 SQL 查询
在此示例中,我们使用 Codex 并采用易于人类阅读的格式解释 SQL 查询的用途。
SELECT DISTINCT department.name
FROM department
JOIN employee ON department.id = employee.department_id
JOIN salary_payments ON employee.id = salary_payments.employee_id
WHERE salary_payments.date BETWEEN '2020-06-01' AND '2020-06-30'
GROUP BY department.name
HAVING COUNT(employee.id) > 10;
-- Explanation of the above query in human readable format
--
编写单元测试
在 Python 中只需添加注释“单元测试”并启动函数即可创建单元测试。
# Python 3
def sum_numbers(a, b):
return a + b
# Unit test
def
检查代码是否有误
通过使用示例,可以向 Codex 展示如何识别代码中的错误。 在某些情况下不需要任何示例,但展示级别和细节可提供说明,有助于 Codex 了解要查找什么内容以及如何解释。 (Codex 执行错误检查不应取代用户的仔细评审。)
/* Explain why the previous function doesn't work. */
使用源数据编写数据库函数
正如人类程序员可以通过了解数据库结构和列名而获益一样,Codex 也可以使用这些数据来帮助编写准确的查询请求。 在此示例中,我们插入数据库的架构,并告知 Codex 查询数据库的哪些内容。
# Table albums, columns = [AlbumId, Title, ArtistId]
# Table artists, columns = [ArtistId, Name]
# Table media_types, columns = [MediaTypeId, Name]
# Table playlists, columns = [PlaylistId, Name]
# Table playlist_track, columns = [PlaylistId, TrackId]
# Table tracks, columns = [TrackId, Name, AlbumId, MediaTypeId, GenreId, Composer, Milliseconds, Bytes, UnitPrice]
# Create a query for all albums with more than 10 tracks
在不同语言之间转换
可以按照一种简单的格式让 Codex 从一种语言转换为另一种语言:在注释中列出要转换的代码的对应语言,接着列出代码,然后提供要转换到的目标语言的注释。
# Convert this from Python to R
# Python version
[ Python code ]
# End
# R version
重写库或框架的代码
如果希望 Codex 使函数更高效,可以为其提供要重写的代码,后跟有关使用何种格式的说明。
// Rewrite this as a React component
var input = document.createElement('input');
input.setAttribute('type', 'text');
document.body.appendChild(input);
var button = document.createElement('button');
button.innerHTML = 'Say Hello';
document.body.appendChild(button);
button.onclick = function() {
var name = input.value;
var hello = document.createElement('div');
hello.innerHTML = 'Hello ' + name;
document.body.appendChild(hello);
};
// React version: