AI는 시키는 대로 정확히 행동한다—그게 문제다
출처: Dev.to
Claude에게 제품 리스트에 페이지네이션을 추가해 달라고 요청했습니다. 30초 만에 받은 응답: 깔끔하고, 기능적이며, 완전했습니다. 그런데 앱의 나머지 부분과는 전혀 연결되지 않았습니다. 잘못된 페이지네이션 컴포넌트(우리는 이미 하나 가지고 있었음), 만들어낸 스타일, 기존 필터가 깨짐. 기술적으로는 맞지만, 그대로는 사용할 수 없었습니다.
문제가 AI가 아니라 프롬프트였습니다. 저는 “이 리스트에 페이지네이션을 추가해 주세요.”라고만 적었죠. AI는 바로 그대로 수행했습니다. 더도 말고, 덜도 말고.
현재 모델들(Claude 4.x, GPT‑4o)은 “의도 추론” 행동을 버렸습니다. 프롬프트를 문자 그대로 해석합니다. 전체적으로는 진보이지만, 코드를 요청하는 방식 자체가 근본적으로 바뀝니다. 좋은 코드 프롬프트는 트릭이 아니라, 프로젝트에 새로 합류한 주니어 개발자에게 제공할 컨텍스트와 동일해야 합니다.
저는 네 가지 가장 흔한 코딩 작업에 대해 수십 가지 표현을 테스트하고 점수를 매겼습니다. 실제로 효과가 있던 방법을 공유합니다.
좋은 코드 프롬프트에 공통적인 네 요소
- 스택/컨텍스트 — 언어, 버전, 프레임워크, 관련 파일
- 구체적인 작업 — 질문이 아니라 명령 형태로 원하는 바를 기술
- 제약 조건 — 건드리지 말아야 할 부분, 범위 제한
- 예상 출력 — diff, 전체 코드, 설명만, CVSS 점수 등
Anthropic의 황금 규칙이 이를 요약합니다: “프롬프트를 전혀 모르는 동료에게 보여 주세요. 그 동료가 혼란스러워한다면 AI도 마찬가지입니다.”
여러 파일·복잡한 지시가 포함된 큰 프롬프트
XML 태그를 사용해 섹션을 구분하면 응답 품질이 30 ~ 39 % 향상됩니다. 예시:
<stack>PHP 8.1, Laravel 10, multi-tenant app</stack>
<task>Add pagination to ProductList</task>
<do-not-touch>getFilteredProducts()</do-not-touch>
<files>[paste files here]</files>
두 번째 규칙: 코드 먼저, 질문은 마지막
컨텍스트와 파일을 앞에 두고, 지시를 마지막에 배치하면 큰 컨텍스트에서도 정확도가 ≈30 % 상승합니다. AI는 “행동하기 전에 모든 것을 읽는다”는 점을 기억하세요.
흔한 실수: “이 코드가 안 돼요”만 적기
AI는 문제의 원인을 정확히 알 수 없습니다. “이 코드가 안 돼요”만 적으면,
- 프로그램이 크래시 나는지,
- 잘못된 값을 반환하는지,
- 단순히 느린 건지
등을 추측하고 그럴듯한 문제를 만들어 “수정”합니다.
function getUserById($id) {
$result = $db->query("SELECT * FROM users WHERE id = $id");
return $result->fetch();
}
전형적인 결과: SQL 인젝션을 방지하기 위해 PDO 준비문으로 바꾸지만, 실제 오류는 무시합니다. 기술적으로는 옳지만, 요구한 바와는 다릅니다.
버그 리포트 예시
Stack: PHP 8.1 + PDO, Laravel 10.
Current behavior:
Call to a member function fetch() on bool
→ only when the ID doesn't exist in the table
Expected behavior:
Return null if user doesn't exist (no exception thrown)
Already tried:
isset($result) before fetch() — same error
Code:
function getUserById($id) {
$result = $db->query("SELECT * FROM users WHERE id = $id");
return $result->fetch();
}
“Already tried” 라인을 넣는 것이 핵심입니다. 없으면 AI가 이미 시도한 해결책을 다시 제시합니다. 있으면 PDO::query()가 실패 시 false를 반환한다는 점을 짚어 $result !== false ? $result->fetch() : null; 로 고쳐줍니다.
버그 수정 템플릿
Stack: [언어 + 버전 + 프레임워크]
Current behavior: [정확한 증상 — 오류 메시지, 잘못된 반환값, 관찰된 동작]
Expected behavior: [코드가 해야 할 일]
Already tried: [이전 시도와 왜 실패했는지]
Code: [버그를 재현할 최소 코드]
“댓글 시스템 추가”와 같은 모호한 요청
AI는 스택(데이터베이스), UI(모달·인라인·전용 페이지), 검증(클라이언트·서버) 등을 스스로 선택합니다. 그 선택이 프로젝트와 맞지 않을 가능성이 높습니다.
예시 프롬프트
Add a comment system to this blog.
가능성 높은 결과: MySQL + jQuery 폼, 기존 디자인과 전혀 맞지 않는 UI.
구체적인 프롬프트 예시
Stack: PHP 8 + Bootstrap 3, no database (JSON file storage).
Task: Add comments to blog articles.
Acceptance criteria:
- Form: name + message (no email, no account required)
- Server‑side validation only (no JS)
- Storage: one JSON file per article at /blog/comments/{slug}.json
- Email notification to author on each new comment (PHPMailer already installed)
Out of scope:
- No moderation for now
- No nested replies
- No changes to existing CSS
Files involved: [blog_footer.php, template.php]
Out of scope 섹션이 핵심 차이점입니다. 구현하지 말아야 할 부분을 명시하면 AI가 과잉 설계(중재, 인증, 중첩 스레드 등)를 피하고, 존재하지 않는 제약을 만들어 내는 일을 방지합니다.
새로운 기능 템플릿
Stack: [기술적 컨텍스트]
Integration context: [기존 컴포넌트·프로젝트 패턴과 어떻게 통합될지]
Task: [구체적인 기능 설명]
Acceptance criteria: [예상 동작 리스트]
Out of scope: [지금 구현하지 않을 내용]
Files involved: [수정·생성할 파일]
“코드 리팩터링” 요청은 최악의 프롬프트
AI는 자체 품질 기준을 적용해 메서드 시그니처를 바꾸거나, 원치 않는 추상화를 추가해 기존 퍼블릭 API를 깨뜨릴 수 있습니다.
전형적인 프롬프트
Refactor this code to make it cleaner.
[450 lines of OrderService]
전형적인 결과: 8개의 private 메서드 추출, 이름 변경, 인터페이스 추가, “미래 유연성을 위한” 추상 클래스 생성. 컴파일은 되지만 테스트가 깨집니다.
구체적인 상황
Concrete problem:
OrderService::processOrder() (450 lines) is called from 8 places
with different parameter combinations.
Impossible to know which cases are covered by existing tests.
Goal:
Extract pricing rules into immutable Value Objects.
One class = one rule (e.g., DiscountRule, TaxRule, ShippingRule).
Hard constraints:
- Observable behavior unchanged — existing tests must pass without modification
- Do not modify public method signatures
- Do not change return types
Scope: pricing calculation only, not persistence or validation.
Code: [OrderService.php]
핵심 문구: “observable behavior unchanged — existing tests must pass without modification.” 이 제약이 없으면 AI는 스스로 최적화를 진행합니다.
리팩터링 템플릿
Concrete problem: [왜 이 코드가 문제인지 — 단순히 “지저분함”이 아니라 실제 영향]
Goal: [리팩터링 후 기대하는 바]
Hard constraints:
- [변경하면 안 되는 사항: 시그니처, 테스트, 관찰 가능한 동작]
Scope: [포함·제외 범위]
Code: [리팩터링할 코드]
코드 리뷰 요청도 포커스가 필요
프롬프트에 초점을 지정하지 않으면 AI는 스타일 검토에만 머무르고, 실제 보안·성능 문제를 놓칠 수 있습니다.
전형적인 리뷰 요청
Review this code as a senior dev and give me improvement suggestions.
전형적인 결과: 80 % 스타일 제안(네이밍·주석), 20 % 실제 이슈(숨겨진 SQL 인젝션) — 잡음이 많아 효율이 떨어집니다.
포커스를 지정한 리뷰 템플릿
Context:
Public endpoint POST /api/documents/upload
Unfiltered incoming data, filesystem access, JWT auth verified upstream.
Review focus: security only
- Injection (command, SQL, path)
- Path traversal
- Malicious file uploads (server‑side execution)
- IDOR
Intentional decisions (do not flag):
- The (int) cast on ID is deliberate
- Minimal error handling is intentional (internal app, centralized logs)
- Variable name $tmp follows team convention
Output format:
For each issue: severity (critical/high/medium) + description + fix with code.
Code: [upload-handler.php]
Intentional decisions 섹션이 잡음을 절반으로 줄여줍니다. AI는 이미 알고 있는 부분을 다시 지적하지 않고, 요청한 영역에 집중합니다.
코드 리뷰 템플릿
Context: [endpoint type, who calls it, input data, auth in place]
Focus: [security / performance / business logic / architecture — 한 가지 관