今天用 OpenCode 写一个命令行工具:网站健康检查器。给它一组网址,它能并发检测每个网站的 HTTP 状态码和响应时间,快速告诉你哪些网站挂了、哪些正常。
技术栈:Go 语言原生 net/http + sync 并发。最终代码约 90 行,编译后一个二进制文件随处运行。
首先确保你安装了 OpenCode 和 Go(1.18+)。打开终端,进入工作目录后启动 OpenCode:
opencode
> 如果你还没安装 OpenCode,参考官网文档:npm install -g opencode,然后配置好 API Key 即可使用。
我直接告诉 OpenCode 我的需求,不需要写任何代码:
我对 OpenCode 说:
> 用 Go 写一个命令行网站健康检查器,叫 urlcheck。要求:
> 1. 并发检查多个 URL 的 HTTP 状态码和响应时间
> 2. 支持从文件读取 URL 列表(-f 参数)
> 3. 支持自定义超时时间(-t 参数)
> 4. 输出要有色彩感——成功绿色、失败红色
OpenCode 秒懂了意图,它先创建了 main.go,把项目骨架搭好:main 函数、flag 解析、goroutine 并发、channel 收集结果。10 秒不到,一个 80 行的初版就出来了。
关键要点: 描述需求时要把"做什么"说清楚,OpenCode 会自动补齐"怎么做"。上面那句提示词包含了功能点、参数名、输出要求,足够让 AI 生成高质量初版。
测试时我发现输入 baidu.com 会报错,因为缺少 http:// 前缀。我对 OpenCode 说:
我对 OpenCode 说:
> checkURL 函数里,如果 URL 没有 http:// 或 https:// 前缀,自动在前面加上 https://
OpenCode 响应: 它在 checkURL 函数开头插入了一个判断:
if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
url = "https://" + url
}
就加了三行代码,问题解决。这就是用 AI 编程的日常——发现小问题,一句话修复,不用自己翻文档。
初版功能跑通了,但输出体验一般。我继续提要求:
我对 OpenCode 说:
> 在开始检查前打印"正在检查 N 个网站...",结束时打印"结果: X/N 个网站正常"。另外在输出结果前加一个空行,让输出更清晰。
OpenCode 响应: 它在 goroutine 启动前加了 fmt.Printf("正在检查 %d 个网站...\n\n", len(urls)),在 channel 消费循环里用 success 变量计数,最后加了一行汇总。
这种体验优化在传统开发里属于"懒得改的小细节",但有了 OpenCode,改起来毫无心理负担——说一句话的事。
代码写完了,我对 OpenCode 说:
我对 OpenCode 说:
> 编译运行一下,试试检查百度、GitHub 和谷歌
OpenCode 自动执行了 go build 和测试命令,输出大致如下:
正在检查 3 个网站...
[正常] https://www.baidu.com
状态码: 200 (耗时 0.23s)
[正常] https://github.com
状态码: 200 (耗时 1.12s)
[失败] https://www.google.com
错误: context deadline exceeded (耗时 10.00s)
结果: 2/3 个网站正常
完美运行——不用我手动敲编译命令,全程自然语言对话完成。
package main
import (
"bufio"
"flag"
"fmt"
"net/http"
"os"
"strings"
"sync"
"time"
)
type Result struct {
URL string
Code int
Elapsed time.Duration
Err error
}
func checkURL(url string, timeout time.Duration) Result {
if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
url = "https://" + url
}
client := http.Client{Timeout: timeout}
start := time.Now()
resp, err := client.Get(url)
elapsed := time.Since(start)
if err != nil {
return Result{URL: url, Elapsed: elapsed, Err: err}
}
defer resp.Body.Close()
return Result{URL: url, Code: resp.StatusCode, Elapsed: elapsed}
}
func main() {
fileFlag := flag.String("f", "", "从文件读取 URL 列表(每行一个)")
timeoutFlag := flag.Int("t", 10, "超时时间(秒)")
flag.Parse()
timeout := time.Duration(*timeoutFlag) * time.Second
var urls []string
if *fileFlag != "" {
f, err := os.Open(*fileFlag)
if err != nil {
fmt.Printf("无法打开文件: %v\n", err)
os.Exit(1)
}
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if line != "" && !strings.HasPrefix(line, "#") {
urls = append(urls, line)
}
}
}
urls = append(urls, flag.Args()...)
if len(urls) == 0 {
fmt.Println("用法: urlcheck [选项] <url1> [url2] ...")
fmt.Println(" urlcheck -f urls.txt")
flag.PrintDefaults()
os.Exit(1)
}
var wg sync.WaitGroup
results := make(chan Result, len(urls))
fmt.Printf("正在检查 %d 个网站...\n\n", len(urls))
for _, url := range urls {
wg.Add(1)
go func(u string) {
defer wg.Done()
results <- checkURL(u, timeout)
}(url)
}
go func() {
wg.Wait()
close(results)
}()
success := 0
for r := range results {
dur := fmt.Sprintf("%.2fs", r.Elapsed.Seconds())
if r.Err != nil {
fmt.Printf(" [失败] %s\n 错误: %v (耗时 %s)\n", r.URL, r.Err, dur)
} else if r.Code >= 200 && r.Code < 400 {
fmt.Printf(" [正常] %s\n 状态码: %d (耗时 %s)\n", r.URL, r.Code, dur)
success++
} else {
fmt.Printf(" [异常] %s\n 状态码: %d (耗时 %s)\n", r.URL, r.Code, dur)
}
}
fmt.Printf("\n结果: %d/%d 个网站正常\n", success, len(urls))
}
这个工具如果手写,从查 net/http 文档到调并发逻辑,可能要 15-20 分钟。用 OpenCode,我只说了 4 句话就得到了一个可运行的工具:
"用 Go 写一个网站健康检查器"——生成骨架
"URL 没前缀自动加 https"——修复边界情况
"加进度提示和统计"——优化体验
"编译运行测试一下"——验证结果
全程没写一行 Go 代码,只是在对话。AI 编程的本质不是"让 AI 替程序员写代码",而是让程序员用自然语言描述意图,把精力放在"要做什么"而非"怎么做"上。90 行并发工具,4 分钟搞定,这就是 OpenCode 带来的效率质变。