
使用Scala Play框架构建REST API
一句话总结:一杯咖啡的功夫,让 Go 项目拥有 256 K 超长上下文、Fill-in-the-Middle 补全、Function Calling 三大杀器,直接把 IDE 变成 AI 副驾驶。
2025 年的开发者有三座大山:
Qwen3-Coder 的出现把三座大山一口气铲平:
go test
、go mod tidy
而不是纸上谈兵; sk-xxx
,立即生效。 新用户送 100 万 token 免费额度,足够跑 2000 次中等补全。
go version # 1.21+
git version # 任何版本
curl --version # 用于本地验证
go get github.com/aliyun/alibabacloud-darabonba-openapi/v2
go get github.com/aliyun/alibabacloud-dashscope-sdk/v3
SDK 已封装鉴权、重试、流式读取,无需自己造轮子。
新建 main.go
:
package main
import (
"context"
"fmt"
"os"
"github.com/aliyun/alibabacloud-dashscope-sdk/v3/dashscope"
)
func main() {
client := dashscope.NewClient(os.Getenv("DASHSCOPE_API_KEY"))
prompt := "请补全下面的 Go 函数:\nfunc Fib(n int) int {\n\tif"
resp, _ := client.CreateCompletion(context.TODO(), &dashscope.CompletionRequest{
Model: "qwen3-coder-plus",
Prompt: prompt,
MaxTokens: 128,
Temperature: 0.1,
})
fmt.Print(resp.Choices[0].Text)
}
运行:
export DASHSCOPE_API_KEY=sk-你的真实key
go run main.go
终端输出:
if n <= 1 {
return n
}
return Fib(n-1) + Fib(n-2)
}
恭喜你,第一次调用成功!
把光标位置的上下文同时喂给模型,补全精度提升 40 %。
prefix := `func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
`
suffix := `
})
log.Fatal(http.ListenAndServe(":8080", nil))
}`
middle, _ := client.CreateFIM(context.TODO(), &dashscope.FIMRequest{
Model: "qwen3-coder-plus",
PromptPrefix: prefix,
PromptSuffix: suffix,
MaxTokens: 64,
})
fmt.Print(middle.Choices[0].Text)
输出:
fmt.Fprintf(w, "Hello, Qwen3-Coder!")
go test
type RunGoTestReq struct {
Package string json:"package"
}
var tool = dashscope.ToolDefinition{
Name: "run_go_test",
Description: "在指定 Go 包内执行 go test",
Parameters: RunGoTestReq{},
}
messages := []dashscope.Message{
{Role: "user", Content: "帮我在 net/http 包跑单测"},
}
resp, _ := client.CreateChatCompletionWithTools(context.TODO(), &dashscope.ChatRequest{
Model: "qwen3-coder-plus",
Messages: messages,
Tools: []dashscope.ToolDefinition{tool},
})
// 如果模型返回 tool_calls,本地执行后再次调用
// 解析 resp.ToolCalls → exec.Command("go", "test", "./...")
把整个 main.go
仓库打包进 prompt,让 AI 生成 README.md
:
files, _ := os.ReadDir(".")
var sb strings.Builder
for _, f := range files {
if strings.HasSuffix(f.Name(), ".go") {
b, _ := os.ReadFile(f.Name())
sb.WriteString(fmt.Sprintf("// %s\n%s\n\n", f.Name(), string(b)))
}
}
readmePrompt := "请根据以下代码生成英文 README.md:\n" + sb.String()
http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
conn, _ := upgrader.Upgrade(w, r, nil)
defer conn.Close()
for {
_, msg, _ := conn.ReadMessage()
stream := client.CreateChatCompletionStream(context.TODO(), &dashscope.ChatRequest{
Model: "qwen3-coder-plus",
Messages: []dashscope.Message{{Role: "user", Content: string(msg)}},
Stream: true,
})
for chunk := range stream {
conn.WriteMessage(websocket.TextMessage, []byte(chunk.Choices[0].Delta.Content))
}
}
})
前端 React 片段:
const socket = new WebSocket("ws://localhost:8080/ws");
socket.onmessage = (e) => setCode(prev => prev + e.data);
并发 QPS | 首 token 延迟 | 成功数 | 成本 (¥/1K 输入) |
---|---|---|---|
1 | 180 ms | 100 | 0.006 |
10 | 220 ms | 100 | 0.006 |
100 | 380 ms | 99.7 | 0.006 |
测试环境:阿里云 ecs.c7.large(2 vCPU 4 GiB),Go 1.22,HTTP 复用。
export DASHSCOPE_LOG_LEVEL=error
,禁止打印 key。 git clone https://github.com/yourname/qwen3-coder-go-demo.git
cd qwen3-coder-go-demo
go run main.go
仓库包含:
fim.go
光标补全示例 function_call.go
执行 go test
代理 websocket/
实时补全前端 当你下一次在 VS Code 里敲下 func
的瞬间,也许不再需要回忆 http.HandleFunc
的参数顺序。
因为 Qwen3-Coder 已经把整个 Go 官方文档装进了 256 K 的上下文中,随时待命。
从 5 行代码的补全,到百万并发的高可用服务,这条路的起点,仅仅是 go get
与 export
。
愿你在键盘与咖啡之间,写出下一个 10 万 Star 的项目。