帮你快速理解、总结文档立即下载
文档中心>TC-AICC可信计算>快速入门>Node.js SDK 接入快速入门

Node.js SDK 接入快速入门

最近更新时间:2026-10-28 15:51:54
本文档已由 AI 辅助审校
我的收藏
本文介绍使用 AICC Node.js SDK 在业务代码中接入 AICC 机密推理服务的方法。AICC Node.js SDK 用于对发往大语言模型(Large Language Model,LLM)的请求与响应做端到端加密:请求在您的程序中加密后才离开本机,响应在您的程序中解密。SDK 只负责会话握手与加解密,超文本传输协议(HyperText Transfer Protocol,HTTP)请求由您的程序自行发送。当前 SDK 版本为 1.3.0。

操作场景

业务系统需要直接调用 AICC 机密推理服务,且具备代码改造条件时,可在业务代码中集成 AICC Node.js SDK。集成后由业务侧自行发起加密请求并解密响应,无需在业务侧额外部署安全代理。若业务系统不便修改代码,可改用安全代理方式接入,请参见 AICC-Proxy 集成快速入门。

前提条件

运行环境为 Node.js 18 及以上版本。
SDK 同时提供 ECMAScript 模块(ES Modules,ESM)与 CommonJS 两种入口,并带有 TypeScript 类型声明。
已提交 AICC 试用申请并经审核通过,服务已开通。
已获取 API 密钥(Application Programming Interface Key,API Key)、安全会话服务地址、网关地址与模型名称。
运行环境可访问安全会话服务与网关地址。
说明:
请妥善保管 API 密钥,不要将 API 密钥写入代码仓库。

概念说明

安全会话服务:负责握手并下发会话密钥的服务,地址对应代码中的 <AICC_BASE_URL>。
网关:接收加密请求并返回加密响应的服务,地址对应代码中的 <AICC_GATEWAY_URL>。
端点:服务端集群的路由标识。SDK 按模型名称自动发现端点,您无需处理。
ModelPool:按模型名称发现端点,并管理各端点的会话池。
Request:一轮 HTTP 请求的加解密上下文。每轮请求需新建一个。

步骤1:安装 SDK

说明:
SDK 暂不直接提供下载。AICC 试用申请通过后,请您提交工单联系我们获取。
执行以下命令,安装 SDK。
npm install @tencent/tcaicc

步骤2:发起非流式请求

以下示例使用 OpenAI Chat Completions 协议。请先将代码中尖括号包围的占位符替换为实际值。
import { Protocol, SessionFactory, SessionPool, defaultPolicy, newModelPool } from '@tencent/tcaicc'

const BASE_URL = '<AICC_BASE_URL>' // 安全会话服务地址
const GATEWAY_URL = '<AICC_GATEWAY_URL>' // 网关地址
const API_KEY = '<API_KEY>'
const MODEL = '<MODEL_NAME>' // 模型名称
const TTL = 8 * 60 * 60 // 会话寿命与模型/端点绑定时长,单位为秒

async function main(): Promise<void> {
// 1. 创建模型池。回调必须为每个端点新建一个独立的工厂。
const models = newModelPool(BASE_URL, API_KEY, TTL, () =>
new SessionPool(new SessionFactory(BASE_URL, API_KEY, { ttl: TTL }), 4), // 4 为池中最多保留的会话数
)
try {
// 2. 每轮 HTTP 请求取一个 Request。
const req = await models.newRequest(MODEL, [])
const policy = defaultPolicy(Protocol.OPENAI)

// 3. 加密请求体。
const body = { model: MODEL, messages: [{ role: 'user', content: '你好' }] }
const encBody = req.encryptRequest(Buffer.from(JSON.stringify(body)), policy)

// 4. 发送请求。
const r = await fetch(GATEWAY_URL, {
method: 'POST',
body: encBody.toString(),
headers: {
'Content-Type': 'application/json',
'X-AICC-Mode': '1', // 标识这是密文请求
Authorization: `Bearer ${API_KEY}`,
},
})
const raw = Buffer.from(await r.arrayBuffer())
if (!r.ok) throw new Error(`gateway ${r.status}: ${raw.toString()}`)

// 5. 解密响应体。
const plain = req.decryptResponse(raw, policy)
console.log(JSON.parse(plain.toString()).choices[0].message.content)
req.close()
} finally {
models.close()
}
}

main().catch((e) => {
console.error(e)
process.exit(1)
})

