工具接入接口文档

工具接入接口文档

适用范围

这份文档面向 2026-04-17 已落地的工具插件架构。适合平台管理员、外部工具开发者和站内工具开发者按统一协议接入 tripai / NextDevTpl

后台导入

先在 /admin/tool-config 导入工具定义,再补管理员默认配置

统一能力

用户、积分、AI、存储、审计统一复用平台能力

外部工具协议

外部服务使用 launch_ticket、runtime token 和 platform API

接入模式

适合只想复用平台账号体系、后台配置和入口管理的工具。

推荐做法:

  • 导入工具定义
  • 配好字段
  • 入口指向外部地址或内部页面

适合主要依赖统一 AI 网关的工具。

推荐做法:

  • 导入工具定义
  • 配置 features
  • /admin/ai 绑定模型和 provider

适合前后端独立部署的产品。

推荐做法:

  • authMode = launch_ticket
  • 平台生成启动票据
  • 外部服务端用 runtime token 换用户身份并读取配置

适合像 RedInk 这样有专属页面、专属流程和专属适配层的工具。

推荐做法:

  • 工具业务逻辑放工具模块
  • 用户、AI、积分、存储仍走平台统一能力

接入前提

平台侧

平台已部署,数据库迁移完成,/admin/tool-config、/admin/ai、/admin/storage 可正常访问

工具侧

明确 toolKey、入口类型、是否要用户配置、积分、AI、存储、外部票据

外部工具额外要求

必须有自己的服务端,用来安全保存 runtime token,不能把 token 暴露给浏览器

命名约定

Prop

Type

标准接入流程

管理员进入 /zh/admin/tool-config,导入工具定义 JSON

/zh/admin/tool-config 填管理员默认配置、密钥和 JSON 字段

如果工具需要 AI,去 /zh/admin/aifeature 绑定模型和 provider

如果工具要上传资源,去 /zh/admin/storage 检查对象存储和前缀规则

如果工具允许用户个人覆盖配置,到 /zh/dashboard/settings 验证字段是否按预期暴露

如果工具是外部服务,再串联 launch_ticketsession/exchangeruntimeruntime-save

手机号认证(AutoLive 等工具)

