很多人尝试codex模型的第一反应该都是,这家伙怎么那么喜欢写脚本改代码啊???
我第一次用的时候也很迷惑,因为按道理来说openai不至于在gpt5的基础上训练出一个更弱智的模型,并且还放出来,并且还作为codex cli 0.40.0版本的默认模型。
所以我又去掏codex的源码了
也就是说codex模型和gpt5模型用的是不一样的system prompt
/// The `instructions` field in the payload sent to a model should always start
/// with this content.
const BASE_INSTRUCTIONS: &str = include_str!("../prompt.md");
const GPT_5_CODEX_INSTRUCTIONS: &str = include_str!("../gpt_5_codex_prompt.md");
并且由于codex模型没有设置 needs_special_apply_patch_instructions: true
所以也不会添加apply_patch的相关提示词
/// Returns a `ModelFamily` for the given model slug, or `None` if the slug
/// does not match any known model family.
pub fn find_family_for_model(slug: &str) -> Option<ModelFamily> {
if slug.starts_with("codex-") || slug.starts_with("gpt-5-codex") {
model_family!(
slug, slug,
supports_reasoning_summaries: true,
reasoning_summary_format: ReasoningSummaryFormat::Experimental,
base_instructions: GPT_5_CODEX_INSTRUCTIONS.to_string(),
)
} else if slug.starts_with("gpt-5") {
model_family!(
slug, "gpt-5",
supports_reasoning_summaries: true,
needs_special_apply_patch_instructions: true,
)
} else {
None
}
}
/// Detailed instructions for gpt-4.1 on how to use the `apply_patch` tool.
pub const APPLY_PATCH_TOOL_INSTRUCTIONS: &str = include_str!("../apply_patch_tool_instructions.md");
impl Prompt {
pub(crate) fn get_full_instructions<'a>(&'a self, model: &'a ModelFamily) -> Cow<'a, str> {
let base = self
.base_instructions_override
.as_deref()
.unwrap_or(model.base_instructions.deref());
// When there are no custom instructions, add apply_patch_tool_instructions if:
// - the model needs special instructions (4.1)
// AND
// - there is no apply_patch tool present
let is_apply_patch_tool_present = self.tools.iter().any(|tool| match tool {
OpenAiTool::Function(f) => f.name == "apply_patch",
OpenAiTool::Freeform(f) => f.name == "apply_patch",
_ => false,
});
if self.base_instructions_override.is_none()
&& model.needs_special_apply_patch_instructions
&& !is_apply_patch_tool_present
{
Cow::Owned(format!("{base}\n{APPLY_PATCH_TOOL_INSTRUCTIONS}"))
} else {
Cow::Borrowed(base)
}
}
pub(crate) fn get_formatted_input(&self) -> Vec<ResponseItem> {
self.input.clone()
}
}
而在这一篇中,我们提到过apply_patch就是codex用于修改文件的tool。
于是非常聪明的codex模型在发现没有可以用于修改文件的工具后,就开始了使用各种脚本进行修改文件的尝试,这就是开局提到的现象。
那么应该怎么解决呢,也很简单,我们把缺失的apply_patch提示词补上就可以了。
但问题是,openai官方为什么故意不添加apply_patch的提示词呢?
我的猜测是codex模型就是基于gpt5模型的coding数据sft出来的模型,所以openai很自信的认为已经不需要提示它使用apply_patch了,但结果很明显,codex模型根本不知道还有一个apply_patch工具被hook在了shell工具之中,导致tool定义里没有apply_patch的时候,是完全不知道可以使用apply_patch的。
更可能的原因是codex模型的测试集就没有在win上跑过,但是codex识别到环境是win,会倾向于使用pwsh命令,(比如就算我说明我安装了find sed等工具,新模型偶尔还是倾向于使用Get-Content命令,并且对于pwsh的反引号转义一窍不通),于是出错概率很大。
但我不想换linux,也不想跑wsl。 ::melting_face::
所以我下一篇可能会写怎么在git bash上跑
基于以上猜测,我们就可以不完全补上apply_patch的提示词了
# Text Editing Tools
When performing text editing, must use the `apply_patch` tool instead of running temporary scripts with Python commands to edit files (e.g `{"command":["apply_patch","*** Begin Patch\n*** Add File: test.txt\n+test\n*** End Patch\n"],"workdir":"<workdir>","justification":"Create file test.txt"}`)
只需要添加上apply_patch的调用例子,并且强调应该使用apply_patch进行文件修改,应该就和gpt5模型行为对齐了。