跳到主要内容

2 篇博文 含有标签「VSCode」

查看所有标签

修复 WSL2 无法访问 Windows 宿主机代理 — 三个隐形坑

· 阅读需 6 分钟

在 WSL2 环境下使用 Claude Code、Roo 等 AI 编程工具时,工具需要通过 Windows 宿主机代理访问 API,却反复报 ConnectionRefused。解决防火墙问题后,又遇到两个隐藏坑。记录完整排查过程。

TL;DR

WSL2 的 vEthernet (WSL) 虚拟网卡每次启动重建,Windows 防火墙无法为其分配 Network Profile,导致所有入站规则对这个接口都不生效EnforcementStatus: NotApplicable)。不需要加规则,直接对接口禁用防火墙即可:

# 在 Windows PowerShell (管理员) 中执行
Set-NetFirewallProfile -DisabledInterfaceAliases "vEthernet (WSL)"

此外,修复防火墙后,还可能遇到两个额外坑

  1. 动态 IP 问题:宿主机 IP 在 WSL/Windows 重启后变化
  2. 配置缓存问题~/.claude.json~/.claude/settings.json 里缓存了旧 API key 导致认证冲突

问题现象

环境:Windows 10 21H2 + WSL2 2.5.10.0(NAT 模式),宿主机 Clash Verge(端口 7897,Allow LAN 已开启)。

症状:

# 从 WSL ping 宿主机 — 无响应
ping 172.22.80.1

# 测试代理端口 — 无响应
nc -zv 172.22.80.1 7897

# Claude Code / Roo 报错
# API Error: ConnectionRefused

# 但直接访问外网正常
curl https://example.com # OK

Windows 侧 Clash 健康运行: netstat 显示 0.0.0.0:7897 监听中,Test-NetConnection localhost 7897 成功。

根因一:防火墙隐形拦截

vEthernet (WSL) 是 WSL2 每次启动时动态创建的虚拟网卡。 Windows 防火墙的 Network Profile(域/专用/公用)无法关联到这个接口。

这意味着:

  1. 鯿火墙入站规则绑定到 Profile
  2. vEthernet(WSL) 不属于任何 Profile
  3. 所有入站规则对这个接口显示 EnforcementStatus: NotApplicable
  4. 规则被直接跳过 — 不是拒绝,是根本不评估

无论加多少条端口规则或 InterfaceAlias 绑定都没用,因为规则根本不会对这个接口执行。

解决方案一:一条命令修复防火墙

第一步:确认根因

在 Windows PowerShell(管理员)中:

# 查看虚拟网卡接口
Get-NetAdapter | Where-Object { $_.Name -like "*WSL*" }

# 查看入站规则的 EnforcementStatus
Get-NetFirewallRule -DisplayName "*7897*" |
Get-NetFirewallInterfaceFilter |
Get-NetFirewallPortFilter |
Format-Table -Property * -AutoSize

如果规则存在但 WSL 仍不通,说明 Profile enforcement 是问题所在。

第二步:一条命令修复

# 直接对 vEthernet(WSL) 禁用防火墙
Set-NetFirewallProfile -DisabledInterfaceAliases "vEthernet (WSL)"

这条命令的效果:

  • 仅对 vEthernet (WSL) 这个虚拟网卡接口生效
  • 物理网卡(Wi-Fi、以太网)的防火墙规则完全不受影响
  • 设置持久化,重启后保留

第三步:验证

# WSL 内测试连通性
nc -zv 172.22.80.1 7897
# 输出: Connection to 172.22.80.1 7897 port [tcp/*] succeeded!

# 测试代理
curl -x http://172.22.80.1:7897 https://api.anthropic.com

根因二:动态 IP 变化

修复防火墙后,代理可能仍然失败。为什么?vEthernet (WSL) 的 IP 每次启动都会变。

如果在 .bashrc 里硬编码了 IP:

export http_proxy=http://172.22.80.1:7897  # 这个 IP 可能变了!

修复:在 .bashrc 中动态获取宿主机 IP:

# 从 DNS 服务器自动获取宿主机 IP
export WINDOWS_IP=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}')
export http_proxy="http://${WINDOWS_IP}:7897"
export https_proxy="http://${WINDOWS_IP}:7897"

根因三:配置文件残留缓存

修复防火墙和动态 IP 后,Claude Code/GLM 可能仍报认证冲突。为什么?缓存的 key 存在于:

  1. ~/.bashrc 顶部全局 export ANTHROPIC_API_KEY=sk-ant-...
  2. ~/.claude.jsoncustomApiKeyResponses.approved 存了之前用过的 Anthropic key
  3. ~/.claude/settings.jsonenv 字段可能有硬编码的环境变量

切换到 GLM 模式时,unset ANTHROPIC_API_KEY 临时有效,但 bashrc 重新加载后又 export 了。Claude Code 读取这三个来源,发现冲突。

解决方案三:清理缓存 Key

# 1. 检查是否冲突
echo $ANTHROPIC_API_KEY $ANTHROPIC_AUTH_TOKEN

# 2. 清理 ~/.claude.json 缓存
cat ~/.claude.json | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('customApiKeyResponses', {}))"

# 3. 检查 ~/.claude/settings.json
cat ~/.claude/settings.json | grep -A2 '"env"'

修复:删除 settings.json 里的硬编码值:

