十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

多租户问数用 ChatGPT Work,TaoToken 的隔离键怎么划

多租户问数用 ChatGPT Work,TaoToken 的隔离键怎么划 1. ChatGPT Work Data agent 的模型调用侧多租户问数为什么先划隔离键OpenAI 近期把 Data agent 放进 ChatGPT Work让用户通过自然语言连接企业数据、分析变化并生成可分享的交互式仪表盘。对多租户 SaaS 开发者来说交互层再顺滑底层也会落到一次次模型请求A 租户问“本月退款率为什么上升”B 租户问“库存周转是否异常”每一次问数、解释、图表摘要、多轮追问都会消耗 Token。本文不讨论 Data agent 的前端体验只聚焦模型调用侧当这些请求从你的 SaaS 后端发出时TaoToken 的隔离键怎么划才能既能计量又能限流还能对账。准备凭据时先到 TaoToken 官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contenttenant_isolation_intro 获取 Key并把模型请求的 Base URL 设为 https://taotoken.net/api。这里“隔离键”不是单指一个字段而是一组能贯穿请求、Key、日志、账单的标识。最小集合至少包括 tenant_id、workspace_id、scene、env。tenant_id 回答“是谁在消耗 Token”workspace_id 回答“租户内哪个项目或工作区在消耗”scene 回答“是问数对话、仪表盘刷新、字段解释还是报告摘要”env 回答“是否生产流量”。如果只用一个全局 Key 接所有租户短期省事长期会出现三个后果第一账单无法拆分财务只能按总用量摊派第二限流互相影响一个租户的批量问数把其他租户拖慢第三排障困难出现异常模型调用时无法快速定位租户与场景。多租户问数的 Token 消耗和普通聊天不同。普通聊天通常是一问一答而问数场景经常包含 schema 摘要、指标解释、SQL 生成辅助、结果解释、图表标题、异常归因、多轮追问。一次用户点击可能触发多次模型调用。如果没有隔离键你只知道“今天用了多少 Token”不知道“谁用的、为什么用、是否该由该租户承担”。所以隔离键的第一目标不是安全口号而是成本归因与限流边界。本文给出可复现产出一套隔离键规则一张租户账单表以及 TaoToken 在模型调用侧的 Key 与 Base URL 配置方式。文中不会让 MCP、Agent 或代理直接连接 Oracle、MySQL 生产库所有 SQL 和命令都由你在本地或测试环境执行问数 SQL 应由你的数据服务在受控只读副本上完成。2. 隔离键四段式规则tenant_id workspace scene env先确定规则再写代码。很多团队反过来先在代码里到处传 tenantId最后发现日志字段不统一、Key 命名混乱、账单无法聚合。建议把隔离键固定为四段式段位字段示例来源是否进入 Key 别名是否进入请求头用途1tenant_idacme服务端会话/JWT是是租户账单、限流、审计2workspace_idanalytics服务端上下文建议是租户内项目分摊3scenedata_qa_chat路由/任务类型是是区分问数、刷新、解释4envprod部署环境是是隔离测试与生产消耗Key 别名建议采用tt_{tenant_id}_{env}_{scene}_{purpose}例如tt_acme_prod_data_qa_chat tt_acme_prod_dashboard_refresh tt_globex_staging_schema_explain这样在控制台看到 Key 别名时就能知道它属于哪个租户、哪个环境、哪个场景。请求头建议至少带X-Tenant-Id: acme X-Workspace-Id: analytics X-Scene: data_qa_chat X-Env: prod X-Request-Id: 01J...注意tenant_id 必须由服务端鉴权后注入不能信任前端 body 里的 tenantId。否则租户 A 可以伪造租户 B 的 ID导致账单和限流全部错位。更稳的做法是网关从 JWT、Session 或 API Gateway 上下文里取 tenant_id然后覆盖请求体中的同名字段。隔离键规则可以直接落成配置{ isolationKey: { tenantId: { source: server_session, required: true, trustClient: false }, workspaceId: { source: server_context, required: false, default: default }, scene: { source: route_or_task, required: true, allowed: [ data_qa_chat, dashboard_refresh, schema_explain, report_summary ] }, env: { source: deployment_env, required: true, allowed: [dev, staging, prod] } } }这份配置本身不调用模型但它是后续 Key 创建、请求头注入、日志落库的依据。你可以把它放在配置中心也可以放在环境变量里。关键是所有问数请求都必须经过同一套提取逻辑而不是每个服务各自拼字段。3. 在 TaoToken 创建租户级 Key控制台路径与 Base URL 配置隔离键确定后下一步是准备凭据。TaoToken 的官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentcreate_tenant_key 你可以从这里进入控制台。创建 Key 时建议按“租户 环境 场景”粒度来建不要把生产、测试、问数、摘要全部塞进一个 Key。推荐步骤打开 TaoToken 官网登录控制台。进入 API Keys 页面为每个租户创建独立 Key。Key 别名按第 2 节的规则命名例如tt_acme_prod_data_qa_chat。复制 Key 后只放在服务端环境变量或密钥管理服务中不要写进前端、移动端或公开仓库。把模型请求的 Base URL 统一设为https://taotoken.net/api。在测试环境先用一个租户 Key 发一条最小请求确认鉴权、模型、用量字段都正常。环境变量可以这样放export TAOTOKEN_API_KEYYOUR_API_KEY export TAOTOKEN_BASE_URLhttps://taotoken.net/api export TAOTOKEN_MODELYOUR_MODEL_ID如果你使用 OpenAI 兼容 SDK通常只需要设置 baseURL 和 apiKey。注意 Base URL 是https://taotoken.net/api不要在末尾多写/v1也不要写成带 UTM 参数的地址。UTM 只用于官网和文档入口模型请求地址保持干净。最小连通性测试可以在本地执行curl -sS https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer ${TAOTOKEN_API_KEY} \ -H Content-Type: application/json \ -H X-Tenant-Id: acme \ -H X-Workspace-Id: analytics \ -H X-Scene: data_qa_chat \ -H X-Env: staging \ -d { model: ${TAOTOKEN_MODEL}, messages: [ { role: user, content: 用一句话说明退款率环比变化可能受哪些维度影响。 } ], stream: false }如果返回 401先检查Authorization头和 Key 是否有多余空格如果返回 404检查 Base URL 是否误写成https://taotoken.net/api/v1后又在 SDK 里重复拼接如果返回 429先看是不是多个租户共用了同一个 Key。多租户场景下Key 本身就是限流和账单的第一道边界。创建更多租户 Key 时仍然从 API Keys 页面进入https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contenttenant_isolation_apikey 。建议把 Key 创建动作纳入租户开通流程新租户开通时自动生成tt_{tenant}_{env}_data_qa_chat租户停用时禁用 Key而不是删除日志。4. 网关代理写法把隔离键注入请求头并保留 request_id多租户 SaaS 不应让前端直接调用模型接口。更合理的结构是前端调用你的业务后端业务后端完成鉴权、租户识别、权限校验、问数 SQL 执行再把需要模型解释的内容发往 TaoToken。下面是一个简化的 Node.js/TypeScript 代理示例重点不是业务逻辑而是隔离键如何从服务端上下文进入请求头。// server/tenantModelProxy.ts import express from express; import fetch from node-fetch; const app express(); app.use(express.json()); // 生产环境建议从密钥管理服务按租户加载不要硬编码 const TENANT_KEY_MAP: Recordstring, string { acme: process.env.TAOTOKEN_KEY_ACME!, globex: process.env.TAOTOKEN_KEY_GLOBEX! }; const TAOTOKEN_BASE_URL process.env.TAOTOKEN_BASE_URL!; const DEFAULT_MODEL process.env.TAOTOKEN_MODEL!; app.post(/api/data-qa, async (req, res) { // 真实项目中由鉴权中间件写入不要从 req.body.tenantId 取 const auth (req as any).auth; const tenantId auth?.tenantId as string; const workspaceId (req.body.workspaceId as string) || default; const scene data_qa_chat; const env process.env.NODE_ENV production ? prod : staging; const apiKey TENANT_KEY_MAP[tenantId]; if (!apiKey) { return res.status(403).json({ error: tenant_not_configured }); } const requestId req.headers[x-request-id]?.toString() || crypto.randomUUID(); const startedAt Date.now(); const upstream await fetch(${TAOTOKEN_BASE_URL}/v1/chat/completions, { method: POST, headers: { Authorization: Bearer ${apiKey}, Content-Type: application/json, X-Tenant-Id: tenantId, X-Workspace-Id: workspaceId, X-Scene: scene, X-Env: env, X-Request-Id: requestId }, body: JSON.stringify({ model: req.body.model || DEFAULT_MODEL, messages: req.body.messages, stream: false }) }); const data await upstream.json(); const latencyMs Date.now() - startedAt; // usage 字段由上游返回写入你的租户账单表 console.log(JSON.stringify({ requestId, tenantId, workspaceId, scene, env, model: req.body.model || DEFAULT_MODEL, usage: data.usage, status: upstream.status, latencyMs })); return res.status(upstream.status).json(data); }); app.listen(3000, () { console.log(tenant model proxy listening on :3000); });这段代码的关键点有三个第一tenant_id 来自服务端鉴权上下文不来自前端 JSON。否则租户可以伪造身份。 第二每个租户映射到独立 Key。这样 TaoToken 侧看到的是不同 Key 的用量限流和账单天然分层。 第三请求头里保留 workspace、scene、env、request_id。日志系统、账单系统、排障系统都靠这些字段串联。不要把这段代理直接连到生产库。问数场景里的 SQL 应该由你的数据服务在只读副本或数仓上执行模型只负责解释和总结。MCP、Agent 或类似自动化方案也不应绕过权限直接执行生产库 DDL/DML。本文所有 SQL 只建议在本地或测试库执行。5. 租户账单表设计从 Token 日志到可对账 SQL有了隔离键下一步是让账单可复现。建议在业务库或日志库中建一张模型用量表字段至少覆盖请求标识、租户、工作区、场景、Key 别名、模型、Token 用量、延迟和时间。CREATE TABLE tenant_model_usage ( id BIGSERIAL PRIMARY KEY, request_id TEXT NOT NULL, tenant_id TEXT NOT NULL, workspace_id TEXT, scene TEXT NOT NULL, env TEXT NOT NULL, key_alias TEXT NOT NULL, model TEXT NOT NULL, prompt_tokens INT NOT NULL DEFAULT 0, completion_tokens INT NOT NULL DEFAULT 0, total_tokens INT GENERATED ALWAYS AS (prompt_tokens completion_tokens) STORED, latency_ms INT, status_code INT, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX idx_tenant_model_usage_tenant_day ON tenant_model_usage (tenant_id, created_at); CREATE INDEX idx_tenant_model_usage_scene ON tenant_model_usage (scene, created_at);插入数据时不要把前端上报的用量直接当作财务依据。更稳的是以服务端代理收到的上游响应为准或者以 TaoToken 控制台导出的账单为对账依据。业务表用于实时看板和限流控制台账单用于最终结算两者通过request_id、tenant_id、key_alias、时间窗口对齐。按租户和日期聚合SELECT tenant_id, date_trunc(day, created_at) AS day, scene, sum(prompt_tokens) AS prompt_tokens, sum(completion_tokens) AS completion_tokens, sum(total_tokens) AS total_tokens, count(*) AS request_count, round(avg(latency_ms)) AS avg_latency_ms FROM tenant_model_usage WHERE created_at now() - interval 7 days GROUP BY tenant_id, day, scene ORDER BY tenant_id, day, scene;按租户做成本估算时可以把单价替换成你与 TaoToken 的实际结算单价。下面 SQL 只是结构示例不要直接使用未核实的数字SELECT tenant_id, date_trunc(month, created_at) AS month, sum(total_tokens) AS total_tokens, sum(total_tokens) * :unit_price AS estimated_cost FROM tenant_model_usage WHERE env prod GROUP BY tenant_id, month ORDER BY tenant_id, month;建议再加两个视图CREATE VIEW tenant_daily_usage AS SELECT tenant_id, date_trunc(day, created_at) AS day, sum(total_tokens) AS total_tokens FROM tenant_model_usage WHERE env prod GROUP BY tenant_id, day; CREATE VIEW tenant_scene_usage AS SELECT tenant_id, scene, sum(total_tokens) AS total_tokens FROM tenant_model_usage WHERE env prod GROUP BY tenant_id, scene;这样你就能回答三个问题哪个租户消耗最多哪个场景消耗最多某天异常升高是问数对话还是仪表盘刷新导致的如果发现某个租户的dashboard_refresh用量突然上升可以先在网关层对该租户该场景做限流而不是直接停掉整个租户。6. 排障清单401、429、串租与 Codex/Claude Code 配置错位多租户问数接入模型网关时常见问题集中在鉴权、限流、租户识别和工具配置错位。下面按现象给出排查顺序。现象一401 Unauthorized 或 invalid api key。先检查请求头curl -i https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer YOUR_API_KEY \ -H Content-Type: application/json \ -d {model:YOUR_MODEL_ID,messages:[{role:user,content:ping}]}常见原因包括Key 复制时带了空格环境变量未加载Base URL 写成了官网地址而不是https://taotoken.net/api把 UTM 参数错误地拼到了 API 地址上。记住UTM 只用于官网、文档、控制台入口模型请求 Base URL 不加 UTM。现象二404 Not Found。多数是 Base URL 末尾路径重复。例如 SDK 内部拼接/v1/chat/completions而你把 baseURL 写成了https://taotoken.net/api/v1最终变成/api/v1/v1/chat/completions。统一使用https://taotoken.net/api现象三429 Too Many Requests。多租户场景优先检查是否多个租户共用了同一个 Key。如果 A 租户做了批量仪表盘刷新B 租户的正常问数就可能被一起限流。解决方式是按租户拆分 Key并在你的网关层做租户级令牌桶。网关限流键建议使用tenant_id scene env而不是只按 IP 或全局 QPS。现象四账单里出现串租。检查 tenant_id 是否从req.body.tenantId读取。必须改为从服务端 Session、JWT 或 API Gateway 上下文读取并在日志中记录X-Request-Id。如果已经出现串租先停止使用前端传入的 tenant_id再按请求日志回溯。现象五Claude Code 配置不生效。Claude Code 使用settings.json或ANTHROPIC_*环境变量。示例{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_AUTH_TOKEN: YOUR_API_KEY, ANTHROPIC_MODEL: YOUR_MODEL_ID } }或在 shell 中export ANTHROPIC_BASE_URLhttps://taotoken.net/api export ANTHROPIC_AUTH_TOKENYOUR_API_KEY export ANTHROPIC_MODELYOUR_MODEL_ID现象六Codex 配置不生效。Codex 使用config.toml不要把ANTHROPIC_*套到 Codex 上。示例model YOUR_MODEL_ID model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY wire_api chat然后设置export TAOTOKEN_API_KEYYOUR_API_KEY注意env_key指向的是环境变量名不是 Key 本身。不要把 Key 明文写进config.toml后提交到仓库。7. 开发工具侧验证Claude Code、Codex、CC Switch 三件套多租户问数的主链路在服务端但开发和运维侧也会用 Claude Code、Codex、CC Switch 等工具做脚本、排障和配置验证。这里的原则是业务租户 Key 与开发者个人 Key 分开生产 Key 与测试 Key 分开。开发工具只用于验证配置是否正确不要拿生产问数 Key 做个人实验。Claude Code 侧已经给出settings.json和ANTHROPIC_*示例。再补充一个可复制的settings.json{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_AUTH_TOKEN: YOUR_API_KEY, ANTHROPIC_MODEL: YOUR_MODEL_ID, ANTHROPIC_SMALL_FAST_MODEL: YOUR_FAST_MODEL_ID } }Codex 侧使用config.tomlmodel YOUR_MODEL_ID model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY wire_api chatCC Switch 类工具通常关注三件套供应商名称、Base URL、API Key。配置时不要只填 Key还要把供应商的 Base URL 指向https://taotoken.net/api。一个 JSON 结构示例{ providers: [ { name: taotoken-tenant-acme-staging, baseUrl: https://taotoken.net/api, apiKey: YOUR_API_KEY, models: [YOUR_MODEL_ID] } ] }如果你在团队内共享配置模板建议把YOUR_API_KEY留空并写明从 TaoToken 官网创建https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentdev_tool_config 。团队成员的 Key 应各自创建不要共用一个生产租户 Key。这样才能在控制台里区分“某个人调试用超了”和“某个租户生产问数超了”。8. 多租户问数上线检查表与 CTA上线前可以用下面这份检查表快速过一遍tenant_id 是否只从服务端鉴权上下文读取是否每个租户、每个环境、每个关键场景拥有独立 Key 别名模型请求 Base URL 是否统一为https://taotoken.net/api请求头是否包含X-Tenant-Id、X-Workspace-Id、X-Scene、X-Env、X-Request-Id模型用量是否写入tenant_model_usage表是否能按租户、日期、场景聚合出 Token 账单是否在网关层按tenant_id scene env做限流是否禁止前端、移动端、公开仓库出现真实 Key是否禁止 MCP、Agent、代理直连 Oracle/生产库是否把问数 SQL 放在本地或受控只读副本执行模型只做解释与总结如果这 10 项都通过你就能把 ChatGPT Work Data agent 带来的“自然语言问数”体验落到可计量、可限流、可对账的多租户模型调用链路上。隔离键不是额外负担而是租户账单和稳定性的地基。需要快速验证模型对话能力可以从模型对话入口开始https://taotoken.net/models/detail/chat?utm_sourcetaotoken_aicg_blog_endutm_contenttenant_isolation_chat 。如果你的团队要长期做多租户问数、代码辅助和自动化排障可以再看 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contenttenant_isolation_coding 。准备好租户级 Key 后进入 API Keys 页面创建https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contenttenant_isolation_apikey 。Claude Code 的详细配置可参考文档https://taotoken.net/doc/ClaudeCodeAnthropic?utm_sourcetaotoken_aicg_blog_endutm_contenttenant_isolation_claudecode 。把 Base URL 设为https://taotoken.net/api用YOUR_API_KEY先跑通本地测试再按租户拆分 Key最后把用量日志接入你的账单表。
返回列表