AI가 내 프롬프트를 흘려듣는 이유: 원리부터 다시 본 컨텍스트 엔지니어링
분명 가이드에 다 적었는데, 왜 안 될까요?
분명 가이드에 다 적어놨습니다. 그런데 AI는 또 엉뚱한 코드를 내놓았습니다.
저는 디자인 시스템 안에서 MCP(Model Context Protocol) 서버 개발을 주도하고 있었습니다. AI가 우리 디자인 시스템 규칙에 맞는 코드를 생성하도록 가이드하는 게 목적이었고, 그러려면 우리가 원하는 코드가 무엇인지를 모델에게 정확히 전달해야 했습니다.
가이드라인을 짜고 실제 데이터를 넣어가며 테스트했지만 원하는 결과가 잘 나오지 않았습니다. 처음엔 프롬프트 문구나 가이드 양을 탓했습니다. 더 자세히, 더 많이 넣으면 나아지겠지 싶었죠. 그런데 증상이 묘하게 일관되지 않았습니다. 같은 입력인데 어떤 날은 멀쩡하고, 어떤 날은 가이드를 통째로 무시한 코드가 나왔습니다.
아래 두 코드를 비교해 보면 차이가 분명합니다. 첫 번째 코드는 기본값을 명시하지 않은 것은 좋았으나 스페이싱, 디자인시스템 컴포넌트 미사용, 커스텀 스타일 사용 등 규칙을 무시했고, 두 번째 코드는 대체로 규칙을 지켰지만, 기본값을 명시한 예외가 발생했습니다.
//생성 예제 1
@Composable
private fun FavoriteStoreProductCard(
item: FavoriteStoreProductItem,
onClick: () -> Unit,
onFavoriteClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier.width(102.dp),
verticalArrangement = Arrangement.spacedBy(10.dp), // 1. 정의된 스페이싱 안 씀
) {
Thumbnail(
...
onClicked = onClick,
//2. 기본값 명시 안 함
)
Text( //3. 디자인시스템 내 텍스트 사용 안 함
text = item.title,
modifier = Modifier.fillMaxWidth(),
style = ItemTitleTextStyle, //4. 커스텀 스타일 선언
maxLines = 2,
overflow = TextOverflow.Ellipsis,
)
}
}
//생성 예제 2
@Composable
private fun FavoriteItemCard(
item: FavoriteSectionItem,
itemWidth: Dp,
onClick: () -> Unit,
favoriteIcon: @Composable () -> Unit,
) {
Column(
modifier = Modifier.width(itemWidth),
verticalArrangement = Arrangement.spacedBy(ClayMintTheme.spacings.spacing125),
//1. 정의된 스페이싱 사용
) {
Thumbnail(
...
pressedEffect = PressedEffect.None, // 2. 기본값 명시
onClicked = onClick,
)
ClayText(//3. 디자인시스템 내 텍스트 사용
text = item.title,
modifier = Modifier.fillMaxWidth(),
color = ClayMintTheme.colorScheme.foregroundPrimary,
style = ClayMintTheme.typography.descriptionMedium, //4. 디자인시스템 내 스타일 사용
maxLines = 2,
overflow = TextOverflow.Ellipsis,
)
}
}
도구를 더 만지기 전에, 의심의 방향을 틀었습니다.
가이드를 못 써서가 아니라, 이 모델이 글을 어떻게 읽는지를 내가 모르고 있는 것 아닐까.
팁을 더 찾기 전에, 원리를 먼저 봤습니다
검색하면 프롬프트 팁은 많이 나옵니다. 하지만 팁은 왜 되는지를 알려주지 않아서, 안 될 때 어디를 고쳐야 하는지도 알 수 없었습니다.
그래서 두 가지를 직접 파봤습니다. 하나는 LLM이 입력을 어떻게 처리하는지(원리), 다른 하나는 Claude, GPT, Gemini 같은 최신 모델에서 프롬프팅 권고가 어떻게 바뀌었는지(경향)입니다.
그 전에 하나만 짚고 가자면, LLM은 문장을 사람처럼 이해하는 게 아니라, 다음에 올 확률에 따라 단어(토큰)를 계속 이어 붙입니다. 출력이 확률 분포에서 하나를 고르는 일이다 보니, 같은 입력에도 답이 매번 조금씩 달라질 수 있습니다. 제가 겪은 "어떤 날은 되고 어떤 날은 안 되는" 현상의 뿌리가 여기였습니다. 가이드를 따르는 것조차 확정이 아니라 확률이었던 거죠.
LLM을 깊이는 모르고 활용만 해왔다면, 다음 세 단어만 잡고 기억하고 가면 됩니다.
- 컨텍스트 윈도우(Context Window): 모델이 한 번에 보는 작업 공간
- 어텐션(Attention): 그 공간에서 무엇에 주목할지 정하는 방식
- 컨텍스트 엔지니어링: 그 공간에 무엇을 담을지 설계하는 일
이 세 가지를 축으로 두 개의 질문을 따라갑니다. 먼저 모델이 글을 어떻게 읽는지를 봅니다. 순서대로 읽지 않고 관련도를 한꺼번에 따지는 어텐션, 무한하지 않은 컨텍스트 윈도우, 그리고 나에게 동의하려는 아첨 성향까지요.
첫 번째 질문: LLM은 글을 어떻게 읽을까요?
LLM 모델이 사람처럼 글을 왼쪽에서 오른쪽으로 순서대로 읽는다고 막연히 생각했는데, 아니었습니다. LLM 모델은 어텐션기반으로 컨텍스트 윈도우에 있는 필요한 정보를 한 번에 가져옵니다.
LLM은 순서가 아니라 관련도로 읽습니다
먼저, 어텐션은 입력 안의 각 단어가 다른 모든 단어와 얼마나 관련 있는지를 동시에 따져 의미를 만드는 방식입니다. 순서대로 훑는 게 아니라 한 번에 펼쳐놓고 관련도를 가중치로 계산합니다. 다만 이때 각 단어의 위치(순서) 정보도 함께 반영되며, 특히 앞이나 끝에 놓인 내용일수록 더 큰 가중치를 받는 경향이 있습니다. 모델이 어디에 주의를 두느냐가 곧 결과를 좌우한다는 뜻입니다.
여기서 실제로 도움이 되는 점 두 가지가 나옵니다. 먼저, 관련된 지시와 자료끼리 관계를 분명히 드러내야 한다는 것입니다. 모델은 무엇이 무엇과 얼마나 관련 있는지를 스스로 따지는데, 정작 이어져야 할 지시와 자료 사이에 상관없는 내용이 잔뜩 끼면 그 관련도가 희석됩니다. 그래서 가이드에 줄 글이 아닌 양식이 있으면 도움이 되는데, 그 방법으로 가장 널리 쓰이고 양식이 무겁지 않은 MarkDown 파일이 쓰입니다.
반면, 정보가 많을수록 오히려 정확도가 떨어질 수 있다는 것입니다. 모든 단어 쌍의 관련도를 계산하니 입력이 길어질수록 계산량이 제곱으로 늘고 주의가 묽어집니다. 가이드를 더 많이 넣으면 나아지겠지 했던 게 정확히 반대로 작용하던 이유입니다.
다음은 어텐션이 문장 내 단어 간 관련도를 가중치로 계산하는 방식을 보여줍니다.

