把项目交给 AI 前,先用 Python 自动生成一份 .aiignore
AI 编程工具越强,开发者越容易犯一个错误:
直接把整个项目交给 AI。

以前我们只是复制一段代码给 ChatGPT,它最多看见一个函数。
现在 Cursor、Kiro、Codex、Claude Code 这类工具更像项目级助手,可以读仓库、理解上下文、生成 patch,甚至帮你跑一段完整任务。
这当然方便。
但问题也更明显:
项目里不是所有东西都适合给 AI 看。
比如:
.env
.env.production
id_rsa
server.key
storage/logs/error.log
database.sqlite
backup.sql
config/database.php
uploads/user_avatar/
这些文件里可能有数据库连接、API Key、用户数据、服务器地址、日志堆栈、支付配置、Cookie、Token,甚至私钥。
你让 AI 读项目之前,如果不先设边界,就很容易把不该共享的内容一起带进去。
所以我现在更建议在项目里准备一个类似 .gitignore 的文件:
.aiignore
它的作用很简单:告诉 AI 编程工具,哪些内容不应该进入上下文。
这篇文章就写一个 Python 脚本,自动扫描项目,生成 .aiignore 和安全检查报告。
它不是完整的安全审计工具,但非常适合作为开发者把项目交给 AI 前的第一道检查。
一、为什么需要 .aiignore

