1. 多智能体上 K8s 后,Key 为什么成了最先崩的那块
把 Kars 智能体跑在 Kubernetes 上,很多人第一反应是编排、调度、扩缩容。真正上手之后你会发现,最先出问题的往往不是调度,而是 Key。一个财经短视频流水线里,Research、Market-Data、Scriptwriter、Compliance、Publisher 各自要调模型,如果每个 Sandbox 都塞一份真实 API Key,那么凭据就散落在五六个 Pod 的 env 里。任何一个被提示词注入攻陷的智能体,都能把 Key 读走,进而访问这个 Key 能触达的一切。
Kars 的设计思路是:智能体容器没有自己的网络,只能访问 localhost,所有对模型、工具、其他智能体的调用都必须经过 Pod 内的 Router。Router 用独立 UID 运行,真实云凭证只存在 Router 里,智能体进程永远看不到。适配器会把模型 Base URL 强制指向http://127.0.0.1:8443,并用占位符ROUTED-VIA-KARS替换真实 Key。也就是说,智能体内部从物理层面就无法直接访问公网模型服务。
这套模型要落地,前提是有一个统一的上游 API 通道,让 Router 只认一个入口、一套 Key,而不是每个智能体各自维护一份。TaoToken 在这里扮演的就是这个统一 Key/API 通道的角色:Router 侧配置一次,所有 Sandbox 共享同一条受治理的调用链路,Key 不再进入智能体容器。下面我把 config.toml、settings.json 的配置骨架,以及 K8s Secret 注入方式完整写出来,你可以直接照着改。
2. 前置:TaoToken 统一 Key 与 API 通道准备
在动手改 Kars 配置之前,先把上游通道准备好。TaoToken 提供统一的 API 入口,模型对话、Coding Plan、控制台、API Keys 都有独立页面。你需要做的是拿到一个可用的 Key,并确认 API Base URL。
访问官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 了解整体能力,然后进入控制台创建 Key。API 入口是 https://taotoken.net/api,注意这个地址不带 UTM 参数,配置里要写干净。
创建 Key 的入口在 API Keys 页面:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite 。拿到形如sk-xxxx的 Key 之后,先不要写进任何 YAML 明文,后面我们用 K8s Secret 注入。
如果你只是想先验证模型通不通,可以直接用模型对话页面发一条请求:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite 。确认返回正常,再进入 Kars 配置环节。长期跑编码类或 Agent 类负载的话,Coding Plan 页面有更细的额度说明:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite 。
这里有个关键点:Kars 的 Router 是唯一持有真实 Key 的组件,智能体侧只拿到占位符。所以 TaoToken 的 Key 只需要注入到 Router 能读到的地方,不需要分发到每个 Sandbox。这正是解决「Key 分散、权限混乱」的核心。
3. 可复制配置:config.toml 与 settings.json 骨架
Kars 的适配器会读取运行时的配置文件,把模型入口指向本地 Router。不同运行时的配置文件名不一样,OpenClaw 系用config.toml,部分 SDK 系用settings.json。下面给出两份可直接改的骨架。
3.1 config.toml:把模型入口锁到本地 Router
# config.toml —— 智能体侧配置,真实 Key 不在这里 [model] # 强制指向 Pod 内 Router,智能体无法直连公网 base_url = "http://127.0.0.1:8443/v1" # 占位符,Router 会替换为真实凭据 api_key = "ROUTED-VIA-KARS" provider = "openai-compatible" [model.routing] # 上游统一通道,由 Router 持有真实 Key upstream = "taotoken" # 请求级 Token 上限,超限 Router 直接返回 429 max_tokens_per_request = 8192 # 租户级日配额 daily_token_quota = 2000000 [mesh] # 智能体间通信走加密 Mesh enabled = true trust = "entra" [telemetry] # 自动接入 OpenTelemetry otlp_endpoint = "http://otel-collector.kars-system:4317"注意base_url写的是127.0.0.1:8443,不是公网地址。这是 Kars 适配器的硬约束:SDK 从物理层面无法绕过 Router。api_key写占位符ROUTED-VIA-KARS,真实 Key 由 Router 在转发时注入。
3.2 settings.json:SDK 系运行时的等价配置
{ "model": { "baseUrl": "http://127.0.0.1:8443/v1", "apiKey": "ROUTED-VIA-KARS", "provider": "openai-compatible" }, "routing": { "upstream": "taotoken", "maxTokensPerRequest": 8192, "dailyTokenQuota": 2000000, "rateLimitPerMinute": 120 }, "mesh": { "enabled": true, "trust": "entra" }, "contentSafety": { "enabled": true, "minimumLevel": "Medium" } }两份配置的语义一致:模型入口锁本地、Key 用占位符、预算和速率限制在 Router 侧执行。contentSafety.minimumLevel不能低于集群准入阶段设定的最低安全等级,否则 Sandbox 不会进入 Ready。
3.3 K8s Secret 注入:真实 Key 只进 Router
真实 Key 通过 Secret 注入,且只挂载到 Router 容器,不挂到智能体容器。先创建 Secret:
kubectl create secret generic taotoken-upstream \ --namespace finvideo \ --from-literal=TAOTOKEN_API_KEY='sk-你的真实Key' \ --from-literal=TAOTOKEN_BASE_URL='https://taotoken.net/api'然后在 Router 的 Deployment 里引用,注意envFrom只出现在 Router 容器段:
apiVersion: apps/v1 kind: Deployment metadata: name: kars-router namespace: finvideo spec: replicas: 1 selector: matchLabels: app: kars-router template: metadata: labels: app: kars-router spec: containers: - name: router image: ghcr.io/azure/kars-router:latest envFrom: - secretRef: name: taotoken-upstream ports: - containerPort: 8443 securityContext: runAsUser: 1001 readOnlyRootFilesystem: true allowPrivilegeEscalation: false capabilities: drop: ["ALL"]智能体容器段则完全不引用这个 Secret,只挂载config.toml:
containers: - name: scriptwriter image: ghcr.io/azure/kars-openclaw:latest volumeMounts: - name: agent-config mountPath: /etc/kars/config.toml subPath: config.toml securityContext: runAsUser: 1000 readOnlyRootFilesystem: true capabilities: drop: ["ALL"] volumes: - name: agent-config configMap: name: scriptwriter-configRouter 用 UID 1001,智能体用 UID 1000,配合egress-guardInit Container 安装的 iptables 规则,智能体 UID 只能访问本地 Router。即使智能体被完全攻陷,也读不到TAOTOKEN_API_KEY,因为它根本不在这个容器的文件系统和环境变量里。
4. 验证请求:多智能体鉴权与调用链路
配置写完,必须验证三件事:Router 能拿到上游 Key、智能体只能走 Router、调用链路可审计。下面按顺序来。
4.1 验证 Router 到 TaoToken 的连通性
先进 Router Pod 发一条最小请求:
kubectl exec -n finvideo deploy/kars-router -- \ curl -s -o /dev/null -w "%{http_code}\n" \ -X POST "$TAOTOKEN_BASE_URL/v1/chat/completions" \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"gpt-4.1","messages":[{"role":"user","content":"ping"}],"max_tokens":8}'返回200说明 Router 侧通道正常。如果返回401,检查 Secret 里的 Key 是否有多余空格;返回429,说明触发了速率或配额限制,属于预期行为。
4.2 验证智能体无法直连公网
进智能体 Pod,尝试直连上游,应该失败:
kubectl exec -n finvideo deploy/scriptwriter -- \ curl -s -m 5 -o /dev/null -w "%{http_code}\n" \ https://taotoken.net/api/v1/models预期结果是超时或连接被拒。如果这里返回了200,说明egress-guard的 iptables 规则没生效,或者 NetworkPolicy 没应用,需要立刻排查——这是安全模型失效的信号。
4.3 验证智能体经 Router 调用成功
再让智能体走本地 Router:
kubectl exec -n finvideo deploy/scriptwriter -- \ curl -s -X POST http://127.0.0.1:8443/v1/chat/completions \ -H "Authorization: Bearer ROUTED-VIA-KARS" \ -H "Content-Type: application/json" \ -d '{"model":"gpt-4.1","messages":[{"role":"user","content":"生成一句财经标题"}],"max_tokens":32}'返回正常内容,说明「智能体 → Router → TaoToken」链路打通。注意这里用的是占位符ROUTED-VIA-KARS,真实 Key 由 Router 替换。
4.4 验证多智能体 Mesh 通信与审计
用kars_mesh_send让 Scriptwriter 把脚本交给 Compliance:
kubectl exec -n finvideo deploy/scriptwriter -- \ kars_mesh_send --to compliance-agent \ --role reviewer \ --payload '{"script_id":"s-001","content":"..."}'然后在审计侧确认这条调用被记录:
kubectl logs -n finvideo deploy/kars-router --tail=50 | grep s-001你应该能看到带哈希链的审计条目,包含发起方、接收方、时间戳和策略版本哈希。这条记录就是监管场景下要的防篡改凭证。
5. 本篇常见错排查
5.1 Sandbox 一直不 Ready
最常见原因是InferencePolicy里的contentSafetyMinimum低于集群准入最低等级,准入阶段直接拒绝。用kubectl describe sandbox <name> -n finvideo看 Events,如果出现admission denied: content safety below cluster minimum,把等级调到不低于集群设定值即可。
5.2 智能体报 401 但 Router 正常
说明智能体侧配置里的api_key没写成占位符,或者写成了真实 Key。检查config.toml/settings.json,api_key必须是ROUTED-VIA-KARS。写成真实 Key 不仅会 401,还意味着 Key 泄漏进了智能体容器,属于必须立刻轮换的安全事件。
5.3 调用超时且日志显示连接公网
egress-guardInit Container 没跑成功,iptables 规则没装。检查 Init Container 日志:
kubectl logs -n finvideo deploy/scriptwriter -c egress-guard如果报权限不足,确认 Pod 的securityContext允许 Init Container 操作网络命名空间,同时 NetworkPolicy 已正确选择该 Pod。
5.4 触发 429 但不确定是速率还是配额
Router 的 429 响应头会区分原因。看X-Kars-Limit-Type:值为rate是速率限制,值为quota是 Token 配额。速率限制始终启用,配额按InferencePolicy里的daily_token_quota执行。调优时优先调速率,配额是安全兜底,不建议为了跑通就放开。
5.5 Mesh 通信失败
先确认--mesh-trust模式一致。用entra时,Controller 会为每个 Sandbox 创建独立的 Entra Agent ID 并配置联邦凭据;如果某个 Sandbox 还是anonymous模式,JWT 校验会失败。用kars attest <name>查看该 Sandbox 的信任模式,确保全链路一致。
6. 把统一 Key 通道固化进你的 Kars 工作流
走到这里,你应该已经跑通了「智能体零凭据、Router 持 Key、TaoToken 做统一上游」这条链路。我的建议是把上面三份配置直接进 Git 仓库,用 Argo 或 Flux 对账,让 Key 注入、预算、出口策略都变成可审查的 YAML。这样安全团队审的是配置,不是 Python 代码,审计链也是现成的。
后续要扩展时,接入文档里有更细的 Router 参数和策略字段说明:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 。如果你用的是 Claude Code 或 Anthropic 系 SDK 跑 Agent,对应的接入方式在 https://taotoken.net/claudecode-anthropic?utm_source=taotoken_aicg_blog_end&utm_content=claude_code&utm_campaign=rewrite 。长期跑编码类 Agent 负载,Coding Plan 的额度模型比按量更可控,前面给过入口。
最后提醒一句:Key 轮换时只需要更新taotoken-upstream这个 Secret,重启 Router 即可,所有 Sandbox 无需改动。这正是把 Key 收敛到单一通道的价值——轮换成本从「改 N 个 Pod」变成「改一个 Secret」。