가이드 방법 중 하나인 few-shot 즉, 원하는 형식을 몇 개 보여주는 것이 먹히는 이유도 여기서 설명됩니다. 모델 안에는 앞선 패턴을 그대로 복사해 잇는 메커니즘(induction heads)이 있어서, 예시를 본 뒤 같은 형식을 이어가려는 경향이 생깁니다. 예시는 논리를 가르치는 도구가 아니라 형식을 복사하게 만드는 도구인 셈인데, 이 점이 뒤에서 다시 중요해집니다.
컨텍스트 윈도우는 무한한 메모리가 아니라 유한한 책상입니다
컨텍스트 윈도우는 모델이 한 번에 올려놓고 보는 작업 공간입니다. 여기 올라가는 건 제 질문만이 아닙니다. 시스템 프롬프트, 그동안의 대화 이력, 도구와 검색 결과, 지금 생성 중인 답이 전부 같은 공간을 나눠 씁니다.
MCP나 긴 세션에서 대답이 들쑥날쑥했던 체감이 컸던 이유가 이거였습니다. 도구가 돌려준 결과와 누적된 대화가 알게 모르게 쌓여, 정작 중요한 가이드를 책상 밖으로 보이지 않게 밀어내고 있었습니다.
게다가 책상이 넓다고 다 똑같이 잘 보는 것도 아닙니다. 정보가 입력의 한가운데 있으면 활용도가 떨어지는 현상이 관측됩니다(lost in the middle). 중요한 지시는 앞이나 끝에 둘 때 가장 알아듣습니다. 그래서 시스템프롬프트나 사용자의 명령에는 잘 따른다고 느껴질 수 있습니다.
다음은 lost-in-the-middle이 발생할 수 있는 상황에 대한 예시를 보여줍니다.

