跳至正文

远程模型提供器与流式接入 ​

本页阅读位置

完成第一轮对话后,按当前业务需求深入。Spring 常规声明优先使用 RegistrationManifest 与注解;本页的底层 register / publish 或直连方法供协议细化与兼容集成参考。

选择接入方式 ​

直接兼容 Chat Completions 的模型使用 OPENAI_CHAT。厂商协议需要转换、内部模型网关或业务独立密钥托管时使用 REMOTE;供应商转换驻留自己的服务,平台只接收统一 message/usage 或 REMOTE 1.0 流帧。你可以使用 Java、Kotlin 或按机器合同实现其他语言服务。

模式单次响应原生流工具/结构化输出适配边界
OPENAI_CHATchoices[].messageChat Completions SSE须由模型实际支持并声明服务仅支持其他 API 时不可直接选择
REMOTE,stream=falsemessage/usage关闭转为统一 message.tool_calls 或字符串 JSON旧非流服务保持兼容,忽略新增元数据
REMOTE,stream=true业务调用走 REMOTE 1.0 SSE支持工具片段完整组装后执行;结构化文本完整校验后展示服务必须支持非流合成检查及版本化流,不能返回 OpenAI SSE/[DONE]

每个发布版本固定模式与地址,不在已发布版本上修改协议。流式 Provider 要在对应 Model 声明 streaming=true;工具/结构化功能也分别声明,声明不代表实网验证。部署先配置精确 origin、独立回调密钥和允许的能力所属应用,再发布依赖链。

SDK 接口 ​

Java 接口位于 dev.sparktide.sdk,Java 17 独立 Jar,无 Kotlin 运行时依赖。

类型/方法用途
ModelProvider.generate(ModelRequest)返回 CompletionStage<ModelResult>,转换非流厂商结果
ModelProvider.stream(ModelRequest)返回 java.util.concurrent.Flow.Publisher<ModelDelta>;默认明确拒绝流式
ModelRequest不可变 model/messages/tools/参数、输出上限、期限、消费应用与身份快照
ModelResult受限 assistant message 与实际 usage;text(text, usage) 创建文本响应
ModelDelta.Text / Tool / Usage文本、工具参数碎片、供应商回执;Tool(index,id,name,arguments) 的后续帧可用 null 省略身份
ModelDelta.Completed / Error明确终结,完成原因 STOP/TOOL_CALLS/LENGTH;错误只传机器代码
ModelProviderException将上游认证、限流、超时等错误分类,异步异常同样保留分类
ModelProviderCallbacks.handler生成 HttpHandler,独立校验凭据、消费应用白名单、请求期限与大小

ModelRequest 的 messages/tools/body 深复制并不可修改。业务身份来自认证平台;即使是平台提供的身份,业务服务仍按自身租户和权限规则处理。SYNTHETIC_PROBE 不包含 subjectId/tenantId/runId/traceId,不能将它解释为管理员业务请求,也不能执行业务工具或检索真实业务知识。

Kotlin 接口位于 dev.sparktide.sdk.kotlin.ModelProvider:suspend fun generate(request): ModelResult 与 fun stream(request): kotlinx.coroutines.flow.Flow<ModelDelta>。asJavaProvider() 转换为 Java 接口,保留协程取消、请求期限与订阅需求。Flow 必须传播取消给厂商客户端;仅取消协程不能撤销已被供应商接收的计费请求。

kotlin
import dev.sparktide.sdk.ModelRequest
import dev.sparktide.sdk.ModelResult
import dev.sparktide.sdk.ModelDelta
import dev.sparktide.sdk.kotlin.ModelProvider
import dev.sparktide.sdk.kotlin.asJavaProvider
import kotlinx.coroutines.flow.Flow

class CompanyModelProvider(private val gateway: CompanyModelGateway) : ModelProvider {
    override suspend fun generate(request: ModelRequest): ModelResult =
        gateway.generate(request)
    override fun stream(request: ModelRequest): Flow<ModelDelta> =
        gateway.stream(request)
}

