# 整体架构 ## 核心流程 1. 客户端 POST /v1/chat/completions 到本地端口 2. 中间件做三件事: - 校验本地 API Key(Authorization: Bearer ) - 读 body 里的 model,按前缀路由 - 如果带前缀,把 model 改成去掉前缀后的上游模型名 3. 根据 stream 字段选择转发方式: - stream=true → 打开上游 SSE,字节流实时转发 - 非流式 → 缓冲上游完整响应后返回 ## 模型前缀路由 | 前缀 | ProviderKind | Region | |---|---|---| | wbcn- / workbuddy-cn / codebuddy- | WORKBUDDY_CN | CN | | wbintl- / workbuddy-intl / workbuddy- | WORKBUDDY_INTL | INTL | | traecn- / trae-cn / trae- | TRAE_CN | CN | | traeintl- / trae-intl | TRAE_INTL | INTL | | 其它 | OPENAI_COMPATIBLE(Sub2API 透传) | - | ## 请求生命周期 POST /v1/chat/completions -> authorized() // 401 if invalid key -> extractModel(rawBody) // "traecn-glm-5.2" -> router.route(model) // (TRAE_CN, CN) -> stripModelPrefix(model) // "glm-5.2" -> rewriteModelBody() // 替换 body.model -> pooled = pool.next(kind, region, sessionKey) -> traeChatProxy.openStreamingChat(body, pooled?.accountId, region) -> respondOutputStream(...) // 逐块写上游字节 ## 账号池 - 从 CredentialRepository.accountsFor(service) 读取实时账号 - 每个 ProviderKind 一个轮询游标(round-robin) - 会话粘性:X-Conversation-Id 或 body user 作为 key,同会话复用同一账号 - 地区匹配:优先选择 credential.region == route.region,没有则回退全部 ## 本地服务 - GET /health → 存活检查 - GET /v1/models → 透传 Sub2API 模型列表 - POST /v1/chat/completions → 聊天代理