JetBrains/go-modern-guidelines:AI 写 Go 代码总翻车?JetBrains 官方“急救包”来了 🚑

想象一下这个场景:你正美滋滋地在 Cursor 里敲下提示词,让 AI 助手帮你写一个 Web 服务。几秒钟后,代码生成完毕——启动、测试、一切正常。你心满意足地点了点头。

直到三周后,你打开项目准备加需求,看到那令人窒息的 var globalDB *sql.DB、塞满 interface{} 的函数签名,以及用 sync.Mutex 手搓的并发控制……你忽然明白了一个道理:AI 写的代码,能跑和能维护是两回事。

这恰恰是 JetBrains/go-modern-guidelines 想要解决的问题。这个由 JetBrains 官方在 2026 年 8 月底发布的项目,一句话概括就是:给 AI 编码代理看的“Go 技术红宝书” 📖。

AI 时代的 Go 开发:为何如此拧巴?

Go 语言的设计哲学向来是 “少即是多”。它不像 Java 那样推崇繁复的设计模式,也不像 Python 那样追求极致的动态灵活。用 gofmt 统一格式,用 context.Context 串联调用链,用 errors.Is 做错误链比对——这些都是 Go 社区多年沉淀下来的“最佳实践共识”。

但问题来了:大语言模型在训练时“吞”了 GitHub 上海量的 Go 代码,其中既有高质量的 kubernetes 源码,也有大量从 2014 年就没人维护的“祖传项目”(比如那些还在用 ioutil.ReadAll 的代码)。AI 没有人类工程师的“代码审美”,它只会做一件事:根据概率补全最可能的 token。于是,你经常看到 AI 生成出令人哭笑不得的代码:


// AI 生成的“老古董”风格
func GetUser(id string) (interface{}, error) {
    rows, err := db.Query("SELECT name, age FROM users WHERE id = ?", id)
    if err != nil {
        return nil, err
    }
    defer rows.Close()
    for rows.Next() {
        var name string
        var age int
        rows.Scan(&name, &age)
        return User{Name: name, Age: age}, nil
    }
    return nil, errors.New("not found")
}

这段代码全对吗?对。能跑吗?能。但这绝不是 2026 年的 Go 风格。缺少 context 透传、用了空接口、错误处理用了字符串哨兵错误……而这些恰恰是 JetBrains 这个新项目要消灭的目标。

与同类方案对比:它不是一份“死”文档 🆚

市面上写给 人类 的 Go 代码规范已经不少了,最著名的当属 Google Go Style Guide 和社区硬通货 golang-standards/project-layout。但 go-modern-guidelines 的定位截然不同:它是一份“机器可读”的工程规范

对比维度Google Style GuideEffective Go(官方文档)JetBrains/go-modern-guidelines
目标读者AI 代理(及人类)
组织形式散文+代码片段散文紧凑的 Markdown / Agent 提示语
可操作性模糊规则,凭经验哲学性讨论明确的是非判断
更新速度更慢持续更新

打个比方:Google 的规范像大学课程教材,告诉你“为什么”;而这个项目更像一本战术手册,直接告诉 AI “该怎么做”。它的每个条目都短小精悍,比如:


### 使用 context.Context 作为第一个参数
- 不要:让函数内部创建 context.Background()
- 必须:让调用方传递 context 负责取消/超时控制

这种结构让 AI 大模型更容易“吞咽”。毕竟,模型做 few-shot(少样本学习)时,简洁明确的指令比长篇大论有效得多。

探秘技术核心:这些规则直击 AI 痛点 🧠

浏览一遍 go-modern-guidelines 的仓库,你会感觉 JetBrains 的工程师们像是把 Go 的“屠龙刀”磨了一遍又一遍。我挑几个最具代表性的规则来拆解:

1. 配置管理:拒绝全局变量

AI 特别爱写这种代码:var config = loadConfig()。在 main 函数以外的地方初始化配置,导致测试时无法替换依赖。规范里明确要求:配置应该在 main() 的最开始加载,然后显式传递给各个组件。这就强制了依赖注入的上层设计,虽然略显啰嗦,却让架构清晰得像是被 go vet 清洗过。

2. 泛型的高性价比用法

Go 1.18 引入泛型后,很多人第一反应就是“我全都要”。但实际上过度使用泛型反而让代码变成天书。这个项目给出了非常实际的建议:API 设计中优先考虑泛型方法,而非泛型结构体。好比说 map[string]V 也许比 map[K]V 更好用——因为大多数时候 Key 就是字符串。


// ✅ 合理的泛型使用
func MapValues[K comparable, V any](m map[K]V) []V {
    out := make([]V, 0, len(m))
    for _, v := range m {
        out = append(out, v)
    }
    return out
}

// ❌ 过度设计
type Resource[T any, R any] struct { ... }

3. 并发:让死锁远离 AI

AI 在处理并发时总是“用力过猛”。明明一个 sync.Map 或者 atomic.Int64 就能解决的事,它非要写个带 chan struct{} 的复杂 goroutine 管理器。guidelines 里给出了标准化建议:对于简单的计数器,直接用原子操作;对于极简缓存,用 sync.Map 而不是造轮子。这些建议直击“代码可读性”的命脉。

把它变成 AI Agent 的“出厂设定” 🛠️

这个项目最有价值的应用方式,是直接接入到你的 AI 编码工作流里。JetBrains 的构想其实很有野心:它希望能成为 Go 社区关于现代化工程实践的统一标准数据集,进而被各家 AI 工具消费。

目前最流行的玩法有两种:

  • 直接喂给 AI 作为系统提示:把项目里边的 markdown 文件做成 AGENTS.md 放入项目根目录,像 Cursor、GitHub Copilot Workspace、Tabby 都会自动读取。在 JetBrains 自家的 AI Assistant(现在已经和 GigaCode 深度融合)中,这种行为更是被深度优化。

# 快速体验:克隆项目并手动加入规则
git clone https://github.com/JetBrains/go-modern-guidelines.git
cat go-modern-guidelines/rules/*.md > /你的项目/AGENTS.md
  • 集成到 CI 流水线:AI 把 PR 提交上来后,用这个规则库做一次代码风格审查。不但查 gofmt,还要查“AI 味”很重的代码模式。JetBrains 在自己的代码审查服务 Qodana 中已经内置了部分规则,并开放了扩展点。

适用边界:它不是银弹,但是最佳画框 🖼️

任何工具都有局限。go-modern-guidelines 主要聚焦在工程最佳实践API 设计层面,它基本不涉及具体业务架构(比如微服务拆分、事件溯源范式)。如果你的团队写 Go 的方式完全是特立独行的(比如你们公司内部约定把所有文件放在 pkg/ 下还爱用包级错误变量),那么这份官方规范可能未必百分之百合适。

但你可以 fork 一份,裁剪成自己的团队规范。它的 Markdown 结构足够简洁,哪怕不是 AI,招聘一个新同学进来,让他读两小时这个规范,也能快速适应团队节奏。

在 2026 年的今天,AI 辅助编程已经成为所有开发者的“标准外挂”。但外挂的质量取决于它的数据。JetBrains 的这份 go-modern-guidelines,本质上是在帮我们给 AI 补上“现代 Go 工程学”这一课。

💡 我的建议:把这个项目加入你的 AI 提示词库根目录。它不一定能让你写出惊艳的架构,但绝对能帮你挡住大多数“能跑但没法维护”的尴尬。

也许有一天,AI 生成的代码会和资深工程师写的毫无二致。而那一天到来之前,我们需要像 go-modern-guidelines 这样的“标准答案集”,一点一点把 AI 拉回正轨。🚂