CompanyModelGateway 是你项目中的厂商转换层:读取 request.messages()、tools()、body() 里的生成参数和 request.deadline(),调用实际厂商并转换为 ModelResult/ModelDelta。不要把客户端 appId 当作授权,不要让模型指定回调地址,也不要在此层自动重试已经输出或结果未知的调用。

暴露认证回调 ​

获得自己的 ModelProvider 实例后,以下代码可用于独立业务服务;Spring 项目也可以在现有认证 HTTP 入口按同一合同实现。回调密钥与平台管理员令牌分离,值由部署环境注入,不写入 Registry 或文档。

java
// provider 是实现 ModelProvider 的厂商转换服务。
var server = com.sun.net.httpserver.HttpServer.create(
    new java.net.InetSocketAddress("127.0.0.1", 19101), 0);
var workers = java.util.concurrent.Executors.newFixedThreadPool(8);
server.setExecutor(workers);
server.createContext("/model", dev.sparktide.sdk.ModelProviderCallbacks.handler(
    java.util.Set.of("monitor"),
    () -> System.getenv("REMOTE_ADAPTER_KEY"), provider));
server.start();
// 服务关闭时 server.stop(0),然后 workers.shutdownNow()。

示例监听本机;正式部署通过受控 HTTPS 反向代理暴露,平台 origin 白名单与 secret origin 必须匹配代理地址。HttpHandler 必须部署在有并发/请求限流的服务中;输入最多 1 MiB,输出单次最多 1 MiB、流最多 4 MiB。请求最多等待 60 秒且受平台尝试期限限制。Provider 方法必须异步返回,并尊重流需求和取消;不要在 generate/stream/subscribe 方法中阻塞等待厂商响应。错误不返回厂商响应正文、凭据或地址。

注册和续租 ​

java
var definition = java.util.Map.<String,Object>of(
    "mode", "REMOTE", "endpoint", "https://models.example.com/model",
    "secretRef", "REMOTE_ADAPTER_KEY", "stream", true, "leaseRequired", true);
manager.register("model-providers", "company-provider", "1.0.0", definition)
    .toCompletableFuture().join();
manager.publish("model-providers", "company-provider", "1.0.0")
    .toCompletableFuture().join();
var heartbeat = new dev.sparktide.sdk.LeaseHeartbeat(manager,
    "model-providers", "company-provider", "1.0.0", "gateway-1", 60,
    error -> System.err.println("模型服务续租失败:" + error.getClass().getSimpleName()));
heartbeat.start().toCompletableFuture().join();

manager 使用目标应用的管理凭据。Provider 发布后先取得首次租约,再按“模型 → 绑定 → 配置 → 智能体”发布;模型 definition 引用 company-provider/1.0.0、真实 modelId 和能力声明。心跳 close() 停止续租,现有租约到期后拒绝调用,不等同模型协议健康证据。应用消费全局 Provider 时,密钥授权给 global 所属能力,同时回调白名单必须明确列出实际消费应用。

配置模型与最终聊天见同领域的能力/路由教程。原生流开关在 REMOTE 与 OPENAI_CHAT 都可编辑;保存后重新读取精确版本验证协议和开关,不直接改旧发布版本。

REMOTE 1.0 请求 ​

请求使用 POST JSON、Authorization: Bearer 独立密钥、Idempotency-Key=invocationId。所有身份、调用标识与期限由平台组装;messages/context 中的文字不能覆盖它们。

json
{
  "protocolVersion":"1.0", "purpose":"BUSINESS", "appId":"monitor",
  "subjectId":"alice", "tenantId":"team-a", "runId":"run_1", "traceId":"tr_1",
  "invocationId":"model_1", "deadline":1893456000000,
  "model":"internal-model", "messages":[{"role":"user","content":"查询设备"}],
  "max_completion_tokens":32, "stream":true
}

