记录一下自己在windows 11下使用codex遇到的一些问题和原因
我是都把全局utf8打开的,因为我没有老旧软件使用的需求,所以可能也因此没有遇到过codex乱码问题。
codex的shell机制
codex本身并没有读取文件和编辑文件的工具,也就是cc那样的read,write工具
cc自带的工具
codex自带的工具 (可以说是非常的克制了
所以为了codex方便的修改文件,codex在shell工具里加了一个机制
-
命令是否为bash -lc开头, 是则去掉并使用系统bash执行命令
-
命令是否为apply_patch,是则执行文件编辑操作
官方指令中的apply_patch prompt 有兴趣可以看看
## `apply_patch`
Use the `apply_patch` shell command to edit files.
Your patch language is a stripped‑down, file‑oriented diff format designed to be easy to parse and safe to apply. You can think of it as a high‑level envelope:
使用 `apply_patch` shell 命令编辑文件。
你的补丁语言是一种精简的、面向文件的差异格式,设计为易于解析和安全应用。你可以将其视为一个高级封装:
*** Begin Patch
[ one or more file sections ]
*** End Patch
Within that envelope, you get a sequence of file operations.
You MUST include a header to specify the action you are taking.
Each operation starts with one of three headers:
在该封装内,你得到一系列文件操作。
你必须包含标头来指定你要执行的操作。
每个操作都以三个标头之一开始:
*** Add File: <path> - create a new file. Every following line is a + line (the initial contents).
*** Delete File: <path> - remove an existing file. Nothing follows.
*** Update File: <path> - patch an existing file in place (optionally with a rename).
*** Add File: <path> - 创建新文件。每个后续行都是 + 行(初始内容)。
*** Delete File: <path> - 删除现有文件。没有后续内容。
*** Update File: <path> - 就地修补现有文件(可选择重命名)。
May be immediately followed by *** Move to: <new path> if you want to rename the file.
Then one or more "hunks", each introduced by @@ (optionally followed by a hunk header).
Within a hunk each line starts with:
如果要重命名文件,可以立即跟随 *** Move to: <new path>。
然后是一个或多个"块",每个都由 @@ 引入(可选择跟随块标头)。
在块内,每行开始于:
For instructions on [context_before] and [context_after]:
- By default, show 3 lines of code immediately above and 3 lines immediately below each change. If a change is within 3 lines of a previous change, do NOT duplicate the first change's [context_after] lines in the second change's [context_before] lines.
- If 3 lines of context is insufficient to uniquely identify the snippet of code within the file, use the @@ operator to indicate the class or function to which the snippet belongs. For instance, we might have:
关于 [context_before] 和 [context_after] 的说明:
- 默认情况下,显示每个更改正上方的 3 行代码和正下方的 3 行代码。如果更改在前一个更改的 3 行内,不要在第二个更改的 [context_before] 行中重复第一个更改的 [context_after] 行。
- 如果 3 行上下文不足以唯一标识文件内的代码片段,使用 @@ 操作符指示片段所属的类或函数。例如,我们可能有:
@@ class BaseClass
[3 lines of pre-context]
- [old_code]
+ [new_code]
[3 lines of post-context]
- If a code block is repeated so many times in a class or function such that even a single `@@` statement and 3 lines of context cannot uniquely identify the snippet of code, you can use multiple `@@` statements to jump to the right context. For instance:
- 如果代码块在类或函数中重复如此之多,以至于即使单个 `@@` 语句和 3 行上下文也无法唯一标识代码片段,你可以使用多个 `@@` 语句跳转到正确的上下文。例如:
@@ class BaseClass
@@ def method():
[3 lines of pre-context]
- [old_code]
+ [new_code]
[3 lines of post-context]
The full grammar definition is below:
Patch := Begin { FileOp } End
Begin := "*** Begin Patch" NEWLINE
End := "*** End Patch" NEWLINE
FileOp := AddFile | DeleteFile | UpdateFile
AddFile := "*** Add File: " path NEWLINE { "+" line NEWLINE }
DeleteFile := "*** Delete File: " path NEWLINE
UpdateFile := "*** Update File: " path NEWLINE [ MoveTo ] { Hunk }
MoveTo := "*** Move to: " newPath NEWLINE
Hunk := "@@" [ header ] NEWLINE { HunkLine } [ "*** End of File" NEWLINE ]
HunkLine := (" " | "-" | "+") text NEWLINE
完整的语法定义如下:
补丁 := 开始 { 文件操作 } 结束
开始 := "*** Begin Patch" 换行
结束 := "*** End Patch" 换行
文件操作 := 添加文件 | 删除文件 | 更新文件
添加文件 := "*** Add File: " 路径 换行 { "+" 行 换行 }
删除文件 := "*** Delete File: " 路径 换行
更新文件 := "*** Update File: " 路径 换行 [ 移动到 ] { 块 }
移动到 := "*** Move to: " 新路径 换行
块 := "@@" [ 标头 ] 换行 { 块行 } [ "*** End of File" 换行 ]
块行 := (" " | "-" | "+") 文本 换行
A full patch can combine several operations:
完整的补丁可以组合多个操作:
*** Begin Patch
*** Add File: hello.txt
+Hello world
*** Update File: src/app.py
*** Move to: src/main.py
@@ def greet():
-print("Hi")
+print("Hello, world!")
*** Delete File: obsolete.txt
*** End Patch
It is important to remember:
重要的是要记住:
- You must include a header with your intended action (Add/Delete/Update)
- You must prefix new lines with `+` even when creating a new file
- File references can only be relative, NEVER ABSOLUTE.
- 你必须包含你预期操作的标头(Add/Delete/Update)
- 即使在创建新文件时,也必须为新行添加 `+` 前缀
- 文件引用只能是相对的,永远不能是绝对的。
You can invoke apply_patch like:
你可以这样调用 apply_patch:
shell {"command":["apply_patch","*** Begin Patch\n*** Add File: hello.txt\n+Hello, world!\n*** End Patch\n"]}
-
如果都不符合则使用,pwsh或者powershell.exe -NoLogo -NoProfile -Command包裹执行
-
如果使用的是rg命令则会显示
-
如果使用的是sed命令则会显示

明白了这些之后,我们就可以解释一些问题了
- 有时候会使用powershell执行apply_patch,因为gpt5输出了使用powershell包裹执行的apply_patch,所以导致了shell检测到的是powershell,而不是apply_patch,于是被当作命令执行了。
这个问题会导致全部命令都使用包裹执行,于是还会导致全是

而不是
所以我们可以在prompt中添加相关的约束
禁止使用`bash -lc`或者`pwsh -Command`包裹调用
而是直接调用(e.g `{"command":["sg", "-p", "'console.log($$$ARGS)'"],"timeout_ms":120000,"workdir":"C:\\Users\\username"}`)
- 但新出的codex模型上面的问题会出现的更频繁,新模型是gpt5经过coding语料微调的,但是很明显大翻车,coding sft之后指令遵循能力变弱了,于是上面的指令已经约束不了了,于是我又遇到了和上面一样的情况。然后我就升级了我的prompt
### 已安装
- ast-grep
- busybox (无需带busybox前缀 e.g `{"command":["sed","-n","1p","file"]}`)
- rg
- dust (Like du but more intuitive)
- gh
- jq
### shell调用限制
进行代码搜索或批量替换时必须优先使用`ast-grep` 而不是使用`rg` 因为`ast-grep`更适合查找代码
已安装的工具必须直接调用(e.g `{"command":["sg", "-p", "'console.log($$$ARGS)'"],"timeout_ms":120000,"workdir":"C:\\Users\\username"}`)
必须使用`workdir`指定路径 而不是在命令中使用`cd`
禁止使用`bash -lc`或者`pwsh.exe -NoLogo -NoProfile -Command`或者`powershell.exe -NoLogo -NoProfile -Command`包裹调用已安装的工具
- “感觉codex新模型降智了”。有这种感觉很正常,因为发布中说的
很明显是基于router的技术,也就是使用分类模型判断你的请求应该分配更长的思考时间,还是直接就不需要分配。这个技术我就不评价了,为了省钱大家都在这样做(点名某ultrathink。但是codex这次很明显都没有调好就放出来了,于是就会导致复杂任务反而没怎么分配思考,导致效果较差。对于这个问题,我暂时没有很好的办法,因为openai并没有像anthropic那样在文档中说明可以使用关键词触发强制思考,所以最好的办法就是暂时不要使用codex模型,而是使用gpt5。



