
使用Scala Play框架構建REST API
本文將帶你用 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!