deadline 是绝对 UTC 毫秒,示例必须替换成当前请求的实际期限。purpose 为 SYNTHETIC_PROBE 时不包含四个业务身份字段。tools、response_format、temperature、top_p、seed、tool_choice 按需传递;REMOTE 不传 OpenAI stream_options。未知请求字段、错误版本、重复 JSON 属性和尾随 JSON 拒绝。非流返回 {message:{role:"assistant",content:"..."},usage:{...}},工具调用的 arguments 为完整 JSON 对象字符串;没有回执使用空 usage,不能生成全零费用证明。

流式事件与完整性 ​

响应 Content-Type 为 text/event-stream,每条 data 是完整 JSON 对象,帧以空行结束。SSE 可以分网络片段发送,UTF-8 中文和工具 JSON 可跨片段;工具 id/name 是稳定标识,重复同值不追加、变化拒绝,arguments 才按顺序拼接。

text
data: {"protocolVersion":"1.0","type":"text.delta","text":"正在查询"}

data: {"protocolVersion":"1.0","type":"tool.delta","index":0,"id":"call-1","name":"tool_0","arguments":"{\"query\":"}

data: {"protocolVersion":"1.0","type":"tool.delta","index":0,"arguments":"\"设备\"}"}

data: {"protocolVersion":"1.0","type":"usage","usage":{"prompt_tokens":10,"completion_tokens":5,"total_tokens":15}}

data: {"protocolVersion":"1.0","type":"model.completed","finishReason":"TOOL_CALLS"}

工具名称取本次 request.tools,不由示例固定;不得调用没有提供的名称。只有完整参数、有效结束且通过平台 Schema/权限检查后才执行业务工具;LENGTH 不能用于带工具调用的未完成结果。文本回复使用 STOP,输出被长度截断但无工具时可使用 LENGTH,任务的输出 Schema 仍须通过校验。流中断、未知类型、非法 UTF-8、重复终结、终结后数据、重复调用 ID、变更工具身份、畸形参数或未终结 EOF 均失败,不显示成功状态。

非流错误使用非 2xx HTTP 和闭合 {error:{code:"MODEL_PROTOCOL_ERROR"}};平台优先保留分类,协议错误不因 502 被当作瞬时故障。回调只传安全机器代码。错误帧为 {"protocolVersion":"1.0","type":"model.error","code":"MODEL_UNAVAILABLE"}。允许代码 MODEL_UNAVAILABLE/MODEL_TIMED_OUT/MODEL_RATE_LIMITED/MODEL_AUTH_FAILED/MODEL_REQUEST_REJECTED/MODEL_FEATURE_UNSUPPORTED/MODEL_PROTOCOL_ERROR。认证/协议/请求拒绝不自动降级;已经收到文字或工具参数后任何错误都不切换候选。message.completed 是 Agent Protocol 的任务终结事件,失败/取消时 status 为 FAILED/CANCELLED,不能仅凭事件名称认为任务成功。

用量回执逐帧写入调用账本;流后续失败仍保留已经收到的用量和配置费用。未知费用保持未知,不因取消变成零。浏览器断开平台事件流不自动取消 Run;明确取消 Run 或尝试超时才中断供应商连接,SDK 回调也取消上游 Publisher/协程。厂商已接收的调用不可撤销。

验证与升级 ​

先调用管理页面“模型健康”检查文本、工具、流和结构化证据,再以业务用户验证实际 Run、文本输出、调用账本和取消。合成检查不会执行真实工具,不能替代业务集成与厂商质量验收。新接口没有数据库迁移;回退先切换为旧非流精确配置,保留历史账本和健康记录,不重放未知请求。

下载 REMOTE 1.0 机器合同。完整字段同时见数据结构参考。

文档来源与验证记录
字段内容
状态已确认
日期2026-09-30
来源REMOTE 1.0 契约、ModelProviderCallbacks、模型流与取消测试
责任人SparkTide 维护者
关联任务M04
适用版本:0.1 发布线 · 最近核对:2026-10-09 · SparkTide 产品文档

汇聚智能,驱动涌现。