apply_patch 工具讓 GPT-5.1 透過結構化差異,在你的程式碼庫中建立、更新和刪除檔案。模型不僅會提出編輯建議,還會輸出修補操作,由你的應用程式套用並回報結果,實現可反覆執行的多步驟程式碼編輯工作流程。
以下是使用 apply_patch 的一些常見情境:
- 跨檔案重構 :一次在多個檔案中重新命名符號、抽取輔助函式,或重新組織模組。
- 錯誤修正 :讓模型診斷問題,並輸出精確的修補程式。
- 產生測試與文件 :在變更程式碼的同時,建立新的測試檔案、測試治具和文件。
- 遷移與制式編輯 :套用重複性的結構化更新,例如 API 遷移、型別註記、格式修正等。
只要你能以文字描述程式碼庫和所需變更,apply_patch 通常就能產生對應的差異。
搭配 Responses API 使用 apply_patch 的大致流程如下:
- 呼叫 Responses API 並啟用
apply_patch 工具
- 在
input 中提供可用檔案的上下文或摘要,或提供工具讓模型探索你的檔案系統。
- 使用
tools=[{"type": "apply_patch"}] 啟用工具。
- 讓模型傳回一或多個修補操作
- Response 輸出會包含一或多個
apply_patch_call 物件。
- 每次呼叫會描述一項檔案操作:建立、更新或刪除。
- 在你的環境中套用修補程式
- 執行修補程式任務執行框架或指令碼,以完成下列工作:
- 解讀每個
apply_patch_call 的 operation 差異。
- 將修補程式套用至你的工作目錄或程式碼庫。
- 記錄每個修補程式是否套用成功,以及任何記錄或錯誤訊息。
- 向模型回報修補結果
- 再次呼叫 Responses API,使用
previous_response_id,或將對話項目放入 input 傳回。
- 為每個
call_id 加入一個 apply_patch_call_output 事件,其中包含 status,並可選擇加入 output 字串。
- 保留
tools=[{"type": "apply_patch"}],讓模型在需要時能繼續編輯。
- 讓模型繼續編輯或說明變更
- 模型可能會發出更多
apply_patch_call 操作,或
- 向使用者說明變更內容及原因。
步驟 1:要求模型規劃並輸出修補程式
1
2
3
4
5
6
7
8
9const response = await client.responses.create({
model: "gpt-6-astra",
input: fileContext,
tools: [{ type: "apply_patch" }],
});
const patchCalls = response.output.filter(
(item) => item.type === "apply_patch_call"
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42from openai import OpenAI
client = OpenAI()
# For brevity, we are including file context in the example input.
# Most agentic use cases should instead equip the model with tools
# for exploring file system state.
RESPONSE_INPUT = """
The user has the following files:
<BEGIN_FILES>
===== lib/fib.py
def fib(n):
if n <= 1:
return n
return fib(n-1) + fib(n-2)
===== run.py
from lib.fib import fib
def main():
print(fib(42))
<END_FILES>
You are a helpful coding assistant that should assist the user with whatever they
ask.
User query:
Help me rename the fib() function to fibonacci()
"""
response = client.responses.create(
model="gpt-6-astra",
input=RESPONSE_INPUT,
tools=[{"type": "apply_patch"}],
)
# response.output may contain multiple apply_patch_call entries, e.g.:
# - update lib/fib.py
# - update run.py
patch_calls = [
item.model_dump() for item in response.output if item.type == "apply_patch_call"
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String(responseInput)},
Tools: []responses.ToolUnionParam{{OfApplyPatch: &responses.ApplyPatchToolParam{}}},
})
if err != nil {
panic(err)
}
patchCalls := make([]responses.ResponseOutputItemUnion, 0)
for _, item := range response.Output {
if item.Type == "apply_patch_call" {
patchCalls = append(patchCalls, item)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.responses.ApplyPatchTool;
import com.openai.models.responses.ResponseCreateParams;
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input(
"Rename fib() to fibonacci() in lib/fib.py and update run.py to use the new name.")
.addTool(ApplyPatchTool.builder().build())
.build();
client.responses().create(params).output().stream()
.flatMap(item -> item.applyPatchCall().stream())
.forEach(System.out::println);
1
2
3
4
5
6
7
8
9
10
11require "openai"
client = OpenAI::Client.new
response = client.responses.create(
model: "gpt-6-astra",
input: "Rename fib() to fibonacci() in lib/fib.py and update run.py to use the new name.",
tools: [{ type: :apply_patch }]
)
patch_calls = response.output.select { |item| item.type == :apply_patch_call }
puts(patch_calls)
apply_patch_call 物件範例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18{
"id": "apc_08f3d96c87a585390069118b594f7481a088b16cda7d9415fe",
"type": "apply_patch_call",
"status": "completed",
"call_id": "call_Rjsqzz96C5xzPb0jUWJFRTNW",
"operation": {
"type": "update_file",
"diff": "
@@
-def fib(n):
+def fibonacci(n):
if n <= 1:
return n
- return fib(n-1) + fib(n-2) + return fibonacci(n-1) + fibonacci(n-2),
",
"path": "lib/fib.py"
}
}
步驟 2:套用修補程式並回傳結果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19const results = patchCalls.map((call) => {
const { success, output } = applyOperation(call.operation);
return {
type: "apply_patch_call_output",
call_id: call.call_id,
status: success ? "completed" : "failed",
output,
};
});
const followup = await client.responses.create({
model: "gpt-6-astra",
previous_response_id: response.id,
input: results,
tools: [{ type: "apply_patch" }],
});
console.log(followup.output_text);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22from apply_patch_harness import apply_operation # your implementation
results = []
for call in patch_calls:
op = call["operation"]
success, maybe_log_output = apply_operation(op)
results.append(
{
"type": "apply_patch_call_output",
"call_id": call["call_id"],
"status": "completed" if success else "failed",
"output": maybe_log_output,
}
)
followup = client.responses.create(
model="gpt-6-astra",
previous_response_id=response.id,
input=results,
tools=[{"type": "apply_patch"}],
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20results := make(responses.ResponseInputParam, 0, len(patchCalls))
for _, call := range patchCalls {
success, logOutput := applyOperation(call.Operation)
status := "completed"
if !success {
status = "failed"
}
result := responses.ResponseInputItemParamOfApplyPatchCallOutput(call.CallID, status)
result.OfApplyPatchCallOutput.Output = openai.String(logOutput)
results = append(results, result)
}
_, err = client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
PreviousResponseID: openai.String(response.ID),
Input: responses.ResponseNewParamsInputUnion{OfInputItemList: results},
Tools: []responses.ToolUnionParam{{OfApplyPatch: &responses.ApplyPatchToolParam{}}},
})
if err != nil {
panic(err)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.responses.ApplyPatchTool;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseInputItem;
import java.util.List;
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.inputOfResponse(
List.of(
ResponseInputItem.ofApplyPatchCallOutput(
ResponseInputItem.ApplyPatchCallOutput.builder()
.callId(System.getenv("OPENAI_EXAMPLE_APPLY_PATCH_CALL_ID"))
.status(ResponseInputItem.ApplyPatchCallOutput.Status.COMPLETED)
.output("Patch applied successfully.")
.build())))
.previousResponseId(System.getenv("OPENAI_EXAMPLE_PREVIOUS_RESPONSE_ID"))
.addTool(ApplyPatchTool.builder().build())
.build();
client.responses().create(params).output().stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.text()));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20require "openai"
client = OpenAI::Client.new
response_id = ENV.fetch("OPENAI_RESPONSE_ID")
patch_call_id = ENV.fetch("OPENAI_APPLY_PATCH_CALL_ID")
response = client.responses.create(
model: "gpt-6-astra",
previous_response_id: response_id,
input: [
{
type: :apply_patch_call_output,
call_id: patch_call_id,
status: :completed,
output: "Patch applied successfully."
}
],
tools: [{ type: :apply_patch }]
)
puts(response.output_text)
如果修補程式套用失敗(例如找不到檔案),請設定 status: "failed",並加入有助於排除問題的 output 字串,讓模型能從錯誤中恢復:
1
2
3
4
5
6{
"type": "apply_patch_call_output",
"call_id": "call_cNWm41dB3RyQcLNOVTIPBWZU",
"status": "failed",
"output": "Could not apply patch to lib/foo.py — file not found on disk"
}
| 操作類型 | 用途 | 承載資料 |
|---|
create_file | 在 path 建立新檔案。 | diff 是代表完整檔案內容的 V4A 差異。 |
update_file | 修改位於 path 的現有檔案。 | diff 是包含新增、刪除或取代內容的 V4A 差異。 |
delete_file | 移除位於 path 的檔案。 | 沒有 diff;直接刪除整個檔案。 |
你的修補程式任務執行框架負責解讀 V4A 差異格式並套用變更。如需參考實作,請參閱 Python Agents SDK 或 TypeScript Agents SDK 的程式碼。
使用 apply_patch 工具時,你不需要提供輸入結構描述;模型知道如何建構 operation 物件。你需要負責下列工作:
- 從 Response 解析操作
- 掃描 Response,找出具有
type: "apply_patch_call" 的項目。
- 針對每次呼叫,檢查
operation.type、operation.path,以及可能存在的 diff。
- 執行檔案操作
- 針對
create_file 和 update_file,將 V4A 差異檔套用至檔案系統或記憶體內的工作區。
- 針對
delete_file,刪除位於 path 的檔案。
- 記錄每項操作是否成功,以及所有日誌或錯誤訊息。
- 回傳
apply_patch_call_output 事件
- 針對每個
call_id,必須產生且僅產生一個 apply_patch_call_output 事件,並依下列情況設定:
- 若操作已成功套用,則設為
status: "completed"。
- 若遇到錯誤,則設為
status: "failed"(並附上一段簡短、易讀的 output 字串)。
- 路徑驗證:防止目錄穿越,並將編輯範圍限制在允許的目錄內。
- 備份:套用修補程式前,請考慮備份檔案(或在暫存副本中作業)。
- 錯誤處理:無法套用修補程式時,務必回傳
failed 狀態,並附上清楚說明問題的 output 字串。
- 原子性:決定要採用「全部成功或全部不套用」的語意(任一修補程式失敗就回復所有變更),還是逐一判定各檔案的操作成功或失敗。
你也可以透過 Agents SDK 使用套用修補程式工具。你仍須實作負責實際檔案操作的任務執行框架,但可以使用 applyDiff 函式處理差異檔。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51import { applyDiff, Agent, run, applyPatchTool } from "@openai/agents";
class WorkspaceEditor {
async createFile(operation) {
// convert the diff to the file content
const content = applyDiff("", operation.diff, "create");
// write the file content to the file system
return { status: "completed", output: `Created ${operation.path}` };
}
async updateFile(operation) {
// read the file content from the file system
const current = "";
// convert the diff to the new file content
const newContent = applyDiff(current, operation.diff);
// write the updated file content to the file system
return { status: "completed", output: `Updated ${operation.path}` };
}
async deleteFile(operation) {
// delete the file from the file system
return { status: "completed", output: `Deleted ${operation.path}` };
}
}
const editor = new WorkspaceEditor();
const agent = new Agent({
name: "Patch Assistant",
model: "gpt-6-astra",
instructions:
"You can edit files inside the /tmp directory using the apply_patch tool.",
tools: [
applyPatchTool({
editor,
// could also be a function for you to determine if approval is needed
needsApproval: true,
onApproval: async (_ctx, _approvalItem) => {
// create your own approval logic
return { approve: true };
},
}),
],
});
const result = await run(
agent,
"Create tasks.md with a shopping checklist of 5 entries."
);
console.log(`\nFinal response:\n${result.finalOutput}`);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54from agents import Agent, ApplyPatchTool, Runner, apply_diff
class WorkspaceEditor:
async def create_file(self, operation):
# convert the diff to the file content
content = apply_diff("", operation.diff, mode="create")
# write the file content to the file system
return {"status": "completed", "output": f"Created {operation.path}"}
async def update_file(self, operation):
# read the file content from the file system
current = ""
# convert the diff to the new file content
new_content = apply_diff(current, operation.diff)
# write the updated file content to the file system
return {"status": "completed", "output": f"Updated {operation.path}"}
async def delete_file(self, operation):
# delete the file from the file system
return {"status": "completed", "output": f"Deleted {operation.path}"}
editor = WorkspaceEditor()
agent = Agent(
name="Patch Assistant",
model="gpt-6-astra",
instructions="You can edit files inside the /tmp directory using the apply_patch tool.",
tools=[
ApplyPatchTool(
editor=editor,
# could also be a function for you to determine if approval is needed
needs_approval=True,
# Implement your own approval logic
on_approval=lambda _ctx, _approval_item: {"approve": True},
),
],
)
async def main():
result = await Runner.run(
agent,
input="Create tasks.md with a shopping checklist of 5 entries.",
)
print(f"\nFinal response:\n{result.final_output}")
if __name__ == "__main__":
import asyncio
asyncio.run(main())
你可以在 GitHub 上找到完整且可執行的範例。
在 TypeScript 中搭配 Agents SDK 使用套用修補程式工具的範例
在 Python 中搭配 Agents SDK 使用套用修補程式工具的範例
使用 status: "failed" 並附上清楚的 output 訊息,協助模型從錯誤中復原。
找不到檔案
1
2
3
4
5
6{
"type": "apply_patch_call_output",
"call_id": "call_abc",
"status": "failed",
"output": "Error: File not found at path 'lib/baz.py'"
}
修補程式衝突
1
2
3
4
5
6{
"type": "apply_patch_call_output",
"call_id": "call_abc",
"status": "failed",
"output": "Error: Invalid Context:\n@@ def fib(n):"
}
模型接著便能根據這些錯誤訊息調整後續的差異檔,例如重新讀取提示詞中的檔案,或簡化變更。
- 提供清楚的檔案上下文
- 呼叫 Responses API 時,請直接在請求中附上檔案快照(如範例所示),或提供模型可用來探索檔案系統的工具(例如
shell 工具)。
- 考慮搭配
shell 工具使用
- 搭配
shell 工具使用時,模型可以探索檔案系統目錄、讀取檔案,並使用 grep 搜尋關鍵字,讓智慧體能自主尋找及編輯檔案。
- 鼓勵產生範圍小且目標明確的差異檔
- 在系統指示中,引導模型進行最少且有針對性的編輯,而非大幅重寫。
- 確保變更能順利套用
- 套用一系列修補程式後,請執行測試或程式碼檢查工具,並在下一次
input 中回報失敗資訊,讓模型修正問題。