에이전틱 코딩 좀 더 잘하기 2
LLM의 특성을 알면 더 잘 쓴다
특성을 알면 달라지는 행동
- 지시가 무시될 때 → 최근 편향. 새 대화를 시작한다
- 앞뒤가 모순일 때 → 자기회귀 한계. 앞을 확정하고 뒤를 요청한다
- 컨벤션을 안 따를 때 → 학습 데이터의 인력. 강한 어조로 명시한다
- 괄호가 안 맞을 때 → 상태 추적 취약. 린터에게 맡긴다
- "좋습니다"만 할 때 → 동의 편향. 테스트로 검증한다
LLM은 어떻게 작동하는가
토큰화 (Tokenization)
LLM은 원문 문자열을 그대로 처리하지 않는다. 토크나이저가 텍스트를 토큰(token)이라는 단위로 변환하고, LLM은 이 토큰 시퀀스를 처리한다. 흔한 단어는 통째로 하나의 토큰이 되지만, 드문 단어는 여러 토큰으로 쪼개진다. 토큰화 방식은 모델마다 다르다. 코드에서는 변수명, 함수명, 구문 구조도 토큰 단위로 처리되는데, 하나의 식별자가 여러 토큰으로 쪼개지는 경우가 흔하다.
이것이 의미하는 것: 흔한 네이밍 패턴일수록 적은 토큰으로 처리된다. 토큰 수가 적다고 반드시 성능이 좋아지는 것은 아니지만, 학습 데이터에 자주 등장한 패턴을 LLM이 더 잘 예측하는 경향이 있다.
다음 토큰 예측 (Next Token Prediction)
LLM의 핵심 메커니즘은 단순하다. 지금까지의 텍스트를 보고, 다음에 올 토큰을 예측한다. 이것을 반복한다. "코드를 생성한다"는 말은 사실 "다음에 올 코드 토큰을 계속 예측한다"는 뜻이다.
기본 메커니즘은 한 토큰씩 전진이지만, o1이나 Claude의 extended thinking 같은 reasoning 모델 계열은 내부 추론 토큰을 통해 코드 출력 전에 계획을 세운다. 또한 단일 forward pass에서도 네트워크 내부 representation이 전체 구조 정보를 어느 정도 담고 있다는 연구가 있다. 그럼에도 autoregressive 특성의 한계는 여전히 존재한다.
다음 토큰을 고를 때 "가장 확률 높은 토큰"만 고르는 것은 아니다. 온도(temperature)라는 설정이 선택의 무작위성을 조절한다. 온도가 낮으면 확률 높은 토큰을 거의 그대로 고르고, 높으면 확률이 낮은 토큰도 선택될 수 있다. 같은 프롬프트에 같은 질문을 해도 결과가 매번 다른 이유다. API를 직접 호출하면 온도를 조절할 수 있지만, Claude Code나 Cursor 같은 에이전틱 코딩 도구에서는 보통 사용자가 직접 조절하지 않는다. 이 특성을 알면 "아까는 됐는데 지금은 안 된다"는 상황이 납득된다.
어텐션 (Attention)
"이 토큰은 앞의 어떤 토큰들과 관련이 있는가"를 계산하는 메커니즘이다. 함수 호출을 생성할 때, 앞에서 정의한 함수 시그니처에 어텐션이 걸린다. 이 메커니즘 덕분에 LLM은 멀리 떨어진 맥락을 참조할 수 있다.
하지만 어텐션에도 한계가 있다. 모든 토큰에 균일하게 주의를 기울이지 않는다. 이것이 아래에서 다룰 편향의 원인 중 하나다. (최근 편향, 중간 손실 등은 어텐션뿐 아니라 positional encoding, 학습 데이터 분포, RLHF 등 여러 요인이 복합적으로 작용한다.)
컨텍스트 윈도우 (Context Window)
LLM이 한 번에 볼 수 있는 토큰의 양에는 한계가 있다. 이것이 컨텍스트 윈도우다. 대화가 길어져서 컨텍스트 윈도우를 초과하면, 구현에 따라 오래된 내용이 잘리거나 에러가 발생한다. 코드베이스 전체를 한 번에 이해하는 것이 아니라, 창문을 통해 일부를 보는 것에 가깝다.
학습 데이터 (Training Data)
LLM은 공개 웹 텍스트, 제휴 데이터, 사람의 피드백 등으로 학습되었다. 이것이 의미하는 것: 학습 데이터에 많이 등장한 언어, 프레임워크, 패턴에서 대체로 더 강하다. Python, Java, JavaScript 같은 메이저 언어에서 일반적으로 잘하는 경향이 있지만, 모델과 태스크에 따라 일부 언어가 Python과 비슷하거나 상회하는 사례도 보고되어 있어 일률적이지는 않다.
LLM의 특성과 실전 대응
1. 최근 편향 (Recency Bias)
특성: 긴 대화에서 마지막에 가까운 내용에 더 강하게 영향 받는다.
모르면: 대화 초반에 "에러 핸들링 반드시 포함해줘"라고 지시했는데, 20번 왕복 후 에이전트가 에러 핸들링을 빼먹는다. "분명 말했는데 왜 무시하지?" 하고 에이전트의 능력을 의심한다.
알면: 능력 문제가 아니라 구조적 한계다. 중요한 지시가 무시되기 시작하면, 대화 끝에 다시 상기시키거나 새 대화를 시작한다. 맥락이 흐려진 대화를 이어가는 것보다 새 대화가 더 낫다는 판단을 할 수 있다.
2. 중간 손실 (Lost in the Middle)
특성: 긴 입력에서 처음과 끝에 비해 가운데 내용에 대한 주의가 떨어지는 경향이 있다. 최신 모델에서는 이 현상이 상당히 완화되었지만, 완전히 사라진 것은 아니다.
모르면: 요구사항 10개를 한 번에 나열했는데, 4~7번 항목이 빠져있다. "꼼꼼하지 못하네" 하고 다시 전체 목록을 붙여넣는다. 또 빠진다.
알면: 가운데가 약하다는 구조를 아니까, 가장 중요한 요구사항을 처음이나 끝에 배치한다. 또는 한 번에 10개를 주는 대신 3개씩 단계별로 나눈다. 파일을 읽힐 때도 전체 파일 대신 관련 부분만 보여준다.
3. 동의 편향 (Sycophancy)
특성: 사용자의 말에 동의하려는 경향이 있다. "이 코드 괜찮지?" 하면 "네, 좋습니다" 하기 쉽다.
모르면: "이 접근법 맞지?" → "네, 좋은 접근입니다" → 구현 후 버그 발견. "좋다고 해놓고!" 하고 화가 난다.
알면: 에이전트의 "좋습니다"를 신뢰하지 않는다. "맞지?"가 아니라 "이 코드의 버그를 찾아줘"처럼 구체적인 검증을 요청한다. 더 근본적으로는, 에이전트의 판단이 아니라 테스트로 검증한다. 1탄의 핵심: 루프를 닫아야 한다.
4. 흔한 답으로 수렴 (Common Pattern Bias)
특성: 학습 데이터에서 자주 본 패턴으로 끌려간다. 여기에 정렬(RLHF) 과정, 디코딩 전략, 안전 정책 등도 다양성을 줄이는 방향으로 작용해, "정석적인" 답을 내놓으려 한다.
모르면: 프로젝트가 Zustand를 쓰는데 에이전트가 자꾸 useState로 작성한다. "말을 안 듣네" 하고 매번 수동으로 고친다.
알면: 학습 데이터의 인력(引力)이라는 걸 아니까, 말로 부탁하는 것만으로는 부족하다는 것을 안다. CLAUDE.md에 "이 프로젝트는 Zustand를 사용한다"고 적되, 강한 어조로 써야 한다. "WebFetch 실패 시 → Read 도구로 fallback.md를 읽고 그 방법을 따를 것"이라고 썼더니 무시했지만, "반드시 읽고 그 방법을 따를 것. 자체 판단으로 다른 방법을 먼저 시도하지 말 것"으로 바꾸니 지켜졌다. 약한 어조는 학습 데이터의 인력을 이기지 못한다.
5. 정밀한 상태 추적에 취약 (Weak at Precise State Tracking)
특성: LLM 내부에는 히든 스테이트가 존재하지만, 명시적 카운팅이나 정밀한 수치 추적에서 자주 취약하다. 괄호 개수, 들여쓰기 깊이를 실수하기 쉽다.
모르면: 에이전트가 생성한 코드에서 괄호가 안 맞거나 들여쓰기가 어긋난다. "이런 기본적인 것도 못하나?" 하고 실망한다.
알면: 손가락 없이 숫자를 세는 것과 같다는 걸 아니까, 코드 구조 자체를 평탄하게(flat) 유도한다. Early return, 작은 함수로 중첩을 줄인다. 그리고 구문 오류는 에이전트에게 기대하지 않고 린터/포맷터로 자동 검증한다.
6. 한 토큰씩 전진 (Autoregressive)
특성: 단일 생성 과정에서 한번 출력한 토큰은 되돌릴 수 없다. 코드 앞부분을 쓰면서 뒷부분의 구조를 바꿀 수 없다. (에이전트 워크플로에서는 재생성·수정이 가능하지만, 한 번의 생성 안에서는 이 제약이 존재한다.)
모르면: "이 API 모듈 전체를 작성해줘" → 앞부분에서 정한 타입이 뒷부분 함수에서 안 맞는다. "자기가 쓴 코드인데 왜 앞뒤가 모순이지?" 하고 에이전트를 의심한다.
알면: 한번 출력한 토큰을 되돌릴 수 없으니, 앞을 확정하고 뒤를 요청한다. 함수 시그니처(입출력)를 먼저 정의하게 하고, 그 다음 구현을 요청한다. "작게 나눠라"는 일반론이 아니라, "앞부분이 확정되어야 뒷부분이 정확해진다"는 구체적 전략이 된다.
참고문헌
아키텍처 & 학습
- Attention Is All You Need ↗ - Transformer 아키텍처 원논문
- Language Models are Few-Shot Learners (GPT-3) ↗ - 자기회귀 생성, 학습 데이터 구성
- Training language models to follow instructions (InstructGPT) ↗ - RLHF 기반 정렬
토큰화
Reasoning 모델
- DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via RL ↗ - 강화학습 기반 추론 모델
- OpenAI reasoning tokens 설명 ↗
내부 표현 & 계획
- Future Lens: Anticipating Subsequent Tokens from a Single Hidden State ↗ - 히든 스테이트가 미래 토큰 정보를 담고 있음을 보인 연구
편향 & 행동 특성
- Lost in the Middle: How Language Models Use Long Contexts ↗ - 중간 손실 현상
- Towards Understanding Sycophancy in Language Models ↗ - 동의 편향
- RLHF와 다양성 트레이드오프 ↗
- 모드/선호 붕괴 관련 ↗