1.4 安全与版权:AI 代码的使用边界
准备把工具箱的第一批脚本推给团队用的时候,我做了一次代码梳理,结果吓出一身汗:一个生成的大模型调用脚本里,API 密钥被写死在了源码里,跟着提交记录躺了两周;另一个抓取脚本里借了一段开源代码,原始协议是 GPL,而我们的项目是内部闭源使用——严格来说已经构成协议违规。深层原因在于:AI 生成代码时并没有安全意识这根弦,它眼里的好代码是能完成任务、简洁、优雅——恰恰不包含安全。它不会主动提醒你密钥别写死,也不会检查依赖的传染协议,这些活本来就是人的职责。把安全检查固化进流程,而不是寄希望于模型的自觉,是这一篇要讲清楚的核心立场。
这篇讲的就是这最后一道闸门的具体内容:密钥怎么管、依赖和生成代码的协议怎么查、以及生成内容的版权归属到底算谁的。从那以后,过不了这道闸门的代码,一律不进主干。
场景:一次差点发生的密钥泄漏
先说密钥的事。AI 生成调用代码时,有一个非常自然的倾向:把密钥当成普通参数填进代码里。因为对模型来说,一个能跑的示例远比一段读环境变量的间接代码直观。最早的脚本是这样的:
import requests
def ask_llm(question):
url = "https://example.com/v1/chat/completions"
key = "sk-abcdef1234567890"
headers = {"Authorization": f"Bearer {key}"}
return requests.post(url, headers=headers, json={"q": question})
跑是能跑,但这个文件一旦进了 git,密钥就永久留在历史记录里。哪怕后来删掉,删不掉的是历史;更糟的是私有仓库如果哪天共享出去,密钥等于白送。我第一时间去控制台把这个 key 吊销重置,然后花了一下午清理 git 历史。清理用到的命令大致是 git filter-branch 加历史重写推强更新,整个过程心惊肉跳——重写历史一旦出错,协作者的本地仓库全会乱套。这也是为什么安全检查必须自动化——靠人眼盯着每个生成代码里的字符串,早晚漏一个。事后我定的规矩是:任何包含疑似密钥的字符串,在提交前就拦下来,而不是等事后清理。
方案:三层防护
密钥管理的标准做法不复杂,难在养成习惯。我落地的是三层防护,外加一条总原则:所有密钥一律不进代码、不进聊天记录、不进截图。三个不做到,密钥才谈得上安全;有一条破了,后面的防护都是在补漏洞。
第一层,配置与代码分离。所有密钥放 .env 文件,代码里只读取:
import os
key = os.getenv("LLM_API_KEY")
if not key:
raise RuntimeError("请在 .env 中配置 LLM_API_KEY")
第二层,.env 进 .gitignore,并且提交前用工具扫一遍。git-secrets 或者 TruffleHog 都行,专门翻历史和暂存区里有没有疑似密钥的字符串。.env 的加载用 python-dotenv 一行搞定:
from dotenv import load_dotenv
load_dotenv() # 从同目录 .env 注入环境变量
配合下面的 gitignore 片段,把敏感文件彻底挡在仓库外:
.env
.env.local
*.key
secrets/
规则简单,但每隔三个月都会有人(包括我自己)在调试时忍不住把 key 写回代码里图方便,所以说到底还是靠扫描工具兜底——人可以松懈,脚本不会。
第三层,定期轮换。就算前两层全做到,密钥用久了仍然有暴露面,控制台里设个每九十天提醒重置就行。腾讯云的密钥管理在访问管理里可以一键禁用和重建,发现疑似泄漏时先禁用再排查,顺序不能反。我自己有过一次误操作:先排查再禁用,排查的两小时里泄漏面一直敞着,事后想想要是真泄漏,这两小时够人把额度刷光了。
顺带一提的是权限最小化。工具箱只需要调用大模型 API,那给的密钥就只开通这个权限,不要图省事用主账号的全能密钥。云函数那边的授权也是一个道理,具体做法在 第四篇云函数实践 里有展开。
版权这边的问题更微妙,分两块看。第一块是生成代码里引用的开源代码:模型训练语料里包含大量开源实现,生成时可能原样吐出一段带协议要求的代码。这类情况通常发生在常见算法和工具函数上,比如排序、缓存、连接池,因为这些实现网上多、模式集中。遇到明显是整段照搬的代码,最稳妥的做法是问一句这段实现是否有已知来源,模型有时会主动给出出处;不管它给不给,主流做法是保留原始许可声明,核对协议要求。常见协议的注意点:
| 协议 | 是否需开源 | 附加要求 | 适合场景 |
|---|---|---|---|
| MIT | 否 | 保留许可声明 | 商用闭源最友好 |
| Apache 2.0 | 否 | 保留声明加专利授权 | 大型项目常用 |
| BSD 3-Clause | 否 | 不得用作者名背书 | 工具类库 |
| LGPL | 动态链接可不开源 | 修改需回馈 | 谨慎用于库 |
| GPL | 衍生作品必须开源 | 传染性最强 | 只适合 GPL 项目 |
第二块是生成内容本身的归属。目前主流模型的用户协议基本约定:输出内容的使用权归用户,但哪家模型、哪一版协议、什么用途,细节各不相同。企业环境下这事得让法务看一眼,个人项目至少保留生成记录,证明自己正常使用。一个现实问题是:模型很难证明某段输出完全独立于训练语料中的某个受保护作品,所以涉及核心文案、商标、外观的部分,我会留出人工创作的空间,而不是整段直接采用。关于这块边界更系统的讨论可以看 腾讯 ADP Agent 指南,里面对模型使用的合规要点有专门章节。
踩坑:协议检查不能靠猜
落地这套机制的过程中,最容易被忽略的是协议检查的自动化。我原本靠生成后手动看 import,结果漏掉了通过文档示例复制进来的代码片段。后来用 scancode-toolkit 之类的工具扫依赖树,一次扫出三个间接依赖带了 GPL 传染协议,其中一个被 第三篇 RAG 知识库 的某个数据处理库间接引入。如果等上线法务才发现,整改成本至少翻十倍。这事的教训是:依赖的依赖也有协议,眼睛看到的第一层永远不够。
第二个坑是测试数据泄密。让 AI 生成单测时,它会随手用真实业务数据造样例——客户名单、金额、内部编号,跟着测试代码一起进仓库。我的对策是数据字典制度:所有进入代码和测试的样例必须来自字典里的脱敏数据,真实数据只存在于本地不入库。这个习惯顺带解决了另一个问题:演示和分享时不用再临时打码,直接用脱敏样例。
第三个坑是输出内容版权的隐性风险。用 AI 生成产品宣传文案时,如果提示词里写了请模仿某品牌的风格,生成物可能带有他人作品的影子。风格本身难界定,但稳妥的做法是在关键文案上注明 AI 辅助生成,重要场景过一遍人工。文字如此,代码也一样——核心算法和商业逻辑,我始终自己写,AI 只做周边工具。
整理成一张日常检查清单:
| 检查项 | 频次 | 工具或做法 |
|---|---|---|
| 密钥扫描 | 每次提交 | git-secrets 等自动扫描 |
| 依赖协议核查 | 引入新包时 | scancode-toolkit 扫依赖树 |
| 测试数据脱敏 | 每次写单测 | 对照脱敏数据字典 |
| 密钥轮换 | 每九十天 | 控制台提醒加重置 |
| 输出归属记录 | 生成即记录 | 保存提示词与输出快照 |
第三个经验是养成扫描习惯:新人进项目先讲这套规范,每周跑一次全量扫描。安全和版权这件事,制度比记忆可靠,工具比制度可靠。
小结
安全和版权是 AI 辅助开发里最容易被跳过的两章,因为它们不影响代码跑不跑,只决定出事之后多疼。三层防护加两张清单,覆盖了密钥、协议、数据三个主要风险点,落地成本不高,收益全在看不见的地方。这也是为什么我在 1.3 代码审查 的清单里把敏感信息单列出来——安全和审查本来就是一套机制的两面。回过头看这一篇的三个场景,密钥泄漏、协议误用、数据泄密,每一个都没有让项目立刻出事,但每一个都埋着能让项目停摆的雷。拆雷的成本远低于排雷,这就是全部道理。第一篇到这里就结束了,从效率差、提示词、审查到安全,四件事拼起来就是一条完整的 AI 辅助开发流水线。下一章我们进实战,看这条流水线跑在日常脚本上是什么效果。
工具箱最终部署在腾讯云轻量服务器上,密钥管理用的就是我上面这套方案,服务器的开通和初始化可以参考 轻量应用服务器建站指南,活动价入口还是那个 AI 办公助手活动页。
