
使用Scala Play框架构建REST API
“2025 年 8 月,Anthropic 正式放出 Claude 4.1 Opus——200 K 超大上下文、原生 Function Calling、SWE-bench 74.5 % 的代码能力,一举刷新大模型编程榜单。
本文将带你用 Go 语言在 15 分钟 内完成接入,并用 30 行代码 跑通一个生产级对话微服务。
维度 | Claude 4.1 Opus | GPT-4o | Gemini-1.5-Pro |
---|---|---|---|
最大上下文 | 200 K | 128 K | 200 K |
SWE-bench | 74.5 % | 67 % | 65 % |
Function Calling | ✅ 原生 | ✅ | ✅ |
支持图像 | ✅ | ✅ | ✅ |
价格(in/out) | $15 / $75 | $5 / $15 | $3.5 / $10.5 |
国内直连 | ✅ laozhang.ai 中转 | ❌ | ❌ |
一句话:代码能力最强、上下文最长、国内有高速中转,并且 限时送 10 元代金券 。
sk-ant-
JnIT
再返 10 % go version # 需要 ≥1.20
go mod init claude-demo
go get github.com/anthropics/anthropic-sdk-go
// main.go
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/anthropics/anthropic-sdk-go"
)
func main() {
client := anthropic.NewClient(os.Getenv("CLAUDE_API_KEY"))
resp, err := client.Messages.New(context.Background(), anthropic.MessageNewParams{
Model: anthropic.F("claude-opus-4-1-20250805"),
MaxTokens: anthropic.Int(128),
Messages: anthropic.F([]anthropic.MessageParam{
{Role: anthropic.F(anthropic.MessageParamRoleUser),
Content: anthropic.F([]anthropic.ContentBlockParamUnion{
anthropic.TextBlockParam{Type: anthropic.F(anthropic.TextBlockParamTypeText),
Text: anthropic.F("用 Go 写快速排序"),
},
})},
}),
})
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.Content[0].Text)
}
运行:
export CLAUDE_API_KEY=sk-xxx
go run main.go
看到快速排序代码即成功!
// chat.go
package main
import (
"bufio"
"context"
"fmt"
"os"
"github.com/anthropics/anthropic-sdk-go"
)
func main() {
client := anthropic.NewClient(os.Getenv("CLAUDE_API_KEY"))
reader := bufio.NewReader(os.Stdin)
fmt.Print("👋 说点什么:")
for {
text, _ := reader.ReadString('\n')
resp, _ := client.Messages.New(context.Background(), anthropic.MessageNewParams{
Model: anthropic.F("claude-opus-4-1-20250805"),
MaxTokens: anthropic.Int(512),
Messages: anthropic.F([]anthropic.MessageParam{
{Role: anthropic.F(anthropic.MessageParamRoleUser),
Content: anthropic.F([]anthropic.ContentBlockParamUnion{
anthropic.TextBlockParam{Type: anthropic.F(anthropic.TextBlockParamTypeText),
Text: anthropic.F(text),
},
})},
}),
})
fmt.Println("🤖 Claude:", resp.Content[0].Text)
}
}
// stream.go
r := gin.Default()
r.GET("/chat", func(c *gin.Context) {
c.Header("Content-Type", "text/event-stream")
c.Header("Cache-Control", "no-cache")
c.Header("Connection", "keep-alive")
ctx := context.Background()
stream := client.Messages.NewStreaming(ctx, anthropic.MessageNewParams{
Model: anthropic.F("claude-opus-4-1-20250805"),
MaxTokens: anthropic.Int(1024),
Messages: anthropic.F([]anthropic.MessageParam{{Role: anthropic.F(anthropic.MessageParamRoleUser), Content: anthropic.F([]anthropic.ContentBlockParamUnion{anthropic.TextBlockParam{Type: anthropic.F(anthropic.TextBlockParamTypeText), Text: anthropic.F(c.Query("q"))}})}}),
})
for stream.Next() {
if delta, ok := stream.Current().(*anthropic.ContentBlockDeltaEvent); ok {
fmt.Fprintf(c.Writer, "data: %s\n\n", delta.Delta.Text)
c.Writer.Flush()
}
}
})
<div id="answer"></div>
<script>
const es = new EventSource("/chat?q=写一段Go的并发安全Map");
es.onmessage = e => document.getElementById("answer").innerHTML += e.data;
</script>
tools := []anthropic.ToolParam{{
Type: anthropic.F(anthropic.ToolTypeFunction),
Function: anthropic.F(anthropic.FunctionDefinitionParam{
Name: anthropic.F("get_weather"),
Description: anthropic.F("获取城市天气"),
Parameters: anthropic.F(map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"city": map[string]string{"type": "string"},
},
"required": []string{"city"},
}),
}),
}}
场景:把 180 K 的 Go 仓库一次性塞给模型让它加单测。
b, _ := os.ReadFile("project.zip") // 压缩包
resp, _ := client.Messages.New(ctx, anthropic.MessageNewParams{
Model: anthropic.F("claude-opus-4-1-20250805"),
MaxTokens: anthropic.Int(4000),
Messages: anthropic.F([]anthropic.MessageParam{
{Role: anthropic.F(anthropic.MessageParamRoleUser),
Content: anthropic.F([]anthropic.ContentBlockParamUnion{
anthropic.TextBlockParam{Type: anthropic.F(anthropic.TextBlockParamTypeText),
Text: anthropic.F("请为以下项目补全单元测试,使用标准 testing 包:")},
anthropic.DocumentBlockParam{
Type: anthropic.F(anthropic.DocumentBlockParamTypeDocument),
Source: anthropic.F(anthropic.DocumentBlockParamSource{
Type: anthropic.F(anthropic.DocumentSourceTypeBase64),
MediaType: anthropic.F("application/zip"),
Data: anthropic.F(base64.StdEncoding.EncodeToString(b)),
}),
},
})},
}),
})
fmt.Println(resp.Content[0].Text)
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o claude-svc ./cmd/server
FROM gcr.io/distroless/static
COPY --from=builder /app/claude-svc /
ENV PORT=8080
EXPOSE 8080
ENTRYPOINT ["/claude-svc"]
version: "3.9"
services:
claude-svc:
build: .
environment:
CLAUDE_API_KEY: ${CLAUDE_API_KEY}
ports:
- "8080:8080"
redis:
image: redis:7-alpine
一键启动:
docker compose up -d
优化手段 | 节省比例 | 实现成本 |
---|---|---|
Redis 缓存 FAQ | 85 % | 5 行代码 |
Prompt 模板压缩 | 20 % | 正则去空格 |
批处理 10 条 | 50 % | 官方支持 |
示例:批量问答
batch := []anthropic.BatchedMessageParam{{/* ... */}}
client.Messages.NewBatch(ctx, batch)
错误码 | 场景 | 解决 |
---|---|---|
429 |
限流 | 指数退避重试 |
400 |
context 过长 | 裁剪或切分 |
401 |
Key 无效 | 检查 laozhang.ai 余额 |
日志:使用 zerolog
JSON 输出 + Loki 可视化。
log.Info().
Str("model", "claude-opus-4-1").
Int("input_tokens", usage.InputTokens).
Int("output_tokens", usage.OutputTokens).
Msg("claude_request")
.github/workflows/ai-review.yml
name: AI Review
on: [pull_request]
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with: { go-version: '1.22' }
- run: go run ./cmd/review --pr=${{ github.event.number }}
env:
CLAUDE_API_KEY: ${{ secrets.CLAUDE_API_KEY }}
cmd/review/main.go
读取 diff → 调 Claude → 在 PR 评论里贴出改进建议。
官方文档:Anthropic Docs
国内中转:laozhang.ai
Happy Hacking!