让 AI 从 .env.example 和 Dockerfile 抽配置,生成的部署文档才不靠模型瞎猜默认值
很多团队用 AI 写部署文档时都踩过同一个坑:模型不知道你项目里实际有哪些环境变量,于是开始编造 REDIS_URL、JWT_SECRET 这类看起来合理但根本不存在的配置。解法很简单——别让模型空手写,先把 .env.example、Dockerfile、docker-compose.yml 这些真实配置文件喂给它,让它从源码里抽取,而不是从训练记忆里猜。
我最近在一个 Go 服务项目里完整跑了一遍这个流程,生成的部署文档准确率从「大概能看」提升到「可以直接交给运维执行」。这篇文章把这个方法拆开讲清楚。
核心思路:把配置抽取和文档生成拆成两步
直接让 AI「读项目然后写部署文档」的效果不稳定,因为模型会同时处理太多信息:代码结构、依赖关系、配置项、部署步骤。更可靠的做法是两步走:先让 AI 只做一件事——从配置文件中抽取出结构化的环境变量清单,然后再基于这份清单生成文档。
第一步的输出应该是这样的结构化数据:
{
"variables": [
{
"name": "DATABASE_URL",
"required": true,
"default": null,
"description": "PostgreSQL connection string",
"source": ".env.example:12"
},
{
"name": "LOG_LEVEL",
"required": false,
"default": "info",
"description": "Logging level",
"source": "Dockerfile:8"
}
]
}
有了这份清单,第二步让模型写文档时就有了硬约束——它只能使用清单里的变量,不能凭空添加。我在 prompt 里加了一句:「如果文档中需要引用环境变量,只能使用上述清单中的变量名,不得新增或改名。」效果立竿见影。
第一步实操:从 .env.example 抽取环境变量
先看一个典型的 .env.example 文件:
# Server
PORT=8080
HOST=0.0.0.0
# Database
DATABASE_URL=postgres://user:password@localhost:5432/mydb?sslmode=disable
DB_MAX_CONNS=20
DB_IDLE_TIMEOUT=30s
# Redis (optional)
REDIS_ADDR=localhost:6379
REDIS_PASSWORD=
REDIS_DB=0
# Auth
JWT_SECRET=
JWT_EXPIRY=24h
给 AI 的 prompt 要明确三点:一是识别注释行并作为变量描述,二是保留默认值(空值也要标记),三是标记哪些变量明显是必须填写的(比如 JWT_SECRET 后面没有默认值)。我用的 prompt 大致这样:
从以下 .env.example 文件内容中抽取所有环境变量,输出 JSON 格式。
规则:
1. 每行 KEY=VALUE 是一个变量,KEY 为变量名
2. 注释行(以 # 开头)如果紧邻变量上方,作为该变量的描述
3. VALUE 为空字符串时,default 字段设为 null,required 设为 true
4. VALUE 非空时,default 为该值,required 设为 false
5. 保留变量在文件中的行号,记录到 source 字段
这里有个细节:要求模型输出行号(source 字段),是为了后续人工复核时能快速定位。别小看这个,当模型抽错或者漏抽时,行号能帮你 10 秒内发现问题。
第二步实操:从 Dockerfile 抽取构建时配置
Dockerfile 里的配置分两类:ENV 声明的运行时环境变量,和 ARG 声明的构建参数。两者都要抽,但在文档里要分开处理。
FROM golang:1.22-alpine AS builder
ARG VERSION=dev
ARG BUILD_TIME=unknown
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build \
-ldflags="-X main.Version=${VERSION} -X main.BuildTime=${BUILD_TIME}" \
-o /app/server .
FROM alpine:3.19
ENV PORT=8080 \
LOG_LEVEL=info \
TZ=Asia/Shanghai
RUN apk add --no-cache tzdata ca-certificates
COPY --from=builder /app/server /usr/local/bin/server
EXPOSE 8080
ENTRYPOINT ["server"]
给 AI 的 prompt 需要额外说明:
从以下 Dockerfile 中抽取配置项,分为两类:
1. ENV 指令:运行时环境变量,记录默认值
2. ARG 指令:构建参数,标记为 build_arg: true
输出 JSON,格式与之前一致,source 字段记录行号。
实际测试中,GPT-4o 和 Claude 3.5 Sonnet 都能准确区分 ENV 和 ARG,但有一个常见错误:把 EXPOSE 8080 也当成配置项抽出来。需要在 prompt 里明确排除 EXPOSE、WORKDIR、COPY、RUN 等指令,只关注 ENV 和 ARG。
第三步:合并去重,处理冲突
两个来源抽取出的变量可能有重叠。比如 .env.example 里有 PORT=8080,Dockerfile 里也有 ENV PORT=8080。合并时的规则要提前定好:
- 同名变量,如果默认值一致,合并为一条,source 记录两个来源
- 同名变量,如果默认值不一致,以
.env.example为准(因为它是面向部署者的配置入口),但在 description 里标注 Dockerfile 中的差异 - 只在 Dockerfile 中出现的变量,保留,标记
source: "Dockerfile"
这个合并逻辑我直接写在了 prompt 里让模型执行,对于十几个变量的项目,模型处理得很干净。但如果你的项目有 50+ 个变量,建议写个小脚本做合并,不要让模型做这种机械操作——模型在大量重复性合并任务上容易出错。
第四步:基于清单生成部署文档
拿到最终的变量清单后,生成文档的 prompt 核心约束就一句话:
以下是该项目的完整环境变量清单。生成部署文档时:
1. 只能使用清单中的变量名,不得新增、修改或遗漏任何变量
2. 每个变量的默认值必须与清单一致
3. 标记为 required 的变量,文档中必须明确说明「部署者必须自行设置」
4. 标记为 build_arg 的变量,放在「构建参数」小节,不要混入运行时环境变量
这一步生成的文档质量取决于清单质量。清单准,文档就准;清单有遗漏,文档就会漏配置——但至少不会瞎编。
实际效果对比:不用这个方法时,模型生成的文档里出现了 REDIS_URL(项目里实际叫 REDIS_ADDR)、DB_HOST/DB_PORT(项目里用的是一个完整的 DATABASE_URL),还漏掉了 TZ 这个在 Dockerfile 里定义的变量。用了清单约束后,这些错误全部消失。
进阶:引入 docker-compose.yml 和 CI 配置
如果你的项目还有 docker-compose.yml、Kubernetes manifests 或 CI 配置文件,这些也是配置项的重要来源。docker-compose.yml 里可能有 environment 段、.env 文件引用、secrets 声明。CI 配置里可能有部署环境特定的变量。
把这些也纳入抽取范围,prompt 里加一条来源标记规则即可。比如:
source 字段取值规则:
- .env.example 中的变量 → ".env.example"
- Dockerfile 中的变量 → "Dockerfile"
- docker-compose.yml 中的变量 → "docker-compose.yml"
- 多个来源都有 → 用逗号连接,如 ".env.example,Dockerfile"
我最近处理的一个项目,配置分散在 4 个文件里,最终清单有 37 个变量。模型一次抽取全部成功,但前提是每个文件的 prompt 都写清楚了该文件特有的语法规则(比如 YAML 的 environment 段格式、${VAR:-default} 语法)。
常见问题
为什么不直接让 AI 读整个项目然后生成文档?
因为模型处理大量文件时注意力分散,容易凭训练记忆补全它认为「应该有」的配置。把抽取和生成分开,每一步的任务边界清晰,出错概率大幅降低。而且中间产物(变量清单)可以人工检查,发现问题及时修正再继续。
清单抽取这一步,模型漏掉变量怎么办?
在 prompt 里加一条强制规则:「输出完成后,请自查:是否覆盖了输入文件中的每一行配置声明?如有遗漏,重新输出完整清单。」实测这条规则能减少大约 80% 的遗漏。另外,如果你用 Claude,可以开启 extended thinking,对长文件的抽取准确率有明显提升。
配置文件里用了变量嵌套,比如 DATABASE_URL=${DB_HOST}:${DB_PORT}/mydb,怎么处理?
这种情况下要让模型在 description 里说明这个变量的实际组成部分,并把 DB_HOST、DB_PORT 也作为独立变量列出(如果它们在文件里有定义的话)。prompt 里加一条:「如果变量的值中包含对其他变量的引用(${VAR} 语法),将被引用变量也加入清单,并在描述中标注引用关系。」
这个方法适合多大体量的项目?
变量数在 50 以内的项目,直接让模型处理完全没问题。超过 50 个变量,或者配置分散在 10 个以上文件的项目,建议写脚本做初步抽取(正则匹配 KEY=VALUE 模式),再让模型做语义理解和描述生成。模型擅长理解,不擅长穷举——这是目前 LLM 的普遍特性。