JAC-1.1 侏罗纪AI通信标准(Jurassic AI Communication Standard)
文档编号:JAC-SPEC-1.1 状态:正式发布(Release) 发布机构:侏罗纪AI标准工作组(Jurassic AI Standard Working Group, JASWG) 发布日期:2026-09-05 版本:1.1(正式版;在 JAC-1.0 基础上并入文件传输扩展,原扩展文档 JAC-EXT-FT-1.0 自本版起并入并废止)
依循基础标准:
- RFC 6455 —— The WebSocket Protocol(唯一传输基础)
- RFC 8259 —— The JavaScript Object Notation (JSON) Data Interchange Format
- RFC 2119 / RFC 8174 —— 规范性用语
- Chat Completions API 惯例 —— 工具定义与流式增量格式兼容
与 JAC-1.0 的差异(本版增补,全部向下兼容):
| # | 增补内容 | 落点 |
|---|---|---|
| 1 | 双向文件传输:file.offer/accept/reject/ack/complete/cancel 控制面消息 + file.data 二进制数据帧,credit 窗口流控、SHA-256 校验、断点续传、终态状态机 | §9.5(新增章) |
| 2 | 能力声明 server_caps 新增 "file.transfer";能力协商失败时按 §5.2 忽略降级 | §4.5、§9.5 |
| 3 | 错误码新增 4403~4406 | 附录A |
| 4 | 一致性等级 L2/L3 纳入文件传输能力 | §13 |
| 5 | 关闭语义、心跳、子协议 jac.v1、既有消息类型均不变(线上与 JAC-1.0 完全互通) | 全文 |
版本摘要:本标准定义运行于 WebSocket 之上的侏罗纪AI(JAI)实体间 JSON 应用层协议,核心特性:
- 一条会话 = 一条 WebSocket 连接;
- 会话上下文(环境、可用工具、代码模块)一次声明、终身有效;
- 纯流式输出(无非流式模式);
- 工具定义与流式增量兼容 Chat API;
- 模型思考过程(thinking)流式披露,深度可设置(effort / depth);
- 三级 Token 与消息统计(chunk 快照 / turn 明细 / 会话累计);
- 双向文件传输(credit 流控 + SHA-256 校验 + 断点续传)。
目录
- 范围与术语
- 核心模型
- 传输层要求
- 会话建立与上下文声明
- 消息格式
- 消息类型注册表
- 用户消息
- 工具定义与工具调用
- 代码模块、多模态分块与文件传输
- 流式输出、思考字段与统计
- 心跳、超时与关闭
- 安全要求
- 一致性等级与符合性测试
- 附录A:错误码注册表
- 附录B:完整会话示例(含文件传输)
- 附录C:与 Chat API 字段映射表
- 附录D:基础标准条款对照
1. 范围与术语
1.1 范围
本标准规定运行于 WebSocket(RFC 6455)之上的侏罗纪AI(JAI)实体间 JSON 应用层协议(下称 JAC 协议),包括:
- 连接建立、上下文声明与能力协商;
- 会话推进:用户消息、流式输出、工具调用、代码模块执行、多模态传输;
- 模型思考过程的披露与深度控制;
- Token 与消息统计;
- 会话内双向文件传输(1.1 新增);
- 心跳、超时、关闭、安全与一致性要求。
本标准不规定:模型内部实现、训练协议、服务发现机制、底层 TLS 密码套件细节。
1.2 核心原则
| # | 原则 | 规范落点 |
|---|---|---|
| P1 | 一连接一会话:打开连接即创建会话,关闭连接即销毁会话 | §2、§11 |
| P2 | 上下文一次声明:环境、可用工具、代码模块仅在首条消息声明 | §4.3 |
| P3 | 会话五要素:环境、可用工具、代码模块、用户消息、工具调用输出 | §2、§7、§8 |
| P4 | 纯流式:assistant 输出只有流式增量一种交付方式 | §10.1 |
| P5 | Chat API 兼容:工具定义、流式增量、思考字段与 Chat Completions API 互通 | §4.4、§8、附录C |
| P6 | 思考可控:思考过程可披露(thinking 流),深度可设置(effort/depth) | §4.3、§10.2、§10.3 |
| P7 | 统计完备:chunk 快照 → turn 明细 → 会话累计 | §10.4、§10.5 |
| P8 | 文件可控传输(1.1 新增):控制面 JSON + 数据面二进制、credit 流控、完整性校验、可续传、可取消 | §9.5 |
1.3 术语
| 术语 | 定义 |
|---|---|
| JAI 实体 | 实现本标准的 AI 客户端或服务端节点 |
| 会话(Session) | 一次完整对话上下文,与一条 WebSocket 连接一一对应 |
| 上下文声明 | 会话首条消息 session.declare(环境 + 工具 + 模块) |
| turn(轮次) | 一次 user.message 到 assistant.done 的完整交互 |
| thinking(思考) | 模型生成最终回复前的推理过程文本 |
| effort / depth | 思考投入档位(minimal/low/medium/high)/ 数值深度(0~10) |
| 生效深度(effective) | 服务端钳制/降级后本轮实际采用的深度 |
| usage 快照 | chunk 内携带的截至该 seq 的累积用量 |
| session_usage | 自会话建立以来的累计用量 |
| 文件传输(File Transfer) | 会话内以 file.* 消息族进行的双向文件交换(1.1 新增) |
| file_id | 一次文件传输的唯一标识,发起方生成,终态后不得复用 |
| credit | 接收方授予发送方的数据块发送配额(文件传输流控) |
| DID | 实体标识,did:jai: |
| Chat API | Chat Completions 类 API 的工具定义/消息/流式增量惯例 |
1.4 规范性用语
MUST / MUST NOT / SHOULD / MAY 按 RFC 2119 / RFC 8174 解释。
2. 核心模型
┌────────────────────── 一条 WebSocket 连接 ──────────────────────┐ │ [打开] │ │ C→S session.declare (环境 + 工具 + 模块 + reasoning 配置, │ │ 仅此一次) │ │ S→C session.ready (accepted_tools、生效深度、统计策略、 │ │ server_caps 含 file.transfer?) │ │ │ │ [会话推进](turn 循环) │ │ C→S user.message (可含轮次级 reasoning 覆盖) │ │ S→C assistant.chunk ×n (thinking / content / tool_calls 增量, │ │ 节流 usage 快照) │ │ S→C tool.call → C→S tool.output(可循环,深度恒定) │ │ S→C assistant.chunk ×n … │ │ S→C assistant.done (usage + stats + session_usage + │ │ effective_reasoning) │ │ │ │ [文件传输](与会话推进并行,双向,1.1 新增) │ │ 发起方 file.offer → 接收方 file.accept(credit) │ │ → file.data ×n(二进制帧,credit 窗口) │ │ → file.ack ×k(流控/续传基线) │ │ → file.complete(SHA-256 终态确认) │ │ 任意时刻 file.cancel / file.reject 可终止 │ │ │ │ [关闭] │ │ 双向 session.end → WebSocket Close │ └──────────────────────────────────────────────────────────────────┘
强制约束:
- 一条连接上 MUST 只有唯一会话;第二条
session.declareMUST 触发error(4002)并关闭(关闭码 4002); - 环境、工具、模块 MUST NOT 在后续消息中重复完整声明;工具变更仅可走 §8.5 的
tool.update增量操作; - 服务端 MUST 以流式增量交付全部 assistant 输出(P4);
session.ready之前收到的其他消息类型 MUST 被拒绝(error 4001);- 文件传输与会话推进并行进行,同一连接复用;文件传输不改变 turn 语义。
3. 传输层要求
3.1 连接与握手
- 端点 MUST 按 RFC 6455 §4 完成握手,子协议协商:
Sec-WebSocket-Protocol: jac.v1
服务端 MUST 回显同值;不回显时客户端 SHOULD 视为不支持本标准并关闭。 (注:1.1 不升级子协议,文件传输经 server_caps 能力声明协商,保证与 JAC-1.0 线上互通。)
3.2 帧与 JSON
- JAC 控制面消息 MUST 使用 WebSocket 文本帧(opcode=0x1),载荷为 UTF-8 编码的 JSON,遵循 RFC 8259(含 §8.1 互操作性约束:UTF-8 合法性、对象键唯一);
- 单条消息(含分片重组后)MUST NOT 超过
max_msg_bytes(服务端在 ready 中声明,默认 4 MiB);超长消息 SHOULD 使用 RFC 6455 §5.4 continuation 分片发送; - 二进制帧(opcode=0x2)仅用于:① 多模态分块数据(§9.4);② 文件传输数据
file.data(§9.5,1.1 新增);二者首块前 MUST 有对应的 JSON 控制消息; - 根对象 MUST 为 JSON 对象且 MUST 含字符串字段
"type";键名 snake_case;接收方 MUST 忽略未知字段(前向兼容)。
3.3 URI
wss://<authority>/jac/v1/session
- 跨网络通信 MUST 使用
wss://(TLS 1.2+,SHOULD TLS 1.3);明文ws://仅限内网测试域。
4. 会话建立与上下文声明
4.1 时序
- 完成 TCP/TLS 与 WebSocket 握手(子协议
jac.v1); - 客户端 MUST 在 5 秒内发送
session.declare(超时关闭码 4001); - 服务端 MUST 回复
session.ready(成功)或error(失败后关闭连接)。
4.2 session.declare(会话内仅一次)
{
"type": "session.declare",
"msg_id": 1,
"did": "did:jai:9f3c01a2",
"auth": { "kind": "jwt", "token": "..." },
"session": {
"session_id": "s-7f21",
"model": "jurassic-1.1-tyranno",
"time_format": "ms",
"reasoning": {
"expose": "always",
"effort": "medium",
"depth": 5,
"include_tokens": true
}
},
"environment": {
"runtime": "node-22",
"os": "linux",
"locale": "zh-CN",
"tz": "Asia/Shanghai",
"cwd": "/workspace",
"limits": { "max_tokens_per_turn": 8192, "deadline_ms": 60000 },
"metadata": { "client_version": "jai-sdk/1.1" }
},
"tools": [
{
"type": "function",
"function": {
"name": "search_fossil",
"description": "检索化石数据库",
"parameters": {
"type": "object",
"properties": {
"era": { "type": "string" },
"query": { "type": "string" }
},
"required": ["query"]
}
}
}
],
"modules": [
{
"module_id": "mod-render",
"kind": "code",
"language": "python",
"uri": "jacmodule://repo/render.py",
"hash": "sha256:1a2b…",
"exports": ["render_scene", "RenderConfig"]
}
]
}| 字段 | 必要性 | 说明 |
|---|---|---|
type | MUST | 固定 "session.declare" |
msg_id | MUST | 客户端消息序号,会话内单调递增 |
did | SHOULD | 客户端实体标识 |
auth | SHOULD | 认证凭据(§12) |
session | MUST | 会话参数:session_id、model、time_format、reasoning |
environment | MUST | 当前运行环境(runtime/os/locale/tz/cwd/limits…),子键可自由扩展 |
tools | MUST(可为空数组) | 全部可用工具,会话内只声明这一次(格式见 §4.4) |
modules | SHOULD | 可引用的代码模块清单(§9.1) |
4.3 reasoning 声明(思考披露与深度)
| 字段 | 取值 | 说明 |
|---|---|---|
expose | "always"(默认)/ "on_done" / "never" | 思考披露策略:流式下发 / 仅 done 摘要 / 不下发 |
effort | "minimal" / "low" / "medium"(默认)/ "high" | 会话级思考投入档位(Chat API 对齐) |
depth | 整数 0~10(可选,侏罗纪扩展) | 数值思考深度,与 effort 等价换算或并用 |
include_tokens | bool(默认 true) | 思考 token 是否计入 thinking_tokens |
effort ↔ depth 换算规则(服务端 MUST 按此归一):
| effort | 等价 depth |
|---|---|
minimal | 0(不思考) |
low | 2 |
medium | 5 |
high | 8 |
- 两者同时提供且矛盾时以
depth为准,服务端 SHOULD 在 ready 的notices中说明; - 仅提供
depth时反向折算:{0}→minimal,{1..3}→low,{4..6}→medium,{7..10}→high; - depth 9~10("深渊级思考")为本标准扩展区间,仅数值深度服务端可用;
- 单调性约束:深度越高,思考资源投入 MUST NOT 减少;
- 校验:非法枚举或 depth 超出 0~10 →
error(4306); - 模型不支持思考时 effort/depth MUST 被忽略,ready 回
reasoning: false并附 notice; - 服务端上限低于请求深度时 MUST 钳制并在 ready 回报生效值,MUST NOT 静默降级。
4.4 tools 字段规范(Chat API 兼容)
tools数组每一项 MUST 为:
{ "type": "function",
"function": {
"name": "<标识符>",
"description": "<描述>",
"parameters": { "<JSON Schema Draft 2020-12>" },
"strict": false
} }function.name:MUST,^[a-zA-Z0-9_-]{1,64}$;function.description:SHOULD;function.parameters:MUST,顶层 SHOULD 为{"type":"object",…};function.strict:MAY,严格 schema 输出模式;- JAC 私有扩展(
timeout_ms/safety等)收纳于可选jac_ext对象,Chat API 网关忽略未知键即天然兼容;
{ "type": "function", "function": { … },
"jac_ext": { "timeout_ms": 30000, "safety": "read_only" } }4.5 session.ready
{
"type": "session.ready",
"msg_id": 1,
"corr_id": 1,
"epoch": 42,
"max_msg_bytes": 4194304,
"heartbeat_ms": 15000,
"first_chunk_deadline_ms": 2000,
"accepted_tools": ["search_fossil"],
"accepted_modules": ["mod-render"],
"stream_only": true,
"reasoning": true,
"reasoning_field": "thinking",
"reasoning_effort": {
"effective_effort": "medium",
"effective_depth": 5,
"max_effort": "high",
"max_depth": 10,
"depth_granularity": 1
},
"usage_interval_chunks": 30,
"server_caps": ["stream", "thinking", "reasoning.effort", "reasoning.depth",
"usage.snapshot", "tool.call", "tool_update", "module.exec",
"mm.chunk", "file.transfer"]
}| 字段 | 说明 |
|---|---|
accepted_tools / accepted_modules | 服务端确认接受的清单;MAY 剔除不支持项并在 notices 说明原因;剔除致空且会话强依赖工具 SHOULD 以 error(4102) 拒绝 |
stream_only | 恒为 true,明示本标准纯流式语义 |
reasoning | 服务端是否产生思考流(bool) |
reasoning_field | 本会话思考字段实际用名:"thinking"(本标准)或 "reasoning_content"(Chat API 别名),全会话恒定,客户端 MUST 按此解析 |
reasoning_effort | 会话级生效深度(钳制后)、服务端上限(max_effort/max_depth/depth_granularity) |
usage_interval_chunks | usage 快照节流间隔(帧数) |
server_caps | 能力声明;1.1 起包含 "file.transfer" 表示支持 §9.5 文件传输;实现 MUST 如实声明,虚报视为不合格 |
5. 消息格式
5.1 通用信封
{
"type": "<消息类型>",
"msg_id": 123,
"corr_id": 100,
"ts": 1735689600000,
"payload": { }
}| 字段 | 必要性 | 说明 |
|---|---|---|
type | MUST | 字符串,见第 6 章注册表 |
msg_id | MUST | 发送方各自的会话内单调递增序号 |
corr_id | SHOULD | 响应/输出类必填,等于触发消息的 msg_id |
ts | SHOULD | 按 time_format 约定 |
payload | MUST | 类型相关载荷对象 |
5.2 通用规则
- 接收方 MUST 忽略未知字段;未知
typeMUST 忽略该消息并 SHOULD 回notice(2010); - 响应与输出的
corr_idMUST 精确等于触发方消息的msg_id; - 帧序即语义序:会话内消息按 WebSocket 帧顺序交付,无重排、无重发;断线即会话终结(§11.3);
- 重放防护:
msg_id单调 +ts窗口 ±120 s(§12)。
6. 消息类型注册表
| type | 方向 | 帧类型 | 说明 |
|---|---|---|---|
session.declare | C→S | text | 上下文声明(环境+工具+模块+reasoning),会话内仅一次 |
session.ready | S→C | text | 确认、生效配置与能力(含 file.transfer?) |
session.end | 双向 | text | 正常结束,可带 reason |
user.message | C→S | text | 用户消息(可含轮次级 reasoning 覆盖) |
assistant.chunk | S→C | text | 流式增量(唯一输出模式):delta.thinking / delta.content / delta.tool_calls,可选累积 usage 快照 |
assistant.done | S→C | text | 流终止:usage + stats + session_usage + effective_reasoning |
tool.call | S→C | text | 工具调用执行请求(完整已解析参数) |
tool.output | C→S | text | 工具调用输出(role=tool 语义) |
tool.update | 双向 | text | 工具清单增量变更(可选能力) |
module.load | 双向 | text | 请求/确认装载代码模块 |
module.exec | S→C | text | 请求在模块命名空间内执行 |
module.result | C→S | text | 模块执行结果 |
mm.begin / mm.end | 双向 | text | 多模态分块传输控制 |
file.offer | 双向 | text | 文件传输发起:元数据声明(1.1) |
file.accept | 双向 | text | 接收方同意(credit、resume_from)(1.1) |
file.reject | 双向 | text | 接收方拒绝(1.1) |
file.ack | 双向 | text | 接收方流控确认与续传基线(1.1) |
file.complete | 双向 | text | 接收方 SHA-256 终态确认(1.1) |
file.cancel | 双向 | text | 任一方取消(1.1) |
mm.data | 双向 | binary | 多模态分块数据 |
file.data | 双向 | binary | 文件数据块(1.1,格式见 §9.5.4) |
ping / pong | 双向 | text | 应用层心跳(pong 可携带统计摘要) |
notice / error | 双向 | text | 通知 / 错误 |
7. 用户消息
7.1 user.message
{
"type": "user.message",
"msg_id": 5,
"payload": {
"turn": 3,
"role": "user",
"content": "帮我检索白垩纪的暴龙化石记录",
"reasoning": { "effort": "high" }
}
}多模态 content(Chat API parts 数组):
{
"type": "user.message",
"msg_id": 6,
"payload": {
"turn": 4,
"role": "user",
"content": [
{ "type": "text", "text": "这块化石是什么?" },
{ "type": "image_url", "image_url": { "url": "jacmm://mm-asset-01" } }
]
}
}role恒为"user";客户端 MUST NOT 伪造 assistant/system 历史注入(历史由服务端维护);content为 string 或 parts 数组(text/image_url等,未知 part MUST 忽略);image_url.url支持data:、https:、jacmm://(通道内资产);turn单调递增,服务端据此维护历史;payload.reasoning(可选):轮次级深度覆盖,字段与 §4.3 相同;仅对本 turn 生效,下一 turn 自动回落到 ready 确认的会话默认;非法值 →error(4306),本 turn 拒绝执行;超上限时服务端 MUST 钳制并在 done 的clamped: true明示;- done(非
tool_calls终止)后才接受下一轮user.message,提前到达默认拒绝error(4202)。
7.2 一轮(turn)的构成
user.message(可含 reasoning 覆盖)
└─ assistant.chunk ×n (thinking → content / tool_calls,节流 usage 快照)
[finish_reason:"tool_calls"] → tool.call → tool.output
→(继续同 turn 流式,深度恒定)
└─ assistant.done (usage + stats + session_usage + effective_reasoning)一轮 MUST 以 assistant.done 终止(除非 error 或连接关闭)。
8. 工具定义与工具调用
8.1 声明一次原则
- 工具集合在
session.declare.tools(§4.4 格式)一次性声明; - 会话期间
tool.call只能引用accepted_tools中的function.name,引用未声明工具 MUST 回error(4301)。
8.2 流式 tool_calls 增量(assistant.chunk 内)
{
"type": "assistant.chunk",
"msg_id": 41,
"corr_id": 5,
"payload": {
"turn": 3,
"seq": 7,
"delta": {
"role": "assistant",
"tool_calls": [
{ "index": 0, "id": "call_abc123", "type": "function",
"function": { "name": "search_fossil",
"arguments": "{\"era\":" } }
]
}
}
}- 拼接规则(Chat API 同构):同
index标识一个工具调用槽;首帧含id/type/function.name与arguments首段,后续帧仅含arguments增量段;客户端按seq顺序拼接得完整 JSON 参数。
8.3 tool.call(执行请求)
{
"type": "tool.call",
"msg_id": 45,
"corr_id": 5,
"payload": {
"tool_call_id": "call_abc123",
"function": {
"name": "search_fossil",
"arguments": { "era": "cretaceous", "query": "tyrannosaurid" }
},
"deadline_ms": 30000
}
}tool_call_id与流式增量中的id一致;arguments为已解析 JSON 对象(客户端可只依赖本消息执行,无需自行拼接);- 一轮 MAY 并发多个
tool.call,以tool_call_id区分; - 客户端 MUST 在
deadline_ms(默认 30 s,jac_ext.timeout_ms可覆盖)内回复,超时按timeout处理; - 每轮工具调用深度默认上限 8,超过 MUST 以
error(4302)终止本轮(会话不关闭)。
8.4 tool.output
{
"type": "tool.output",
"msg_id": 6,
"corr_id": 45,
"payload": {
"role": "tool",
"tool_call_id": "call_abc123",
"content": "{\"hits\": 2, \"records\": [\"FMNH PR2081\", \"AMNH 5027\"]}"
}
}- 对齐 Chat API
role:"tool"消息:tool_call_id+content(string,JSON 序列化文本或纯文本); - 执行失败时
content携带错误描述并附加"error": {"code","message"}扩展键; - 服务端 MUST 将 tool.output 并入会话上下文,作为后续生成的可见信息。
8.5 tool.update(增量变更,可选能力)
{ "type": "tool.update", "msg_id": 12,
"payload": { "op": "add",
"tools": [ { "type": "function",
"function": { "name": "map_pangea", "description": "…",
"parameters": { } } } ] } }op:add/remove/replace,均为增量操作;条目格式同 §4.4;- 仅双方声明
tool_update能力时可用,否则 MUST 回error(4102); - MUST NOT 用于替代
session.declare的首次声明。
9. 代码模块、多模态分块与文件传输
9.1 模块清单
session.declare.modules 每项:module_id(MUST)、language(MUST)、uri 或内联 source(二选一)、hash(SHA-256,SHOULD)、exports(SHOULD)。
9.2 module.load / 模块校验
{ "type": "module.load", "msg_id": 50, "payload": { "module_id": "mod-render" } }- 客户端以二进制帧分块返回源码,或小模块直接在应答中携带
source; - 接收方校验
hash,不符 MUST 回error(4401)。
9.3 module.exec / module.result
{ "type": "module.exec", "msg_id": 51, "corr_id": 5,
"payload": { "exec_id": "e-1", "module_id": "mod-render",
"entry": "render_scene", "args": { "scene": "jurassic_night" } } }
{ "type": "module.result", "msg_id": 9, "corr_id": 51,
"payload": { "exec_id": "e-1", "status": "ok", "value": { "png": "mm-asset-07" } } }- 执行于会话声明的
environment沙箱内;超时/异常以status:"error"+error字段描述; - 服务端 MUST NOT 请求超出
exports清单的符号;模块 MUST NOT 获得 environment 之外的系统权限; - 大型结果 SHOULD 走多模态分块通道。
9.4 多模态分块
mm.begin:声明mm_id、mime、total_bytes、sha256;mm.data:WebSocket 二进制帧(opcode=0x2),每块 ≤ 256 KiB,前 16 字节为mm_id哈希前缀;mm.end:接收方校验长度与指纹,失败回error(4402)(可经 extensionsresend-from请求重传)。
9.5 文件传输(1.1 新增)
会话内双向文件传输:上传(C→S)与下载(S→C)使用同一套消息,方向由发起方决定。能力经 server_caps: ["file.transfer"] 声明;未声明即不支持,对端 MUST 降级为不发起(或按 §5.2 忽略并回 notice(2010))。
设计原则:控制面 JSON 文本帧、数据面二进制帧;credit 窗口流控;SHA-256 端到端校验;可续传、可取消;同一连接与会话推进并行复用。
9.5.1 消息族与流程
发起方 接收方 │ file.offer ─────────────────────────▶│ │◀────────────── file.accept(credit) ──│ (或 file.reject) │ file.data ×n(二进制,credit 窗口内) │ │◀────────── file.ack(bytes, credit) ──│ (周期性) │ file.data … 直至发满 size │ │◀────────────── file.complete(ok) ────│ (SHA-256 校验后) (任意时刻任一方可 file.cancel)
9.5.2 file.offer(发起方 → 接收方)
{
"type": "file.offer",
"msg_id": 30,
"payload": {
"file_id": "f-9c2e",
"name": "t-rex-scan.ply",
"size": 10485760,
"mime": "application/octet-stream",
"sha256": "1a2b3c…",
"chunk_size": 262144,
"direction": "upload",
"meta": { "scan_date": "2026-08-30" }
}
}| 字段 | 必要性 | 说明 | |
|---|---|---|---|
file_id | MUST | 发起方生成的传输唯一标识(会话内唯一,建议 UUID) | |
name | MUST | 文件名(UTF-8,禁止路径分隔符;接收方 MUST 只取 basename,防路径穿越) | |
size | MUST | 总字节数(>0) | |
mime | SHOULD | MIME 类型,默认 application/octet-stream | |
sha256 | SHOULD | 全文件 SHA-256(十六进制小写);提供时接收方完成校验,未提供时 file.complete.status 恒为 "ok"(仅长度校验) | |
chunk_size | MUST | 数据块字节数,范围 [4096, 262144],默认 262144 | |
direction | MUST | "upload"(发起方为客户端)或 "download"(发起方为服务端),仅作元信息 | |
meta | MAY | 自由扩展键值;续传时可携带 `meta.resume: {token\ | from}` |
约束:同一 file_id 未终态(complete/cancel/failed)前 MUST NOT 复用(违反回 error(4404));并发传输数建议 ≤ 4,超出接收方 MAY file.reject{reason:"too_many"}。
9.5.3 file.accept / file.reject(接收方 → 发起方)
{ "type": "file.accept", "msg_id": 31, "corr_id": 30,
"payload": { "file_id": "f-9c2e", "credit": 8,
"resume_from": 0, "resume_token": null } }
{ "type": "file.reject", "msg_id": 32, "corr_id": 30,
"payload": { "file_id": "f-9c2e", "reason": "disk_full" } }- 接收方 MUST 在
file.offer后 30 s 内回file.accept或file.reject;超时未回,发起方以file.cancel结束; credit:初始信用(允许发送的数据块数,§9.5.5);resume_from:续传起始偏移(0 为全新);resume_token:MAY,接收方断点令牌(opaque),发起方须在续传 offer 的meta.resume中原样带回;reject.reason建议值:disk_full/permission/too_many/policy/unsupported/ 自定义。
9.5.4 file.data(数据面,二进制帧 opcode=0x2)
+----------------------+----------------+--------------------+ | 8B file_id 哈希前缀 | 4B seq(网络序) | 4B data_len(网络序)| +----------------------+----------------+--------------------+ | data (≤ chunk_size) | +----------------------------------------------------------+
| 字段 | 说明 |
|---|---|
| file_id 哈希前缀 | file_id 的 SHA-256 前 8 字节(控制面 MAY 携带 file_prefix 便于调试配对) |
| seq | 块序号,从 0 单调递增(resume_from > 0 时从对应块号续起) |
| data_len | 本块字节数(最后一块可小于 chunk_size) |
| data | 原始字节(不嵌套 JSON) |
- 接收方按 seq 缓冲重排,连续字节数才计入 ack 基线;重复块丢弃;
- 丢失块不逐块 NACK:接收方以 ack 连续基线 + 续传策略处理;
- 数据块不计入
max_msg_bytes(JSON 限额仅约束控制面)。
9.5.5 流控(credit 窗口)
- 每收到一次
file.ack{bytes_received, credit},发送方信用恢复为ack.credit(窗口默认 8 块 = 2 MiB @256 KiB); bytes_received为连续已落盘字节数,同时是续传基线;- credit 为 0 时发送方 MUST 等待;超过 60 s MAY
file.cancel{reason:"stalled"}(error 4406); - ack SHOULD 周期性发送(每 8~16 块或 500 ms),MUST NOT 逐块发送;
- 文件传输 credit 独立于 §10.1 assistant 流式 credit。
9.5.6 file.complete / file.cancel(终态)
{ "type": "file.complete", "msg_id": 36, "corr_id": 30,
"payload": { "file_id": "f-9c2e", "status": "ok",
"bytes_received": 10485760, "sha256_verified": true } }
{ "type": "file.cancel", "msg_id": 37,
"payload": { "file_id": "f-9c2e", "reason": "user_abort" } }- 接收方收满
size后 MUST 校验并发送file.complete:status: "ok"或"failed"(SHA-256 失败,附error: {code:4403});终态后file_id不得复用; file.cancel任一方可发(reason:user_abort/stalled/policy…);接收方应清理半成品(或保留.jacpart供续传,经meta声明)。
9.5.7 断线与恢复
- 传输中途断线:
file_id随会话销毁;接收方实现 MAY 保留.jacpart并生成resume_token; - 重连后的新会话中,发起方重发
file.offer(同 sha256/size,meta.resume: {token|from}),接收方以file.accept{resume_from, resume_token}续传; - 端点 SHOULD 限定续传令牌有效期(建议 ≤ 24 h)。
9.5.8 与既有机制的关系
| 既有机制 | 关系 |
|---|---|
| §9.4 多模态分块 | mm 通道面向模型输入资产;文件传输是通用文件语义(落盘/续传/流控/终态),二者共存,jacmm:// 可引用已传输文件 |
| §10.1 流式 credit | 相互独立,各自计数 |
| §5.2 未知类型忽略 | 未支持本能力的端点自然降级 |
10. 流式输出、思考字段与统计
10.1 纯流式约束
- 服务端 MUST 以
assistant.chunk增量交付全部输出;不存在非流式响应消息类型; - 首 chunk MUST 在
first_chunk_deadline_ms(默认 2000 ms;高深度时服务端 MAY 在 ready 声明放宽值,如 depth ≥ 8 用 8000 ms)内发出,可为空增量心跳帧;超时error(4203); payload.seq本轮内单调递增,客户端据此保序去重(断裂error 4204);- 合并节奏 SHOULD 为 20~50 ms 或 8~32 token;
delta.role仅首 chunk 携带("assistant");- 背压:客户端 MAY 携带
extensions.credit: n(可接收 chunk 配额);服务端发满 n 个 MUST 暂停,直至新 credit 或 2×heartbeat 自动补半;持续背压 > 60 s 任一方 MAY 以关闭码 4020 关闭。
10.2 模型思考字段(S→C)
{
"type": "assistant.chunk",
"msg_id": 20,
"corr_id": 5,
"payload": {
"turn": 3,
"seq": 2,
"delta": { "thinking": "先确认用户要的是白垩纪暴龙科标本,需要调用检索工具…" }
}
}- 字段名:正式字段
delta.thinking,Chat API 兼容别名reasoning_content;session.ready.reasoning_field声明本会话实际用名(恒定,MUST NOT 混用),客户端 MUST 按该字段解析;实现 MUST 同时具备两个字段名的解析能力; - 披露策略:由
session.reasoning.expose控制(always/on_done/never);on_done时 done MAY 携带thinking_summary; - 流式语义:thinking 增量与 content 同构,按
seq拼接;通常先于 content/tool_calls 出现,MAY 交错或同帧共存; - 呈现与隔离:客户端 SHOULD 与最终回复视觉区分;thinking 不计入正文,MUST NOT 作为上下文回传;
expose:"never"时出现 thinking 字段客户端 MUST 忽略(实现缺陷),冲突回error(4305)。
10.3 思考深度生效语义
- 优先级:
user.message.payload.reasoning(轮次覆盖)>session.declare.session.reasoning(会话默认)> 服务端默认(medium/depth 5); - 工具循环内恒定:同一 turn 内(含
tool_calls续流)生效深度不变; - 钳制透明:请求深度超服务端上限时钳制并在 done 的
clamped: true明示;静默降级为不合格实现; - 与 thinking 流关系:
minimal/depth 0 时 thinking 流通常为空或极短; - 与统计关系:不同深度思考 token 均计入
thinking_tokens(include_tokens: true时); - 中途变更:会话级默认 MUST NOT 中途变更(重连即新会话);仅轮次级覆盖可逐轮变化。
10.4 assistant.done(终帧与统计)
{
"type": "assistant.done",
"msg_id": 65,
"corr_id": 5,
"payload": {
"turn": 3,
"finish_reason": "stop",
"usage": {
"prompt_tokens": 812,
"completion_tokens": 214,
"thinking_tokens": 96,
"total_tokens": 1122
},
"effective_reasoning": {
"effort": "high",
"depth": 8,
"clamped": false
},
"stats": {
"chunks": 37,
"thinking_chunks": 11,
"content_chunks": 26,
"tool_calls": 1,
"mm_bytes": 0,
"file_bytes": 0,
"first_chunk_ms": 640,
"elapsed_ms": 5210
},
"session_usage": {
"turns": 3,
"prompt_tokens": 2140,
"completion_tokens": 620,
"thinking_tokens": 233,
"total_tokens": 2993,
"tool_calls": 4
}
}
}| 字段组 | 内容 | 必要性 |
|---|---|---|
finish_reason | "stop" / "tool_calls" / "length" / "abort" / "error";tool_calls 表示等待 tool.output 后继续同 turn 流式输出 | MUST |
usage | 本轮 token 明细:prompt_tokens / completion_tokens(不含 thinking)/ thinking_tokens(分离计数)/ total_tokens(三者之和) | MUST |
effective_reasoning | 本轮实际生效深度(effort+depth 双表示)与 clamped 钳制标志 | SHOULD(L3 必备) |
stats | 消息统计:chunks / thinking_chunks / content_chunks / tool_calls / mm_bytes / file_bytes(1.1 新增,本 turn 期间文件传输字节数) / first_chunk_ms / elapsed_ms | SHOULD(L1 起必备) |
session_usage | 会话累计:turns / 各类 token / tool_calls;以最后一次 done 为准 | SHOULD |
10.5 chunk 级 usage 快照(节流)
{
"type": "assistant.chunk",
"msg_id": 21,
"corr_id": 5,
"payload": {
"turn": 3,
"seq": 31,
"delta": { "content": "……" },
"usage": { "prompt_tokens": 812, "completion_tokens": 120,
"thinking_tokens": 96, "total_tokens": 1028 }
}
}- 快照为截至该 seq 的本轮累积值(非增量);
- 节流:每
usage_interval_chunks帧(默认 30)或 ≥1 s 一次;MUST NOT 每帧都发;最后一帧前 MUST 至少一次快照; - 客户端 MUST 以
assistant.done.usage为权威值,快照仅用于进度展示;非累积/回退回error(4205)。
11. 心跳、超时与关闭
11.1 定时器
| 定时器 | 默认值 | 说明 |
|---|---|---|
| declare 超时 | 5000 ms | 关闭码 4001 |
| heartbeat_ms | 15000 | 应用层 ping/pong |
| 心跳超时 | 2 × interval | 判定半开,客户端 SHOULD 重连(新会话) |
| 工具 deadline | 30000 ms | tool.call.deadline_ms 覆盖 |
| 文件 accept 超时 | 30000 ms | 发起方以 cancel 结束(§9.5.3) |
| 文件 credit 停滞 | 60000 ms | cancel reason:stalled(§9.5.5) |
| first_chunk deadline | 2000 ms(高深度可放宽) | 超时 error(4203) |
| 空闲超时 | 1800 s | 关闭码 4003 |
pongMAY 携带轻量统计摘要(last_seq、累积 usage)供客户端对账。
11.2 正常关闭
- 任一方 MUST 先发
session.end(可带reason),再执行 RFC 6455 关闭握手(Close 帧携带本标准关闭码);关闭前所有进行中的文件传输视为取消; - 连接关闭即会话终结;服务端 MAY 异步留存化石记录用于审计(默认 30 天)。
11.3 故障语义
- 连接与会话 1:1,断线即会话中断;恢复 = 新建连接 + 新会话;
- 客户端 MAY 在新会话
user.message中引用旧session_id与turn号由服务端业务层续接历史(协议层不承诺); - 文件传输可凭 §9.5.7 的 resume 机制在新会话续传。
11.4 WebSocket 关闭码(RFC 6455 §7.4.2 私有区间 4000-4999)
| 码 | 含义 |
|---|---|
| 4000 | 正常结束(session.end 后) |
| 4001 | declare 超时/非法 |
| 4002 | 重复 session.declare |
| 4003 | 会话空闲超时 |
| 4004 | 子协议/能力协商失败 |
| 4010 | 认证失败 |
| 4020 | 消息超限/持续背压 |
| 4030 | JSON 解析或协议结构错误 |
12. 安全要求
- 传输加密:跨网络 MUST TLS 1.2+(SHOULD TLS 1.3);禁用 RC4/3DES/SHA-1 套件;
- 认证:
session.declare.auth三选一按强度降序:mTLS(证书指纹)、短期 JWT(aud = 服务 authority,exp ≤ 10 min)、预共享密钥挑战(内网); - 重放防护:
msg_id单调 +ts窗口 ±120 s,超窗丢弃并notice(2030); - 校验与限额:服务端 MUST 校验
function.parameters(JSON Schema)、tool.output.content、max_msg_bytes、轮次并发与 token 配额(以session_usage为计量依据,超限error(4503)); - 工具安全:
jac_ext.safety(read_only/side_effect/destructive)SHOULD 由客户端执行器强制校验; - 模块沙箱:代码模块执行 MUST 沙箱化,限于
environment声明的权限面; - 思考内容敏感性:thinking 可能含服务端内部策略或未脱敏中间推理,服务端 SHOULD 脱敏审查后披露;客户端 MUST NOT 将 thinking 转发第三方(除非会话方明示授权);
- 深度滥用防护:高深度请求消耗不成比例算力,服务端 MAY 按账户/会话限制最大可用深度与单位时间高深度轮次配额(超限钳制并
clamped: true,或error(4503)); - 文件传输安全(1.1 新增):
- 文件名 MUST 只取 basename,禁止路径分隔符与
..,落盘 MUST 限定在声明目录内(防路径穿越); - 接收方 MUST 强制单会话并发传输上限与磁盘配额;MAY 按文件大小/MIME 策略拒绝(
file.reject{reason:"policy"}); - 未校验完成的文件 MUST 以临时名(如
.jacpart)存放,校验通过后方可重命名生效; - 跨信任域的文件传输 MUST 复用会话 TLS;MAY 对敏感文件在应用层再加密(本标准不规定具体算法)。
13. 一致性等级与符合性测试
13.1 等级
| 等级 | 名称 | 必备能力 |
|---|---|---|
| L0 | 化石级 | 握手+子协议 jac.v1、declare/ready、纯流式输出(含首 chunk 时限)、ping/pong |
| L1 | 迅猛龙级 | tool_calls 增量拼接、tool.call/output、done 的 usage+stats+session_usage、关闭码语义 |
| L2 | 霸王龙级 | thinking 流式披露(双字段解析)、reasoning.effort 档位(会话级)、chunk 级 usage 快照、代码模块、多模态分块、tool.update、文件传输(offer/accept/data/ack/complete + credit 流控 + SHA-256 校验) |
| L3 | 沧龙级 | reasoning.depth 数值深度(轮次覆盖+钳制透明)、文件断点续传(resume_from/resume_token)与并发多文件、背压 credit、沙箱强校验、深度配额、完整错误码矩阵 |
实现 MUST 在 session.ready.server_caps 中如实声明,虚报视为不合格实现。
13.2 强制测试项(摘要)
- 握手:子协议协商、declare 超时、重复 declare 触发 4002;
- 编解码:JSON 往返、超长分片重组、未知字段/未知 type 忽略;
- 流式:首 chunk 时限、seq 有序性、abort 语义、credit 用尽停发;
- 工具:声明一次原则(引用未声明工具回 4301)、增量拼接、deadline 超时、深度上限 4302;
- 思考:expose 三策略、thinking/reasoning_content 别名解析、effort↔depth 换算、轮次覆盖回落、钳制 clamped 标志、4306 非法值;
- 统计:usage 快照节流与单调、done 权威值、session_usage 累计正确性;
- 文件传输(1.1 新增):offer→accept→data→complete 上传/下载往返与 SHA-256 校验;credit 窗口停发与 ack 补充;校验失败回 4403;file_id 复用回 4404;reject/too_many;中途 cancel;stalled 超时 4406;文件名 basename 清洗与落盘目录限定;
- 安全:明文拒绝跨域、token 过期、重放窗口、配额、thinking 转发禁令、文件路径穿越防护;
- 关闭:逐关闭码触发验证。
附录A:错误码注册表(error.payload.code)
| code | 含义 | 可重试 |
|---|---|---|
| 4001 | ready 前非法消息 | 重连 |
| 4002 | 重复 session.declare | 否 |
| 4101 | 模型不存在/不可用 | 否 |
| 4102 | 能力/工具不支持 | 否 |
| 4201 | 消息超 max_msg_bytes | 分片重发 |
| 4202 | 轮次时序非法 | 是 |
| 4203 | 首 chunk 超时 | 是 |
| 4204 | chunk seq 断裂/乱序 | 是(重建会话) |
| 4205 | usage 快照非累积/回退 | 是(以 done 为准) |
| 4301 | 引用未声明工具 | 否 |
| 4302 | 工具循环超限 | 是 |
| 4303 | 工具参数 schema 校验失败 | 是 |
| 4304 | tool_calls 增量拼接非法 | 是 |
| 4305 | thinking 字段与 expose 策略冲突 | 忽略字段 |
| 4306 | reasoning effort/depth 值非法 | 是(修正重发) |
| 4401 | 模块哈希不符 | 是 |
| 4402 | 多模态指纹/长度校验失败 | 是 |
| 4403 | 文件 SHA-256 校验失败 | 是(重传) |
| 4404 | file_id 重复/状态非法 | 否 |
| 4405 | 文件被接收方拒绝(reason 详见 file.reject) | 视 reason |
| 4406 | 文件传输停滞(credit 长期为 0) | 是 |
| 4501 | 认证失败 | 否 |
| 4502 | 授权不足 | 否 |
| 4503 | 配额超限(含高深度配额) | 延迟 |
| 4600 | 服务内部错误 | 是 |
附录B:完整会话示例(含文件传输)
C→S {"type":"session.declare","msg_id":1,
"session":{"session_id":"s-7f21","model":"jurassic-1.1-tyranno",
"reasoning":{"expose":"always","effort":"medium","depth":5}},
"environment":{"runtime":"node-22","os":"linux","locale":"zh-CN"},
"tools":[{"type":"function","function":{
"name":"search_fossil","description":"检索化石数据库",
"parameters":{"type":"object","properties":{
"query":{"type":"string"}},"required":["query"]}}}],
"modules":[]}
S→C {"type":"session.ready","msg_id":1,"corr_id":1,"epoch":42,
"accepted_tools":["search_fossil"],"stream_only":true,
"reasoning":true,"reasoning_field":"thinking",
"reasoning_effort":{"effective_effort":"medium","effective_depth":5,
"max_effort":"high","max_depth":10,"depth_granularity":1},
"usage_interval_chunks":30,
"server_caps":["stream","thinking","reasoning.effort","reasoning.depth",
"usage.snapshot","tool.call","file.transfer"]}
-- 例1:常规推理轮次(同 JAC-1.0,略,见正式版 1.0 附录B) --
-- 例2:客户端向服务端上传扫描件(与会话推进并行) --
C→S {"type":"file.offer","msg_id":30,
"payload":{"file_id":"f-9c2e","name":"t-rex-scan.ply",
"size":10485760,"mime":"application/octet-stream",
"sha256":"1a2b3c…","chunk_size":262144,
"direction":"upload","meta":{"scan_date":"2026-08-30"}}}
S→C {"type":"file.accept","msg_id":40,"corr_id":30,
"payload":{"file_id":"f-9c2e","credit":8,"resume_from":0,"resume_token":null}}
C→S (binary) [8B sha256("f-9c2e")[:8]|4B seq=0|4B len=262144|data]
C→S (binary) [ … seq=1..7 … ] -- 信用窗口内连发
S→C {"type":"file.ack","msg_id":41,
"payload":{"file_id":"f-9c2e","bytes_received":2097152,"credit":8}}
C→S (binary) [ … seq=8.. 续发,直至发满 10485760 字节 … ]
S→C {"type":"file.complete","msg_id":42,
"payload":{"file_id":"f-9c2e","status":"ok",
"bytes_received":10485760,"sha256_verified":true}}
-- 例3:模型请求下载生成的报告(服务端发起) --
S→C {"type":"file.offer","msg_id":50,
"payload":{"file_id":"f-d41a","name":"fossil-report.pdf",
"size":327680,"mime":"application/pdf",
"sha256":"9f8e7d…","chunk_size":262144,
"direction":"download"}}
C→S {"type":"file.accept","msg_id":20,"corr_id":50,
"payload":{"file_id":"f-d41a","credit":8,"resume_from":0}}
S→C (binary) [8B sha256("f-d41a")[:8]|4B seq=0|4B len=262144|data]
S→C (binary) [ … seq=1(尾块 len=65536)… ]
C→S {"type":"file.complete","msg_id":21,
"payload":{"file_id":"f-d41a","status":"ok",
"bytes_received":327680,"sha256_verified":true}}
C→S {"type":"session.end","msg_id":60,"payload":{"reason":"user_close"}}
-- WebSocket Close (4000) --附录C:与 Chat API 字段映射表
| Chat Completions 概念 | JAC-1.1 对应 | ||
|---|---|---|---|
tools[{type:"function", function:{name,description,parameters}}] | session.declare.tools(同构,一次声明) | ||
tool_choice | 不适用(服务端策略);可经 jac_ext.tool_choice 扩展 | ||
| `reasoning_effort: "low"\ | "medium"\ | "high"` | session.reasoning.effort(会话默认)/ user.message.payload.reasoning.effort(轮次覆盖);额外支持 "minimal" |
| reasoning_effort 数值化(业界扩展) | reasoning.depth(0~10,含 9~10 扩展区间) | ||
messages[{role:"user", content}](string/数组) | user.message.payload.{role, content} | ||
messages[{role:"tool", tool_call_id, content}] | tool.output.payload.{role, tool_call_id, content} | ||
streaming delta choices[0].delta.content | assistant.chunk.payload.delta.content | ||
streaming delta choices[0].delta.tool_calls | assistant.chunk.payload.delta.tool_calls(同构增量拼接) | ||
delta reasoning_content(扩展) | assistant.chunk.payload.delta.thinking(正式字段;reasoning_field 声明实际用名,二者等价) | ||
choices[0].finish_reason | assistant.done.payload.finish_reason(stop/tool_calls/length…) | ||
usage{prompt_tokens, completion_tokens, total_tokens} | assistant.done.payload.usage(另增 thinking_tokens;Chat API 侧可丢弃该键) | ||
stream_options.include_usage | 恒开启:done 必带 usage;chunk 快照为本标准扩展 | ||
| 跨请求累计计费 | assistant.done.payload.session_usage(本标准扩展) | ||
| 生效档位回报(无对应) | assistant.done.payload.effective_reasoning(本标准扩展,钳制透明) | ||
content part {type:"image_url", image_url:{url}} | 同构;url 额外支持 jacmm:// | ||
| 文件上传/下载(Files API 概念) | §9.5 file.* 消息族(会话内双向、流控、续传;Chat API 无直接对应,网关需映射) | ||
| HTTP 请求-响应轮次 | 长连接 turn;工具循环与深度覆盖均无需重发请求 |
附录D:基础标准条款对照
| 本标准章节 | 依循基础条款 | 义务 |
|---|---|---|
| 3.1 握手/子协议 | RFC 6455 §4(含 §4.1 Sec-WebSocket-Protocol 协商) | MUST |
| 3.2 文本帧 | RFC 6455 §5.2(opcode 0x1,UTF-8) | MUST |
| 3.2 分片 | RFC 6455 §5.4(continuation) | SHOULD |
| 3.2 JSON | RFC 8259(§8.1 互操作性约束) | MUST |
| 9.4/9.5 二进制帧 | RFC 6455 §5.2(opcode 0x2) | MUST(L2+) |
| 11.2 关闭握手 | RFC 6455 §5.5.1 / §7 | MUST |
| 11.4 关闭码 | RFC 6455 §7.4.2(4000-4999 注册区间) | MUST |
变更管理:JAC-1.1 相对 JAC-1.0 为向下兼容增补(子协议 jac.v1 不变,仅新增消息类型/字段/错误码,未修改、未删除既有语义),JAC-1.0 端点可与 JAC-1.1 端点直接互通。自本版起接口语义冻结:注册表后续增补须向下兼容(仅新增、不修改、不删除)。勘误与注册表增补提交 JASWG 技术委员会。
路线图(评估中,不构成承诺):JAC-1.2 —— 断线会话恢复协议、思考深度自适应;JAC-2.0 —— QUIC/HTTP-3 承载(RFC 9220)、structured outputs 增强、思考过程端到端加密(E2EE thinking)、大文件分片并行传输(多连接聚合)。
本页同源的 Markdown 原文:JAC-1.1 标准 Markdown 原文(供 AI 引擎与离线阅读)