上述代码用到的三个接口如下。
new SessionFactory(baseURL, apiKey, options)
参数
类型
必填
说明
baseURL
string
是
安全会话服务的完整地址。SDK 直接向该地址发送 POST 请求。
apiKey
string
是
API 密钥。
options.ttl
number
是
会话寿命,单位为秒。取值为 0 表示使用默认值 86400。
new SessionPool(factory, num)
参数
类型
必填
说明
factory
SessionFactory
是
会话工厂。
num
number
是
池中最多保留的会话数,取值需大于等于 1。
newModelPool(baseURL, apiKey, ttl, build)
参数
类型
必填
说明
baseURL
string
是
安全会话服务的完整地址。
apiKey
string
是
API 密钥。
ttl
number
是
模型与端点的绑定时长,单位为秒。取值为 -1 表示永不过期。
build
function
是
为指定端点创建会话池的回调。必须为每个端点新建独立的 SessionFactory。

步骤3:发起流式请求

流式请求的步骤与非流式请求相同,区别有以下三处。
1. 请求体设置 stream: true。
2. 请求头增加 Accept: text/event-stream。
3. 使用 StreamDecryptor 逐个解密服务器发送事件(Server-Sent Events,SSE)。SDK 不解析 SSE,您的程序需自行读取每一行。
import type { Policy, Request } from '@tencent/tcaicc'

async function streamChat(req: Request, policy: Policy, encBody: Buffer): Promise<void> {
const r = await fetch(GATEWAY_URL, {
method: 'POST',
body: encBody.toString(),
headers: {
'Content-Type': 'application/json',
Accept: 'text/event-stream',
'X-AICC-Mode': '1',
Authorization: `Bearer ${API_KEY}`,
},
})
if (!r.ok || !r.body) throw new Error(`gateway ${r.status}: ${await r.text()}`)

const sd = req.newStreamDecryptor()
const decoder = new TextDecoder()
let buf = ''
let seenLast = false

for await (const part of r.body) {
buf += decoder.decode(part, { stream: true })
let nl: number
while ((nl = buf.indexOf('\\n')) >= 0) {
const line = buf.slice(0, nl).replace(/\\r$/, '')
buf = buf.slice(nl + 1)
if (!line.startsWith('data: ')) continue
const data = line.slice('data: '.length)
if (data === '[DONE]') continue

const [out, isLast] = sd.decryptEvent(Buffer.from(data), policy)
if (out !== null) { // out 为 null 表示合成尾片,请勿转发
const choices = JSON.parse(out.toString()).choices ?? []
if (choices.length > 0) process.stdout.write(choices[0].delta?.content ?? '')
}
if (isLast) seenLast = true
}
if (seenLast) break
}
if (!seenLast) throw new Error('stream truncated: final chunk missing')
process.stdout.write('\\n')
}

说明:
流式响应必须收到尾片(isLast 为 true)。未收到尾片表示流被截断。
不要在同一个 Request 上同时读取多个流。
加密的流式请求不支持 n > 1。

相关配置

选择协议

defaultPolicy 的参数决定加密哪些字段,取值需与您所调用的接口一致。
接口
协议常量
/v1/chat/completions
Protocol.OPENAI
/v1/messages
Protocol.ANTHROPIC
/v1/responses
Protocol.RESPONSES
使用 OpenAI Chat Completions 以外的协议时,还需在建池回调中为工厂设置密文绑定的协议。
import { SessionFactory, Protocol } from '@tencent/tcaicc'

const factory = new SessionFactory(BASE_URL, API_KEY, { ttl: TTL })
factory.setProtocol(Protocol.ANTHROPIC) // 或 Protocol.RESPONSES

使用须知

每轮 HTTP 请求需新建一个 Request。同一轮请求的所有密文必须来自同一个 Request。
加密后请尽快发送请求。加密时间与服务端当前时间的差值超过 1 小时,请求会被拒绝。
程序退出前调用 models.close()。

常见问题

网关返回 400 且错误码为 decrypt_failed,如何处理?

通常是因为同一轮请求中混用了不同 Request 加密的密文,或加密后等待时间过长才发送。请为每轮请求新建 Request,并在加密后立即发送。

抛出 SecuritySessionError 时如何处理?

表示握手失败,或服务端拒绝了请求。请读取 e.code 判断原因。如果 e.code 为 AttestationFailed 或 CertVerifyFailed,表示 SDK 判定服务端不可信,请停止使用该服务并联系技术支持,请勿绕过验证。

抛出 TransportError 时如何处理?

表示网络失败,请稍后重试。

抛出 DecryptError 时如何处理?

表示密钥不匹配或密文已损坏。请丢弃当前响应或流,重新发起请求。

抛出 ClosedError 时如何处理?

表示对象已关闭。请重新调用 models.newRequest 取一个新的 Request。

抛出 ErrPolicy、ErrBodyFormat 或 ErrUnsupported 时如何处理?

表示请求体或加密策略不符合要求。请确认请求体是合法的 JavaScript 对象表示法(JavaScript Object Notation,JSON),并且协议常量与所调用的接口一致。