项目结构规范与 .env 管理:让 ADK Go 项目更健壮
项目结构规范与 .env 管理:让 ADK Go 项目从"能跑"到"可维护"
个人项目可以随心所欲,但工程化项目必须讲究规范。在带领团队落地多个 ADK Go 生产项目后,我深刻体会到:前期多花 30 分钟建立规范,后期能节省数小时的排障和沟通成本。本章将从目录结构、敏感信息管理、多环境配置、团队协作四个维度,给出一套经过生产验证的 ADK Go 项目组织方案。
标准 ADK Go 项目结构
一个工程化的 ADK Go 项目应该长这样:
my_agent/
├── cmd/
│ └── agent/
│ └── main.go # 应用程序入口(遵循 Go 标准项目布局)
├── internal/
│ ├── agent/
│ │ └── time_agent.go # Agent 定义与配置
│ ├── config/
│ │ └── config.go # 配置加载与校验
│ └── tools/
│ └── custom_tools.go # 自定义工具集
├── pkg/
│ └── utils/
│ └── helpers.go # 可复用的公共工具函数
├── .env # 本地环境变量(绝不提交 git)
├── .env.example # 环境变量模板(提交 git)
├── .env.staging # Staging 环境配置(按需)
├── .gitignore
├── go.mod
├── go.sum
├── Makefile # 常用命令封装
└── README.md
为什么不是单文件结构?
官方 Quickstart 为了演示简洁,把所有代码放在 agent.go 中。但在实际工程中,这种写法很快会遇到瓶颈:
- 代码膨胀:当 Agent 数量增加到 5 个以上,单文件会超过 500 行,可读性急剧下降
- 测试困难:单文件结构难以编写单元测试
- 复用障碍:自定义 Tool 无法被其他项目引用
- 职责混乱:配置、业务逻辑、启动代码耦合在一起
遵循 Go Standard Project Layout 将代码按职责分层,是长期可维护的基础。
go.mod:模块初始化与依赖管理
初始化模块
cd my_agent
go mod init github.com/yourorg/my-agent
模块路径建议使用代码托管平台的完整路径(如 github.com/yourorg/my-agent),这样便于后续被其他项目引用或发布到内部私有仓库。
依赖管理最佳实践
运行 go mod tidy 后,生成的 go.mod 大致如下:
module github.com/yourorg/my-agent
go 1.24.4
require (
google.golang.org/adk v0.2.0
google.golang.org/genai v0.3.0
)
生产环境经验:
锁定主版本:在
go.mod中明确指定 ADK Go 的版本,不要依赖@latest。我们在一次版本升级中遇到过llmagent.Config结构体字段变更,导致编译失败。定期审计依赖:使用
go mod graph | grep检查间接依赖,确保没有引入已知漏洞的库:
go list -m -versions google.golang.org/adk # 查看可用版本
go mod why google.golang.org/genai # 查看为什么依赖这个包
- Vendor 策略:对于需要离线构建或长期存档的项目,考虑使用 vendor 模式:
go mod vendor # 将所有依赖复制到 vendor/ 目录
# 后续构建时加上 -mod=vendor 使用本地依赖
go build -mod=vendor ./cmd/agent
.env 与 .env.example:敏感信息分离策略
这是所有项目中最重要的规范,没有之一。API Key、数据库密码、私钥等敏感信息一旦泄露,后果可能是灾难性的。
核心原则
.env:存放真实值,绝不提交到版本控制.env.example:存放示例值和说明,必须提交到版本控制.env.*:按环境区分的配置文件,根据安全策略决定是否提交
.env.example 模板设计
一个好的模板不仅要列出变量名,还要说明每个变量的用途、格式要求和获取方式:
# ============================================
# ADK Go Agent 环境变量配置模板
# 复制本文件为 .env 并填入真实值
# ============================================
# Google Gemini API Key(必填)
# 获取地址:https://aistudio.google.com/app/apikey
# 注意:每个 Key 有配额限制,生产环境建议使用 Key Pool
export GOOGLE_API_KEY="your-api-key-here"
# 模型选择(可选,默认 gemini-2.0-flash)
# 可选值:gemini-2.0-flash, gemini-2.0-pro, gemini-2.0-flash-exp
# 开发环境建议用 flash(快且便宜),生产复杂任务可切换到 pro
export GEMINI_MODEL="gemini-2.0-flash"
# 日志级别(可选,默认 info)
# 可选值:debug, info, warn, error
export LOG_LEVEL="info"
# 代理配置(中国大陆等受限网络环境必填)
# 格式:http://host:port 或 socks5://host:port
export HTTPS_PROXY=""
# ADK 运行模式(可选,默认 cli)
# 可选值:cli, web
export ADK_MODE="cli"
# Web 模式端口(可选,默认 8080)
export ADK_PORT="8080"
配置加载代码
在 internal/config/config.go 中封装配置加载逻辑:
package config
import (
"fmt"
"os"
"strconv"
)
// Config 保存应用的所有配置项
type Config struct {
APIKey string
Model string
LogLevel string
Proxy string
Mode string
Port int
}
// Load 从环境变量加载配置,并进行必要的校验
func Load() (*Config, error) {
apiKey := os.Getenv("GOOGLE_API_KEY")
if apiKey == "" {
return nil, fmt.Errorf("GOOGLE_API_KEY is required. " +
"Copy .env.example to .env and fill in your API key")
}
port, _ := strconv.Atoi(getEnv("ADK_PORT", "8080"))
return &Config{
APIKey: apiKey,
Model: getEnv("GEMINI_MODEL", "gemini-2.0-flash"),
LogLevel: getEnv("LOG_LEVEL", "info"),
Proxy: os.Getenv("HTTPS_PROXY"),
Mode: getEnv("ADK_MODE", "cli"),
Port: port,
}, nil
}
func getEnv(key, defaultValue string) string {
if v := os.Getenv(key); v != "" {
return v
}
return defaultValue
}
.gitignore 配置
# ============================================
# 敏感信息(绝对不要提交)
# ============================================
.env
.env.local
.env.*.local
*.pem
*.key
# ============================================
# Go 构建产物
# ============================================
bin/
dist/
*.exe
*.dll
*.so
*.dylib
# ============================================
# 依赖管理(go.sum 建议提交,确保构建一致性)
# ============================================
# 注意:go.sum 包含依赖校验和,提交它可避免"在我机器上能跑"的问题
# 如果你坚持不提交 go.sum,取消下面这行的注释
# go.sum
# ============================================
# IDE 与编辑器
# ============================================
.idea/
.vscode/
*.swp
*.swo
*~
# ============================================
# 操作系统
# ============================================
.DS_Store
Thumbs.db
多环境配置:开发 / 测试 / 生产
实际项目中,不同环境往往需要不同的配置:开发环境用轻量级模型、开启 Debug 日志;生产环境用更强的模型、只记录 Error。
环境文件组织
my_agent/
├── .env # 本地开发(不提交 git,每个开发者独立)
├── .env.example # 共享模板(提交 git)
├── .env.staging # 预发布环境(可选,可提交 git 若不含敏感信息)
├── .env.production # 生产环境(不提交 git,由 CI/CD 或 Secret Manager 注入)
环境切换脚本
在 Makefile 中封装环境切换逻辑:
.PHONY: run run-staging run-prod dev staging prod
# 默认运行开发环境
dev:
@test -f .env || (echo "Error: .env not found. Run: cp .env.example .env" && exit 1)
@source .env && go run ./cmd/agent
# Staging 环境
staging:
@source .env.staging && go run ./cmd/agent
# 生产环境(仅用于验证配置,正式部署应使用构建产物)
prod:
@source .env.production && go run ./cmd/agent
# 构建二进制
build:
@go build -o bin/agent ./cmd/agent
# 运行测试
test:
@go test -v ./...
使用方式:
make dev # 开发环境
make staging # 预发布环境
make build # 编译二进制到 bin/agent
代码中的环境感知
package main
import (
"log"
"os"
"my_agent/internal/config"
)
func main() {
cfg, err := config.Load()
if err != nil {
log.Fatalf("Configuration error: %v", err)
}
// 根据环境调整行为
if cfg.Mode == "development" {
log.Println("Running in DEVELOPMENT mode")
// 开发环境特定逻辑:详细日志、模拟数据等
}
// ... 初始化 Agent
}
README.md:团队知识沉淀
README 不是写给机器的,是写给人的。一个好的 README 能让新成员在 10 分钟内跑起项目。
推荐结构
# My ADK Go Agent
## 项目简介
基于 Google ADK Go 构建的智能助手,支持时间查询、天气查询等功能。
## 前置要求
- Go 1.24.4+
- Google API Key([获取方式](https://aistudio.google.com/app/apikey))
- Make(可选,用于快捷命令)
## 快速开始
1. 克隆项目
2. 复制环境变量模板:`cp .env.example .env`,填入真实值
3. 安装依赖:`go mod tidy`
4. 运行:`make dev` 或 `source .env && go run ./cmd/agent`
## 环境变量说明
| 变量 | 说明 | 必填 | 默认值 |
|------|------|------|--------|
| GOOGLE_API_KEY | Google Gemini API Key | 是 | - |
| GEMINI_MODEL | 模型名称 | 否 | gemini-2.0-flash |
| LOG_LEVEL | 日志级别 | 否 | info |
| HTTPS_PROXY | 代理地址 | 否 | - |
## 项目结构
cmd/agent/ # 主入口 internal/ # 私有代码 agent/ # Agent 定义 config/ # 配置管理 tools/ # 自定义工具 pkg/utils/ # 公共工具
## 常用命令
| 命令 | 说明 |
|------|------|
| `make dev` | 开发环境运行 |
| `make build` | 编译二进制 |
| `make test` | 运行测试 |
## 部署说明
生产环境通过 GitHub Actions 自动构建并部署到 [你的平台]。
敏感配置通过 [Secret Manager / K8s Secrets] 注入,不存储在代码仓库中。
团队协作规范
Git 分支策略
推荐采用简化版 Git Flow:
main # 生产分支,永远可部署
├── develop # 开发分支,功能集成
│ ├── feat/search-tool # 功能分支
│ ├── feat/weather-agent
│ └── fix/api-timeout
└── hotfix/v0.1.1 # 紧急修复
分支命名规范:
feat/short-description:新功能fix/short-description:Bug 修复docs/short-description:文档更新refactor/short-description:代码重构
Commit Message 规范
使用 Conventional Commits 规范,便于自动生成 CHANGELOG:
feat(agent): 添加天气查询 Agent
fix(config): 修复 .env 未加载时 panic 的问题
docs(readme): 更新部署说明
refactor(tools): 提取通用 HTTP 客户端
chore(deps): 升级 ADK Go 到 v0.2.1
Code Review 检查清单
每次合并前,Review 者应确认:
-
.env等敏感文件未被提交 - 新增依赖是否必要
- 错误处理是否完善
- 配置项是否已更新
.env.example - 是否包含测试(如有测试框架)
常见问题与深度排障
Q:.env 不小心提交到 git 了怎么办?
立即执行以下操作:
# 1. 从 git 历史中彻底删除(重写历史)
git filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch .env' \
--prune-empty --tag-name-filter cat -- --all
# 2. 强制推送到远程(注意:这会重写远程历史,团队需协调)
git push origin --force --all
# 3. 在 .gitignore 中添加 .env
echo ".env" >> .gitignore
# 4. 立即撤销已泄露的 API Key
# 登录 Google AI Studio,删除旧 Key 并生成新 Key
教训:预防胜于治疗。建议在仓库中配置 git-secrets 或 pre-commit 钩子,在提交前自动检测敏感信息。
Q:团队成员 GOPROXY 配置不同,导致 go mod tidy 结果不一致
解决方案:在项目根目录创建 .gomodproxy 文件(或写入 README),统一代理配置:
# 统一使用 goproxy.cn
go env -w GOPROXY=https://goproxy.cn,direct
go env -w GOSUMDB=sum.golang.org
更彻底的做法是在 CI 中固定代理,确保构建一致性。
Q:多个 Agent 项目需要共享自定义工具,怎么组织?
方案 A:内部工具库(推荐)
创建独立的 Go Module 存放共享工具:
my-org/
├── adk-tools/ # 独立仓库
│ ├── go.mod
│ ├── search/
│ │ └── google_search.go
│ └── weather/
│ └── weather_api.go
├── agent-a/
└── agent-b/
在 Agent 项目的 go.mod 中引用:
require github.com/my-org/adk-tools v1.0.0
方案 B:Mono Repo(适合小团队)
如果工具代码量不大,可以使用 Go Workspace:
# 在父目录初始化 workspace
go work init ./adk-tools ./agent-a ./agent-b
这样所有模块共享同一个 go.work 文件,本地开发时修改工具代码立即生效。
下一步
项目结构规范建立好后,你的代码库已经具备了工程化的基础。接下来进入模块 2:快速入门。我们将从零构建一个完整的 Hello World Agent,深入理解 Model、Tool、Instruction 三要素的协作机制,并学习如何在代码中处理边界情况和错误场景。
← ADK Go 安装与快速验证 | Agent 核心概念 →
想跟着学更多 Go ADK 实战?关注「全栈之巅-梦兽编程」公众号,每周更新 Go / AI 编程实战干货。
也欢迎了解 梦兽编程 AI 编程助手服务 ,帮你把 AI 编程工具用到生产环境。
