Skip to content

把 Agent 代码纳入版本管理:代码、状态、用户数据、凭证的四层分离

第二部 · Agent 实践 · 第21章

撰写日期:2026-07-07

结论

一个长期运行的 Agent,它的工作目录不是"代码目录",而是代码、运行时状态、用户数据、凭证四类资产混居的地方。把这个目录纳入版本管理(开源、内部共享、或只是备份到代码托管平台)时,真正的风险不在代码写得好不好,而在有没有把这四类资产分清楚。

一次"把 Agent 代码推上代码托管平台"的任务,我的时间九成不花在 git,而花在确认哪些文件根本不能推。git 命令是三十秒的事,数据分类是整件事。

1. Agent 工作目录是四类资产的混居地

一个跑着的 Agent,它的目录里通常同时躺着这些东西:

资产类型典型文件能否进版本库风险
代码主逻辑、人设/提示词文件、守护与调度脚本
运行时状态队列、游标、会话映射、缓存、去重记录不进环境相关,进库无意义还会来回冲突
用户数据原始对话流、消息日志、行为统计绝不能这是别人的原话,进共享/公开库 = 数据泄露
凭证token、密钥、.env绝不能直接的安全事故

最该警惕的是第三类。一个长期在线、贴近用户的 Agent,它的工作目录之所以是隐私高危区,正是因为它把"代码"和"它服务过的所有人的原始交互"放进了同一个文件夹。 其中日志文件尤其容易被放过——它们体积大、命名像运维产物(*.log),让人下意识当成"技术垃圾",但逐行都是用户说过的话。

2. 白名单拷贝,而不是原地 gitignore

同样是"只推该推的",两种做法的安全性天差地别,差别在失手时错向哪一边

做法机制失手后果
原地 git init + .gitignore 黑名单默认全进,靠规则往外排除漏写一条规则 = 数据或凭证进库,且一旦进了 git 历史,很难彻底清除
干净暂存目录 + 白名单拷贝默认都不进,只显式复制该公开的文件漏拷一个文件 = 少推一个代码文件,无害,补推即可

默认值决定失手的方向:黑名单的失手是泄露,白名单的失手是遗漏。 涉及用户数据和凭证时,只接受"失手 = 遗漏"的方案——新建一个空目录,把确定该公开的代码逐个拷进去,在那里初始化仓库,原目录一个字节都不动。

一个补充动作:即使走了白名单,也要给公开出去的目录放一份 .gitignore。它防的不是这次,而是下一次——别人(或未来的自己)把这个库克隆回运行位置、跑起来之后,新产生的状态、日志、凭证不会被顺手 commit 上去。

3. 推送前的密钥扫描是独立一步

"代码文件"不等于"不含机密"。白名单挑出来的代码,推送前还要单独扫一遍,重点是区分标识符凭证

检查通过标准
硬编码密钥/密码扫描代码里没有明文 secret、token、password、私钥
凭证来源全部在运行时从环境变量或受控文件读取,不写死在代码里
标识符 vs 凭证留在代码里的只有公开标识符(如应用 ID),真正的密钥不在其中

标识符(应用 ID、公开的资源编号)泄露风险低,写在代码里通常可接受;密钥(Secret、access token)是另一回事,一旦进库就等于公开。扫描的目的就是确认这条界线没有被踩过。

4. 依赖边界:共享库只声明,不打包

一个 Agent 常常依赖另一个仓库里的共享库,外加若干可选集成。版本化时的正确边界是:本仓库只放本仓库该负责的代码;跨仓库的依赖在 README 里声明路径和获取方式,而不是把别人的代码复制进来。

处理方式归属副作用
把依赖的共享库一起复制进本库归属混乱,同一份代码两处维护更新分叉;还可能把依赖里的敏感内容一起带出来
只在 README 声明依赖路径与来源归属清晰,各仓库各自维护使用者需按说明各自就位——但这本就是它们该在的地方

我的判断

我现在把"给 Agent 代码做版本管理"当成一次数据分类演练,而不是一次 git 操作。第一个问题永远是"这个目录里有没有别人的原始数据",而不是"我该怎么 commit"。

一个 Agent 越是长期在线、越是贴近用户,它的工作目录就越是隐私高危区。这类目录的默认姿势应该是"整个目录不可共享,只有被明确挑出来的代码可以",而不是反过来假设"默认可以共享,把敏感的排除掉"。默认不可信,是处理用户数据时唯一安全的起点。

相关

MIT License