Playwright Java API 测试实战:用 APIRequestContext 打通 REST 接口测试与状态管理
Playwright 不仅能驱动 Chromium、Firefox 和 WebKit 完成浏览器端 UI 自动化,还通过 APIRequestContext 提供了完整的 HTTP(S) API 测试能力,让 Java 开发者无需加载页面、无需在页面中执行 JS,即可直接向服务端发送请求。本文以 GitHub REST API 为实例,完整讲解如何在 JUnit 5 中用 Java 编写接口测试、预置服务端状态、校验服务端后置条件以及跨 BrowserContext 复用登录态,帮助你构建“API + UI”一体化的端到端测试体系。
一、为什么需要纯 API 层的测试能力
Playwright 定位为 Web 测试与自动化框架,其文档(docs/src/api-testing-java.md)开篇即指出:你可以用它访问应用暴露的 REST API。在某些场景下,我们希望在 Java 中直接向服务器发送请求,而不加载页面、不运行页面里的 JS 代码。官方文档归纳了三个典型动机:
- 测试你的服务端 API:对接口本身的正确性做回归验证。
- 访问 Web 应用之前预置服务端状态:例如先通过 API 创建账号、数据、仓库,再进入 UI 做交互断言,避免把“造数据”过程写进 UI 用例里。
- 在浏览器中执行操作后,校验服务端后置条件:UI 上的点击最终是否真实写入了后端,用 API 请求做权威校验。
这三类需求都可以通过 APIRequestContext 的方法统一完成——它能发送所有种类的 HTTP(S) 请求。
1.1 APIRequestContext 在仓库中的实现位置
在 packages/playwright-core/src/client/fetch.ts 中可以找到 APIRequestContext 的完整协议实现:它同时提供 fetch、get、post、put、patch、delete、head 等便捷方法,例如:
post(url, options)(fetch.ts)以 POST 语义转发到统一的fetch;get(url, options)(fetch.ts)、delete(url, options)(fetch.ts)同理;- 所有方法最终汇聚到
_innerFetch,在那里统一处理params、headers、data、form、multipart等请求选项,并做合法性校验,例如只允许data、form、multipart三者中指定一个(见 fetch.ts)。
服务端的请求执行逻辑在 packages/playwright-core/src/server/fetch.ts:它会将 baseURL 与相对路径拼接(fetch.ts)、合并 extraHTTPHeaders(fetch.ts),未显式指定 method 时默认使用 GET(fetch.ts),重定向上限默认为 20 次。这些行为是 Java 绑定与仓库协议层共同遵循的契约。
二、编写 GitHub API 测试:从零开始的一个完整例子
官方文档用“通过 GitHub API 测试 Issue 创建”作为贯穿始终的实战示例,测试套件将依次完成:
- 运行测试前创建一个新仓库;
- 创建若干个 Issue 并校验服务端状态;
- 运行结束后删除该仓库。
下面按「配置 → 用例 → 环境搭建与清理 → 完整代码」逐步展开。
2.1 配置:一次授权,全程复用(Configure)
GitHub API 需要鉴权。文档推荐的做法是在创建 APIRequestContext 时统一配置 token 与 baseURL,这样后续每个请求都不用重复携带鉴权头:
package org.example;
import com.microsoft.playwright.APIRequest;
import com.microsoft.playwright.APIRequestContext;
import com.microsoft.playwright.Playwright;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.TestInstance;
import java.util.HashMap;
import java.util.Map;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class TestGitHubAPI {
private static final String API_TOKEN = System.getenv("GITHUB_API_TOKEN");
private Playwright playwright;
private APIRequestContext request;
void createPlaywright() {
playwright = Playwright.create();
}
void createAPIRequestContext() {
Map<String, String> headers = new HashMap<>();
// We set this header per GitHub guidelines.
headers.put("Accept", "application/vnd.github.v3+json");
// Add authorization token to all requests.
// Assuming personal access token available in the environment.
headers.put("Authorization", "token " + API_TOKEN);
request = playwright.request().newContext(new APIRequest.NewContextOptions()
// All requests we send go to this API endpoint.
.setBaseURL("https://api.github.com")
.setExtraHTTPHeaders(headers));
}
@BeforeAll
void beforeAll() {
createPlaywright();
createAPIRequestContext();
}
void disposeAPIRequestContext() {
if (request != null) {
request.dispose();
request = null;
}
}
void closePlaywright() {
if (playwright != null) {
playwright.close();
playwright = null;
}
}
@AfterAll
void afterAll() {
disposeAPIRequestContext();
closePlaywright();
}
}
这里值得注意的配置点有三个:
setBaseURL("https://api.github.com"):所有相对路径请求(如/user/repos)都会拼接到该域名上。仓库协议实现中,拼接逻辑位于服务端 fetch 的constructURLBasedOnBaseURL(defaults.baseURL, params.url)(见 packages/playwright-core/src/server/fetch.ts)。setExtraHTTPHeaders(headers):为所有请求统一附加自定义头,鉴权信息只需配置一次。服务端实现会先把默认的user-agent、accept、accept-encoding头写入,再合并extraHTTPHeaders与单次请求头(见 fetch.ts)。- 生命周期管理:
@BeforeAll创建Playwright与APIRequestContext,@AfterAll依次dispose()掉请求上下文并close()掉 Playwright 驱动,保证测试进程干净退出。
API_TOKEN 与下文要用的 GITHUB_USER 都从环境变量读取,token 不硬编码进源码。运行测试前需要导出:
export GITHUB_USER="你的 GitHub 用户名"
export GITHUB_API_TOKEN="你的 GitHub Personal Access Token"
注意:仓库中与本文等价的开箱即用示例是 TypeScript 版本的 examples/github-api/tests/test-api.spec.ts(连同其 playwright.config.ts),它同样实现了“建仓 → 建 Issue → 删仓”流程,可对照学习跨语言写法。
2.2 编写测试:创建 Bug 报告与 Feature 请求
初始化好 request 对象后,就可以写真正发起接口调用的测试了。下面的用例分别创建 [Bug] report 1 和 [Feature] request 1 两个 Issue,然后回读 Issue 列表验证服务端确实写入了对应标题与正文:
package org.example;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.microsoft.playwright.APIRequest;
import com.microsoft.playwright.APIRequestContext;
import com.microsoft.playwright.APIResponse;
import com.microsoft.playwright.Playwright;
import com.microsoft.playwright.options.RequestOptions;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class TestGitHubAPI {
private static final String REPO = "test-repo-2";
private static final String USER = System.getenv("GITHUB_USER");
private static final String API_TOKEN = System.getenv("GITHUB_API_TOKEN");
private Playwright playwright;
private APIRequestContext request;
// ...
@Test
void shouldCreateBugReport() {
Map<String, String> data = new HashMap<>();
data.put("title", "[Bug] report 1");
data.put("body", "Bug description");
APIResponse newIssue = request.post("/repos/" + USER + "/" + REPO + "/issues",
RequestOptions.create().setData(data));
assertTrue(newIssue.ok());
APIResponse issues = request.get("/repos/" + USER + "/" + REPO + "/issues");
assertTrue(issues.ok());
JsonArray json = new Gson().fromJson(issues.text(), JsonArray.class);
JsonObject issue = null;
for (JsonElement item : json) {
JsonObject itemObj = item.getAsJsonObject();
if (!itemObj.has("title")) {
continue;
}
if ("[Bug] report 1".equals(itemObj.get("title").getAsString())) {
issue = itemObj;
break;
}
}
assertNotNull(issue);
assertEquals("Bug description", issue.get("body").getAsString(), issue.toString());
}
@Test
void shouldCreateFeatureRequest() {
Map<String, String> data = new HashMap<>();
data.put("title", "[Feature] request 1");
data.put("body", "Feature description");
APIResponse newIssue = request.post("/repos/" + USER + "/" + REPO + "/issues",
RequestOptions.create().setData(data));
assertTrue(newIssue.ok());
APIResponse issues = request.get("/repos/" + USER + "/" + REPO + "/issues");
assertTrue(issues.ok());
JsonArray json = new Gson().fromJson(issues.text(), JsonArray.class);
JsonObject issue = null;
for (JsonElement item : json) {
JsonObject itemObj = item.getAsJsonObject();
if (!itemObj.has("title")) {
continue;
}
if ("[Feature] request 1".equals(itemObj.get("title").getAsString())) {
issue = itemObj;
break;
}
}
assertNotNull(issue);
assertEquals("Feature description", issue.get("body").getAsString(), issue.toString());
}
}
上述代码演示了三个最常用的模式:
- 发送带 JSON body 的 POST:通过
RequestOptions.create().setData(map)传入一个Map,Playwright 客户端会把它序列化为 JSON 请求体(底层对应 packages/playwright-core/src/client/fetch.ts 中对data类型对象的JSON.stringify处理,见 fetch.ts)。 - 快速断言 HTTP 状态:
APIResponse.ok()判断状态码是否落在 200–299 区间(仓库实现见 client/fetch.ts)。 - 解析响应文本为 JSON:
APIResponse.text()返回以 UTF-8 解码的响应体字符串(client/fetch.ts),再用 Gson 解析为JsonArray遍历查找目标记录,最后用 JUnit 的assertNotNull/assertEquals完成断言。
2.3 环境搭建与清理(Setup and teardown)
上面两个用例默认仓库已经存在。更规范的做法是在 @BeforeAll 里新建仓库、在 @AfterAll 里删掉仓库,保证测试环境幂等、可重复运行:
public class TestGitHubAPI {
// ...
void createTestRepository() {
APIResponse newRepo = request.post("/user/repos",
RequestOptions.create().setData(Collections.singletonMap("name", REPO)));
assertTrue(newRepo.ok(), newRepo.text());
}
@BeforeAll
void beforeAll() {
createPlaywright();
createAPIRequestContext();
createTestRepository();
}
void deleteTestRepository() {
if (request != null) {
APIResponse deletedRepo = request.delete("/repos/" + USER + "/" + REPO);
assertTrue(deletedRepo.ok());
}
}
// ...
@AfterAll
void afterAll() {
deleteTestRepository();
disposeAPIRequestContext();
closePlaywright();
}
}
这里同样用到了几个值得解释的 API:
assertTrue(newRepo.ok(), newRepo.text()):第二个参数把失败时的响应体作为断言消息,排查 4xx/5xx 时能直接看到 GitHub 返回的错误 JSON,而不是干巴巴的布尔断言。request.delete(...):DELETE 请求同样是APIRequestContext的一等公民方法。
2.4 完整测试示例(Complete test example)
把上述片段整合起来,就是一个可直接运行的完整 JUnit 测试类:
package org.example;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.microsoft.playwright.APIRequest;
import com.microsoft.playwright.APIRequestContext;
import com.microsoft.playwright.APIResponse;
import com.microsoft.playwright.Playwright;
import com.microsoft.playwright.options.RequestOptions;
import org.junit.jupiter.api.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class TestGitHubAPI {
private static final String REPO = "test-repo-2";
private static final String USER = System.getenv("GITHUB_USER");
private static final String API_TOKEN = System.getenv("GITHUB_API_TOKEN");
private Playwright playwright;
private APIRequestContext request;
void createPlaywright() {
playwright = Playwright.create();
}
void createAPIRequestContext() {
Map<String, String> headers = new HashMap<>();
// We set this header per GitHub guidelines.
headers.put("Accept", "application/vnd.github.v3+json");
// Add authorization token to all requests.
// Assuming personal access token available in the environment.
headers.put("Authorization", "token " + API_TOKEN);
request = playwright.request().newContext(new APIRequest.NewContextOptions()
// All requests we send go to this API endpoint.
.setBaseURL("https://api.github.com")
.setExtraHTTPHeaders(headers));
}
void createTestRepository() {
APIResponse newRepo = request.post("/user/repos",
RequestOptions.create().setData(Collections.singletonMap("name", REPO)));
assertTrue(newRepo.ok(), newRepo.text());
}
@BeforeAll
void beforeAll() {
createPlaywright();
createAPIRequestContext();
createTestRepository();
}
void deleteTestRepository() {
if (request != null) {
APIResponse deletedRepo = request.delete("/repos/" + USER + "/" + REPO);
assertTrue(deletedRepo.ok());
}
}
void disposeAPIRequestContext() {
if (request != null) {
request.dispose();
request = null;
}
}
void closePlaywright() {
if (playwright != null) {
playwright.close();
playwright = null;
}
}
@AfterAll
void afterAll() {
deleteTestRepository();
disposeAPIRequestContext();
closePlaywright();
}
@Test
void shouldCreateBugReport() {
Map<String, String> data = new HashMap<>();
data.put("title", "[Bug] report 1");
data.put("body", "Bug description");
APIResponse newIssue = request.post("/repos/" + USER + "/" + REPO + "/issues",
RequestOptions.create().setData(data));
assertTrue(newIssue.ok());
APIResponse issues = request.get("/repos/" + USER + "/" + REPO + "/issues");
assertTrue(issues.ok());
JsonArray json = new Gson().fromJson(issues.text(), JsonArray.class);
JsonObject issue = null;
for (JsonElement item : json) {
JsonObject itemObj = item.getAsJsonObject();
if (!itemObj.has("title")) {
continue;
}
if ("[Bug] report 1".equals(itemObj.get("title").getAsString())) {
issue = itemObj;
break;
}
}
assertNotNull(issue);
assertEquals("Bug description", issue.get("body").getAsString(), issue.toString());
}
@Test
void shouldCreateFeatureRequest() {
Map<String, String> data = new HashMap<>();
data.put("title", "[Feature] request 1");
data.put("body", "Feature description");
APIResponse newIssue = request.post("/repos/" + USER + "/" + REPO + "/issues",
RequestOptions.create().setData(data));
assertTrue(newIssue.ok());
APIResponse issues = request.get("/repos/" + USER + "/" + REPO + "/issues");
assertTrue(issues.ok());
JsonArray json = new Gson().fromJson(issues.text(), JsonArray.class);
JsonObject issue = null;
for (JsonElement item : json) {
JsonObject itemObj = item.getAsJsonObject();
if (!itemObj.has("title")) {
continue;
}
if ("[Feature] request 1".equals(itemObj.get("title").getAsString())) {
issue = itemObj;
break;
}
}
assertNotNull(issue);
assertEquals("Feature description", issue.get("body").getAsString(), issue.toString());
}
}
文档同时提到:如果不想手工管理 Playwright 对象的创建与销毁,可以参考实验性的 JUnit 集成指南(Java),用其提供的
@UsePlaywright注解与request等 fixture 自动初始化 APIRequestContext,把生命周期从测试代码里彻底剥离。
三、三种典型应用模式:API 与 UI 的协作
接口测试能力最大的价值在于和 UI 测试组合使用。官方文档给出两种最常用的交叉模式,下面分别说明。
3.1 模式一:先通过 API 预置状态,再用 UI 断言(Prepare server state)
这个模式解决的是“UI 测试跑得快且稳定”的问题:创建数据这类耗时、易碎的操作交给 API,UI 层只负责验证呈现结果。
public class TestGitHubAPI {
@Test
void lastCreatedIssueShouldBeFirstInTheList() {
Map<String, String> data = new HashMap<>();
data.put("title", "[Feature] request 1");
data.put("body", "Feature description");
APIResponse newIssue = request.post("/repos/" + USER + "/" + REPO + "/issues",
RequestOptions.create().setData(data));
assertTrue(newIssue.ok());
try (Browser browser = playwright.chromium().launch()) {
Page page = browser.newPage();
page.navigate("https://github.com/" + USER + "/" + REPO + "/issues");
Locator firstIssue = page.locator("a[data-hovercard-type='issue']").first();
assertThat(firstIssue).hasText("[Feature] request 1");
}
}
}
流程拆解:
- 通过
request.post(...)创建 Issue,assertTrue(newIssue.ok())先确认服务端接受; - 启动 Chromium 浏览器并导航到 Issue 列表页;
- 用
page.locator(...)取到列表中第一个 Issue,通过LocatorAssertions风格的assertThat(firstIssue).hasText(...)断言其文本——API 写入的数据必须出现在 UI 列表的顶部。
3.2 模式二:先在 UI 操作,再用 API 校验服务端状态
这个模式反过来使用:UI 是“因”,API 是验证“果”的手段。它适用于确认 UI 操作真的把数据持久化到了后端,而不是前端“假成功”。
public class TestGitHubAPI {
@Test
void lastCreatedIssueShouldBeOnTheServer() {
try (Browser browser = playwright.chromium().launch()) {
Page page = browser.newPage();
page.navigate("https://github.com/" + USER + "/" + REPO + "/issues");
page.locator("text=New Issue").click();
page.locator("[aria-label='Title']").fill("Bug report 1");
page.locator("[aria-label='Comment body']").fill("Bug description");
page.locator("text=Submit new issue").click();
String issueId = page.url().substring(page.url().lastIndexOf('/'));
APIResponse newIssue = request.get("https://github.com/" + USER + "/" + REPO + "/issues/" + issueId);
assertThat(newIssue).isOK();
assertTrue(newIssue.text().contains("Bug report 1"));
}
}
}
流程拆解:
- 在浏览器里完成“新建 Issue”的全部 UI 操作;
- 提交后,从
page.url()中截取新 Issue 的 ID; - 用
request.get(...)请求对应的 Issue 详情地址,先断言APIResponse整体 OK(对应 Playwright 的响应级断言,见 docs/src/api/class-apiresponseassertions.md),再检查响应体文本确实包含刚才填写的标题。
这两种模式各司其职、互为验证闭环,正是官方在文档开头强调的“预置服务端状态 / 校验服务端后置条件”的具体落地形态。
四、复用鉴权状态:storageState 在 Browser 与 API 之间互通
Web 应用普遍采用 Cookie 或 Token 鉴权,登录后的状态以 cookies 形式存储。APIRequestContext.storageState() 方法可以取出已认证上下文中的存储状态,并用它创建新的上下文。
storageState 的关键特性是在 BrowserContext 与 APIRequestContext 之间完全互通:你可以通过 API 调用完成登录,然后把拿到的 Cookie 塞进新建的浏览器上下文,页面访问时即为已登录状态——省去 UI 登录步骤。官方文档给出的代码骨架如下:
APIRequestContext requestContext = playwright.request().newContext(
new APIRequest.NewContextOptions().setHttpCredentials("user", "passwd"));
requestContext.get("https://api.example.com/login");
// Save storage state into a variable.
String state = requestContext.storageState();
// Create a new context with the saved storage state.
BrowserContext context = browser.newContext(new Browser.NewContextOptions().setStorageState(state));
要点解释:
setHttpCredentials("user", "passwd"):给 API 上下文配置 HTTP Basic 认证凭据,用于登录请求。requestContext.storageState():返回包含 cookies(以及可选 localStorage/origins 等)的 JSON 字符串。在仓库实现中,该方法还可配合path参数直接把状态落盘(见 client/fetch.ts)。browser.newContext(...).setStorageState(state):新建的BrowserContext会预置这些 Cookie,进入页面即已完成鉴权。- 反向同样成立:
BrowserContext.storageState()的结果也能用来创建APIRequestContext。这意味着通过 UI 登录一次,即可在后续的纯 API 请求中复用同一身份,也可以在任意方向执行“API 登录 → 浏览器复用”或“浏览器登录 → API 复用”。
从仓库协议实现看,服务端在创建请求上下文时会把传入的 storageState 解析为 cookies 与 origins 写入对应存储(见 packages/playwright-core/src/server/fetch.ts),并向外提供等价的 storageState() 读取方法,这保证了两个上下文体系间状态可以无损互换。
补充说明:若使用
BrowserContext/Page内置的 request 对象而非独立创建的上下文,API 请求与浏览器会话还会共享同一个 Cookie jar(详见 APIRequestContext 官方类参考);而playwright.request().newContext(...)创建的独立上下文则拥有自己隔离的 Cookie 存储。
五、进阶:APIRequestContext 的常用选项与响应对象
围绕官方文档示例,再补充几个直接影响实战效果的配置与 API,方便按需查阅(Java 端全部用法以 docs/src/api/class-apirequest.md 与 docs/src/api/class-apirequestcontext.md 为准)。
5.1 创建上下文时可配置的关键项(APIRequest.NewContextOptions)
| 配置 | 作用 | 示例中的用法 |
|---|---|---|
baseURL |
为相对 URL 提供前缀,配合文档约定应以 / 结尾省略路径 |
https://api.github.com |
extraHTTPHeaders |
给所有请求附加统一请求头 | Accept / Authorization |
httpCredentials |
HTTP Basic 认证凭据 | setHttpCredentials("user", "passwd") |
storageState |
预置 Cookie/存储状态,用于复用登录 | 见第四节 |
ignoreHTTPSErrors |
是否忽略 HTTPS 证书错误 | 内部实现对应关闭 rejectUnauthorized(见 server/fetch.ts) |
timeout |
上下文级默认请求超时 | — |
5.2 单次请求选项(RequestOptions)与响应读取
每次 get/post/put/patch/delete 还可传入单次选项:
setParams(map):附加查询字符串参数(内部实现见 client/fetch.ts);setHeaders(map):单次请求头(会与上下文级extraHTTPHeaders合并);setData(object/string):JSON 请求体;换成form则是 urlencoded 表单,multipart支持文件上传(三者互斥,详见 client/fetch.ts);setTimeout(...):单次超时;此外底层还支持maxRedirects(默认 20)与maxRetries等选项(见 server/fetch.ts)。
拿到 APIResponse 后,最常用的读取与断言手段包括:
| API | 作用 |
|---|---|
ok() |
状态码是否 200–299(实现见 client/fetch.ts) |
status() / statusText() |
读取原始状态码与状态文本 |
url() |
最终响应 URL(可判断重定向去向) |
headers() / headersArray() |
读取响应头 |
text() |
以 UTF-8 解码响应体为字符串(client/fetch.ts) |
body() |
以字节数组形式返回响应体(client/fetch.ts) |
响应级断言 assertThat(response).isOK() |
语义化断言,见 docs/src/api/class-apiresponseassertions.md |
六、小结
从本文可以看到,Playwright 的 API 测试能力并不是独立于 UI 自动化之外的“另一个框架”,而是与浏览器自动化深度咬合的一套完整闭环:
- 用
APIRequestContext发送各类 HTTP(S) 请求,直接测试服务端接口; - 在 UI 测试前用它预置数据、在 UI 操作后用它对后端做权威校验;
- 通过
storageState()在BrowserContext与APIRequestContext之间无缝迁移鉴权状态。
若希望进一步自动化管理 Playwright 对象的生命周期、利用 request fixture 免去样板代码,推荐阅读实验性的 JUnit 集成指南(Java);类级别的完整方法签名、参数与取值边界则以仓库中的 APIRequestContext、APIResponse 等官方 API 参考文档为准。仓库内还提供了 TypeScript 版本的等价落地示例 examples/github-api,可作为多语言对照或 CI 冒烟测试的起点。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00