TC-AICC可信计算 Node.js SDK 接入快速入门

使用 AICC Node.js SDK 在业务代码中接入 AICC 机密推理服务的方法。AICC Node.js SDK 用于对发往大语言模型(Large Language Model,LLM)的请求与响应做端到端加密:请求在你的程序中加密后才离开本机,响应在你的程序中解密。SDK 只负责会话握手与加解密,超文本传输协议(HyperText Transfer Protocol,HTTP)请求由你的程序自行发送。当前 。

相关产品
TC-AICC可信计算 产品页,含版本规格、价格与购买入口。

一、操作场景

业务系统需要直接调用 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')}

注意:说明:

七、选择协议

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),并且协议常量与所调用的接口一致。

赞 (0)
上一篇 5天前
下一篇 5天前