跳到主要内容KIMI 与文心一言、通义千问能力对比评测 | 极客日志JavaAIjava
KIMI 与文心一言、通义千问能力对比评测
综述由AI生成通过六个实际场景问题,包括天气查询、房产政策、法律问答及 Java 代码生成(部门树构建、数据处理、多线程下载),对 KIMI、文心一言和通义千问三款国产大模型进行了横向对比。测试结果显示,各模型在不同任务上表现各异:文心一言在实时信息获取和逻辑条理性上表现较好;KIMI 依赖搜索引擎,部分数据存在滞后或错误;通义千问在代码生成简洁性和执行稳定性上具有一定优势。文章旨在客观评估三款模型的实际应用能力,供开发者参考。
微码行者25 浏览 前言
最近国产大模型 KIMI 备受关注。目前国内大模型领域竞争激烈,我们本次不与其他国家产品或收费服务对比,仅针对免费的 KIMI、文心一言和通义千问进行横向测试。
在此说明:本文测试题目为原创,测试结果仅代表这三家大模型在特定问题上的表现,不能全面代表整体优劣程度。
问题一:我今天陪女朋友去杭州西湖游玩应该穿什么衣服
KIMI

文心一言

通义千问

对比

今天西湖边实际天气实拍:温度 18-28 度,多云,15 点 10% 概率有雨,空气有点污染。
对比分析:
- 通义千问:表现较差,未能获取今天杭州西湖的实时天气,答案基于历史经验,参考价值有限。
- 文心一言:给出了杭州西湖的天气信息(气温、风力、空气质量轻度污染),符合实际情况。建议条理清晰,并对衣服颜色给出了具体配色,表现优秀。
- KIMI:查询了网页内容,但查询的天气并非当天数据,导致答案有误。最大错误是空气质量判断不准(实际有污染,它显示很好)。结果条理性不如文心一言,未给出具体配色建议。
小结
文心一言 > KIMI > 通义千问
问题二:我和老婆户口在杭州,有三个娃,请问今天我在杭州西湖区可以买几套二手房?
KIMI

文心一言

