@ai-setu/客户端
先读这个,探员. 此包 = 公务人员到场
openaiSDK,指着 AI 塞图 网关. 狦 你知道OpenAI SDK,你知道这一点。 方法相同,形状相同,流线相同. 只有一个改变: 一个工作空间键,和model携带一个provider/前缀。 下面的一切都是防伪的.
TL; DR( 您仅需要三行)
npm i @ai-setu/client
export AI_SETU_API_KEY=tt_live_…
import { AiSetu } from '@ai-setu/client';
const client = new AiSetu();
const res = await client.chat.completions.create({
model: 'openai/gpt-4o-mini',
messages: [{ role: 'user', content: 'hi' }],
});
console.log(res.choices[0].message.content);
结束了. new AiSetu() 未读参数 AI_SETU_API_KEY 从洞。 没有
baseURL,没有 createClient没有工厂。 一个导入,一个符号.
代理人规则(遵循这些规则,无猜测)
- 模型字符串
provider/model(平台键) 或者说@<slug>/<model>(你的BYOK连接——见下文). 不错:openai/gpt-4o-mini, (中文(简体) ),anthropic/claude-sonnet-4-5, (中文(简体) ),@azure-qdc/gpt-4o-mini。无名无名 按目录排列的前缀路径. - 没有取出终点. 客户端只向网关说话 。 您没有设置 URL
常规使用。 供应商
model前缀,不是通过基址. - 方法取名=OpenAI SDK精确.
chat.completions.create, (中文(简体) ),embeddings.create,流经stream: true+ 键for await任意 你学到了openai,它转移在这里不变. - 密钥输入入内
AI_SETU_API_KEY(形状)tt_live_…) (中文(简体) ). 或者通过new AiSetu({ apiKey })。在您承诺的源中从不使用硬码密钥. - 需要平衡/ 使用/ 密钥吗 ? 这不是这个包裹。 使用
@ai-setu/admin这个 保持纯粹的推论. - 节点 20 或边缘运行时间(Vercel, Cloudflare Workers).
模型——按前缀选择
openai/gpt-4o openai/gpt-4o-mini openai/text-embedding-3-small
anthropic/claude-sonnet-4-5 anthropic/claude-haiku-4-5
bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0 (BYOK — your AWS account)
流( 和 OpenAI 相同)
const stream = await client.chat.completions.create({
model: 'anthropic/claude-sonnet-4-5',
messages: [{ role: 'user', content: 'Write me a haiku.' }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? '');
}
答复 APIclient.responses(中文(简体) )
和您已经知道的一样的 SDK 方法 —— 它现在到达了网关 /v1/responses。 。 。 .
const r = await client.responses.create({
model: 'openai/gpt-4o-mini',
instructions: 'You are a concise support assistant.',
input: [{ role: 'user', content: 'do you have anything in a darker fabric' }],
max_output_tokens: 400,
});
两个规则,都很容易绊倒:
- 只有OpenAI家庭模式.
openai, (中文(简体) ),bedrock-mantle, (中文(简体) ),groq, (中文(简体) ),xai, (中文(简体) ),deepseek, (中文(简体) ),mistral. Anthropic、双子座、Bedrock和Vertex没有反应 表面——它们以明显的出错被关闭,没有无声回落. - 解释咒语每个表面不同. 给
reasoning: { effort: 'none' }。 。 。 . 打开chat.completions这个reasoning_effort: 'none'每个人拒绝对方.
用法又以反应的形式出现—— usage.input_tokens 编号 :
output_tokens,缓存计数器 usage.input_tokens_details - 不是说
聊天形状. promptCacheStats 读两个,所以不需要分行.
语义学潜入 不适用这条路线. 它和每个工具缓存策略读取
messages反应机构无法携带 精确的缓冲,快速缓冲,
预算,利率限制所有正常工作。 需要语义学吗? 使用 chat.completions。 。 。 .
什么是网关实际路线
AiSetu 扩展 openai SDK,所以你的编辑器 显示OpenAI的方法.
继承与路由不同:
| 方法 | 状态 |
|---|---|
chat.completions | 已服务 |
responses | (开放AI-家庭) |
embeddings | 已服务 |
files, (中文(简体) ), batches | 404 (韩语) 无路线 |
嵌入层
const e = await client.embeddings.create({
model: 'openai/text-embedding-3-small',
input: 'hello world',
});
出错 – 从 OpenAI SDK 直接传输获取逻辑
使用类型守护, 不 instanceof 在子类。 理由: openai SDK 制作
APIError 从它的管子内, 所以亚类漂移每一个释放.
警卫将类型缩小到 APIError - 你还在得到 err.code, (中文(简体) ),
err.status, (中文(简体) ), err.requestID。 。 。 .
import {
AuthenticationError,
RateLimitError,
isInsufficientCreditsError,
getInsufficientCreditsDetails,
isProviderError,
} from '@ai-setu/client';
try {
await client.chat.completions.create({
/* … */
});
} catch (err) {
if (err instanceof AuthenticationError) {
/* bad key */
} else if (err instanceof RateLimitError) {
/* slow down */
} else if (isInsufficientCreditsError(err)) {
const { balanceMicros, topupUrl } = getInsufficientCreditsDetails(err);
console.error(`Out of credits (balance ${balanceMicros} micros). Top up: ${topupUrl}`);
} else if (isProviderError(err)) {
/* upstream provider broke */
}
}
环境——一个开关移动整个应用程序
默认=生产(gateway.aisetu.ai) (中文(简体) ). 指向另一个网关(例如a)
由 URL 完全覆盖 :
export AI_SETU_BASE_URL=https://gateway.your-deployment.example.com
优先( 第一局胜出):
new AiSetu({ baseUrl })——明细分明AI_SETU_BASE_URL——完整 URL 覆盖(自主机 / 在-prem)- 生产默认
(Base 总是正常化以结束于 /v1. ) (中文(简体) )
运行时间 + 连接集合( 您通常不碰这个)
- 节点 20 ——全流程保持活性
undici.Agent返回每个AiSetu. 序列调用再利用 TCP 连接(~5ms p50 vs ~30ms sold). - 边缘( Cloudflare 工人/ Vercel) ——倒回站台取回,其中
已经游泳了.
undici是可选的dep,边缘捆绑者跳过它.
池默认值 : connections 32, (中文(简体) ), allowH2 true, (中文(简体) ), keepAliveTimeout 30s, (中文(简体) ),
keepAliveMaxTimeout 90s (匹配网关闲置), bodyTimeout 0 (无盖-)
长思维模式流可以运行几分钟; 取消 AbortSignal) (中文(简体) ).
只有在必须时才能覆盖游泳池:
import { Agent, ProxyAgent } from 'undici';
import { AiSetu } from '@ai-setu/client';
// Corporate proxy:
const proxied = new AiSetu({ dispatcher: new ProxyAgent({ uri: 'http://proxy:8080' }) });
// Self-signed CA (baseUrl normalise to …/v1):
const onPrem = new AiSetu({
baseUrl: 'https://gateway.internal.example',
dispatcher: new Agent({ connect: { ca: fs.readFileSync('ca.pem') } }),
});
// No pooling at all (platform fetch on Node):
const unpooled = new AiSetu({ dispatcher: null });
全过程互换( 在任何 AiSetu ),或与
兄长SDKs:
import { setSharedDispatcher, getSharedDispatcher } from '@ai-setu/client';
import { Agent } from 'undici';
import { AiSetuAdmin } from '@ai-setu/admin';
setSharedDispatcher(new Agent({ connections: 64, allowH2: true }));
const admin = new AiSetuAdmin({ dispatcher: getSharedDispatcher() });
BYOK:每个请求的路线 @<slug>/<model>
您的提供者密钥居住于 连接 (每个都有一个 slug) (中文(简体) ). 挑一个 百分比
请求 在模型字符串中—— @<slug>/<model> ——和出入口路线
通过连接的钥匙。 一个客户端, 混合连接自由, 没有再动.
领先 @ 标记一发子弹(因此一发子弹可以等于提供者名称); 未知或
超范围子弹 未关闭 (4xx),从未出现无声平台键倒置.
const c = new AiSetu();
await c.chat.completions.create({
model: '@azure-qdc/gpt-5.4-mini', // route via the Connection slug "azure-qdc"
messages: [{ role: 'user', content: 'hi' }],
});
await c.chat.completions.create({
model: 'openai/gpt-4o-mini', // platform key (no @slug)
messages: [{ role: 'user', content: 'hi' }],
});
Pin 1 连接整个客户端 connection 选项
@ 可选 :
const c = new AiSetu({ connection: '@azure-qdc' });
缓冲——在SDK打开,而不是在头部
最便宜的储蓄 首先,顺序值得收养.
1. 快速缓存 -- -- 已经开通了,没有损失
提供者跳过重新预填您的提示( 系统) 前缀 即时,工具定义,定点对话),并打折扣这些符号. 模型 仍在运行,输出为 还是新鲜的 ——无停滞风险 都说吧 没有东西可以打开。 大部分代理工作量都占一半 忽略了这种方式而不注意:
import { promptCacheStats } from '@ai-setu/client';
const res = await c.chat.completions.create({ model, messages });
promptCacheStats(res);
// { inputTokens: 1000, cachedTokens: 3000, writeTokens: 0, ratio: 0.75 }
ratio 是避免了全价预填的提示份额。 读取
无论是OpenAI和Anthropic的用法形状, 所以你不分支提供商.
保持您的稳定部分迅速 首发且不变 - 时间戳或
系统顶部的会话 id 提示销毁每个呼叫的前缀 .
2. 反应缓存——击中费用为0美元,返回为~3ms
默认: 网关缓存当 temperature 未设定或 0键入
确切请求体,600秒。 设置全客户端默认值, 然后覆盖
按请求:
const c = new AiSetu({
cache: {
policy: 'support-faq', // TTL + stale window live in the console, not in code
namespace: 'tenant-42', // keep one end-user's entries off another's
},
});
await c.chat.completions.create(
{ model: '@mantle/zai.glm-4.7-flash', messages },
c.withCache({ ttl: '2h', tags: ['sku:123'] }),
);
| 选项 | 它能解决什么 |
|---|---|
policy | 暴发流量在暴发之间终止——为每个呼叫站点设定TTL + stale-while-validate一次 |
ttl | 一次性期限: 3600, (中文(简体) ), '30s', (中文(简体) ), '10m', (中文(简体) ), '2h', (中文(简体) ), '1d'政策上限 |
namespace | 每个终端用户/每个环境分区 |
tags | ['sku:123'] ——当数据变化而不是等待 TTL 时重新验证 |
force | 缓存 a temperature > 0 调用无论如何( 分类、 提取、 路由) |
mode | off (通过) no-store (阅读,从不写) force-refresh {\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}你觉得呢 semantic |
A 类 政策加标签 击败长空 TTL : 标记让你持有一个答案 数小时后 数据发生变化时仍会下降.
坏值 掷出 - 否则,将删除打字的政策名称 关上门 把你藏起来 默默无动于衷.
3. 缓存内代理循环——每个工具的政策
代理转弯是最昂贵的交通 和最少的可缓存,因为 工具结果嵌入活数据。 你不能决定每个请求 —— 收到的文本 是任意的。 不过你 对 每一个工具在添加时都会做什么 所以 政策与工具:
import { withToolCache } from '@ai-setu/client';
const tools = [
withToolCache(getCatalog, { policy: 'catalog', tags: ['catalog', 'sku:{sku}'] }),
withToolCache(getBrandStory, { policy: 'brand-voice' }),
withToolCache(addToCart, { cache: false }),
withToolCache(checkout, { cache: false }),
];
| 声明 | 含义 |
|---|---|
{ cache: false } | 从不缓存引用此工具的转折 |
{ policy: 'catalog' } | 工作空间政策的数字—— 首选 |
{ ttl: '60s', swr: '10m' } | 内入, 如果尚未配置策略 |
{ tags: ['sku:{sku}'] } | 从该呼吁中推断出来 – sku:9f2 |
转弯可缓存性来源于它实际所引用的工具. 任何工具
说 cache: false 绕过整个转弯; TTL 和 SWR 取下 最低
因此,一个转动 触及目录(60年代)和品牌
故事(24h)只和目录一样新鲜. 未经宣布的工具 阻挡什么.
旁道是可见的而不是沉默的:
client.lastCache;
// { status: 'bypass', hit: false, semantic: false, bypassedByTool: 'addToCart' }
4. 语义性缓存——选择进入,而不是第一个接触
mode: 'semantic' 匹配参数,而不仅仅是字节相同的体。 真实
fAQ 形状流量的值——但它是 没有 这是免费的 没有 页:1
低命中率默认修正 :
- 所有准确的..错过 支付嵌入回程( 今天~ 342ms) 提供商甚至被调用。 对于一个已经需要~600毫米的工作量 在共同的道路上,这是一个很大的延迟.
- 匹配质量为英通. 印地语和阿拉伯语家庭语句匹配 目前还很薄弱, Hinglish midle —— 代码切换流量可能会错过真实 语句和意向一致.
在回答短,重复,英语和耐耐性的地方使用.
提升 threshold (单位:千美元)0– 说吧 –1默认值 0.8如果近乎失踪的人正在得到服务.
急急急急急急急急急急急.
5. 对话性AI——分出转弯,否则没有命中
如果你建立语音或聊天代理,这是决定你点击率的部分.
一个用户的言语通常会传到几个供应商的电话中,而不是 同样可缓存。 答复是针对个人的,每个客户每个回合都有独特的答复。 这个 背后的意图分类 完全取决于客户说的话. 要求一个提示同时完成,整个转弯继承了回复的缓存性———— 这是零。 这句话是调和的门槛;这是分解.
将可分享的部分作为自己的呼号:
import { AiSetu, normalizeUtterance, sharedCacheOptions } from '@ai-setu/client';
// Intent classification — shared by every customer who ever says it.
const classifier = new AiSetu().withCache(sharedCacheOptions({ policy: 'intent' }));
await classifier.chat.completions.create({
model,
temperature: 0,
messages: [
{ role: 'system', content: INTENT_LABELS }, // frozen — interpolate nothing
{ role: 'user', content: normalizeUtterance(transcript) },
],
});
// FAQ answer — paraphrase-matched, dropped when the article changes.
const faq = new AiSetu().withCache(
sharedCacheOptions({ mode: 'semantic', policy: 'faq', tags: ['kb:returns-policy'] }),
);
normalizeUtterance 比看起来更重要的事情: 确切的缓存 Cononicalises JSON
但绝不重写信件文本,所以 "Cancel my order" 财务报告和审定财务报表 "cancel my order" 为:
两个条目.
sharedCacheOptions 套装 force (分类器通常运行于 temperature > 0和
如果你通过一个 namespace这是故意的——一个命名空间分隔
键盘空间,所以每个客户一个在可分享的呼叫中,给您一个零命中率,没有
任何地方都出错。 这是这一表面上最昂贵的错误.
最高杠杆的把戏根本不需要SDK 缓存非人性的身体,相接 名字写在后面. 如果模型不需要解释 结束 个人 字段,请不要在提示中出现.
完整的图案,包括能保持快速缓存的快速形状 转弯 : docs.aisetu.ai/概念/谈判-隐藏。 。 。 .
证明它击中
const c = new AiSetu({
onCache: (info) => metrics.increment(info.hit ? 'cache.hit' : 'cache.miss'),
});
await c.chat.completions.create({ model, messages });
c.lastCache;
// { status: 'hit', hit: true, semantic: false, ageSeconds: 42 }
CacheInfo数字 :
| 字段 | 含义 |
|---|---|
status | hit | semantic-hit | stale | miss | refresh |
hit | true 当没有供应商呼叫时(hit, (中文(简体) ), semantic-hit, (中文(简体) ), stale(中文(简体) ) |
semantic | 一个相似的匹配服务它 |
ageSeconds | 服务年龄 |
similarity | 余弦相似度, 仅按语义 |
bypassedByTool | 其声明阻碍开关的工具 bypass 仅限 |
lastCache 留下来 undefined 当请求完全不能缓存时—— a
temperature > 0 调用无 force,或 mode: 'off'这是信号
没有任何东西被抬起头来 从一个 miss。 。 。 .
SDK无法解决的杀手: 用同样的方式拼写模型
每次都这样. zai.glm-4.7-flash 财务报告和审定财务报表 @mantle/zai.glm-4.7-flash 不一样
缓存分区 .
验证您的 BYOK 连接服务( 不是平台密钥)
每个响应的网关邮票属性信头; SDK 解析它们 因此,你可以确认——根据请求——你自己的钥匙已经送达:
const c = new AiSetu({
onRouting: (r) => {
if (!r.byok) throw new Error('expected BYOK, got platform key — bad slug?');
},
});
await c.chat.completions.create({
model: '@azure-qdc/gpt-5.4-mini',
messages: [{ role: 'user', content: 'hi' }],
});
// Or read synchronously after any call:
c.lastRouting;
// { provider: 'openai', byok: true,
// credentialId: '…uuid…', connectionSlug: 'azure-qdc' }
RoutingInfo数字 :
| 字段 | 含义 |
|---|---|
provider | 服务供应商(openai, (中文(简体) ), anthropic, (...) (中文(简体) ) |
byok | true = 钥匙已送达; false = 平台密钥(或未知弹出) |
credentialId | 服务证书(仅BYOK) |
connectionSlug | 服务过的连接语句( 只有 BYOK) |
credentialLabel | 已贬值 的别名 connectionSlug (相同价值) |
回调是最佳效果——内部的一个例外 onRouting 被吞下这样
错听者能断取相. 信头缺失( 门口长于此)
- 没有回话, lastRouting 留下来 undefined证书编号/子弹
并不是秘密 —— 您拥有连接 .
遗产 : 页:1
workspaceCredential选项+label/model模式字符串 已贬值.workspaceCredential仍在工作(别名:connection; 计 数 赤线label/model窗体显示 没有 ——使用@<slug>/<model>。 。 。 .
为什么不用自定义基础URL的原始 OpenAI SDK?
你当然可以. AiSetu 只为你做,并添加: env-var-第一构造
(单位:千美元)new AiSetu() 没有参数,保持静电池 调节到网关,和每个请求
BYOK 路线@<slug>/<model> / 该 connection 选项)。 不关心这些?
点 openai 在网关你自己.
四个AI Setu软件包——你拿哪一个
| 软件包 | 用它当 |
|---|---|
@ai-setu/client | 运行时代理 / app 调用推论。 滴入为 openai。 。 。 . |
@ai-setu/admin | 脚本 / CI / 构建器代理 在 TypeScript 中运行控制平面操作. |
@ai-setu/cli | 同样的控制飞机行动 外壳。 。 。 . |
@ai-setu/mcp | 构建器代理 (Claude Code, Cursor) 开机 + ops 对话. |
全员运行本 = 页:1。 。 。 .
许可证
麻省理工学院.