이를 해소할 수 있는 방안으로 XML 태그나 Markdown 제목처럼 구조를 갖춘 문서가 유리합니다. 제목과 태그가 위치 표지 역할을 해 주면, 모델이 필요한 대목을 더 잘 찾아내 한가운데 묻혀 유실되던 정보가 줄어듭니다.
모델은 사용자에게 동의하고 싶어합니다
토큰 예측만으로 설명되지 않는 동작이 하나 더 있습니다. 모델은 왜 이렇게 고분고분할까요.
사실, 사전학습만 끝낸 모델은 원래 지시를 따르지 않습니다. 지금의 채팅 모델은 그 뒤에 사람의 선호로 보상을 주는 학습(RLHF 등 후처리)을 거쳐, 사람이 좋아하는 답을 내도록 정렬된 결과물입니다. 시스템 프롬프트를 따르는 힘조차 지능이 아니라 이 정렬에서 나옵니다.
문제는 부작용입니다. 보상 과정이 동의는 곧 사용자 만족이라고 함께 학습해버려서, 모델은 사용자에게 동의하고 칭찬하려는 경향이 있습니다(sycophancy, 아첨). 실제로 2025년 4월 OpenAI는 GPT-4o 업데이트가 과도하게 아첨적이라는 이유로 롤백하기도 했습니다.
그래서 "이 설계 괜찮지?"라고 물으면 모델은 "네 좋습니다" 쪽으로 기웁니다. 코드 리뷰에서 "좋은 접근이에요"는 거의 의미없는 멘트입니다. 내가 한 거니까 칭찬하는 것에 가깝죠. 물어보는 방식을 바꿔야 합니다. "이 설계의 약점과 반례부터 찾아줘", "내 결론에 동의하지 말고 반박해줘"처럼요. 사용자의 생각을 드러낸 질문 즉, 유도신문을 피하는 것만으로 답의 정직함이 달라집니다.
두 번째 질문: 그래서 지금은 어떻게 쓸까요?
LLM이 글을 어떻게 읽는지 구조를 들여다보고 나니, 다음 질문이 자연스레 따라왔습니다. 지금 우리가 쓰는 최신 모델은 예전과 무엇이 다를까. AI는 눈에 띄게 좋아졌고, 갈수록 더 복잡한 일을 스스로 처리하도록 설계되고 있습니다. 도구가 이렇게 달라지는데 쓰는 방식만 그대로일 수는 없었죠. 원리는 그대로여도 그 위에서 권장되는 사용법은 모델 세대에 따라 바뀝니다. 그래서 이번엔 최신 모델들의 경향을 따라가 봤습니다.
프롬프트 엔지니어링에서 컨텍스트 엔지니어링으로
원리를 알고 나니, 업계가 왜 프롬프트 엔지니어링에서 컨텍스트 엔지니어링으로 무게중심을 옮겼는지 이해됐습니다. 프롬프트 엔지니어링이 한 줄을 영리하게 쓰는 법이라면, 컨텍스트 엔지니어링은 모델이 볼 토큰 전체를 무엇으로, 얼마나, 어떤 순서로 채울지 설계하는 일입니다. 어텐션과 컨텍스트 윈도우의 한계가 그대로 근거가 됩니다.
프롬프트 기법이 한물갔다는 뜻은 아닙니다. 기법은 그대로 살아 있고, 사고의 단위가 한 줄에서 컨텍스트 전체로 넓어졌을 뿐입니다. 핵심 원칙은 세 가지입니다.
- 다 넣지 말고 관련된 것만 넣습니다. 정보가 많으면 어텐션이 묽어지니까요.
- 핵심 지시와 자료는 앞이나 끝에 둡니다. 한가운데 묻으면 놓치기 쉽습니다.
- 길이는 비용이자 노이즈입니다. 충분한 만큼만 최소로 넣습니다.
특히 마지막이 중요합니다. 관련 없는 텍스트는 그냥 쓸모없는 정도가 아니라 적극적으로 해롭습니다. 어텐션을 분산시켜 틀린 답을 유도하니까요. 혹시 모르니 다 붙여두기가 가장 흔한 안티패턴이고, 제가 바로 그러고 있었습니다.
예를 들어, 이 원리가 잘 드러나는 예가 하위 에이전트(sub-agent) 오케스트레이션입니다. 상위 에이전트, 즉 슈퍼바이저의 작업 공간은 일이 진행될수록 어질러집니다. A안과 B안을 비교하다 A안으로 정해도 기각된 B안과 그동안 쌓인 도구 결과가 그대로 남는데, 정작 "A안을 구현하라"는 작업에는 대부분 노이즈입니다. 그래서 슈퍼바이저가 그 어질러진 공간에서 직접 구현하는 것보다, 정제된 목표만 들려 하위 에이전트를 깨끗한 새 공간에서 돌리는 편이 그 작업에는 더 낫습니다.
다음은 하위 에이전트에게 전달하는 문맥에 따라 발생하는 컨텍스트 윈도우의 차이에 대해 보여줍니다.