python3 -c "
import json
with open('/home/aptop/.claude/settings.json') as f:
d = json.load(f)
d['env'].pop('ANTHROPIC_API_KEY', None)
d['env'].pop('HTTPS_PROXY', None)
d['env'].pop('HTTP_PROXY', None)
with open('/home/aptop/.claude/settings.json', 'w') as f:
json.dump(d, f, indent=2)
"

对于 ~/.claude.json,手动编辑文件,从 customApiKeyResponses.approved 数组中删除过时的 key。

注意事项

  • 代理端口
    • 如果你的 Clash 端口不是 7897,替换成实际端口即可,关键是修复防火墙接口而非端口
    • WSL 更新时 Windows 大版本更新可能重置虚拟网卡配置,复发时重新执行同一条命令
    • Windows 10 不支持 WSL2 的 mirrored 网络模式(仅 Windows 11 23H2+),不要尝试这个方向
  • 动态 IP
    • 始终在 .bashrc 中使用动态获取 IP,不要硬编码宿主机 IP
    • /etc/resolv.conf 里的 DNS 服务器 IP 在 WSL 重启后是稳定的
  • 配置缓存
    • 清理缓存 key 后需重启 Claude Code 才能生效
    • 如果认证仍然失败,按顺序检查三个来源:环境变量、~/.claude.json~/.claude/settings.json

排查顺序(下次参考)

  1. echo $ANTHROPIC_API_KEY $ANTHROPIC_AUTH_TOKEN — 确认是否冲突
  2. cat ~/.claude.json | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('customApiKeyResponses', {}))" — 确认缓存 key
  3. cat ~/.claude/settings.json | grep -A2 '"env"' — 确认 settings 里有无硬编码
  4. curl https://open.bigmodel.cn — 确认 GLM 可达

死路:5 个已排除的方向

#方向结果原因
1代理环境变量排除.bashrc unset/export 模式是设计用于模型切换
2Clash Allow LAN 未开启排除Allow LAN 已开启,监听 0.0.0.0:7897,localhost 测试通过
3防火墙端口规则排除添加端口 7897 入站规则后仍不通 — NotApplicable
4绑定规则到 InterfaceAlias排除Set-NetFirewallRule -InterfaceAlias "vEthernet (WSL)" 无效
5Mirrored 网络模式排除Windows 10 不支持

核心洞察:我们一直尝试添加规则,但问题不是缺少规则 — 而是规则对这个接口根本不生效。


启用 VSCode Copilot Agent Mode 实现自动化编程

· 阅读需 3 分钟

TL;DR

VSCode Copilot Agent Mode 是实验性功能,能让 AI 自动执行多步骤任务(包括编辑文件、运行终端命令)。在 settings.json 中添加 "github.copilot.chat.agent.enabled": true 即可启用,适合处理重复性重构、批量文件修改等场景。

问题现象

传统 Copilot Chat 只能建议代码片段,每次都要:

  1. 手动复制代码
  2. 切换到目标文件
  3. 粘贴并调整
  4. 重复以上步骤

遇到需要修改多个文件的任务时,这种模式效率极低。

根因

Copilot 的 Ask Mode 设计为「建议者」角色:只输出代码,不执行操作。这是安全设计,但对于信任 AI 的开发者来说,增加了大量手动操作。

Agent Mode 则是「执行者」角色:AI 可以直接编辑文件、运行命令,实现真正的自动化编程。

解决方案

1. 启用 Agent Mode

在 VSCode settings.json 中添加:

{
"github.copilot.chat.agent.enabled": true
}

或在设置界面搜索 @id:github.copilot.chat.agent.enabled 勾选启用。

2. 切换到 Agent Mode

在 Copilot Chat 面板中,点击模式下拉框,从「Ask」切换到「Agent」:

┌─────────────────────────────┐
│ Ask ▼ │ Agent ▼ │ Edit │
└─────────────────────────────┘

3. 使用示例

场景:批量重命名函数

将 src/utils 目录下所有文件中的 getUserName 改为 fetchUserProfile

Agent Mode 会自动:

  1. 扫描 src/utils 目录
  2. 找到所有包含 getUserName 的文件
  3. 逐个修改并保存

场景:添加 TypeScript 类型

为 src/api/*.ts 中所有导出的函数添加返回类型注解

4. 工具权限控制

Agent Mode 执行敏感操作前会请求确认。可在设置中调整:

{
"github.copilot.chat.agent.autoToolConfirmation": {
"readFile": true, // 自动允许读文件
"editFile": false, // 编辑文件需确认
"runInTerminal": false // 运行命令需确认
}
}

5. 可用工具列表

Agent Mode 可调用以下工具:

工具功能
readFile读取文件内容
editFile编辑文件
createFile创建新文件
deleteFile删除文件
runInTerminal执行终端命令
listDirectory列出目录内容
search搜索代码

FAQ

Q: Agent Mode 和 Ask Mode 有什么区别?

Ask Mode 只建议代码,需要手动复制粘贴;Agent Mode 可以直接执行文件编辑和终端命令,实现自动化。

Q: Agent Mode 安全吗?

Agent Mode 在执行敏感操作(如删除文件、运行命令)前会请求确认。建议在版本控制的仓库中使用,便于回滚。

Q: 为什么找不到 Agent Mode 选项?

确保已安装最新版 Copilot Chat 扩展(v0.15+),并在设置中启用 github.copilot.chat.agent.enabled

Q: Agent Mode 能执行哪些终端命令?

理论上可以执行任何命令,但建议用于安全的开发命令(如 npm installnpm run build),避免执行删除、部署等高风险操作。