Gin 框架对接 Claude API:用 Go 搭一个高并发 AI 网关
Gin 框架对接 Claude API用 Go 搭一个高并发 AI 网关不少教程讲「Go 怎么调用 Claude API」时通常会从最基础的地方开始安装 SDK、初始化 Client、发起请求然后把结果打印出来。作为入门这当然没问题。但如果你的目标不是写一个 demo而是给前端、内部系统甚至多个业务团队提供统一的 AI 能力那只会调用 Claude API 显然还不够。更实际的做法是在服务端用 Gin 封装一层 AI 网关把 Claude API 的调用、鉴权、限流、日志、成本统计、流式转发和错误处理都收进来。这样一来前端不用接触上游 API Key业务系统也不需要理解 Claude Messages API 里那些具体字段和调用细节。本文主要讨论服务端直接对接 Anthropic Claude API 的工程实现。如果你使用的是 ClaudeAPI 这类第三方 Claude API 兼容接入平台需要先明确一点它不是 Anthropic 官方服务更适合需要兼容接入、多线路选择、中文支持、企业充值、开票以及基础技术协助的场景。具体支持哪些能力、有哪些调用规则还是要以平台官网的最新说明为准。为什么不建议在前端直接调用 Claude API前端直接调用 Claude API最大的问题就是安全。API Key 一旦出现在浏览器代码、移动端包体或者小程序里基本就很难保证不被复制、泄露或者滥用。在企业项目里一个 Gin Claude API 网关通常至少要负责这些事情保护上游 Claude API Key只把它放在后端环境变量或 Secret 中使用业务 token 给调用方做鉴权而不是把上游密钥发给前端按业务方做限流、额度控制、模型路由和调用审计统一注入 system prompt避免每个业务系统都重复拼提示词记录 request_id、耗时、状态码和 token 用量对 429、5xx、超时等错误做统一处理。所以Go AI 网关并不是简单地把 Claude API 代理一遍。更准确地说它是把「模型能力」包装成一个可治理、可观测、也方便扩展的内部服务。整体架构Gin Claude API AI 网关调用链一个真正能上线的 Gin Claude API 网关调用链可以设计成下面这样Client / Frontend | v Gin Router | v Auth / RateLimit / Logger / Recovery | v Chat Handler | v Claude Service | v Claude Client | v Anthropic Claude API 或兼容接入服务这里每一层最好都保持边界清楚。Router 主要负责注册路由比如/api/v1/chat和/api/v1/chat/streamMiddleware 处理鉴权、限流、日志、请求体大小限制等通用逻辑Handler 负责参数绑定、基础校验和响应封装Service 放业务逻辑比如上下文处理、模型路由、错误转换Client 才真正去调用 Claude API同时负责连接复用、超时控制和流式响应处理。这样拆分的好处很明显今天底层接的是 Claude明天如果要换成 OpenAI、Gemini、Bedrock 或 Vertex只要接口抽象做得还可以就不用把 Gin Handler 全部推倒重写。技术选型官方 Anthropic Go SDK 还是第三方 Claude Go ClientGo 调用 Claude API 时可选方案其实不少。比较稳妥的方式是根据场景来选。方案适合场景优点注意点Anthropic 官方 Go SDK直接调用 Claude API官方维护接口更新通常更及时网关层需要自己封装liushuangls/go-anthropic想使用非官方 wrapper示例较多封装也比较灵活模型和 beta 参数可能会滞后claude-agent-sdk-go调用 Claude Code CLI适合做 Claude Code 自动化不是常规 Claude API 服务端调用方式psanford/claude兼容 Anthropic、Bedrock、Vertexprovider 抽象比较好对单一 Gin 网关来说可能稍重如果是从零开始搭 Gin Claude API 网关通常建议优先用官方 SDK。同时在业务代码里留一层接口抽象例如type LLMClient interface { Chat(ctx context.Context, req ChatRequest) (*ChatResponse, error) StreamChat(ctx context.Context, req ChatRequest) (-chan StreamChunk, error) }这样做的好处是当前实现不会变复杂但以后要接多模型、多供应商时也不会被某个 SDK 彻底绑死。初始化 Gin 项目与目录结构项目目录可以按下面这种方式组织gin-claude-gateway/ ├── cmd/server/main.go ├── internal/config/config.go ├── internal/handler/chat_handler.go ├── internal/service/claude_service.go ├── internal/client/claude_client.go ├── internal/middleware/auth.go ├── internal/middleware/ratelimit.go ├── internal/model/chat.go ├── internal/response/response.go ├── go.mod ├── .env.example ├── Dockerfile └── README.md先把 Gin 和 Claude SDK 这些基础依赖装好go mod init gin-claude-gateway go get github.com/gin-gonic/gin go get github.com/anthropics/anthropic-sdk-go go get golang.org/x/time/rate配置不要直接写死在代码里。至少准备下面这些环境变量ANTHROPIC_API_KEYsk-ant-xxx CLAUDE_MODELclaude-3-5-sonnet-latest SERVER_PORT8080 REQUEST_TIMEOUT60s MAX_CONCURRENCY100 RATE_LIMIT_RPS20 GIN_MODErelease模型名称会随着官方更新发生变化所以最好放在配置里。实际使用时以 Anthropic 官方文档或者兼容接入平台的最新说明为准。封装 Claude Client连接复用、超时和模型配置在高并发场景下千万不要每来一个请求就重新创建 HTTP Client 或 Claude Client。Client 应该在程序启动时初始化好然后通过依赖注入传给 Service 使用。这里有几个原则值得注意。第一API Key 只能从环境变量、Secret Manager、Kubernetes Secret 或 CI/CD 注入不要写进代码更不要提交到 Git 仓库。第二所有上游调用都要带上context.Context。在 Gin Handler 里可以直接使用c.Request.Context()。这样用户断开连接后上游请求也能尽快取消避免无意义地继续消耗资源。第三超时一定要设置合理。AI 请求通常比普通接口慢但也不能无限等下去。比较常见的写法是给每次调用包一层 timeoutctx, cancel : context.WithTimeout(c.Request.Context(), cfg.RequestTimeout) defer cancel()如果你使用自定义 HTTP Client还需要配置连接池、空闲连接数和超时时间。否则在高并发下频繁建连性能和稳定性都会受到影响。实现 Gin Chat 接口Go 调用 Claude API 示例对外接口可以先设计成POST /api/v1/chat请求体大概长这样{ messages: [ {role: user, content: 用 Go 写一个 Gin 路由示例} ], max_tokens: 1024, temperature: 0.7 }核心流程并不复杂Handler 绑定请求参数Service 把它转换成 Claude Messages API 需要的结构Client 调用上游最后再返回统一格式的 JSON。这里不太建议直接把上游原始响应透传给前端。更好的做法是封装成网关自己的响应格式{ request_id: gw_123456, model: claude-xxx, content: 这里是模型输出, usage: { input_tokens: 123, output_tokens: 456 } }这样前端和业务系统依赖的是网关协议而不是某个上游 SDK 的字段结构。以后上游字段变了网关内部适配一下就行。多轮对话怎么做无状态、Redis 会话与上下文裁剪单轮对话很容易做真正麻烦的是多轮对话。常见做法大致有三种。无状态网关模式客户端每次都提交完整的messages服务端只负责转发、鉴权、限流和记录日志。这种方式最简单适合 Web 前端自己维护上下文的场景。有状态会话模式客户端只传session_id和本轮输入服务端从 Redis 或数据库里取出历史消息拼接后再调用 Claude API。这种模式更适合多端同步、客服系统、企业内部助手等场景。摘要压缩模式长对话会持续消耗 token成本也会越来越高。超过一定长度后可以把较早的消息压缩成摘要再保留最近几轮原文。这样既能降低成本也能减少触发上下文上限的概率。不管采用哪种模式都应该限制最大上下文长度并由服务端统一注入 system prompt。普通用户不应该有权限直接覆盖系统指令。Gin 实现 Claude 流式响应SSE 转发实战对聊天类产品来说流式输出的体验通常比一次性返回好很多。可以单独提供一个接口POST /api/v1/chat/stream在 Gin 里做 SSE 转发时需要设置响应头c.Header(Content-Type, text/event-stream) c.Header(Cache-Control, no-cache) c.Header(Connection, keep-alive)上游每返回一个 chunk服务端就写入一段 SSE 数据并及时Flush。同时还要监听ctx.Done()。如果用户关闭页面或者网络已经断开服务端应该立刻取消上游 Claude stream避免 goroutine 和连接泄漏。流式接口的错误处理要提前想好。如果响应还没开始可以返回标准 JSON 错误但如果已经开始输出就只能通过 SSE event 发送错误比如event: error然后让前端结束渲染。高并发网关治理限流、并发控制、重试和熔断Go 和 Gin 的性能确实不错但不能把「高并发」理解成无限放量。Claude API 是外部上游服务真正的瓶颈往往在上游延迟、额度限制和网络稳定性上。一般建议至少做两层控制。第一层是 QPS 限流。可以用rate.Limiter控制全局请求速率也可以按业务方分别控制。第二层是最大并发控制。可以用 semaphore 防止瞬时请求把上游连接和本机资源打满select { case sem - struct{}{}: defer func() { -sem }() case -ctx.Done(): return ctx.Err() }错误处理也要分清楚哪些能重试哪些不能重试上游错误网关状态码是否可重试处理建议invalid_request400否检查请求参数authentication_error502/500否检查服务端 API Keyrate_limit_error429是限流或退避重试500/529 overloaded503是熔断、重试或降级context deadline exceeded504是优化超时配置和请求大小重试要谨慎尤其是流式响应和非幂等业务。通常只对短暂网络错误、429、部分 5xx 做指数退避并且一定要设置最大重试次数不能一直重试下去。统一错误码与日志追踪网关不应该把上游错误原样暴露给用户。更合适的方式是返回统一错误结构{ code: CLAUDE_RATE_LIMITED, message: Claude API rate limit exceeded, request_id: gw_123456, retryable: true }日志里至少要记录这些信息request_idapp_id 或 tenant_id模型名称HTTP 状态码上游耗时input_tokens 和 output_tokens是否命中限流、超时或重试。需要特别注意的是不要在日志里记录完整 API Key、业务 token、敏感 prompt 或隐私数据。生产环境最好做采样、脱敏和字段过滤。安全设计API Key 保护、业务鉴权与请求限制Gin Claude API 网关的安全边界一定要清楚上游 Claude API Key 只属于服务端前端最多只能拿业务 token。Auth Middleware 可以校验类似这样的请求头Authorization: Bearer business-token不同业务 token 可以绑定不同额度、模型权限和限流策略。如果是公开 Web 页面还要配合 CORS 白名单、请求体大小限制、IP 风控、验证码等措施。Prompt 注入也不能忽略。服务端 system prompt 应该和用户输入分离不能允许普通用户通过参数直接覆盖。对于敏感业务还可以增加输出审计、关键词过滤甚至人工复核流程。成本控制max_tokens、模型路由与用量统计AI 网关必须关注成本。每次请求都应该设置max_tokens防止模型输出失控。对于特别长的输入可以在进入 Claude API 之前做长度校验、截断、摘要必要时直接拒绝请求。模型路由可以按照任务复杂度来设计简单分类、改写、摘要可以使用成本较低的模型复杂推理、代码分析、长上下文任务再使用能力更强的模型不同业务方可以配置不同的模型白名单和每日额度。响应头里也可以返回一些用量信息方便前端或调用方排查问题X-Request-ID: gw_xxx X-Model: claude-xxx X-Input-Tokens: 1234 X-Output-Tokens: 567如果使用第三方兼容接入服务比如 ClaudeAPI也要以平台实际返回字段和计费说明为准。不要在代码或文档里假设固定价格、固定额度避免后面维护时出问题。本地运行、curl 测试与 Docker 部署本地运行可以直接执行go run ./cmd/server健康检查接口建议保留一个GET /healthz用 curl 测试时可以这样请求curl -X POST http://localhost:8080/api/v1/chat \ -H Authorization: Bearer test-token \ -H Content-Type: application/json \ -d {messages:[{role:user,content:解释一下 Gin middleware}],max_tokens:512}Dockerfile 可以采用多阶段构建。生产环境里通过docker run -e或 Kubernetes Secret 注入 API Keydocker build -t gin-claude-gateway . docker run -p 8080:8080 \ -e ANTHROPIC_API_KEYsk-ant-xxx \ -e CLAUDE_MODELclaude-xxx \ gin-claude-gateway不要把.env打进镜像也不要把它提交到 Git 仓库。这一点看似基础但线上事故里其实很常见。压测与性能优化建议可以用hey或wrk做压测。不过要注意真实 Claude API 调用会受到上游限额、网络延迟和模型生成速度影响所以压测结果不能简单理解成固定性能承诺。示例命令如下hey -n 1000 -c 50 -m POST \ -H Authorization: Bearer test-token \ -H Content-Type: application/json \ -d {messages:[{role:user,content:hello}],max_tokens:128} \ http://localhost:8080/api/v1/chat压测时重点看 P95、P99、错误率、429 数量、超时数量和上游平均耗时。流式响应会占用更长时间的连接所以不能只盯着 QPS还要关注并发连接数、内存、goroutine 数量以及客户端断开后资源是否能正常释放。常见问题 FAQGin 可以直接调用 Claude API 吗可以。Gin 本质上就是 HTTP Web 框架在 Handler 里当然可以调用 Claude SDK 或 HTTP API。不过生产环境更建议通过 Service 和 Client 分层封装不要把上游调用逻辑全堆在 Handler 里。Go 调用 Claude API 用哪个 SDK优先考虑 Anthropic 官方 Go SDK。如果需要兼容 Bedrock、Vertex 或第三方兼容平台可以在网关内部抽象一个LLMClient接口再根据实际场景替换具体实现。Claude API Key 应该放前端还是后端应该放后端。前端只调用 Gin 网关并使用业务 token 做鉴权。上游 API Key 应该从环境变量、Secret Manager 或 Kubernetes Secret 中读取。Gin 如何实现 Claude 流式输出可以使用 SSE 或 fetch stream。Gin 侧设置text/event-stream逐块写入数据并 Flush同时监听请求上下文的取消信号。客户端断开后服务端应立即停止上游 stream。Claude API 返回 429 怎么办这通常说明触发了限流或额度约束。网关应该返回统一错误码必要时做指数退避重试同时降低调用方 QPS。不要无限重试否则只会把问题放大。如何保存 Claude 多轮对话上下文小项目可以让客户端每次传完整 messages中大型项目更建议用 Redis 或数据库保存会话历史并对长上下文做裁剪或摘要压缩。Go AI 网关和普通后端接口有什么区别普通接口更多关注业务数据的读写AI 网关除了这些还要处理模型路由、prompt 模板、token 成本、流式响应、上游限流、输出审计以及多供应商扩展等问题。如何兼容 OpenAI、Gemini 或 Bedrock不要让 Handler 直接依赖某个具体 SDK。可以定义统一的LLMClient接口把 Claude、OpenAI、Gemini、Bedrock 分别做成不同实现再通过配置或路由策略选择。为什么本地能调用部署后却超时常见原因包括出口网络不通、代理配置缺失、容器环境变量没注入、服务端超时时间太短、上游限流或者云平台安全组限制。排查时可以结合 request_id、上游耗时和错误日志一起看。如何统计 Claude API token 成本从上游响应里读取 usage 字段然后按 app、tenant、user、model 和日期聚合。再结合实际计费规则做成本核算。具体价格和额度要以官方或接入平台的最新说明为准。总结从 Go SDK Demo 到生产级 AI 网关Go 调用 Claude API 只是第一步。一个真正能上线的 Gin Claude API 网关还需要同时解决安全、鉴权、限流、并发控制、流式转发、统一错误码、日志追踪、token 成本和部署运维这些问题。比较稳妥的落地路径是先用官方 SDK 打通/api/v1/chat然后补上 SSE 流式接口、限流和统一错误码再往后加入会话管理、模型路由、成本统计和多供应商扩展。这样既能快速上线也不会把系统困在一个简单 demo 结构里。