通义千问
对比
- 通义千问:政策信息滞后,引用的是 2022 年 5 月 17 日的旧政策,且未给出具体可购买数量。
- KIMI:唯一给出正确答案。得益于实时搜索功能,正确检索到杭州取消限购的信息。
- 文心一言:未更新 3 月 14 日取消限购的内容,仍按旧政策回答,结果错误。
小结
问题三:河北邯郸 3 名不满十四周岁初中生杀害同班同学并掩埋,请问这三名初中生在法律上会受到什么惩罚?
KIMI
文心一言
通义千问
对比
- 通义千问:未给出明确答案。
- 文心一言:与 KIMI 回答基本一致,但在细节上更强,提供了具体的法律依据《刑法》第十七条。
- KIMI:回答内容与文心一言基本相同。
小结
问题四:使用 JAVA 代码合成部门树
[
{"id": 1, "pid": 0, "name": "产品研发中心"},
{"id": 2, "pid": 1, "name": "后端"},
{"id": 3, "pid": 1, "name": "前端"},
{"id": 4, "pid": 2, "name": "JAVA"},
{"id": 5, "pid": 3, "name": "JS"},
{"id": 6, "name": "测试数据"}
]
注意最后一条是故意造的错误数据。请通过 id=pid 合成部门树,给出 JAVA 代码。
KIMI
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
class Department {
int id;
String name;
List<Department> children = new ArrayList<>();
public Department(int id, String name) {
this.id = id;
this.name = name;
}
public void addChild(Department child) {
children.add(child);
}
public static Department fromJson(Map<String, Object> jsonMap) {
return new Department((Integer) jsonMap.get("id"), (String) jsonMap.get("name"));
}
}
public class DepartmentTreeBuilder {
public static Department buildTree(List<Map<String, Object>> departments) {
Map<Integer, Department> departmentMap = new HashMap<>();
List<Department> roots = new ArrayList<>();
for (Map<String, Object> deptJson : departments) {
int id = (Integer) deptJson.get("id");
String name = (String) deptJson.get("name");
Department dept = Department.fromJson(deptJson);
departmentMap.put(id, dept);
if (deptJson.get("pid").equals(0)) {
roots.add(dept);
}
}
for (Map<String, Object> deptJson : departments) {
int id = (Integer) deptJson.get("id");
int pid = (Integer) deptJson.get("pid");
if (pid != 0 && departmentMap.containsKey(pid)) {
Department dept = departmentMap.get(id);
Department parent = departmentMap.get(pid);
if (parent != null) {
parent.addChild(dept);
}
}
}
return roots.isEmpty() ? null : roots.get(0);
}
public static void main(String[] args) {
List<Map<String, Object>> departments = new ArrayList<>();
departments.add(Map.of("id", 1, "pid", 0, "name", "产品研发中心"));
departments.add(Map.of("id", 2, "pid", 1, "name", "后端"));
departments.add(Map.of("id", 3, "pid", 1, "name", "前端"));
departments.add(Map.of("id", 4, "pid", 2, "name", "JAVA"));
departments.add(Map.of("id", 5, "pid", 3, "name", "JS"));
Department root = buildTree(departments);
String json = new Gson().toJson(root);
System.out.println(json);
}
}
文心一言
public class DepartmentTreeBuilder {
public static void main(String[] args) {
List<Department> departments = new ArrayList<>();
departments.add(new Department(1, 0, "产品研发中心"));
departments.add(new Department(2, 1, "后端"));
departments.add(new Department(3, 1, "前端"));
departments.add(new Department(4, 2, "JAVA"));
departments.add(new Department(5, 3, "JS"));
departments.add(new Department(6, 0, "测试数据"));
List<Department> tree = buildDepartmentTree(departments);
for (Department dept : tree) {
printDepartmentTree(dept, 0);
}
}
public static List<Department> buildDepartmentTree(List<Department> departments) {
Map<Integer, Department> idMap = new HashMap<>();
List<Department> tree = new ArrayList<>();
for (Department dept : departments) {
idMap.put(dept.getId(), dept);
}
for (Department dept : departments) {
if (dept.getPid() == 0) {
tree.add(dept);
} else {
Department parent = idMap.get(dept.getPid());
if (parent != null) {
if (parent.getChildren() == null) {
parent.setChildren(new ArrayList<>());
}
parent.getChildren().add(dept);
}
}
}
return tree;
}
public static void printDepartmentTree(Department dept, int level) {
for (int i = 0; i < level; i++) {
System.out.print("--");
}
System.out.println(dept.getName());
if (dept.getChildren() != null) {
for (Department child : dept.getChildren()) {
printDepartmentTree(child, level + 1);
}
}
}
static class Department {
private int id;
private int pid;
private String name;
private List<Department> children;
public Department(int id, int pid, String name) {
this.id = id;
this.pid = pid;
this.name = name;
}
public int getId() {
return id;
}
public int getPid() {
return pid;
}
public String getName() {
return name;
}
public List<Department> getChildren() {
return children;
}
public void setChildren(List<Department> children) {
this.children = children;
}
}
}
通义千问
class Department {
int id;
int pid;
String name;
List<Department> children = new ArrayList<>();
Department(int id, int pid, String name) {
this.id = id;
this.pid = pid;
this.name = name;
}
@Override
public String toString() {
return "Department{" +
"id=" + id +
", pid=" + pid +
", name='" + name + '\'' +
", children=" + children +
'}';
}
static Department buildDepartmentTree(List<Department> depts) {
Map<Integer, Department> map = new HashMap<>();
for (Department dept : depts) {
map.put(dept.id, dept);
}
for (Department dept : depts) {
if (map.containsKey(dept.pid)) {
map.get(dept.pid).children.add(dept);
}
}
return map.values().stream()
.filter(d -> d.pid == 0)
.findFirst()
.orElse(null);
}
public static void main(String[] args) {
List<Department> depts = new ArrayList<>();
depts.add(new Department(1, 0, "产品研发中心"));
depts.add(new Department(2, 1, "后端"));
depts.add(new Department(3, 1, "前端"));
depts.add(new Department(4, 2, "JAVA"));
depts.add(new Department(5, 3, "JS"));
depts.add(new Department(6, -1, "测试数据"));
Department root = buildDepartmentTree(depts);
System.out.println(root);
}
}
对比
- 通义千问:代码能正确执行,写法简洁,使用了 lambda 表达式,在代码生成领域表现较好。
- KIMI:生成的代码存在错误,Department 类缺少 pid 字段定义,导致逻辑不完整。
- 文心一言:代码能正确执行,但相比通义千问略显冗长。
小结
问题五:使用 JAVA 处理数据
要求:帮我把这两条部门数据去除根组织和部门 ID,将部门名用 - 分隔输出,请给出基于 JDK8 的 JAVA 代码。
EveryOne#根组织/50#侠客集团/96332#工作机动/103965#cy 专属组织/103967#策划部门十一个非常厉害的部门你知道吗
EveryOne#根组织/50#侠客集团/96332#工作机动/103965#cy 专属组织/104014#技术部门懂技术会生活的好部门呢你想来吗
KIMI
侠客集团 -96332#工作机动 -103965#cy 专属组织 -103967#策划部门十一个非常厉害的部门你知道吗
侠客集团 -96332#工作机动 -103965#cy 专属组织 -104014#技术部门懂技术会生活的好部门呢你想来吗
文心一言
根组织 - 侠客集团 - 工作机动 -cy 专属组织 - 策划部门十一个非常厉害的部门你知道吗
根组织 - 侠客集团 - 工作机动 -cy 专属组织 - 技术部门懂技术会生活的好部门呢你想来吗
通义千问
cy 专属组织 - 策划部门十一个非常厉害的部门你知道吗
cy 专属组织 - 技术部门懂技术会生活的好部门呢你想来吗
对比
- 通义千问:多去除了'侠客集团'和工作机动部门,不符合预期。
- 文心一言:只是没有去除根组织,其余部分正确,表现最好。
- KIMI:输出错误,未去除部门 ID,表现最差。
小结
问题六:多线程图片下载
要求:请基于 JDK8 编写代码将输入的 URL 下载到 C://img 下,文件名从 URL 中获取,要考虑 URL 中获取文件名重复问题,要求使用多线程下载。
KIMI
import java.io.*;
import java.net.URL;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.*;
public class ImageDownloader {
private static final String DOWNLOAD_DIR = "C://img";
public static void main(String[] args) {
List<String> imageUrls = Arrays.asList(
"http://pic.people.com.cn/NMediaFile/2024/0324/MAIN17112471760803BC3VHT0EB.jpg",
"http://pic.people.com.cn/NMediaFile/2024/0324/MAIN1711247176118UWI7FVR0OP.jpg"
);
ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
try {
List<Future<Path>> futures = new ArrayList<>();
for (String imageUrl : imageUrls) {
Path path = Paths.get(DOWNLOAD_DIR, getFileNameFromUrl(imageUrl));
futures.add(executorService.submit(() -> downloadImage(imageUrl, path)));
}
for (Future<Path> future : futures) {
future.get();
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
executorService.shutdown();
}
}
private static String getFileNameFromUrl(String url) {
String fileName = url.substring(url.lastIndexOf('/') + 1);
return fileName;
}
private static Path downloadImage(String imageUrl, Path path) throws IOException, InterruptedException {
URL url = new URL(imageUrl);
try (InputStream in = url.openStream();
OutputStream out = new FileOutputStream(path.toFile())) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
Files.createDirectories(path.getParent());
Files.move(path, path.resolveSibling(getUniqueFileName(path.getFileName().toString())));
}
return path;
}
private static String getUniqueFileName(String fileName) {
Path path = Paths.get(DOWNLOAD_DIR, fileName);
int counter = 1;
while (Files.exists(path)) {
path = Paths.get(DOWNLOAD_DIR, fileName.replace(".jpg", "(" + counter + ").jpg"));
counter++;
}
return path.getFileName().toString();
}
}
文心一言
import java.io.BufferedInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ImageDownloader {
private static final String TARGET_DIRECTORY = "C://img";
private static final int THREAD_POOL_SIZE = 5;
public static void main(String[] args) {
List<String> urls = new ArrayList<>();
urls.add("http://pic.people.com.cn/NMediaFile/2024/0324/MAIN17112471760803BC3VHT0EB.jpg");
urls.add("http://pic.people.com.cn/NMediaFile/2024/0324/MAIN1711247176118UWI7FVR0OP.jpg");
ExecutorService executor = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
for (String url : urls) {
executor.submit(() -> downloadImage(url));
}
executor.shutdown();
try {
while (!executor.isTerminated()) {
Thread.sleep(100);
}
System.out.println("All images downloaded.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static void downloadImage(String urlString) {
try {
URL url = new URL(urlString);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
try (InputStream in = new BufferedInputStream(connection.getInputStream());
FileOutputStream fos = getUniqueFileOutputStream(urlString)) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
fos.write(buffer, 0, bytesRead);
}
} finally {
connection.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static FileOutputStream getUniqueFileOutputStream(String urlString) throws IOException {
String fileName = getFileNameFromUrl(urlString);
String filePath = Paths.get(TARGET_DIRECTORY, fileName).toString();
Path path = Paths.get(filePath);
if (Files.exists(path)) {
fileName = getUniqueFileName(fileName);
filePath = Paths.get(TARGET_DIRECTORY, fileName).toString();
}
Path targetPath = Paths.get(filePath);
Files.createDirectories(targetPath.getParent());
return new FileOutputStream(targetPath.toFile());
}
private static String getFileNameFromUrl(String url) {
String[] parts = url.split("/");
return parts[parts.length - 1];
}
private static String getUniqueFileName(String fileName) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] hashBytes = md.digest(fileName.getBytes());
StringBuilder hexString = new StringBuilder();
for (byte b : hashBytes) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
return fileName + "_" + hexString.toString();
}
}
通义千问
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ImageDownloader {
private static final String DOWNLOAD_DIR = "C://img";
public static void main(String[] args) throws IOException {
String[] imageUrls = {
"http://pic.people.com.cn/NMediaFile/2024/0324/MAIN17112471760803BC3VHT0EB.jpg",
"http://pic.people.com.cn/NMediaFile/2024/0324/MAIN1711247176118UWI7FVR0OP.jpg"
};
ExecutorService executor = Executors.newFixedThreadPool(2);
for (String imageUrl : imageUrls) {
Runnable worker = () -> downloadImage(imageUrl);
executor.execute(worker);
}
executor.shutdown();
while (!executor.isTerminated()) {
}
System.out.println("所有图片下载完成!");
}
private static void downloadImage(String imageUrl) {
try {
URL url = new URL(imageUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(5000);
connection.connect();
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
String fileName = extractFileNameFromUrl(url);
Path targetPath = Paths.get(DOWNLOAD_DIR, ensureUniqueFileName(fileName));
Files.createDirectories(targetPath.getParent());
try (ReadableByteChannel rbc = Channels.newChannel(connection.getInputStream());
FileOutputStream fos = new FileOutputStream(targetPath.toFile())) {
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
}
System.out.println("成功下载图片:" + targetPath.toString());
} else {
System.out.println("无法下载图片,响应码:" + connection.getResponseCode());
}
} catch (IOException e) {
System.err.println("图片下载失败:" + imageUrl);
e.printStackTrace();
}
}
private static String extractFileNameFromUrl(URL url) {
String path = url.getPath();
return path.substring(path.lastIndexOf('/') + 1);
}
private static String ensureUniqueFileName(String fileName) {
Path path = Paths.get(DOWNLOAD_DIR, fileName);
if (!Files.exists(path)) {
return fileName;
}
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss_SSS");
LocalDateTime now = LocalDateTime.now();
String timestamp = now.format(formatter);
String extension = fileName.substring(fileName.lastIndexOf('.'));
return fileName.replace(extension, "_" + timestamp + extension);
}
}
对比
- KIMI:代码有错误,无法直接运行;未考虑下载目录不存在的情况;文件名重复处理思路正确但实现有误。
- 文心一言:少了一个异常抛出,修改后可运行;使用 MD5 哈希处理文件名重复,思路可行。
- 通义千问:能正常运行下载,处理逻辑完善;考虑了目录不存在情况;使用时间戳处理文件名重复,能解决大部分冲突。
小结
总结
从这六道题目来看,KIMI 并没有达到预期的惊艳效果。大体结论如下:
- 依赖数据源:KIMI 的回答非常依赖其获取的数据,可能是由于自身训练数据不足或算力限制。
- 通用问题依赖搜索引擎:KIMI 使用实时搜索获取数据源,如果过度依赖搜索引擎,在通用大模型领域可能存在硬伤。
- 代码生成领域不成熟:在 Java 代码生成方面,KIMI 的表现不如另外两家,存在语法错误或逻辑缺失。
- '百模大战'中的一员:KIMI 只是众多大模型中的一员,并未表现出鹤立鸡群的绝对优势。
关于其火爆的原因可能涉及市场运作,但作为开发者,应关注技术本身的实用性与稳定性。
相关免费在线工具
- Keycode 信息
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
- Escape 与 Native 编解码
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
- JavaScript / HTML 格式化
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
- JavaScript 压缩与混淆
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
- RSA密钥对生成器
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
- Mermaid 预览与可视化编辑
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online