USTC 给校内学生提供了 https://chat.ustc.edu.cn,可以免费使用 Deepseek r1 和 Deepseek v3。但是没有提供 API 相关说明,这简直也没啥用。因此,就有了 FkUSTChat(Flexible & Keystone USTC Chat),FkUSTChat 实现了一个 API 层,方便 OpenAI 库对 USTC Chat 的调用。
项目地址:https://github.com/yemaster/FkUSTChat。
项目采用 Python 编写,所以首先需要安装 Python 环境。另外,项目需要使用 Edge 自动登录 USTC Chat,Windows 版的 Edge Driver 已经在项目 ./dependencies 文件夹下,其他系统需要自行下载并修改相关代码,同时安装 Microsoft Edge。
git clone https://github.com/yemaster/fkustchat
cd fkustchat# 创建虚拟环境
python -m venv venv
# 激活环境
# Windows
venv\Scripts\activate
# Linux/macOS
source venv/bin/activatepip install -r requirements.txtpython app.py此时,项目已经跑在了 http://127.0.0.1:5000,访问该页面即可体验简易 Web 聊天界面。
如果需要使用 API 连接,将 API 地址设置为 http://127.0.0.1:5000/v1,密钥设置为任意值即可使用。
但是此时还是不能使用 USTC Chat 相关的模型。我们首先切换 USTC Chat 相关模型:USTC Deepseek r1 或 USTC Deepseek v3,随便输入点什么消息发送,会提示:USTC Chat 适配器需要你的科大账号和密码才能登录,请在 ./config 文件中编辑,这时候会在项目根目录下创建 config 文件,格式为 JSON 格式,编辑其中内容,将 username 和 password 设置为 USTC 的统一身份认证账号密码即可。
FkUSTChat
├─libs # 主要代码
│ ├─core.py # 核心,用于加载 config,adapter 和 modal
│ └─adapter_loader.py # 用于动态加载适配器
├─adapters # 启用的适配器
│ ├─base.py # 适配器基类
│ └─ustc.py # USTC Chat 适配器,包含 Deepseek r1/v3
├─disabled_adapters # 禁用的适配器
├─dependencies # Microsoft Edge Driver 等依赖
├─examples # 示例程序
└─app.py # Flask 程序,程序入口API 层采用 Flask 编写。
ustc.py 中 Class USTC_Adapter 中的 is_login,do_login,get_credentials 分别为获取登录状态,进行登陆操作,获取 token。
ustc.py 中 Class USTC_Adapter 中的 is_login 方法
用已有 credential 向 https://chat.ustc.edu.cn/ms-api/search-app 发送请求,根据响应状态码判断登陆状态。
ustc.py 中 Class USTC_Adapter 中的 do_login 方法
首先使用 Selenium 启动 Microsoft Edge 访问统一身份认证 https://id.ustc.edu.cn/cas/login?service=https:%2F%2Fchat.ustc.edu.cn%2Fustchat%2F(之所以用 Selenium 是因为懒得破请求了,而且还有二次认证这些麻烦事)
然后从配置中读取用户名和密码,自动输入并登录。等待页面跳转到 https://chat.ustc.edu.cn/ustchat(因为有时候需要二次认证,需要手动操作)
然后从 localStorage 中获取 ustchat-user-store 项目的值,从中获取 token,并保存到 credentials
因为不同模型仅是参数的区别,所以用一个统一的 USTC_Base_Model 基类。
首先获取 credentials,需要用这个 credential 进行鉴权。
然后创建一个随机的 queue_code,向 https://chat.ustc.edu.cn/ms-api/mei-wei-bu-yong-deng 发送请求,进行排队。
然后向 https://chat.ustc.edu.cn/ms-api/chat-messages 发送请求,进行对话,并解析结果。
访问系统首页,返回前端页面(供浏览器访问)
/获取系统已加载的所有适配器信息
/v1/adapters{
"object": "list",
"data": [
{
"id": "适配器名称",
"object": "adapter",
"created": null,
"owned_by": "适配器作者",
"permission": [],
"root": "适配器名称",
"parent": null
}
]
}字段说明:
| 字段名 | 类型 | 说明 |
|---|---|---|
| object | string | 响应类型,固定为 "list" |
| data | array | 适配器列表 |
| data[].id | string | 适配器唯一标识(名称) |
| data[].owned_by | string | 适配器作者信息 |
| 其他字段 | - | 预留字段,暂固定默认值 |
获取系统已加载的所有模型信息
/v1/models{
"object": "list",
"data": [
{
"id": "模型唯一标识",
"show": "模型显示名称",
"object": "model",
"created": null,
"owned_by": "模型所属适配器",
"permission": [],
"root": "模型唯一标识",
"parent": null
}
]
}字段说明:
| 字段名 | 类型 | 说明 |
|---|---|---|
| object | string | 响应类型,固定为 "list" |
| data | array | 模型列表 |
| data[].id | string | 模型唯一标识(调用时使用) |
| data[].show | string | 模型显示名称(友好展示) |
| data[].owned_by | string | 模型所属适配器名称 |
| 其他字段 | - | 预留字段,暂固定默认值 |
核心聊天交互接口,支持流式 / 非流式响应、搜索增强和工具调用
/v1/chat/completionsContent-Type: application/json{
"stream": false,
"with_search": false,
"model": "__USTC_Adapter__deepseek-r1",
"messages": [
{
"role": "user",
"content": "用户提问内容"
}
],
"tools": []
}参数说明:
| 参数名 | 类型 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|---|
| stream | boolean | 否 | false | 是否启用流式响应:true - 流式(text/event-stream),false - 非流式(JSON) |
| with_search | boolean | 否 | false | 是否启用搜索增强功能 |
| model | string | 是 | __USTC_Adapter__deepseek-r1 | 模型唯一标识(需从 /v1/models 接口获取) |
| messages | array | 是 | [] | 聊天消息列表,格式参考 OpenAI 规范 |
| messages[].role | string | 是 | - | 角色:user(用户)、assistant(助手)、system(系统) |
| messages[].content | string | 是 | - | 消息内容 |
| tools | array | 否 | [] | 工具调用配置(预留字段,当前暂不支持复杂工具定义) |
{
"id": "响应唯一标识",
"object": "chat.completion",
"created": 1699999999,
"model": "使用的模型标识",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "助手回复内容"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 10,
"completion_tokens": 20,
"total_tokens": 30
}
}字段说明:
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | string | 响应唯一标识 |
| object | string | 响应类型,固定为 "chat.completion" |
| created | number | 响应生成时间戳(秒级) |
| model | string | 实际使用的模型标识 |
| choices | array | 回复选项列表(默认 1 个) |
| choices[].message | object | 助手回复消息 |
| choices[].finish_reason | string | 结束原因:stop(正常结束)、length(长度限制)等 |
| usage | object | 令牌使用统计(预留字段) |
data: {"id":"响应唯一标识","object":"chat.completion.chunk","created":1699999999,"model":"使用的模型标识","choices":[{"index":0,"delta":{"role":"assistant","content":"助手回复内容片段1"},"finish_reason":null}]}
data: {"id":"响应唯一标识","object":"chat.completion.chunk","created":1699999999,"model":"使用的模型标识","choices":[{"index":0,"delta":{"content":"助手回复内容片段2"},"finish_reason":null}]}
data: [DONE]字段说明:
| 字段名 | 类型 | 说明 |
|---|---|---|
| object | string | 响应类型,固定为 "chat.completion.chunk" |
| delta | object | 增量内容(每次返回部分回复) |
| finish_reason | string | 最后一块数据中为 "stop",其他为 null |
| 最后一行 | string | 固定为 "data: [DONE]",标识流结束 |
{
"error": {
"message": "错误描述信息",
"type": "错误类型",
"param": "相关参数(如有)",
"code": "错误码(如有)"
}
}| 状态码 | 错误类型 | 说明 |
|---|---|---|
| 400 | invalid_request_error | 请求参数错误(如模型不存在) |
| 500 | server_error | 服务器内部错误(如模型调用失败) |
{
"error": {
"message": "Model 'invalid-model' not found",
"type": "invalid_request_error",
"param": null,
"code": null
}
}{
"error": {
"message": "模型调用失败:连接超时",
"type": "server_error",
"param": null,
"code": null
}
}