很多开发者已经习惯写 .gitignore。
比如:
node_modules/
vendor/
.env
dist/
coverage/
但 .gitignore 解决的是“哪些文件不提交到 Git”。
AI 编程工具要解决的是另一个问题:
哪些文件不应该被 AI 读取、分析、总结、上传或参与上下文。
这两个范围有重叠,但不完全一样。
比如:
.env.example 通常可以提交到 Git,但如果里面写了真实示例 key,就不一定适合给 AI。
日志文件可能没进 Git,但本地 AI 工具扫描目录时可能看得到。
数据库备份不一定在仓库里,但可能放在项目根目录。
一些内部接口文档可以提交,但可能包含真实域名、内部 Token、测试账号。
所以 .aiignore 的价值是:
在 AI 读项目之前,先给它一条边界线。
二、这个脚本要做什么
我们写一个 make_aiignore.py,功能包括:
- 扫描项目目录;
- 跳过
node_modules、vendor、.git等无意义目录; - 根据文件名识别高风险文件;
- 根据文件内容识别疑似 token、password、数据库连接串、私钥;
- 生成
.aiignore; - 生成一份
AI_SAFE_SHARE_REPORT.md; - 给出一段适合发给 AI 的项目读取边界提示词。
生成后的 .aiignore 可以放在项目根目录。
生成后的 Markdown 报告可以人工看,也可以发给 AI,让它先知道哪些地方不能碰。
三、完整 Python 脚本
新建文件:
touch make_aiignore.py
写入下面代码:
#!/usr/bin/env python3
from __future__ import annotations
import argparse
import fnmatch
import os
import re
from dataclasses import dataclass
from pathlib import Path
DEFAULT_SKIP_DIRS = {
".git", ".svn", ".hg",
"node_modules", "vendor",
"dist", "build", ".next", ".nuxt",
".venv", "venv", "__pycache__",
".idea", ".vscode",
"coverage", "target", "bin", "obj",
".pytest_cache", ".mypy_cache",
"storage/logs", "runtime", "cache", "logs",
}
DEFAULT_SAFE_EXTENSIONS = {
".py", ".js", ".jsx", ".ts", ".tsx", ".vue",
".php", ".go", ".rs", ".java", ".kt", ".cs",
".md", ".yml", ".yaml", ".json", ".toml",
".xml", ".sql", ".sh", ".css", ".scss", ".html",
}
SENSITIVE_FILE_PATTERNS = [
".env",
".env.*",
"*.pem",
"*.key",
"*.p12",
"*.pfx",
"*.crt",
"*.cer",
"id_rsa",
"id_ed25519",
"config/*secret*",
"config/*password*",
"*credential*",
"*credentials*",
"*token*",
"*secret*",
"*private*",
"*.sqlite",
"*.db",
"*.log",
]
SENSITIVE_CONTENT_RULES = [
(
"API Key / Token",
re.compile(
r"(?i)(api[_-]?key|access[_-]?token|secret[_-]?key|bearer)"
r"\s*[:=]\s*['\"]?[^'\"\s]+"
),
),
(
"Password",
re.compile(
r"(?i)(password|passwd|pwd)\s*[:=]\s*['\"]?[^'\"\s]+"
),
),
(
"Private Key",
re.compile(r"-----BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY-----"),
),
(
"Database URL",
re.compile(r"(?i)(mysql|postgres|mongodb|redis)://[^ \n'\"]+"),
),
]
@dataclass
class Finding:
path: str
reason: str
evidence: str
def normalize(path: Path) -> str:
return str(path).replace(os.sep, "/")
def is_in_skip_dir(relative: str) -> bool:
parts = relative.split("/")
for index in range(1, len(parts) + 1):
if "/".join(parts[:index]) in DEFAULT_SKIP_DIRS:
return True
return False
def matches_sensitive_name(relative: str) -> str | None:
name = Path(relative).name
for pattern in SENSITIVE_FILE_PATTERNS:
if fnmatch.fnmatch(relative, pattern) or fnmatch.fnmatch(name, pattern):
return f"文件名命中敏感规则:{pattern}"
return None
def read_text_head(path: Path, max_bytes: int = 200_000) -> str:
data = path.read_bytes()[:max_bytes]
return data.decode("utf-8", errors="replace")
def scan_file_content(path: Path) -> tuple[str, str] | None:
try:
text = read_text_head(path)
except OSError:
return None
for title, pattern in SENSITIVE_CONTENT_RULES:
match = pattern.search(text)
if match:
sample = match.group(0)[:120].replace("\n", "\\n")
return title, sample
return None
def collect_findings(root: Path) -> list[Finding]:
findings: list[Finding] = []
for path in sorted(root.rglob("*")):
if not path.is_file():
continue
relative = normalize(path.relative_to(root))
if is_in_skip_dir(relative):
continue
name_reason = matches_sensitive_name(relative)
if name_reason:
findings.append(
Finding(
path=relative,
reason=name_reason,
evidence="文件名风险",
)
)
continue
if path.suffix.lower() not in DEFAULT_SAFE_EXTENSIONS:
continue
content_result = scan_file_content(path)
if content_result:
title, evidence = content_result
findings.append(
Finding(
path=relative,
reason=f"内容疑似包含敏感信息:{title}",
evidence=evidence,
)
)
return findings
def build_aiignore(findings: list[Finding]) -> str:
lines = [
"# Generated by make_aiignore.py",
"# 用于限制 AI 编程工具读取项目时应忽略的敏感文件",
"",
".env",
".env.*",
"*.pem",
"*.key",
"*.p12",
"*.pfx",
"*.log",
"*.sqlite",
"*.db",
"storage/logs/",
"runtime/",
"cache/",
"",
"# Detected risky files",
]
for item in findings:
lines.append(item.path)
return "\n".join(dict.fromkeys(lines)) + "\n"
def build_report(findings: list[Finding]) -> str:
lines = [
"# AI 项目共享前安全检查报告",
"",
"## 总体结论",
"",
]
if findings:
lines.append(f"- 发现 `{len(findings)}` 个建议加入 `.aiignore` 的风险项。")
lines.append("- 不建议直接把完整项目目录交给 AI,请先检查下方文件。")
else:
lines.append("- 未发现明显敏感文件或敏感内容命中。")
lines.append("- 仍建议人工检查 `.env`、配置文件、日志、上传目录和数据库备份。")
lines.extend(["", "## 风险文件列表", ""])
if findings:
for item in findings:
lines.extend(
[
f"### `{item.path}`",
f"- 原因:{item.reason}",
f"- 证据:`{item.evidence}`",
"",
]
)
else:
lines.append("- 暂无。")
lines.extend(
[
"",
"## 建议给 AI 的项目读取边界",
"",
"```text",
"请先阅读项目中允许共享的文件,不要读取 .env、日志、数据库备份、证书、私钥、用户上传文件和任何包含 token/password/secret 的配置。",
"如果你认为需要这些信息,请先说明原因,由我人工提供脱敏版本。",
"```",
"",
]
)
return "\n".join(lines)
def main() -> None:
parser = argparse.ArgumentParser(
description="Generate .aiignore and safe sharing report for AI coding tools."
)
parser.add_argument(
"--root",
default=".",
help="项目根目录",
)
parser.add_argument(
"--aiignore",
default=".aiignore",
help="输出 .aiignore 文件路径",
)
parser.add_argument(
"--report",
default="AI_SAFE_SHARE_REPORT.md",
help="输出安全报告路径",
)
args = parser.parse_args()
root = Path(args.root).resolve()
if not root.exists() or not root.is_dir():
raise SystemExit(f"Root directory not found: {root}")
findings = collect_findings(root)
Path(args.aiignore).write_text(build_aiignore(findings), encoding="utf-8")
Path(args.report).write_text(build_report(findings), encoding="utf-8")
print(f"Generated: {args.aiignore}")
print(f"Generated: {args.report}")
print(f"Risk findings: {len(findings)}")
if __name__ == "__main__":
main()
四、运行方式
在项目根目录执行:
python make_aiignore.py --root . --aiignore .aiignore --report AI_SAFE_SHARE_REPORT.md
如果你想扫描某个指定项目:
python make_aiignore.py \
--root ./my-project \
--aiignore ./my-project/.aiignore \
--report ./my-project/AI_SAFE_SHARE_REPORT.md
执行后会生成两个文件:
.aiignore
AI_SAFE_SHARE_REPORT.md
五、用一个示例项目测试
创建一个测试目录:
mkdir aiignore-demo
cd aiignore-demo
mkdir src config
touch src/app.py
touch .env
touch config/database.py
写入一些模拟内容:
echo 'OPENAI_API_KEY=sk-demo-key' > .env
echo 'print("hello")' > src/app.py
echo "DATABASE_URL='mysql://user:pass@localhost/demo'" > config/database.py
运行脚本:
python ../make_aiignore.py \
--root . \
--aiignore .aiignore \
--report AI_SAFE_SHARE_REPORT.md
输出类似:
Generated: .aiignore
Generated: AI_SAFE_SHARE_REPORT.md
Risk findings: 2
生成的 .aiignore 大概会是这样:
# Generated by make_aiignore.py
# 用于限制 AI 编程工具读取项目时应忽略的敏感文件
.env
.env.*
*.pem
*.key
*.p12
*.pfx
*.log
*.sqlite
*.db
storage/logs/
runtime/
cache/
# Detected risky files
config/database.py
生成的 AI_SAFE_SHARE_REPORT.md 会类似这样:
# AI 项目共享前安全检查报告
## 总体结论
- 发现 `2` 个建议加入 `.aiignore` 的风险项。
- 不建议直接把完整项目目录交给 AI,请先检查下方文件。
## 风险文件列表
### `.env`
- 原因:文件名命中敏感规则:.env
- 证据:`文件名风险`
### `config/database.py`
- 原因:内容疑似包含敏感信息:Database URL
- 证据:`mysql://user:pass@localhost/demo`
这说明脚本至少识别到了两个风险:
.env文件名本身高风险;config/database.py里出现了数据库连接串。
六、为什么不能只靠 .gitignore
很多人会觉得:
“我项目里已经有 .gitignore 了,还要 .aiignore 干嘛?”
原因是两者目标不一样。
.gitignore 关注的是:
哪些文件不要提交到 Git。
.aiignore 关注的是:
哪些文件不要进入 AI 上下文。
举几个例子。
1. 本地日志
日志通常不会提交到 Git,但 AI 工具如果能读本地目录,可能会读到。
日志里可能有:
- 用户邮箱
- 手机号
- 请求参数
- 内部接口
- 报错堆栈
- token 片段
这些内容不一定适合交给 AI。
2. 数据库文件
比如:
dev.sqlite
local.db
backup.sql
这些文件可能只是本地开发用,但里面可能有真实测试数据。
3. 配置文件
有些项目会把配置文件提交到 Git,但里面可能仍然有内部域名、默认密码、测试账号。
比如:
config/database.php
application.yml
docker-compose.override.yml
这些文件不一定不能给 AI,但至少应该先人工看一眼。
4. 上传目录
很多 Web 项目有:
public/uploads/
storage/app/
里面可能是用户上传文件、图片、Excel、合同、附件。
这些更不应该直接进入 AI 上下文。
七、可以继续扩展的规则
这个脚本是基础版,你可以根据技术栈继续加规则。
1. 前端项目
可以加:
SENSITIVE_FILE_PATTERNS.extend([
".npmrc",
".yarnrc",
"firebase.json",
"vercel.json",
])
如果 .npmrc 里有私有源 token,不应该直接给 AI。
2. Java / Spring Boot
可以重点扫:
application-prod.yml
application-prod.properties
bootstrap.yml
规则可以加:
SENSITIVE_FILE_PATTERNS.extend([
"application-prod.yml",
"application-prod.properties",
"bootstrap.yml",
])
3. PHP 项目
可以重点扫:
.env
config/database.php
config/app.php
storage/logs/
public/uploads/
如果是 Laravel,.env 和 storage/logs/ 基本应该默认忽略。
4. Python 项目
可以重点扫:
.env
settings.py
local_settings.py
*.sqlite3
比如 Django 项目里,settings.py 可能包含数据库配置和 SECRET_KEY。
5. Docker 项目
可以重点扫:
docker-compose.override.yml
.env
secrets/
容器编排文件里经常出现数据库账号、Redis 密码、内部服务域名。
八、把 .aiignore 放进团队流程
如果团队里已经开始用 AI 编程工具,不建议每个人各用各的习惯。
可以在项目根目录加:
.aiignore
AI_SAFE_SHARE_REPORT.md
再在 README 里加一段说明:
## AI 工具使用边界
使用 ChatGPT、Claude、Cursor、Kiro 等 AI 工具分析本项目时,请先阅读 `.aiignore`。
禁止直接上传或共享:
- `.env`
- 私钥、证书
- 线上日志
- 数据库备份
- 用户上传文件
- 包含 token、password、secret 的配置
如果你们有 PR 模板,也可以加:
## AI 工具检查
- [ ] 是否使用 AI 辅助修改代码?
- [ ] 是否确认没有把敏感文件交给 AI?
- [ ] 是否更新或检查 `.aiignore`?
- [ ] 是否人工 Review 了 AI 输出内容?
这样 AI 不是“个人偷偷用”,而是进入团队可控流程。
九、把安全边界提示词一起给 AI
除了生成 .aiignore,你还可以把下面这段提示词固定放进 AI 对话开头:
你现在要辅助我分析一个项目。
请遵守这些边界:
1. 不要要求我提供 .env、私钥、证书、数据库备份、线上日志、用户上传文件;
2. 如果你认为需要敏感信息,请说明原因,我会提供脱敏版本;
3. 不要根据缺失的敏感配置自行编造真实值;
4. 不要输出任何看起来像真实 token、password、secret 的内容;
5. 对不确定的信息,请标注“需要人工确认”。
在分析代码前,请先告诉我:
- 你需要哪些非敏感文件;
- 哪些文件不应该提供;
- 你将如何控制分析范围。
这段提示词的作用不是让 AI 更聪明,而是让它更守边界。
AI 参与项目开发时,边界感比“多写几行代码”更重要。
十、工具订阅轻提示
如果你长期使用 ChatGPT Plus、Claude Pro、Grok、Gemini Advanced、Cursor、Kiro 这类 AI 工具,也可以顺手了解 gpt68.com。它是 AI会员充值平台,适合作为 AI 工具订阅充值入口之一。
但对开发者来说,订阅工具只是第一步。
真正让 AI 安全进入项目开发的,是你有没有清楚的上下文边界、敏感文件规则和人工验收流程。
别让 AI 读了不该读的东西,也别让它改了不该改的地方。
十一、代码验证范围
这份脚本已做基础验证:
验证环境:
- Python 3.11
- macOS / Linux 风格路径
- 示例项目包含 .env、src/app.py、config/database.py
验证结果:
- Python 语法检查通过
- 能正常生成 .aiignore
- 能正常生成 AI_SAFE_SHARE_REPORT.md
- 能识别 .env 文件名风险
- 能识别 config/database.py 中的 mysql:// 数据库连接串
- 能跳过 node_modules、vendor、.git 等目录
需要注意:
- 这是关键词和文件名扫描,不是完整安全审计
- 命中风险不代表一定泄露,只代表需要人工检查
- 未命中风险也不代表 100% 安全
- 不同团队需要根据自己的技术栈补充规则
- 真正提供给 AI 前,仍建议人工打开报告检查一遍
十二、总结
AI 编程工具越像项目助手,开发者越要先想清楚:
哪些内容可以给它看?
哪些内容必须忽略?
哪些内容只能脱敏后提供?
哪些地方必须人工确认?
.aiignore 解决的就是这个边界问题。
它不是为了限制 AI,而是为了让 AI 在更安全的范围内发挥作用。
这篇文章里的脚本很简单,但可以放进日常流程:
扫描项目
→ 生成 .aiignore
→ 生成安全报告
→ 人工检查风险项
→ 再把安全上下文交给 AI
AI 可以帮你读代码、改 bug、写测试、整理文档。
但前提是:
你先别把不该给它看的东西,一起塞进去。
更多推荐



所有评论(0)