平台已支持手机号 + 密码登录;注册与改密使用短信验证码。外部工具不要在客户端直连 TripAI /api/auth/*,应由工具服务端 Relay:

  • 登录POST /v1/auth/platform/exchange body { phone, password, device, licenseKey? }
  • 注册发码POST /v1/auth/phone/send-otp → 平台 phone-number/send-otp
  • 注册POST /v1/auth/phone/register body { phone, code, password, name?, licenseKey?, device } — 无 licenseKey 时仍可完成平台注册并返回 token,响应含 requiresLicenseActivation: true,客户端再调 POST /v1/license/activate
  • 忘记密码POST /v1/auth/phone/password-reset/requestPOST /v1/auth/phone/password-reset/confirm

平台侧对应:sign-in/phone-number/api/platform/auth/phone/registerphone-number/request-password-resetreset-password

详见 docs/phone-auth-integration-plan-2026-05-22.html(2026-05-23 修订)。

工具定义结构

后台导入和接口导入使用同一结构

你在 /admin/tool-config 页面顶部粘贴的 JSON,和 POST /api/platform/tools/import 接口请求体中的 definition 完全一致。

{
  "toolKey": "notes-ai",
  "name": "Notes AI",
  "description": "会议纪要和知识整理工具",
  "entry": {
    "type": "external_url",
    "url": "https://notes.tripai.icu"
  },
  "runtimeMode": "platform_api",
  "authMode": "launch_ticket",
  "billingMode": "ai_gateway",
  "storageMode": "platform_storage",
  "capabilities": {
    "adminConfig": true,
    "userConfig": true,
    "credits": true,
    "ai": true,
    "storage": true
  },
  "enabled": true,
  "sortOrder": 60,
  "fields": [
    {
      "fieldKey": "config1",
      "label": "notes.defaultTone",
      "description": "默认输出风格",
      "group": "config",
      "type": "select",
      "adminOnly": true,
      "userOverridable": false,
      "defaultValueJson": "formal",
      "optionsJson": ["formal", "concise", "friendly"]
    },
    {
      "fieldKey": "secret1",
      "label": "notes.webhookSecret",
      "description": "外部回调签名密钥",
      "group": "secret",
      "type": "secret",
      "adminOnly": true,
      "userOverridable": false
    },
    {
      "fieldKey": "json1",
      "label": "notes.templateCatalog",
      "description": "模板目录",
      "group": "json",
      "type": "json",
      "adminOnly": true,
      "userOverridable": false,
      "defaultValueJson": {
        "summary": "会议总结",
        "todo": "待办提取"
      }
    }
  ],
  "features": [
    {
      "featureKey": "meeting_summary",
      "name": "会议总结",
      "description": "生成会议纪要",
      "requestType": "chat",
      "defaultOperation": "text.generate",
      "requiredCapabilities": ["text"],
      "enabled": true,
      "sortOrder": 10,
      "pricing": {
        "billingMode": "token_based",
        "minimumCredits": 1,
        "inputTokensPerCredit": 1000,
        "outputTokensPerCredit": 500
      }
    }
  ],
  "storage": {
    "prefixRules": [
      {
        "prefix": "notes-ai/attachments/",
        "purpose": "attachment",
        "retentionClass": "temporary",
        "ttlHours": 72,
        "enabled": true,
        "maxSizeBytes": 10485760,
        "contentTypes": ["application/pdf", "image/png", "image/jpeg"]
      }
    ]
  }
}

关键字段说明

元数据字段

Prop

Type

字段定义

Prop

Type

功能定义

Prop

Type

常用平台接口

1. 会话与账户

GET /api/platform/session

返回当前登录用户、套餐和积分余额。

{
  "success": true,
  "user": {
    "id": "user_xxx",
    "name": "Alice",
    "email": "alice@example.com",
    "phoneNumber": "+8613812345678",
    "primaryContact": "+8613812345678",
    "primaryContactType": "phone",
    "emailIsPlaceholder": false,
    "canReceiveEmail": true,
    "image": null,
    "role": "user"
  },
  "plan": {
    "code": "pro",
    "name": "Pro",
    "hasActiveSubscription": true
  },
  "credits": {
    "balance": 520.5,
    "status": "active"
  }
}

积分精度(2026-06)balance 与扣费 amount 均为显示积分number,最多 2 位小数,最小 0.01)。服务端内部以 creditUnits = round(display × 100) 记账;工具端请按小数解析,勿再假设整数积分。

2. 积分

POST /api/platform/credits/check

{
  "amount": 3.5
}

响应示例:

{
  "success": true,
  "sufficient": true,
  "balance": 520.5,
  "required": 3.5
}

POST /api/platform/credits/consume

{
  "amount": 0.06,
  "serviceName": "notes_ai_summary",
  "description": "生成会议纪要",
  "metadata": {
    "tool": "notes-ai",
    "feature": "meeting_summary"
  }
}

POST /api/platform/credits/delegated/check

外部工具服务端用 runtime token 代表指定平台用户检查积分。请求头必须带:

Authorization: Bearer <runtime-token>

该 token 必须属于请求里的 projectKey + tool,并拥有 credits:read scope。

{
  "projectKey": "nextdevtpl",
  "tool": "autolive",
  "userId": "user_xxx",
  "amount": 3.5
}

POST /api/platform/credits/delegated/consume

外部工具服务端用 runtime token 代表指定平台用户消费积分。请求头必须带:

Authorization: Bearer <runtime-token>

该 token 必须属于请求里的 projectKey + tool,并拥有 credits:consume scope。

{
  "projectKey": "nextdevtpl",
  "tool": "autolive",
  "userId": "user_xxx",
  "amount": 0.06,
  "serviceName": "autolive:reply",
  "description": "直播回复扣费",
  "metadata": {
    "sessionId": "live_xxx",
    "replyId": "reply_xxx"
  }
}

POST /api/platform/credits/delegated/refund

仅用于补偿已经成功的 delegated consumption(例如音色槽位扣分成功、工具侧 entitlement 落库失败)。使用同一个 credits:consume runtime scope;平台校验原交易属于同一 projectKey / tool / userId,且 orderId 与原消费 metadata 一致。

{
  "projectKey": "nextdevtpl",
  "tool": "autolive",
  "userId": "user_xxx",
  "transactionId": "原 delegated consume 返回的 transactionId",
  "orderId": "voice_slot_order_xxx",
  "reason": "voice slot entitlement allocation failed"
}

退款按 delegated_refund:{transactionId} 幂等;并发或重复请求只会增加一次余额。成功返回 refundedAmountremainingBalanceoriginalTransactionIdidempotent

POST /api/platform/tools/{toolKey}/entitlement/delegated

外部工具服务端用 runtime token 代表指定平台用户查询 license entitlement。无需用户 runtimeSessionToken。请求头:

Authorization: Bearer <runtime-token>

该 token 必须属于请求里的 projectKey + tool,并拥有 runtime:read scope。

{
  "projectKey": "nextdevtpl",
  "tool": "my-crm",
  "userId": "user_xxx",
  "deviceId": "optional_device_id"
}

响应示例:

{
  "success": true,
  "toolKey": "my-crm",
  "userId": "user_xxx",
  "entitled": true,
  "summary": {
    "activeKeyId": "lk_xxx"
  },
  "keys": []
}

POST /api/platform/tools/{toolKey}/entitlement/runtime 的区别:runtime 版需要用户 runtimeSessionToken(客户端会话);delegated 版仅服务端 runtime token + userId,适用于 Frappe 等外部后端。

POST /api/platform/tools/{toolKey}/license/activate/delegated

外部工具服务端用 runtime token 代表指定平台用户激活 license。无需用户 runtimeSessionToken。请求头:

Authorization: Bearer <runtime-token>

该 token 必须拥有 runtime:write scope。

{
  "projectKey": "nextdevtpl",
  "tool": "my-crm",
  "userId": "user_xxx",
  "licenseKey": "XXXX-XXXX",
  "deviceId": "device_fingerprint",
  "deviceLabel": "可选设备名称"
}

POST /api/platform/tools/{toolKey}/license/activate/runtime 对称;scope 与 runtime 版一致(runtime:write),不要credits:consume 混用。

2.1 autolive-server 当前配置

autolive-server 是外部 Go 服务,NextDevTpl 侧按数据库工具配置接入。

当前约定:

  • project key:nextdevtpl
  • tool key:autolive
  • 显示名:autolive-server
  • 入口类型:external_url
  • 本地入口:http://127.0.0.1:8080
  • 认证方式:launch_ticket
  • AI feature:按业务动作独立配置:talent-script-draftscript-image-understandsegment-performance-analysisknowledge-extractlive-replylive-reply-batchsegment-variantsegment-variant-batchsegment-rewrite;娱乐模式另增 7 个独立 feature:entertainment-talent-script-draftentertainment-segment-performance-analysisentertainment-live-replyentertainment-live-reply-batchentertainment-segment-variantentertainment-segment-variant-batchentertainment-segment-rewrite(详见 docs/autolive-entertainment-mode.md §16.6)
  • TTS feature:按合成场景独立配置:live-reply-ttssegment-ttsdeep-train-ttsguide-phrase-ttslive-tts 仅保留兼容旧调用方
  • AI provider:geekai
  • 默认模型:gemini-2.5-flash
  • TTS provider:bailian-ttsfishaudio
  • TTS 默认模型:cosyvoice-v3-flash 或对应 Fish Audio TTS model
  • 计费方式:固定 1 积分 / 次

autolive-server 需要的环境变量:

$env:TRIPAI_BASE_URL="http://127.0.0.1:3000"
$env:TRIPAI_PROJECT_KEY="nextdevtpl"
$env:TRIPAI_TOOL_KEY="autolive"
$env:TRIPAI_RUNTIME_TOKEN="<tool_runtime_token>"
$env:TRIPAI_AI_API_KEY="<api_key>"
$env:TRIPAI_AI_TOOL_KEY="autolive"
$env:TRIPAI_AI_FEATURE_KEY="live-reply"
$env:TRIPAI_TALENT_SCRIPT_DRAFT_FEATURE_KEY="talent-script-draft"
$env:TRIPAI_SEGMENT_PERFORMANCE_ANALYSIS_FEATURE_KEY="segment-performance-analysis"
$env:TRIPAI_KNOWLEDGE_EXTRACT_FEATURE_KEY="knowledge-extract"
$env:TRIPAI_SEGMENT_VARIANT_BATCH_FEATURE_KEY="segment-variant-batch"
$env:TRIPAI_SEGMENT_REWRITE_FEATURE_KEY="segment-rewrite"
$env:TRIPAI_ENTERTAINMENT_TALENT_SCRIPT_DRAFT_FEATURE_KEY="entertainment-talent-script-draft"
$env:TRIPAI_ENTERTAINMENT_LIVE_REPLY_FEATURE_KEY="entertainment-live-reply"
$env:TRIPAI_ENTERTAINMENT_LIVE_REPLY_BATCH_FEATURE_KEY="entertainment-live-reply-batch"
$env:TRIPAI_ENTERTAINMENT_SEGMENT_VARIANT_FEATURE_KEY="entertainment-segment-variant"
$env:TRIPAI_ENTERTAINMENT_SEGMENT_VARIANT_BATCH_FEATURE_KEY="entertainment-segment-variant-batch"
$env:TRIPAI_ENTERTAINMENT_SEGMENT_REWRITE_FEATURE_KEY="entertainment-segment-rewrite"
$env:TRIPAI_ENTERTAINMENT_SEGMENT_PERFORMANCE_ANALYSIS_FEATURE_KEY="entertainment-segment-performance-analysis"
$env:AUTOLIVE_ENTERTAINMENT_MODE_ENABLED="true"
$env:TRIPAI_LIVE_REPLY_TTS_FEATURE_KEY="live-reply-tts"
$env:TRIPAI_SEGMENT_TTS_FEATURE_KEY="segment-tts"
$env:TRIPAI_DEEP_TRAIN_TTS_FEATURE_KEY="deep-train-tts"
$env:TRIPAI_GUIDE_PHRASE_TTS_FEATURE_KEY="guide-phrase-tts"

TRIPAI_RUNTIME_TOKEN 至少需要:

  • runtime:read
  • runtime:write
  • session:exchange
  • credits:read
  • credits:consume

TRIPAI_AI_API_KEY 建议限制:

  • allowed tools:["autolive"]
  • allowed models:["gemini-2.5-flash"]

密钥保存

明文 runtime token 和 API key 只在生成时可见,不要写入仓库文档、提交记录或前端代码。

娱乐模式:玩法目录与用户玩法(autolive-server)

autolive-server 侧(非 TripAI 平台 API):

方法路径说明
GET/v1/settings/live-mode{ "entertainmentEnabled": true };Admin 热开关优先,否则回退 AUTOLIVE_ENTERTAINMENT_MODE_ENABLED
GET/PATCH/v1/admin/settings/live-mode管理员立刻开关全站娱乐模式,无需重启
GET/v1/live-playbook-catalog内置 + 当前用户玩法目录;项含 refbuiltin:* / user:*)、nameinstructionfingerprint
GET/POST/v1/live-playbooks用户自定义玩法列表 / 创建
PATCH/DELETE/v1/live-playbooks/:id更新 / 删除用户玩法
GET/POST/PATCH/DELETE/v1/admin/live-playbooks平台管理员维护内置玩法

娱乐 AI 请求走独立 TripAI feature(entertainment-*),与卖货 feature 分开计费与路由。完整产品契约见 docs/autolive-entertainment-mode.md

3. AI 网关

POST /api/platform/ai/chat

{
  "tool": "notes-ai",
  "feature": "meeting_summary",
  "input": "请整理这段会议记录"
}
{
  "tool": "notes-ai",
  "feature": "meeting_summary",
  "messages": [
    {
      "role": "system",
      "content": "你是会议纪要助手"
    },
    {
      "role": "user",
      "content": "请总结下面内容"
    }
  ],
  "model": "gpt-4o-mini",
  "operation": "text.generate"
}

支持的常见 operation

  • text.generate
  • image.understand
  • image.generate
  • image.edit
  • video.understand
  • video.generate
  • audio.understand
  • audio.generate
  • file.understand

GET /api/platform/ai/chat/result?requestId=...

用于查询任务型 AI 结果。

POST /api/platform/ai/tts

用于真正的 TTS/语音合成请求。当前网关会按 provider 分流到真实上游:

  • Fish Audio:POST https://api.fish.audio/v1/tts
  • 阿里百炼 CosyVoice / Qwen-Audio-TTS:POST .../api/v1/services/audio/tts/SpeechSynthesizer
  • VoxCPM2:POST .../v1/audio/speech(二进制上传对象存储后返回 audio.url

最小请求:

{
  "tool": "autolive",
  "feature": "segment-tts",
  "input": "欢迎来到直播间",
  "model": "cosyvoice-v3-flash",
  "voice": "longxiaochun",
  "format": "mp3",
  "sampleRate": 44100
}

带引擎无关表演控制(推荐;P1 网关编译 + P2 live_reply* 桥接 + P3 话术/变体/deep_train + P4 开关扩展与管理编辑均已落地):

{
  "tool": "autolive",
  "feature": "segment-tts",
  "input": "今天这款真的很适合日常通勤,先别急,我把区别讲清楚。",
  "performance": {
    "instruction": "亲切但有说服力,前半句轻快,解释区别时放慢一点",
    "language": "zh",
    "cues": [{ "after": "先别急", "kind": "pause" }]
  }
}

performance 字段:

字段说明
instruction可选,引擎无关自然语言表演描述;禁止 SSML / [] 标签 / (style) 前缀
language可选,受限语言代码(如 zh/en);只影响合成语言提示,不翻译正文
cues可选,最多 4 个;kind ∈ 平台 canonical 集合(pause/laugh/sigh/cough/gasp/giggle/clear_throat/snort/uhm/shh);after 必须是正文中唯一短语

约定:

  • input 必须是纯净展示正文,不得包含 SSML / [laughing] / (style) 等供应商语法
  • 污染正文返回稳定错误码 tts_input_not_clean(HTTP 400,field=input);不计费、不写 ai_request_log,但会落 event=tts_validation_rejected 审计日志
  • 网关在选定实际 TTS 引擎后临时编译:CosyVoice → instruction/SSML;Qwen-Audio → instruction/官方标签;Vox → 文本 (prefix) 与白名单事件标签
  • 顶层 instruction / language / languageHints 仍兼容,会规范化到 performance
  • AutoLive live_reply* 由 Server 自动附带 performancetalent_script_draft / 变体深训(deep_train)同样持久化并转发;深训/单段合成受「TTS 语气指令」开关约束;第三方调用方也可直接传同一结构
  • enableSsml 不再由调用方决定;是否启用 SSML 由模型与音色能力自动决定
  • extraBody.input 不得覆盖 text / instruction / enable_ssml / language_hints / rate / pitch / volume(错误码 tts_reserved_extra_input
  • 用户计费按纯净 input 字符数,不含编译插入的标签、SSML 或 Vox 前缀
  • 响应 content / output.text 始终为纯净正文,不返回 synthesisText
  • 成功响应可含权威 synthesisFingerprintsynthesisProvenancerouteRevision / engineFamily / modelKey / sourceRevision / renderTargetId / compilerContractVersion / performanceControls.{applied,degraded,dropped});请求明细 attempt meta 同步可查
  • 同正文不同情绪请让调用方把规范化 performance 纳入 externalIdempotencyKey(可用 fingerprintTtsPerformance

端到端产品闭环、表演编译与音色身份进度见 docs/autolive-tts-voice.md

POST /api/platform/ai/tts/preflight

只读、不计费、不写 ai_request_log。按当前 tool/feature 路由解析引擎能力快照与音色 target 就绪状态,供 AutoLive Server / App 渲染可用标签与深训预检。

{
  "tool": "autolive",
  "feature": "segment-tts",
  "audio": {
    "enrollmentKey": "tripai:nextdevtpl:autolive:user:...:voice_..."
  }
}

成功时返回(脱敏,不含 API key / providerVoiceId / reference URL / 供应商语法):

  • capabilityRevision / routeRevision(形如 segment-tts:42
  • routeengineFamily / modelKey / displayName / providerKind
  • performanceinstructionModesupportsInstructionsupportsRichTags、可用 cues[](含 label)、instructionPresets[]maxCueslanguages
  • voice:可选;identityStatus / targetStatus / strategy / sourceRevision / renderTargetId
  • fingerprintContext:供调用方计算期望合成指纹的字段子集

Vox 路由下 instructionModetext_prefix 时,supportsInstructionsupportsRichTags 均为 true(与编译器一致)。

POST /api/platform/ai/voice-enrollment/ensure

幂等确保 CosyVoice 复刻音色已注册(多部署共享 enrollmentKey)。首次调用需 reference.referenceUrl;已存在且上游仍有效时只校验并返回 primary provider 的 providerVoiceId

Shadow Clone 响应扩展(2026-06-29;现行语义以分片文档为准):

  • bindings[]:各 provider 上的 binding 状态(providerKey / providerVoiceId / syncStatus);用户默认仅 ownerRF=1),不再全池复制
  • poolReadinessfull | partial | none(历史字段;新逻辑以 required target ready 为准)
  • primaryProviderKey:HTTP 同步 clone 的主账号凭证

TTS 推荐只传 audio.enrollmentKey,由网关按 owner binding 的配额账号 + 健康凭证 与路由 model 对应的 render target 解析 voice_idprimary_only 不再表示固定全局 bailian-tts。AutoLive Server 对复刻音色已稳定发送 audio.enrollmentKey,普通请求不再附带从音色推断的 Cosy model;系统音色无 enrollment 时可继续只传 voice

分层身份(2026-07-28)+ 容量分片(2026-07-31):同一 enrollmentKey 可挂多个引擎×模型 render target;binding 挂 renderTargetId,并带 quota_account_id / placement_role。详见 docs/autolive-tts-voice.mddocs/autolive-bailian-voice-account-sharding.md

逻辑 enrollment(2026-07-31;App 新建音色主路径):

  • POST /api/platform/ai/voice-enrollments:创建(默认 Qwen Flash;容量预留;session 或 API Key)
  • GET /api/platform/ai/voice-enrollments/{enrollmentKey}?tool=...:状态(requiredTargets / ready / failed+脱敏 errorCode
  • DELETE /api/platform/ai/voice-enrollments/{enrollmentKey}?tool=...:tombstone + 上游删除
  • POST /api/platform/ai/voice-commitments?action=commit|release:付费席位 hard commitment(runtime token credits:consume;购买前先 commit)
  • POST /api/platform/credits/delegated/refund:工具 entitlement 落库失败时按原消费 transaction + orderId 幂等退款

创建幂等: 同用户同 enrollmentKey 已 ready,或 processing 且仍有活动预留/Shadow job → 返回现状,不再二次预留;createFailed/failed 允许 repair。跨用户冲突 → 409 enrollment_key_conflict

错误体形状: enrollment 路由多为嵌套 { "error": { "code", "message" } };commitment / legacy voice-clone 410 多为 flat { "error", "message" }

Commitment orderId(可选): 传入时写入 ai_voice_commitment_event 幂等;重放返回既有 quotaAccountId / hardCommittedSlots / softCommittedSlots / materializedSlots / delta。commit 与 release 须使用不同 orderId。无 orderId 则每次真实变更。失败 voice_capacity_unavailable → 503。

成功创建响应示例(脱敏,不含 quota account / provider key):

{
  "success": true,
  "status": "processing",
  "ready": false,
  "errorCode": null,
  "enrollmentKey": "tripai:nextdevtpl:autolive:user:u1:voice:v1",
  "requiredTargets": [
    {
      "engine": "qwen_audio_tts",
      "model": "qwen-audio-3.0-tts-flash",
      "required": true,
      "status": "pending"
    }
  ],
  "targets": []
}

DELETE:全部上游确认清理完成返回 200 { status: "deleted" };仍有 pending binding 返回 202 { status: "deleting", pendingBindings }

逻辑 enrollment / 音色身份相关错误码:

errorHTTP含义调用方建议
tts_voice_not_ready409当前 model 对应 target 无 ready binding,或 Vox 缺 reference等待物化/补参考音频;不要当「音色已删」
voice_model_mismatch400遗留 enrollment.targetModel / target 与当前路由 model 不一致修 Admin 场景 model,或改用匹配目标的音色;不要重录
voice_target_unsupported400如 Qwen 路由尚无独立复刻目标(不可复用 Cosy binding)切换到已 ready 的引擎/model,或 Admin 对该 model 执行 materialize
voice_unavailable400上游确认音色失效/不存在重新选择或重新克隆
voice_capacity_unavailable503无可分配百炼席位(对账过期/账号 full/容量不足)稍后重试或联系管理员扩容;勿向用户展示账号配额数字
enrollment_key_conflict409enrollmentKey 已被其他用户占用换 key 或使用本人既有 key
not_found404GET/DELETE 时 enrollment 不存在或非本人(不泄露存在性)勿向用户展示「无权」细节
voice_reference_invalid400参考音频不符合要求重新录制清晰连续朗读
voice_delete_in_progressGET 状态为 deleting 时的 errorCode(非独立 HTTP 错误)用户文案:音色正在删除
voice_clone_create_deprecated410用户侧遗留 POST /voice-clone action=create 已弃用改调 POST /voice-enrollments;诊断可设 VOICE_CLONE_LEGACY_USER_CREATE=1

约定:

  • ensure 禁止把已有 enrollment 的 targetModel 静默改写为另一模型(返回 voice_model_mismatch
  • 跨模型 / 控制参数错误不会把健康 enrollment 标为 expired
  • Vox 无稳定系统音色语义;带 enrollmentKey 时必须能解析参考音频
  • 上述确定性本地错误发生在预扣前,不会产生扣费流水
  • 合成成功时响应与请求明细均可观察 synthesisFingerprint / synthesisProvenance / performanceControls;话术缓存失效以指纹为准
  • create 后 query_voice 暂未通过时 binding 保持 syncing、shadow job 以 verify_pending 退避重试,不会因一次 miss 立刻终态 failed
  • Voice Clone / ensure 路径会把 refText 写入 cloneSpec 并进入 source revision(历史空值可在 ensure 时补齐)
  • 新 Provider 加入 Voice Pool 不会自动 backfill 全部用户音色
  • 全池 Shadow 手动 sync 需 Admin 传 confirmFullPool=true(或 VOICE_SHADOW_FULL_SYNC_ENABLED=1

Admin 配置(无需改数据库):

  1. /admin/ai音色资源:创建 quota account、填写 quota_scope_key、挂载 Provider(同主账号多 Key 同 scope)、对账(对账超过 15 分钟将拒绝新 placement)
  2. /admin/aiProvider:百炼 dashscope TTS;同配额账号下标记 primary/secondary 凭证
  3. /admin/tool-config → autolive:场景仍可 primary_only;实际发往哪个 Key 由 owner 账号决定
  4. /admin/ai模型绑定:TTS 绑定可设置 429/503 重试次数maxRetries,建议 1–2)
  5. 旧「音色 Shadow」诊断面板仍可用于预设/job 排查;用户音色创建走逻辑 enrollment / user-qwen-v1
{
  "tool": "autolive",
  "feature": "voice-clone",
  "enrollmentKey": "tripai:nextdevtpl:autolive:preset:zxlive_5262",
  "targetModel": "cosyvoice-v3-flash",
  "reference": { "referenceUrl": "https://cdn.example.com/ref.wav" },
  "prefix": "autolive",
  "metadata": { "presetId": "zxlive_5262", "kind": "cloned_preset" }
}

POST /api/platform/ai/voice-clone

百炼 CosyVoice 声音复刻的遗留入口。产品新建音色请走 POST /api/platform/ai/voice-enrollments

用户侧 action=create 默认返回 HTTP 410voice_clone_create_deprecated),删除版本标签 v2026.08-voice-clone-create。运维诊断可设 VOICE_CLONE_LEGACY_USER_CREATE=1;Admin session 仍可 create。get / list / delete 仍可用至兼容窗口结束。

{
  "tool": "autolive",
  "feature": "voice-clone",
  "action": "create",
  "targetModel": "cosyvoice-v3-flash",
  "prefix": "autolive",
  "reference": {
    "referenceUrl": "https://cdn.example.com/autolive/voices/user_1/ref/demo.wav"
  },
  "languageHints": ["zh"]
}

成功响应示例:

{
  "success": true,
  "requestId": "air_vc_001",
  "providerVoiceId": "cosyvoice-v3-flash-autolive-xxx",
  "status": "ready",
  "demoUrl": null,
  "billing": {
    "chargedCredits": 10,
    "remainingBalance": 90
  }
}

成功响应会统一返回 output.audio

  • 百炼 / CosyVoice 通常返回 output.audio.url
  • Fish Audio 通常返回 output.audio.data(Base64)和 output.audio.mimeType
  • sampleRate 当前仅对百炼 / CosyVoice 生效;传给其他 TTS provider 会直接返回 4xx,而不会再被静默忽略

4. 用户配置

GET /api/platform/tool-config/editor?projectKey=nextdevtpl&tool=notes-ai

读取用户侧可见配置表单。

POST /api/platform/tool-config/user

{
  "projectKey": "nextdevtpl",
  "tool": "notes-ai",
  "values": {
    "config2": "friendly"
  },
  "clearSecrets": []
}

5. 对象存储

POST /api/platform/storage/presigned-image

{
  "filename": "cover.png",
  "contentType": "image/png",
  "toolKey": "notes-ai",
  "purpose": "attachment",
  "retentionClass": "temporary",
  "requestId": "req_xxx"
}

6. 结果归档

POST /api/platform/results/save

{
  "tool": "notes-ai",
  "type": "meeting_summary",
  "payload": {
    "title": "周会纪要",
    "content": "..."
  },
  "requestId": "req_xxx"
}

外部工具接入协议

外部工具的核心原则

浏览器不应该直接持有 runtime token。正确做法是:平台前端拿一次性 ticket,外部工具服务端持有 runtime token 去换用户身份和读写配置。

启动时序

平台前端调用 GET /api/platform/tools/{toolKey}/launch

平台拿到 ticketlaunchUrl 后跳转到外部工具

外部工具服务端用 POST /api/platform/tools/session/exchange 换到当前用户

外部工具服务端再调用 runtime / runtime-save 读取和写回工具配置

GET /api/platform/tools/{toolKey}/launch

成功响应示例:

{
  "success": true,
  "tool": "notes-ai",
  "ticket": "ticket_xxx",
  "launchUrl": "https://notes.tripai.icu?ticket=ticket_xxx&projectKey=nextdevtpl",
  "expiresAt": "2026-04-17T10:30:00.000Z"
}

POST /api/platform/tools/session/exchange

请求头:

Authorization: Bearer <runtime-token>

请求体:

{
  "projectKey": "nextdevtpl",
  "tool": "notes-ai",
  "ticket": "ticket_xxx"
}

成功响应:

{
  "success": true,
  "toolKey": "notes-ai",
  "user": {
    "id": "user_xxx",
    "name": "Alice",
    "email": "alice@example.com"
  },
  "expiresAt": "2026-04-17T10:35:00.000Z"
}

POST /api/platform/tool-config/runtime

请求头:

Authorization: Bearer <runtime-token>

请求体:

{
  "projectKey": "nextdevtpl",
  "tool": "notes-ai",
  "userId": "user_xxx",
  "knownRevision": 12
}

For the autolive tool, the resolved runtime response also exposes config.aiResolvedFeatures["voice-clone"].defaultCredits from json2. The field is optional; a missing value means 0. A configured value of 0 is valid and means the platform voice-clone operation is free. Consumers must not infer this value from minimumCredits or maintain a local fallback price.

POST /api/platform/tool-config/runtime-save

请求头:

Authorization: Bearer <runtime-token>

请求体:

{
  "projectKey": "nextdevtpl",
  "tool": "notes-ai",
  "userId": "user_xxx",
  "values": {
    "config2": "friendly"
  },
  "clearSecrets": []
}

GET /api/platform/tool-config/revision?projectKey=nextdevtpl&tool=notes-ai

请求头:

Authorization: Bearer <runtime-token>

用途:

  • 只读取版本号
  • 适合检测配置是否变化

管理后台接口

GET /api/platform/tools

读取工具状态列表、最近导入、最近 AI 请求和运行时访问情况

POST /api/platform/tools/import

导入一份新的工具定义

POST /api/platform/tools/{toolKey}/disable

停用工具但保留历史记录

POST /api/platform/tools/{toolKey}/rollback

回滚最近一次工具定义变更

推荐联调顺序

先完成工具定义导入,不要先写接口调用

先把后台默认配置、密钥和 JSON 字段填完整

再绑定 AI provider 和模型

再验证上传和对象存储前缀

再打通外部票据和运行时配置

最后串联完整业务流:AI、积分、归档、错误处理

常见失败原因

  • 只导入了工具定义,没有补后台默认配置
  • AI 功能没有在 /admin/ai 绑定模型
  • 工具被停用
  • 字段被设置成 adminOnly = true
  • 没开 userOverridable = true
  • authMode 不是 launch_ticket
  • runtime token 没有 session:exchange 权限
  • 外部工具扣积分时,runtime token 没有 credits:readcredits:consume 权限
  • 启动票据过期或已被消费
  • toolKey 传错
  • purpose 传错
  • 后台没有对应的工具存储规则

一句话结论

推荐做法

新工具接入时,先导入工具定义,再补管理员配置,再绑定 AI 和存储,最后按是否为外部服务决定是否接 launch_ticket 和运行时接口。不要反过来做。