Windows 上彻底解决 Codex / Claude / OpenCode 中文乱码
Windows AI CLI 中文乱码解决方案 本文针对 Windows 系统上 Codex/Claude/OpenCode 等 AI 工具的中文乱码问题提供完整解决方案。首先区分终端显示乱码和文件内容损坏两种情况,指出后者会直接影响源码质量。分析问题根源在于 Windows 默认使用 GBK 编码而 AI 工具输出 UTF-8 编码的冲突。 提供快速诊断方法检查当前编码状态,并给出完整的一键修复
Windows 上彻底解决 Codex / Claude / OpenCode 中文乱码
乱码不修,AI 会把你的源码写坏。这篇给出诊断+修复+全自动部署脚本,支持按需选择安装哪个工具。
一、先判断:是显示乱码,还是文件被写坏了?
打开 AI 工具跑几个命令,如果看到:
中文 → ?????、äã、â–、锟斤拷、测试
emoji → 方框、问号
首先要区分两种情况:
| 类型 | 表现 | 严重程度 |
|---|---|---|
| 终端显示乱码 | 只在终端输出里乱码,源码文件本身正常 | 烦人但不危险 |
| 文件内容损坏 | VS Code 打开源码也乱码,git diff 看到 AI 改了文件 | 必须立即处理 |
重点原则:不要让 AI 看到终端乱码后去"修复"源文件。 它会把正常的中文替换成真的乱码字节。
二、为什么 Windows 上 AI CLI 会乱码?
Windows 中文版默认使用 CP936 (GBK) 编码,而 AI 工具内部调用的 PowerShell / Bash 输出的中文是 UTF-8。这两者对不上,就成了乱码。
关键链路:
AI 调用 PowerShell
→ powershell.exe -NoProfile(跳过了你的 UTF-8 设置)
→ Console OutputEncoding = gb2312
→ UTF-8 字节被按 GBK 解码
→ 乱码传给 AI
三个工具的共同问题:
- Windows PowerShell 5.1 默认 code page 是 936(中文系统)
- AI 工具常用
-NoProfile启动 PowerShell,绕过了用户的 profile 设置 - Console OutputEncoding 不是 UTF-8,管道输出被错误编码
- 字体不含 CJK(中文/日文/韩文)字符
三、快速诊断(30 秒)
在 PowerShell 中运行:
# 查看当前编码状态
cmd /c chcp
# 查看 PowerShell 编码设置
[Console]::InputEncoding.WebName
[Console]::OutputEncoding.WebName
$OutputEncoding.WebName
# Unicode 烟雾测试
"中文测试 😀 äöü Привет こんにちは 한국어"
期望看到:
Active code page: 65001 # ← 必须是 65001
ConsoleInputEncoding = utf-8
ConsoleOutputEncoding = utf-8
OutputEncoding = utf-8
中文测试 😀 äöü Привет こんにちは 한국어 # ← 完整显示
如果你的 code page 是 936,OutputEncoding 是 gb2312,中文显示成 ??? → 继续往下看。
四、一键修复脚本(支持按需安装)
下面的脚本会:
- 安装 PowerShell 7(如果还没装)
- 创建 UTF-8 启动 wrapper(
codexu/claudeu/opencodeu) - 给 PowerShell profile 添加 UTF-8 引导
- 配置 Git UTF-8 参数
- 为每个已安装的 AI 工具添加编码规则
完整部署脚本
把下面脚本保存为 setup-ai-cli-utf8.ps1,以管理员身份运行:
# setup-ai-cli-utf8.ps1
# Windows AI CLI 乱码修复一键脚本
# 支持 Codex CLI / Claude Code / OpenCode
# 用法: powershell -ExecutionPolicy Bypass -File .\setup-ai-cli-utf8.ps1
param(
[switch]$Codex, # 只配置 Codex CLI
[switch]$Claude, # 只配置 Claude Code
[switch]$OpenCode, # 只配置 OpenCode
[switch]$All # 配置所有已安装的工具(默认)
)
$ErrorActionPreference = "Stop"
# 如果没有指定,默认处理所有已安装的工具
if (-not ($Codex -or $Claude -or $OpenCode)) {
$All = $true
}
Write-Host "========================================" -ForegroundColor Cyan
Write-Host " Windows AI CLI UTF-8 修复脚本" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
# === 诊断当前状态 ===
Write-Host "`n=== 诊断当前编码状态 ===" -ForegroundColor Yellow
$CurrentCodePage = cmd /c chcp 2>&1
Write-Host "当前 Code Page: $CurrentCodePage"
$ConsoleOutEnc = [Console]::OutputEncoding.WebName
$OutputEnc = $OutputEncoding.WebName
Write-Host "Console OutputEncoding: $ConsoleOutEnc"
Write-Host "OutputEncoding: $OutputEnc"
if ($ConsoleOutEnc -eq "utf-8" -and $OutputEnc -eq "utf-8") {
Write-Host "编码已为 UTF-8,无需修复。" -ForegroundColor Green
Write-Host "如果仍有乱码,可能是字体问题,跳转到字体检查部分。"
$NeedsFix = $false
} else {
Write-Host "编码不是 UTF-8,需要修复。" -ForegroundColor Red
$NeedsFix = $true
}
# === [1/6] 安装 PowerShell 7 ===
Write-Host "`n=== [1/6] 检查并安装 PowerShell 7 ===" -ForegroundColor Yellow
$HasPwsh = Get-Command pwsh -ErrorAction SilentlyContinue
if ($HasPwsh) {
Write-Host "PowerShell 7 已安装: $(pwsh -Version)" -ForegroundColor Green
} else {
Write-Host "正在通过 winget 安装 PowerShell 7..." -ForegroundColor Yellow
try {
winget install --id Microsoft.PowerShell --source winget --accept-source-agreements --accept-package-agreements
Write-Host "PowerShell 7 安装完成" -ForegroundColor Green
} catch {
Write-Host "winget 安装失败,请手动安装: https://github.com/PowerShell/PowerShell" -ForegroundColor Red
}
}
# === [2/6] 创建 UTF-8 Core 脚本 ===
Write-Host "`n=== [2/6] 创建 UTF-8 引导脚本 ===" -ForegroundColor Yellow
$BinDir = Join-Path $env:USERPROFILE "bin"
New-Item -ItemType Directory -Path $BinDir -Force | Out-Null
$CoreScript = Join-Path $BinDir "ai-cli-utf8-core.ps1"
$CoreContent = @'
# ai-cli-utf8-core.ps1
# 所有 AI CLI wrapper 共用的 UTF-8 引导脚本
try {
chcp 65001 | Out-Null
} catch {
# chcp 不可用时忽略
}
$Utf8NoBom = [System.Text.UTF8Encoding]::new($false)
try { [Console]::InputEncoding = $Utf8NoBom } catch {}
try { [Console]::OutputEncoding = $Utf8NoBom } catch {}
$global:OutputEncoding = $Utf8NoBom
# 语言运行时编码
$env:PYTHONUTF8 = "1"
$env:PYTHONIOENCODING = "utf-8"
$env:LESSCHARSET = "utf-8"
# Git Bash / MSYS 兼容
if (-not $env:LANG) {
$env:LANG = "C.UTF-8"
}
'@
Set-Content -Path $CoreScript -Value $CoreContent -Encoding UTF8
Write-Host "核心引导脚本已创建: $CoreScript" -ForegroundColor Green
# === [3/6] 创建 Wrapper 脚本 ===
Write-Host "`n=== [3/6] 创建 UTF-8 Wrapper ===" -ForegroundColor Yellow
function New-Wrapper {
param([string]$ToolName)
$Ps1Path = Join-Path $BinDir "$($ToolName)u.ps1"
$CmdPath = Join-Path $BinDir "$($ToolName)u.cmd"
# .ps1 wrapper
$Ps1Content = @"
param(
[Parameter(ValueFromRemainingArguments = `$true)]
[string[]]`$RemainingArgs
)
. "`$PSScriptRoot\ai-cli-utf8-core.ps1"
`$cmd = Get-Command "$ToolName" -ErrorAction SilentlyContinue
if (-not `$cmd) {
Write-Error "Command '$ToolName' was not found in PATH. Install it first, then retry."
exit 127
}
& "$ToolName" @RemainingArgs
exit `$LASTEXITCODE
"@
Set-Content -Path $Ps1Path -Value $Ps1Content -Encoding UTF8
# .cmd wrapper (兼容直接在 cmd 中调用)
$CmdContent = @"
@echo off
chcp 65001 >nul
where pwsh >nul 2>nul
if errorlevel 1 (
powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -File "%~dp0$($ToolName)u.ps1" %*
) else (
pwsh -NoLogo -NoProfile -ExecutionPolicy Bypass -File "%~dp0$($ToolName)u.ps1" %*
)
"@
Set-Content -Path $CmdPath -Value $CmdContent -Encoding ASCII
Write-Host " $($ToolName)u.ps1 / $($ToolName)u.cmd 已创建" -ForegroundColor Green
}
# 检查哪些工具已安装
$HasCodex = Get-Command codex -ErrorAction SilentlyContinue
$HasClaude = Get-Command claude -ErrorAction SilentlyContinue
$HasOpenCode = Get-Command opencode -ErrorAction SilentlyContinue
if ($Codex -or $All) {
if ($HasCodex) {
New-Wrapper "codex"
} else {
Write-Host " Codex CLI 未安装,跳过" -ForegroundColor DarkYellow
}
}
if ($Claude -or $All) {
if ($HasClaude) {
New-Wrapper "claude"
} else {
Write-Host " Claude Code 未安装,跳过" -ForegroundColor DarkYellow
}
}
if ($OpenCode -or $All) {
if ($HasOpenCode) {
New-Wrapper "opencode"
} else {
Write-Host " OpenCode 未安装,跳过" -ForegroundColor DarkYellow
}
}
# === [4/6] 配置 PATH ===
Write-Host "`n=== [4/6] 配置系统 PATH ===" -ForegroundColor Yellow
$UserPath = [Environment]::GetEnvironmentVariable("Path", "User")
if ($UserPath -notlike "*$BinDir*") {
$NewPath = if ($UserPath) { "$UserPath;$BinDir" } else { $BinDir }
[Environment]::SetEnvironmentVariable("Path", $NewPath, "User")
$env:Path = "$env:Path;$BinDir"
Write-Host "已将 $BinDir 添加到用户 PATH" -ForegroundColor Green
} else {
Write-Host "$BinDir 已在 PATH 中" -ForegroundColor DarkYellow
}
# === [5/6] 配置 PowerShell Profile ===
Write-Host "`n=== [5/6] 配置 PowerShell Profile ===" -ForegroundColor Yellow
$ProfileDir = Split-Path $PROFILE -Parent
New-Item -ItemType Directory -Path $ProfileDir -Force | Out-Null
$Marker = "# >>> AI CLI UTF-8 bootstrap >>>"
$ProfileNeedsPatch = $true
if (Test-Path $PROFILE) {
$ProfileNeedsPatch = -not (Select-String -Path $PROFILE -SimpleMatch $Marker -Quiet)
}
if ($ProfileNeedsPatch) {
$Snippet = @"
# >>> AI CLI UTF-8 bootstrap >>>
`$AiCliUtf8Core = Join-Path `$env:USERPROFILE 'bin\ai-cli-utf8-core.ps1'
if (Test-Path `$AiCliUtf8Core) {
. `$AiCliUtf8Core
}
# <<< AI CLI UTF-8 bootstrap <<<
"@
Add-Content -Path $PROFILE -Value $Snippet -Encoding UTF8
Write-Host "PowerShell Profile 已添加 UTF-8 引导" -ForegroundColor Green
} else {
Write-Host "Profile 中已存在 UTF-8 引导" -ForegroundColor DarkYellow
}
# 同样为 PowerShell 7 配置 profile
$PwshProfile = Join-Path ([Environment]::GetFolderPath('MyDocuments')) "PowerShell\Microsoft.PowerShell_profile.ps1"
$PwshProfileDir = Split-Path $PwshProfile -Parent
New-Item -ItemType Directory -Path $PwshProfileDir -Force | Out-Null
$PwshNeedsPatch = $true
if (Test-Path $PwshProfile) {
$PwshNeedsPatch = -not (Select-String -Path $PwshProfile -SimpleMatch $Marker -Quiet)
}
if ($PwshNeedsPatch) {
Add-Content -Path $PwshProfile -Value $Snippet -Encoding UTF8
Write-Host "PowerShell 7 Profile 已添加 UTF-8 引导" -ForegroundColor Green
}
# === [6/6] 配置 Git & 工具规则 ===
Write-Host "`n=== [6/6] 配置 Git UTF-8 和工具编码规则 ===" -ForegroundColor Yellow
# Git
try {
git config --global core.quotepath false
git config --global i18n.logOutputEncoding utf-8
git config --global i18n.commitEncoding utf-8
Write-Host "Git UTF-8 配置完成" -ForegroundColor Green
} catch {
Write-Host "Git 配置失败(可能未安装),跳过" -ForegroundColor DarkYellow
}
# 编码规则内容
$EncodingRules = @"
# Windows encoding rules
- When running PowerShell on Windows, set UTF-8 first:
`chcp 65001; [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new(`$false); `$OutputEncoding = [System.Text.UTF8Encoding]::new(`$false)`.
- Do not judge source file corruption from terminal-rendered mojibake alone.
- Before rewriting files that contain non-ASCII text, validate bytes using strict UTF-8 decoding.
- Preserve existing file encoding where possible.
- Prefer UTF-8 without BOM for cross-platform source files.
- For `.ps1` scripts intended for Windows PowerShell 5.1 with non-ASCII characters, UTF-8 with BOM may be safer.
"@
# Codex CLI: 写入 AGENTS.md
if ($Codex -or $All) {
if ($HasCodex) {
$CodexDir = Join-Path $env:USERPROFILE ".codex"
if (Test-Path $CodexDir) {
$CodexAgents = Join-Path $CodexDir "AGENTS.md"
$Existing = if (Test-Path $CodexAgents) { Get-Content $CodexAgents -Raw } else { "" }
if ($Existing -notmatch "Windows encoding rules") {
Set-Content -Path $CodexAgents -Value "$Existing$EncodingRules" -Encoding UTF8
Write-Host "Codex CLI AGENTS.md 已添加编码规则" -ForegroundColor Green
} else {
Write-Host "Codex CLI AGENTS.md 已包含编码规则" -ForegroundColor DarkYellow
}
}
}
}
# Claude Code: 写入 CLAUDE.md
if ($Claude -or $All) {
if ($HasClaude) {
$ClaudeDir = Join-Path $env:USERPROFILE ".claude"
if (Test-Path $ClaudeDir) {
$ClaudeMd = Join-Path $ClaudeDir "CLAUDE.md"
$Existing = if (Test-Path $ClaudeMd) { Get-Content $ClaudeMd -Raw } else { "" }
if ($Existing -notmatch "Windows encoding rules") {
Set-Content -Path $ClaudeMd -Value "$Existing$EncodingRules" -Encoding UTF8
Write-Host "Claude Code CLAUDE.md 已添加编码规则" -ForegroundColor Green
} else {
Write-Host "Claude Code CLAUDE.md 已包含编码规则" -ForegroundColor DarkYellow
}
}
}
}
# OpenCode: 写入 AGENTS.md
if ($OpenCode -or $All) {
if ($HasOpenCode) {
$OpenCodeDir = Join-Path $env:USERPROFILE ".opencode"
if (-not (Test-Path $OpenCodeDir)) {
New-Item -ItemType Directory -Path $OpenCodeDir -Force | Out-Null
}
$OpenCodeAgents = Join-Path $OpenCodeDir "AGENTS.md"
$Existing = if (Test-Path $OpenCodeAgents) { Get-Content $OpenCodeAgents -Raw } else { "" }
if ($Existing -notmatch "Windows encoding rules") {
Set-Content -Path $OpenCodeAgents -Value "$Existing$EncodingRules" -Encoding UTF8
Write-Host "OpenCode AGENTS.md 已添加编码规则" -ForegroundColor Green
} else {
Write-Host "OpenCode AGENTS.md 已包含编码规则" -ForegroundColor DarkYellow
}
}
}
# === 完成 ===
Write-Host "`n========================================" -ForegroundColor Green
Write-Host " UTF-8 修复完成!" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Green
Write-Host ""
Write-Host "已创建的 Wrapper 命令:" -ForegroundColor Cyan
if ($HasCodex) { Write-Host " codexu -> 启动 Codex CLI (UTF-8)" -ForegroundColor White }
if ($HasClaude) { Write-Host " claudeu -> 启动 Claude Code (UTF-8)" -ForegroundColor White }
if ($HasOpenCode) { Write-Host " opencodeu -> 启动 OpenCode (UTF-8)" -ForegroundColor White }
Write-Host ""
Write-Host "使用方式:" -ForegroundColor Cyan
Write-Host " # 新开一个 PowerShell 窗口,运行:"
Write-Host ""
if ($HasCodex) { Write-Host " codexu" -ForegroundColor White }
if ($HasClaude) { Write-Host " claudeu" -ForegroundColor White }
if ($HasOpenCode) { Write-Host " opencodeu" -ForegroundColor White }
Write-Host ""
Write-Host "验证 UTF-8 是否生效:" -ForegroundColor Cyan
Write-Host " pwsh -Command `"chcp; Write-Host '中文测试 😀'`""
Write-Host ""
Write-Host "如果仍然乱码,检查:" -ForegroundColor Yellow
Write-Host " 1. 终端字体是否支持 CJK(推荐 Windows Terminal + Sarasa Gothic / Cascadia Code)"
Write-Host " 2. 是否用 codexu/claudeu/opencodeu 启动(而非 codex/claude/opencode)"
Write-Host " 3. 项目是否在 WSL2 中运行效果更好"
按需安装示例
# 安装所有已检测到的工具
powershell -ExecutionPolicy Bypass -File .\setup-ai-cli-utf8.ps1
# 只配置 Codex CLI
powershell -ExecutionPolicy Bypass -File .\setup-ai-cli-utf8.ps1 -Codex
# 只配置 Claude Code
powershell -ExecutionPolicy Bypass -File .\setup-ai-cli-utf8.ps1 -Claude
# 只配置 OpenCode
powershell -ExecutionPolicy Bypass -File .\setup-ai-cli-utf8.ps1 -OpenCode
五、工具专项处理
5.1 Codex CLI 额外配置
Codex CLI 有一个实验性的 powershell_utf8 feature。检查是否可用:
codex features list
如果列表中有 powershell_utf8,启用它:
codex features enable powershell_utf8
如果报 unknown feature,说明你的版本还不支持——没关系,用 codexu wrapper 就够了。
也可以直接编辑配置文件 ~\.codex\config.toml:
[features]
powershell_utf8 = true
5.2 Claude Code 额外配置
Claude Code 可以使用 Git Bash 而不是 PowerShell。如果你的 Git Bash 路径不对,在 ~\.claude\settings.json 中指定:
{
"env": {
"CLAUDE_CODE_GIT_BASH_PATH": "C:\\Program Files\\Git\\bin\\bash.exe"
}
}
如果想强制使用 PowerShell:
{
"env": {
"CLAUDE_CODE_USE_POWERSHELL_TOOL": "1"
},
"defaultShell": "powershell"
}
如果 PowerShell tool 导致乱码而 Git Bash 正常:
{
"env": {
"CLAUDE_CODE_USE_POWERSHELL_TOOL": "0"
}
}
5.3 OpenCode 额外处理
OpenCode 官方推荐 WSL。如果 native Windows 一直乱码:
# 安装 WSL2
wsl --install
# 在 WSL 内
curl -fsSL https://opencode.ai/install | bash
opencode
如果坚持 Windows native,务必用 opencodeu 启动。
六、字体:最后一道防线
编码已经是 UTF-8 了,但中文还是方框?换字体:
Windows Terminal 推荐字体:
- Sarasa Gothic (更纱黑体) — 中英文等宽,自带 Nerd Font
- Cascadia Code — 微软出品,支持 Powerline
- Fira Code — 程序员最爱,带连字
在 Windows Terminal 中:设置 → 配置文件 → PowerShell → 外观 → 字体。
VS Code 集成终端字体:
{
"terminal.integrated.fontFamily": "'Cascadia Code PL', 'Sarasa Mono SC', 'Fira Code'"
}
七、严格 UTF-8 文件校验
如果怀疑某个源文件已经被乱码损坏,用这个函数检查(而非肉眼判断终端输出):
function Test-StrictUtf8File {
param([Parameter(Mandatory = $true)][string]$Path)
$Utf8Strict = [System.Text.UTF8Encoding]::new($false, $true)
try {
$Bytes = [System.IO.File]::ReadAllBytes((Resolve-Path $Path))
$null = $Utf8Strict.GetString($Bytes)
[pscustomobject]@{
Path = $Path
StrictUtf8 = $true
Length = $Bytes.Length
Error = $null
}
} catch {
[pscustomobject]@{
Path = $Path
StrictUtf8 = $false
Length = $null
Error = $_.Exception.Message
}
}
}
# 批量检查源码文件
Get-ChildItem -Recurse -File | Where-Object {
$_.Extension -in ".md",".txt",".json",".js",".ts",".tsx",".py",".ps1",".rs",".go",".toml"
} | ForEach-Object { Test-StrictUtf8File $_.FullName } | Where-Object { -not $_.StrictUtf8 }
八、安全写文件
在 Windows 上写含中文的文件时,不要用:
# 错误——在 PS5.1 中会产生非 UTF-8 输出
"中文内容" > file.txt
"中文内容" | Out-File file.txt
正确做法:
# PowerShell 7
Set-Content file.txt "中文内容 😀" -Encoding utf8NoBOM
# PowerShell 5.1(.NET API 写 UTF-8 without BOM)
$text = "中文内容 😀"
[System.IO.File]::WriteAllText("file.txt", $text, [System.Text.UTF8Encoding]::new($false))
九、执行顺序总结
1. [ ] 运行诊断 → 确认 code page 是 936
2. [ ] 安装 PowerShell 7 → winget install Microsoft.PowerShell
3. [ ] 运行 setup-ai-cli-utf8.ps1 → 自动创建 wrapper + profile + 规则
4. [ ] 新开终端 → codexu / claudeu / opencodeu 启动
5. [ ] 验证 → "中文测试 😀" 完整显示
6. [ ] 换字体 → 如果仍有方框
7. [ ] 检查 Codex features → powershell_utf8
8. [ ] 配置 Claude shell → settings.json
9. [ ] 严格校验文件 → Test-StrictUtf8File
10.[ ] 仍不行 → 迁移到 WSL2
十、WSL2:终极方案
如果以上都试了还是乱码(尤其是 OpenCode),把项目迁移到 WSL2:
# 安装 WSL
wsl --install
# 进入 WSL
wsl
# 在 WSL 内安装工具
npm i -g @openai/codex # Codex CLI
curl -fsSL https://claude.ai/install.sh | bash # Claude Code
curl -fsSL https://opencode.ai/install | bash # OpenCode
WSL 内的 Linux 原生环境天然就是 UTF-8,不存在编码问题。
总结
Windows 中文 AI CLI 乱码三件套:
- PowerShell 7 替代 PS 5.1
- codexu / claudeu / opencodeu wrapper 启动
- AGENTS.md / CLAUDE.md 编码规则,防止 AI 误判
装好就忘,AI 再也不会把你的中文源码写坏了。
更多推荐



所有评论(0)