하위 에이전트가 더 똑똑해서가 아닙니다. 대개 같은 모델이고, 차이는 일꾼이 아니라 깨끗해진 작업 공간에서 옵니다. 다만 공짜는 아닙니다. 슈퍼바이저가 목표를 제대로 정제해 넘겨야 하고, 버린 맥락에 진짜 제약이 숨어 있었다면 그걸 빼먹고 넘기는 순간 하위 에이전트는 같은 함정에 걸립니다. 결국 어려움은 사라지는 게 아니라 무엇을 넘기고 무엇을 뺄지 고르는 일로 옮겨갈 뿐입니다.
이 흐름은 여기서 멈추지 않습니다. 프롬프트, 컨텍스트, 하네스, 루프 엔지니어링 순으로 한 칸씩 올라갑니다. 매번 손으로 시키는 대신 에이전트가 도는 루프(성공 기준, 멈출 조건, 자가 수정)를 설계하는 쪽으로 무게가 옮겨가고, 가치의 단위도 응답 한 번에서 목표까지 가는 방식으로 바뀌어가고 있습니다.
모델이 강해질수록 지시는 가벼워집니다
컨텍스트를 어떻게 채울지가 바뀌면, 프롬프트를 쓰는 습관 자체도 함께 낡습니다. 제가 딱 그랬어요. AI를 처음 익히던 무렵의 모델은 추론이 약해서 단계를 하나하나 알려줘야 했고, 그래서 "단계별로 생각해(let’s think step by step)" 강제, 과한 few-shot, 깐깐한 절차 나열을 좋은 습관으로 배웠습니다.
그런데 지금의 추론 모델들은 복잡한 문제를 해결하도록 발전해왔고 스스로 단계를 나눕니다. 배워둔 습관이 오히려 독이 됐어요. 제약을 스무 개 나열하니 서로 충돌했고, few-shot을 도배하니 그 예시만 사용했고, 어설픈 사고 경로를 강요하면 성능이 떨어지기도 했습니다. 그래서 "어떻게 하는지"를 하나하나 알려주던 걸 접고, "무엇이 성공인지"를 주고 맡기는 쪽으로 제 습관을 바꿨습니다. 제약과 금지를 잔뜩 나열하기보다 핵심만 긍정형으로 남기고, 로직을 가르치려던 few-shot은 형식과 톤을 고정하는 용도로만 줄였습니다.
가장 크게 바꾼 습관은 목표를 검증 가능하게 말하는 것이었습니다.
- ”버그 고쳐줘” → “이 실패하는 테스트를 통과시켜줘”
- “정리해줘” → “이 표에서 누락된 행을 찾아 표시해줘”
이렇게 성공 조건과 지켜야 할 규칙을 못 박아 모델의 행동을 붙들어 두는 층이 하네스입니다. 과도한 절차를 대신 "무엇이 성공인가"를 규정해 두는 것이죠. 그럼 이 방향을 실제 MCP 가이드에는 어떻게 담았을까요.
내가 검토한 두 갈래: 가이드라인과 하네스(프롬프트)
개선 방법은 두 갈래였습니다. 하나는 문맥이 부족하다고 보고 가이드라인을 더 주는 것, 다른 하나는 하네스 엔지니어링이 필요하다고 보고 동작을 규정하는 프롬프트를 더하는 것이었습니다. 둘은 푸는 문제가 다릅니다.
| 구분 | 가이드라인 추가 | 하네스(프롬프트) 추가 |
|---|---|---|
| 푸는 문제 | 모델이 무엇을 알아야 하는가 (지식과 맥락) | 모델이 어떻게 행동해야 하는가 (절차, 검증, 중단 조건) |
| 들어가는 내용 | 디자인 시스템 규칙, 컴포넌트와 토큰 정의, 예시 | 출력 형식 계약, 검증 루프, 유저 입력에 휘둘리지 않게 하는 규정 |
| 강할 때 | 모델이 우리 도메인을 모를 때 | 유저 입력이 들쭉날쭉해도 일관된 동작이 필요할 때 |
| 과하면 | 컨텍스트가 길어져 핵심이 묻힘 | 절차를 과하게 명시해 최신 추론 모델의 발목을 잡음 |
가이드라인 쪽에서 실제로 어려움을 겪은 적이 있습니다. dp 값은 반드시 spacing 토큰으로 지정하라고 가이드했더니, 모델이 이미지 크기 108dp를 spacing1000(80) + spacing300(24) + spacing50(4)으로 조합해버렸습니다. 간격이 아니라 크기 값은 토큰 없이 로우(raw) dp를 써야 하는데 말이죠. 게다가 few-shot 예시까지 함께 넣었더니 그 패턴을 모든 사이즈 계산에 확대 적용했습니다.
규칙이 틀린 게 아니라 너무 문자 그대로였던 게 문제였습니다. 그래서 특정 케이스를 못 박는 대신, "간격과 여백은 spacing 토큰으로, 아이콘이나 이미지 같은 크기 값은 로우 dp로" 처럼 경계를 원리로 이해되게 한 단계 추상화해서 다시 썼습니다.
그래서 무엇이 달라졌나
원리와 경향을 알고 가이드와 프롬프트를 다시 손봤습니다. 크게 세 가지를 바꿨습니다. 관련 있는 것만 남겨 컨텍스트를 큐레이션했고, 흩어져 있던 규칙을 레이어별로 모아 어떤 결정을 어디서 내릴지를 고정했고, 절차를 떠먹이는 대신 성공 기준과 행동 규정(하네스)을 줬습니다.
하네스를 정리했습니다: 긴 문장을 쪼개고, 결정의 자리를 고정
가이드와 프롬프트는 틀리진 않았지만 모호했고, 그 모호함이 흔들림의 1차 원인이었습니다. 60단어를 넘는 한 문장에 규칙 대여섯 개가 뭉쳐 있으면 모델은 그중 일부를 실행마다 다르게 빠뜨렸습니다. 그래서 규칙과 예산은 그대로 둔 채 구조만 바꿔, 한 문장을 원자 단위 지시로 쪼갰습니다.
//Before — 한 문장에 규칙 다섯 개
아이콘마다 search-icon으로 ClayMintDrawable id를 확인하고 ClayMintDrawable import를 추가하며, _fill/_line 쌍은 정적 디자인이 아니라 바인딩된 state/variant에서 접미사를 고르고, 상태가 있는 아이콘은 코드에서 분기한다(state → _fill / !state → _line); ...
//After — 원자 지시로 분해
아이콘마다:
- search-icon으로 ClayMintDrawable id를 확인한다.
- ClayMintDrawable import를 추가한다.
- _fill / _line 쌍은 바인딩된 state/variant에서 접미사를 고른다.
- 코드에서 상태로 분기한다(state → _fill, !state → _line).
- search-icon 결과가 없을 때만 그 드로어블을 추론으로 표시한다.
또 하나는 결정의 소유권을 고정한 것입니다. "raw 픽셀을 토큰으로 바꿀지"(토큰 해석), "그 토큰을 padding에 쓸지 width에 쓸지"(간격 방출), "어디까지 추론으로 표시할지"(추론 경계)까지, 이 세 결정을 한 문장에 섞어두니 모델이 매번 다르게 합쳤습니다. 각 결정을 늘 같은 레이어의 같은 규칙에서 내리도록 나눴더니, 같은 값이 같은 자리에서 같게 처리됐습니다.
절차 대신 성공 기준과 하네스를 줬습니다
"이렇게 저렇게 해라"를 잔뜩 나열하는 대신, 무엇이 맞는지를 정의하고 그걸 스스로 지키게 했습니다. 두 가지가 핵심이었습니다.
첫째, 사후 검증 규칙셋입니다. 생성이 끝난 코드를 컴포넌트 manifest·토큰·아이콘 카탈로그가 확인 사항을 기준으로 삼아 점검하는 규칙 열여섯 개를 뒀습니다. 예를 들어 "컴포넌트 검색 결과가 비면 그 역할에는 컴포넌트가 없다는 뜻이니, 그럴듯한 이름을 지어 부르지 말고 빌딩블록이나 토큰 기반 custom으로 만들라" 같은 식입니다. 도구가 확정할 수 없는 것(픽셀 단위 시각 일치)은 애초에 검증 범위 밖으로 명시해, 규칙이 못 지킬 약속을 하지 않게 했습니다.
둘째, 컴포넌트 선택 사다리입니다. 전에는 "완성형 컴포넌트에 있나 없나" 이분법뿐이라, 없으면 곧장 custom UI로 직행했고 그 구조가 실행마다 달랐습니다. 완성형과 custom 사이에 표준 빌딩블록 단계를 끼워, 완성형 → 빌딩블록 → 토큰 기반 custom → raw 순으로 한 단계씩만 내려가게 했습니다. "없으면 즉흥 custom"이 "표준 재료 우선"으로 수렴했습니다.
도입부에서 소개한 그 코드가 규칙을 지키기 시작했습니다
도입부의 어긋났던 네 지점이 개선 뒤 어떻게 바뀌었는지 나란히 놓으면 이렇습니다.
| 지점 | before (1장 코드) | after |
|---|---|---|
| 스페이싱 | Arrangement.spacedBy(10.dp) |
Arrangement.spacedBy(ClayMintTheme.spacings.spacing125) |
| 기본값 | pressedEffect = PressedEffect.None 명시 |
명시 안 함 |
| 텍스트 | Text(...) |
ClayText(...) |
| 스타일 | style = ItemTitleTextStyle (커스텀 선언) |
style = ClayMintTheme.typography.descriptionMedium |
결과는 분명했습니다. 결과가 상이한 경우가 0이 되진 않았지만, 가이드가 지켜지지 않는 빈도가 5번에 1~2번에서 10번에 1번 미만으로 줄었습니다. 도구가 확정하지 못해 [추론]으로 남기던 영역 자체가 줄어든 덕분입니다. 그러면서 마땅한 완성형 컴포넌트가 없을 때 무엇으로 대신할지 고르는 판단처럼, 사람이 아니면 안 된다고 보고 남겨뒀던 부분도 이제 충분히 맡길 만해졌습니다.
여기서 "어겼다"와 "나아졌다"의 기준은 이렇습니다. 같은 Figma 입력을 여러 번(기본 4회) 실행해 산출물 코드에서 뽑은 구조 신호(어떤 컴포넌트·토큰·아이콘을 썼는지, [추론] 주석을 어디에 달았는지)가 실행마다 갈리면 흔들림 1건으로, 생성 코드가 manifest·토큰·가이드 규칙에 어긋나면 규칙 위반 1건으로 셉니다. 판정은 눈대중이나 LLM 채점이 아니라(채점기 자체가 흔들리니까) 이 신호 집합을 기계적으로 비교해 내렸고, 위 "5번에 1~2번"은 그 반복 실행에서 관찰한 값입니다.
정리
원하는 결과를 얻지 못한 진짜 원인은 도구가 아니라, 모델을 모르고 쓰던 저 자신이었습니다. LLM모델이 프롬프트를 관련성을 따져 읽고, 작업 공간이 유한하며, 나에게 동의하려 한다는 것. 이 세 가지만 알아도 프롬프트를 보는 눈이 달라집니다.
다만 이게 모든 모델에 통하는 만능은 아닙니다. 위 습관들은 추론이 좋은 최신 모델을 전제로 합니다. 오래됐거나 추론이 약한 모델에서는 few-shot과 단계별 가이드가 여전히 잘 먹히고, 작은 경량 모델을 하위 작업에 쓸 때는 오히려 절차와 검증 규칙을 더 촘촘하게 주는 편이 안정적입니다.
결국 남은 몫은 모델에게 잘 부탁하는 법이 아닌, 모델이 어떻게 읽는지를 알고 무엇을 컨텍스트로 제공할지 설계하는 일입니다. 혹시 분명 다 적었는데 왜 안 되지 싶다면, 프롬프트를 한 줄 더 다듬기 전에 책상(Context Window)에 뭐가 올라가 있는지부터 보시길 권합니다.
생성만 놓고 보면 이전보다 훨씬 쉬워졌고, 진짜 실력은 검증과 판단 그리고 방향 설정에 있습니다.
한눈에 보는 결론: Do / Don’t
| Don’t (예전 습관) | Do (지금) |
|---|---|
| 관련 있어 보이면 일단 다 넣는다 | 필요한 것만 골라 넣는다 (컨텍스트 큐레이션) |
| 지시의 중요도와 상관없이 프롬프트를 늘어놓는다 | 핵심 지시는 앞이나 끝에 둔다 |
| 프롬프트가 길수록 더 정확해진다고 믿는다 | 길이는 비용이자 노이즈다. 충분한 만큼만 넣는다 |
| 절차를 하나하나 떠먹인다 | 목표와 성공 기준을 주고 맡긴다 |
| 금지 사항을 잔뜩 나열한다 | 원하는 행동을 긍정형으로 지시한다 |
| 로직까지 few-shot으로 가르친다 | 예시는 형식과 톤 고정용으로만 쓴다 |
| 규칙을 특정 케이스로 못 박는다 | 경계를 원리로 적는다 |
| 큰 작업을 프롬프트 하나에 다 몰아넣는다 | 하위 작업은 정제된 목표만 줘서 분리한다 |
| "이거 괜찮지?"로 확인받는다 | "약점과 반례부터 찾아줘"로 검증시킨다 |
| 한 번 잘 나왔으니 늘 그렇게 나온다고 믿는다 | 출력은 확률이라 매번 흔들린다고 보고, 중요한 건 다시 확인한다 |
| 최신 모델이니 무조건 짧게 쓴다 | 대상 모델의 성격에 맞춰 조절한다 |