Responses API에서 apply_patch를 사용하면 모델이 파일 생성, 수정, 삭제 작업을 구조화된 diff로 제안할 수 있습니다. 애플리케이션은 각 작업을 적용하고 그 결과를 모델에 반환합니다. 예제에서 사용하는 모델은 gpt-6-astra입니다.
사용 시점
apply_patch는 다음과 같은 작업에 사용할 수 있습니다.
- 여러 파일 리팩터링 – 여러 파일에 걸쳐 심볼 이름을 바꾸거나, 헬퍼를 추출하거나, 모듈을 한 번에 재구성합니다.
- 버그 수정 – 모델에 문제 진단과 정확한 수정 패치 생성을 함께 맡깁니다.
- 테스트 및 문서 생성 – 코드를 변경하면서 새 테스트 파일, 픽스처, 문서를 함께 만듭니다.
- 마이그레이션 및 일괄 수정 – API 마이그레이션, 타입 어노테이션 추가, 서식 수정처럼 일정한 규칙에 따라 반복되는 변경을 적용합니다.
레포지토리와 원하는 변경 사항을 텍스트로 설명할 수 있다면 대개 apply_patch로 그에 맞는 diff를 생성할 수 있습니다.
Responses API에서 패치 적용 도구 사용하기
Responses API에서 apply_patch를 사용하는 절차는 다음과 같습니다.
apply_patch도구를 활성화해 Responses API 호출하기input에 사용 가능한 파일에 관한 컨텍스트나 요약을 포함하거나, 모델에 파일 시스템을 탐색할 도구를 제공하세요.tools=[{"type": "apply_patch"}]로 도구를 활성화하세요.
- 모델로부터 하나 이상의 패치 작업 받기
- 응답 출력에는
apply_patch_call객체가 하나 이상 포함됩니다. - 각 호출은 파일 하나에 대한 생성, 수정, 삭제 작업 중 하나를 지정합니다.
- 응답 출력에는
- 작업 환경에 패치 적용하기
- 다음 작업을 수행하는 패치 하네스나 스크립트를 실행하세요.
operation에 담긴 diff를apply_patch_call별로 해석합니다.- 작업 디렉터리나 레포지토리에 패치를 적용합니다.
- 각 패치의 성공 여부를 기록하고, 로그나 오류 메시지가 있으면 함께 기록합니다.
- 다음 작업을 수행하는 패치 하네스나 스크립트를 실행하세요.
- 모델에 패치 결과 전달하기
previous_response_id를 사용하거나 대화 항목을input에 다시 넣어 Responses API를 다시 호출하세요.apply_patch_call_output이벤트를 각call_id에 하나씩 포함하세요. 이벤트에는status가 필요하며output문자열은 선택 사항입니다.- 모델이 필요할 때 편집을 이어갈 수 있도록
tools=[{"type": "apply_patch"}]설정을 유지하세요.
- 모델이 편집을 이어가거나 변경 사항을 설명하도록 하기
- 모델은
apply_patch_call작업을 추가로 요청할 수 있습니다. - 또는 무엇을 왜 변경했는지 사용자에게 설명할 수 있습니다.
- 모델은
예제: 패치 적용 도구로 함수 이름 바꾸기
1단계: 모델에 변경 계획을 세우고 패치를 생성하도록 요청하기
import OpenAI from "openai";
// Application-owned helper; see "Implementing the patch harness" in the guide.
// This demo only applies exact updates to the two in-memory files below.
import { applyOperation } from "../../support/apply-patch.mjs";
const client = new OpenAI();
const 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
print(fib(42))
`,
};
const fileContext = `The user has the following files:
<BEGIN_FILES>
${Object.entries(files)
.map(([path, content]) => `===== ${path}\n${content}`)
.join("\n")}
<END_FILES>
Help me rename the fib() function to fibonacci().`;
let response = await client.responses.create({
model: "gpt-6-astra",
input: fileContext,
tools: [{ type: "apply_patch" }],
});
let patchCalls = response.output.filter(
(item) => item.type === "apply_patch_call"
);apply_patch_call 객체 예시
{
"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단계: 패치를 적용하고 모델에 결과 전달하기
for (let turn = 0; patchCalls.length > 0; turn++) {
if (turn === 8) throw new Error("Patch workflow exceeded eight tool turns.");
const results = patchCalls.map((call) => {
const { success, output } = applyOperation(files, call.operation);
return {
type: "apply_patch_call_output",
call_id: call.call_id,
status: success ? "completed" : "failed",
output,
};
});
response = await client.responses.create({
model: "gpt-6-astra",
previous_response_id: response.id,
input: results,
tools: [{ type: "apply_patch" }],
});
patchCalls = response.output.filter(
(item) => item.type === "apply_patch_call"
);
}
console.log(response.output_text);
for (const [path, content] of Object.entries(files)) {
process.stdout.write(`===== ${path}\n${content}`);
}파일을 찾을 수 없는 등의 이유로 패치 적용에 실패하면 status: "failed"로 설정하세요. 모델이 오류를 해결할 수 있도록 원인을 설명하는 output 문자열을 포함하세요.
{
"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 diff입니다. |
update_file |
path에 있는 기존 파일을 수정합니다. |
diff는 추가, 삭제 또는 교체할 내용을 담은 V4A diff입니다. |
delete_file |
path에 있는 파일을 삭제합니다. |
diff 없이 파일 전체를 삭제합니다. |
패치 하네스는 V4A diff 형식을 해석하고 변경 사항을 적용합니다. 구현 예시는 Python Agents SDK 또는 TypeScript Agents SDK 코드를 참고하세요.
패치 하네스 구현하기
apply_patch 도구에는 입력 스키마를 제공할 필요가 없습니다. 모델이 operation 객체를 구성하는 방법을 알고 있기 때문입니다. 하네스에서는 다음 작업을 구현하세요.
- 응답에서 작업 파싱하기
- 응답에서
type: "apply_patch_call"인 항목을 찾으세요. - 각 호출의
operation.type과operation.path를 확인하고,diff가 있으면 함께 확인하세요.
- 응답에서
- 파일 작업 적용하기
create_file과update_file의 경우 파일 시스템이나 메모리 내 워크스페이스에 V4A diff를 적용하세요.delete_file의 경우path에 있는 파일을 삭제하세요.- 각 작업의 성공 여부를 기록하고, 로그나 오류 메시지가 있으면 함께 기록하세요.
apply_patch_call_output이벤트 반환하기- 각
call_id에 대해apply_patch_call_output이벤트를 정확히 하나 반환하세요. 이벤트의 상태는 다음과 같이 설정하세요.- 작업을 성공적으로 적용했으면
status: "completed"로 설정하세요. - 오류가 발생했으면
status: "failed"로 설정하고 사람이 이해하기 쉬운 짧은output문자열을 포함하세요.
- 작업을 성공적으로 적용했으면
- 각
안전성과 견고성
- 경로 검증: 디렉터리 트래버설을 방지하고 허용된 디렉터리 안에서만 파일을 편집하도록 제한하세요.
- 백업: 패치를 적용하기 전에 파일을 백업하거나 임시 복사본에서 작업하는 방법을 고려하세요.
- 오류 처리: 패치를 적용할 수 없으면 항상
failed상태와 함께 원인을 설명하는output문자열을 반환하세요. - 원자성: 패치 하나라도 실패하면 전체 변경을 롤백할지, 파일별로 성공과 실패를 처리할지 결정하세요.
Agents SDK에서 패치 적용 도구 사용하기
Agents SDK에서도 패치 적용 도구를 사용할 수 있습니다. 실제 파일 작업을 수행하는 하네스는 직접 구현해야 하지만, diff 처리는 applyDiff 함수에 맡길 수 있습니다.
import {
mkdirSync,
realpathSync,
lstatSync,
readFileSync,
writeFileSync,
unlinkSync,
} from "node:fs";
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
import { applyDiff, Agent, run, applyPatchTool } from "@openai/agents";
class WorkspaceEditor {
constructor(root = "workspace") {
mkdirSync(root, { recursive: true });
this.root = realpathSync(root);
}
path(name) {
const target = resolve(this.root, name);
const relativePath = relative(this.root, target);
if (
!relativePath ||
isAbsolute(relativePath) ||
relativePath === ".." ||
relativePath.startsWith(`..${sep}`)
) {
throw new Error("Patch paths must stay inside the workspace");
}
let current = this.root;
for (const part of relativePath.split(sep)) {
current = join(current, part);
if (lstatSync(current, { throwIfNoEntry: false })?.isSymbolicLink()) {
throw new Error("Patch paths must not traverse symbolic links");
}
}
return target;
}
async createFile(operation) {
const path = this.path(operation.path);
const content = applyDiff("", operation.diff, "create");
mkdirSync(dirname(path), { recursive: true });
writeFileSync(path, content, { encoding: "utf8", flag: "wx" });
return { status: "completed", output: `Created ${operation.path}` };
}
async updateFile(operation) {
const path = this.path(operation.path);
const content = applyDiff(readFileSync(path, "utf8"), operation.diff);
writeFileSync(path, content, "utf8");
return { status: "completed", output: `Updated ${operation.path}` };
}
async deleteFile(operation) {
unlinkSync(this.path(operation.path));
return { status: "completed", output: `Deleted ${operation.path}` };
}
}
const editor = new WorkspaceEditor();
const agent = new Agent({
name: "Patch Assistant",
model: "gpt-6-astra",
instructions:
"Use apply_patch to edit files in the workspace. Supply paths relative to that workspace.",
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}`);GitHub에서 실행 가능한 전체 예제를 확인할 수 있습니다.
TypeScript에서 Agents SDK와 함께 패치 적용 도구를 사용하는 예제
Python에서 Agents SDK와 함께 패치 적용 도구를 사용하는 예제
자주 발생하는 오류 처리하기
모델이 오류를 해결할 수 있도록 status: "failed"와 함께 원인을 명확히 설명하는 output 메시지를 반환하세요.
{
"type": "apply_patch_call_output",
"call_id": "call_abc",
"status": "failed",
"output": "Error: File not found at path 'lib/baz.py'"
}{
"type": "apply_patch_call_output",
"call_id": "call_abc",
"status": "failed",
"output": "Error: Invalid Context:\n@@ def fib(n):"
}모델은 이러한 오류 메시지를 바탕으로 프롬프트에 포함된 파일을 다시 읽거나 변경 내용을 단순화해 다음 diff를 조정할 수 있습니다.
권장 사항
- 파일 컨텍스트를 명확히 제공하기
- Responses API를 호출할 때는 예제처럼 요청에 파일 스냅샷을 직접 포함하거나, 모델에 파일 시스템을 탐색할 도구(예:
shell도구)를 제공하세요.
- Responses API를 호출할 때는 예제처럼 요청에 파일 스냅샷을 직접 포함하거나, 모델에 파일 시스템을 탐색할 도구(예:
shell도구와 함께 사용하는 방안 고려하기shell도구를 함께 사용하면 모델이 디렉터리를 탐색하고, 파일을 읽고, grep으로 키워드를 검색하면서 편집할 파일을 스스로 찾아 수정할 수 있습니다.
- 변경 범위가 작은 diff 생성 유도하기
- 시스템 지침에 코드를 대대적으로 다시 작성하기보다 필요한 부분만 최소한으로 수정하도록 명시하세요.
- 변경 사항이 제대로 적용됐는지 확인하기
- 일련의 패치를 적용한 뒤 테스트나 린터를 실행하세요. 실패한 항목은 다음
input에 포함해 모델이 문제를 수정할 수 있도록 하세요.
- 일련의 패치를 적용한 뒤 테스트나 린터를 실행하세요. 실패한 항목은 다음