近一年来大模型越来越火,在研发领域的代码大模型也如雨后春笋般出现。蚂蚁也发布了自己的百灵代码大模型 CodeFuse,作为内部技术同学,当然要尝试下它的能力能否胜任日常的编码工作,于是在网上找了一些评测常用的问题,以及根据自己日常研发会遇到的问题进行了一些测试,下面就是评测结果。
需要注意,本文所评测的 CodeFuse 是 2023 年 11 月初的蚂蚁内部版本,其结果表现仅适用于该版本。
好了,CodeFuse 具体表现如何,就由大家自行评判吧。
编程语言
数据研发-SQL
综合测试
表结构识别
设宾馆酒店业数据库有四张表:
Hotel(hotelNo, hotelName, city)
Room(roomNo, hotelNo, type(房间类型), price)
Booking(roomNo, guestNo, dateFrom(起始日期), dateTo(终止日期))
Guest(guestNo, guestName, guestAddress)
请帮忙生成表的结构
可以看出GPT生成的结构正确,且根据命名生成了较为合理的测试数据
这里是每个表的结构: * Hotel: | hotelNo | hotelName | city | |---------|-----------|--------| | 100 | 香格里拉 | 北京 | | 101 | 喜达屋 | 上海 | | 102 | 海航 | 广州 | * Room: | roomNo | hotelNo | type | price | |--------|---------|-----------|-------| | 2001 | 100 | 标准双床 | ¥2999 | | 2013 | 100 | 豪华单人 | ¥5199 | | 3006 | 101 | 标准双床 | ¥2599 | | 4008 | 101 | 豪华单人 | ¥4599 | | 5009 | 102 | 标准双床 | ¥2899 | | 6007 | 102 | 豪华单人 | ¥4899 | * Booking: | roomNo | guestNo | dateFrom | dateTo | |--------|---------|----------|--------| | 2001 | 123456 | 2022-01-15 | 2022-02-14 | | 2013 | 789012 | 2023-03-05 | 2023-04-08 | | 3006 | 567890 | 2024-06-11 | 2024-07-13 | | 4008 | 987654 | 2025-08-17 | 2025-09-19 | | 5009 | 543210 | 2026-10-22 | 2026-11-24 | | 6007 | 321202 | 2027-12-29 | 2028-01-31 | * Guest: | guestNo | guestName | guestAddress | |---------|-----------|--------------| | 123456 | 张三 | 北京市朝阳区 | | 789012 | 李四 | 上海市浦东新区 | | 567890 | 王五 | 广州市天河区 | | 987654 | 赵六 | 成都市锦江区 | | 543210 | 孙七 | 南京市玄武区 | | 321202 | 周八 | 沈阳市铁西区 |
1.列出“长春”的所有宾馆的宾馆号和宾馆名称;
2.列出“长春宾馆”的所有房间类型和价格;
3.检索2023年6月1号(’20230601’)入住“长春宾馆”的客人号码和客人姓名。
4.建表语句
定义关系模式Hotel和Room,要求在模式中完成以下完整性约束的定义:定义模式的主码;定义参照完整性;房间价格不能低于100元;定义type、price和hotelName不能为空
以下是Hotel和Room两张表的关系模式,包含了完整性约束的定义:
- Hotel表的主码为hotelNo,参照完整性为hotelName和city,定义如下:
CREATE TABLE Hotel ( hotelNo INT PRIMARY KEY, hotelName VARCHAR(50) NOT NULL, city VARCHAR(20) NOT NULL, ... FOREIGN KEY (hotelName, city) REFERENCES Hotel(hotelName, city) );
- Room表的主码为roomNo,参照完整性为hotelNo和type,定义如下:
CREATE TABLE Room ( roomNo INT PRIMARY KEY, hotelNo INT NOT NULL, type VARCHAR(20) NOT NULL, price DECIMAL(10, 2) NOT NULL CHECK (price >= 100), ... FOREIGN KEY (hotelNo) REFERENCES Hotel(hotelNo) );
其中,price字段使用了CHECK约束来限制价格不能低于100元,type和hotelName字段不能为空。
5.统计各个宾馆房间数量
6.插入语句
7.创建一个断言,限制每个宾馆单人间的房间数不能多于8个
8.生成视图
JSON、XML相关
帮忙生成json数据,生成5个用户的数据,每个用户都有名字、年龄和职业
[ { "name": "John", "age": 25, "occupation": "Engineer" }, { "name": "Jane", "age": 30, "occupation": "Doctor" }, { "name": "Bob", "age": 42, "occupation": "Teacher" }, { "name": "Alice", "age": 19, "occupation": "Students" }, { "name": "Tom", "age": 35, "occupation": "Businessman" } ]
针对以上内容,返回XML格式
表现很不错!
<users> <user> <name>John</name> <age>25</age> <occupation>Engineer</occupation> </user> <user> <name>Jane</name> <age>30</age> <occupation>Doctor</occupation> </user> <user> <name>Bob</name> <age>42</age> <occupation>Teacher</occupation> </user> <user> <name>Alice</name> <age>19</age> <occupation>Students</occupation> </user> <user> <name>Tom</name> <age>35</age> <occupation>Businessman</occupation> </user> </users>
应用研发
Http服务调用
用java实现httpclient请求10.77.70.184:5000的服务,post传入body:{"name":"a"}
import java.io.IOException; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.json.JSONObject; public class HttpClientExample { public static void main(String[] args) throws ClientProtocolException, IOException { // 创建HTTP客户端 CloseableHttpClient httpClient = HttpClients.createDefault(); // 创建POST请求 HttpPost httpPost = new HttpPost("https://10.77.70.184:5000/api"); // 设置请求体 JSONObject requestBody = new JSONObject().put("name", "a"); StringEntity requestEntity = new StringEntity(requestBody.toString()); httpPost.setEntity(requestEntity); // 执行请求并获取响应 HttpResponse response = httpClient.execute(httpPost); // 获取响应内容 int statusCode = response.getStatusLine().getStatusCode(); if (statusCode == 200) { HttpEntity entity = response.getEntity(); String responseBody = EntityUtils.toString(entity, "UTF-8"); System.out.println(responseBody); } else { throw new RuntimeException("Failed : HTTP error code : " + statusCode); } // 关闭连接 httpClient.close(); } }
优化代码
以下是对以上代码进行优化的示例:
import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import java.io.IOException; public class HttpClientExample { private static final String URL = "http://10.77.70.184:5000"; private static final String REQUEST_BODY = "{\"name\":\"a\"}"; public static void main(String[] args) { HttpClient httpClient = HttpClients.createDefault(); HttpPost httpPost = new HttpPost(URL); httpPost.setEntity(new StringEntity(REQUEST_BODY)); try { HttpResponse response = httpClient.execute(httpPost); HttpEntity entity = response.getEntity(); String responseBody = EntityUtils.toString(entity); System.out.println("Response: " + responseBody); } catch (IOException e) { e.printStackTrace(); } finally { try { httpClient.close(); } catch (IOException e) { e.printStackTrace(); } } } }
优化说明:
- 将URL和REQUEST_BODY定义为常量,提高代码可读性和可维护性。
- 使用try-with-resources语句自动关闭HttpClient。
- 将IOException捕获并处理,使代码更加健壮。
- 将HttpResponse和HttpEntity类型改为适当的类,提高代码可读性。
- 将代码格式化以提高可读性。
测试开发
用java编写冒泡排序的单元测试代码,使用acts进行封装
基本上可以完整写出来,但仅能理解通用逻辑
import java.util.Arrays; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; import acts.core.ActContext; import acts.core.actimpl.ActImplUtils; import acts.util.SortedArray; /** * 冒泡排序单元测试 */ public class BubbleSortTest { private static SortedArray sortedArr; private static ActContext context; @BeforeClass public static void setUp() throws Exception { sortedArr = new SortedArray(Integer.class); context = ActImplUtils.createDefaultContext(); } @AfterClass public static void tearDown() throws Exception { // 清理环境 sortedArr.clear(); context.close(); } @Test public void testBubbleSort() { int[] arr = new int[]{3,1,4,2}; // 待排序数组 BubbleSort bubbleSort = new BubbleSort(); bubbleSort.sort(arr); // 调用排序方法进行排序 assertEquals("排序后的结果不符合预期",new int[]{1,2,3,4},arr); // 判断排序是否正确 } @Test public void testBubbleSortWithActs() { int[] arr = new int[]{3,1,4,2}; // 待排序数组 BubbleSort bubbleSort = new BubbleSort(); bubbleSort.sort(arr, context); // 调用排序方法进行排序 assertTrue("排序后的结果不符合预期", Arrays.equals(new int[]{1,2,3,4}, sortedArr)); // 判断排序是否正确 } }
生成注释
(在原先0注释的代码上,表现非常出色啊,可以有效帮助新人理解代码)
/** * 获取访问令牌 * @param diUserId DI用户ID * @param usageType 访问令牌使用类型 * @return 返回获取到的访问令牌 */ public String getAccessToken(String diUserId, String usageType) { // 创建获取访问令牌请求对象 GetAccessTokenRequest getAccessTokenRequest = new GetAccessTokenRequest(); // 设置访问令牌使用类型 getAccessTokenRequest.setUsageType(TokenUsageEnum.valueOf(usageType)); // 设置DI编码 getAccessTokenRequest.setDiCode(diCode); // 设置开放平台用户ID getAccessTokenRequest.setOpenUserId(diUserId); // 设置命名空间ID getAccessTokenRequest.setNamespaceId(namespaceId); // 设置租户ID getAccessTokenRequest.setTenantId(tenantId); // 设置操作员ID getAccessTokenRequest.setOperatorId(operatorId); // 创建OpenApiClient对象 OpenApiClient openApiClient = new OpenApiClient(accessId, accessKey, url, MethodEnum.GET_ACCESS_TOKEN, getAccessTokenRequest); // 执行获取访问令牌请求并获取响应结果 DIResult<GetAccessTokenResponse> diResult = null; try { diResult = openApiClient.execute(); } catch (Throwable th) { // 打印错误日志并抛出自定义异常 LogPrinter.printBizError(String.format("调用getAccessToken-http异常,getAccessTokenRequest:%s", JSON.toJSONString(getAccessTokenRequest)), th); throw DappBaseException.noRetry(BizErrorCodeEnum.DI_INVOKE_ERROR, "调用getAccessToken-http异常"); } // 判断响应结果是否存在且成功 if (diResult == null ||!diResult.isSuccess()) { // 打印错误日志并抛出自定义异常 LogPrinter.printBizError(String.format("调用getAccessToken返回值为空,getAccessTokenRequest:%s", JSON.toJSONString(getAccessTokenRequest))); throw DappBaseException.noRetry(BizErrorCodeEnum.DI_GET_ACCESS_TOKEN_FAIL, "调用getAccessToken返回值为空"); } // 获取访问令牌响应数据 GetAccessTokenResponse getAccessTokenResponse = diResult.getData(); // 判断响应数据是否存在且成功 if (getAccessTokenResponse == null ||!getAccessTokenResponse.isSuccess()) { // 打印错误日志并抛出自定义异常 LogPrinter.printBizError(String.format("调用getAccessToken返回业务值为空,getAccessTokenRequest:%s,diResult:%s", JSON.toJSONString(getAccessTokenRequest), JSON.toJSONString(diResult))); throw DappBaseException.noRetry(BizErrorCodeEnum.DI_GET_ACCESS_TOKEN_FAIL, "调用getAccessToken返回业务值为空"); } // 返回获取到的访问令牌 return getAccessTokenResponse.getAccessToken(); }
优化技巧
明确指令
Prompt的设计应该与任务目标相关,并明确要求模型生成的内容。例如,在进行文本生成时,Prompt应该指导模型生成与主题相关的文本内容。一个好的Prompt应该是一个明确的指令,而不是一个问题。例如,如果要求模型生成一段关于“猫”的文本,那么一个好的Prompt应该是“猫是什么?”,而不是“猫是什么动物?”。因为前者是一个明确的指令,而后者是一个问题,模型可能会回答“猫是一种动物”,而不是“猫是一种宠物”。
下面是一个好的Prompt示例。上半部分用"""包起来的,是输入到模型的Prompt。下半部分用绿色高亮起来的,是模型给出的反馈。模型自动帮我们把电话和邮件按照我们要求的指令隐藏起来了。这是因为我们的Prompt明确给出了指令:
帮忙用[AK]替换上述代码中accessKey变量的值
角色提示(Role Prompting)
角色提示是另外一种Prompt技巧,通过为AI分配角色的方式引导AI给出更准确的输出。通过为 AI 分配一个角色,我们给它提供了一些上下文。这个上下文有助于 AI 更好地理解问题,因此 AI 往往可以给出更好的答案。例如,可以在开始的时候,提示AI"你是一名顶级计算机工程师"或"你是一名顶级数学家",然后要求AI回答一些相关的医学或法律问题,以此来增强其专业性和准确性。举个例子:
下面给出了两个示例,第一个例子问AI “1000 * 100 / 400 * 56 是多少?”,它给出了错误的答案 272.8。第二个例子中,我们在Prompt中加入了角色提示,提示AI"你是一个能解决世界上任何问题的杰出数学家。试着解决下面的问题:",然后再问GPT “1000 * 100 / 400 * 56 是多少?”,这次给出了正确的答案。
第一次:
第二次:
上下文学习(In-Context Learning)
语言模型对上下文进行学习,以获得更好的理解和执行能力。它利用上下文信息来提高模型在执行任务时的准确性。在这种学习方法中,模型不仅考虑当前任务所提供的信息,还会考虑上下文环境中的其他信息。例如先前的句子或文本段落。在这种情况下,模型可以更好地理解任务的背景和目的,从而输出更准确的信息。
上下文学习有助于模型更好地理解任务的背景和目的,从而输出更准确的信息。例如,如果要求模型生成一段关于“http调用”的代码,那么在Prompt中加入一些关于“调用服务”的上下文信息,例如“,可以帮助模型更好地理解任务的背景和目的,从而输出更准确的信息。
上下文学习可以根据Prompt中样本的数量,简单分为三种类型:
零样本(Zero-shot) 学习:没有样本或者说上下文信息。单样本(One-Shot)学习与少样本学习类似,但不允许使用大量演示数据,而只能通过少量的样本来进行任务描述。即使对于人类来说,理解任务格式也可能很困难,尤其是在没有先前的示例的情况下,这使得该设置在某些情况下显得“不公平的难度”。例如,如果要求某人“生成一个机器学习调用类”,这个请求可能是含混不清的,因为可能不清楚表格的格式应该是什么,应该包含什么内容(即使进行了仔细的澄清,确切理解所需的内容也可能很困难)。尽管如此,在至少一些情况下,零样本是最接近人类执行任务的方法。
少样本(Few-shot) 学习:在Prompt中有少量样本。在少样本学习中,通过提供K个上下文和补全(completion)示例,然后期望模型输出最后一个上下文的completion。
这是一个简单的少样本学习的例子:假设我们有一个任务,要求我们训练一个语言模型,能够根据一个问题生成一个答案。我们有一个包含问题和对应答案的数据集,但是数据集中只有很少的样本,我们需要使用少样本学习来完成任务。我们可以提供给模型K个上下文和补全示例,比如:
此时,我们期望模型能够输出相应的补全,即 “谷歌。”。使用这些样本,我们可以训练模型以在少样本学习的条件下快速适应新的问题并给出正确的答案。
单样本(One-shot) 学习:在Prompt只有一个样本。单样本学习与少样本学习类似,只允许一个演示数据,并附带任务的自然语言描述。将单样本学习与少样本学习和零样本学习(下文)区分开来的原因是,它最接近某些任务与人类交流的方式。例如,在要求人类在上生成数据集时,通常会给出一个任务演示。相比之下,如果没有示例,则有时很难传达任务的内容或格式。
思维链(Chainn of Thought)
思维链(Chainn of Thought)是一种使用少量示例来指导人工智能模型完成任务的技巧。思维链的目的是让模型能够理解任务的逻辑和步骤,而不仅仅是复制示例。例如,想让模型回答一个问题,可以在输入中提供一些相关的信息和推理过程,而不只是一个简单的问题。
例子:
我写一个Java日期类,检查日期字符串是否"HH:mm"的格式 /** * 检查日期字符串是否"HH:mm"的格式 * * @param dateStr 日期字符串 * @return */ public static Boolean isHourMinDateString(String dateStr) { return dateStr.matches("((0|1)[0-9]|2[0-3]):[0-5][0-9]"); } 通过正则表达式检查了是否符合HH:mm格式, 帮我写一个函数,检查日期字符串是否"mm"的格式
零样本思维链(Zero-shot Chainn of Thought)
零样本思维链(Zero-shot Chainn of Thought)是思维链的另外一种实现,通过在问题的结尾附加让我们一步步思考。 这句话,大语言模型能够生成一个回答问题的思维链。从这个思维链中,他们能够提取更准确的答案。零样本思维链有效地改善一些基本的推理任务。然而,它通常不如思维链提示有效。但是当无法构建思维链示例的时候,零样本思维链可以派上用场。