Fill-in-the-Middle, 코드 LLM 학습 방법, 토큰화, AST 인식 등 AI 코딩 어시스턴트의 핵심 기술 원리를 깊이 있게 분석합니다.
AI 코딩 어시스턴트를 효과적으로 사용하려면, 그것이 내부적으로 어떻게 동작하는지 이해하는 것이 중요합니다. 자동차를 운전하기 위해 엔진의 모든 부품을 알 필요는 없지만, 엔진이 어떤 원리로 작동하는지 이해하면 더 효율적으로 운전할 수 있는 것과 같습니다.
특히 다음과 같은 상황에서 내부 원리에 대한 이해가 도움이 됩니다.
전통적인 언어 모델은 왼쪽에서 오른쪽으로 텍스트를 생성합니다. 주어진 프리픽스(Prefix) 다음에 올 토큰을 예측하는 방식입니다. 하지만 코드 자동완성에서는 이 방식이 한계를 가집니다.
실제 개발 상황을 떠올려 보겠습니다. 함수 중간에 커서를 놓고 코드를 작성할 때, AI는 커서 앞의 코드(프리픽스)뿐만 아니라 커서 뒤의 코드(서픽스)도 참고해야 합니다.
function processOrder(order: Order): ProcessedOrder {
const validated = validateOrder(order);
// [커서 위치] — 여기에 코드를 삽입해야 합니다
return { ...validated, total: calculatedTotal, tax: calculatedTax };
}이 문제를 해결하는 것이 Fill-in-the-Middle(FIM) 기법입니다. FIM은 입력을 세 부분으로 나눕니다.
학습 시에는 기존 코드를 임의의 위치에서 세 부분으로 분할하고, 모델이 프리픽스와 서픽스를 보고 중간 부분을 예측하도록 훈련합니다. 이를 위해 특수 토큰을 사용합니다.
[PRE] function processOrder(order: Order): ProcessedOrder {
const validated = validateOrder(order);
[SUF] return { ...validated, total: calculatedTotal, tax: calculatedTax };
}
[MID]모델은 [MID] 이후에 올 토큰들, 즉 프리픽스와 서픽스 사이에 들어갈 코드를 생성합니다. 이 기법 덕분에 AI가 커서 위치에 관계없이 문맥에 맞는 코드를 삽입할 수 있습니다.
FIM은 코드 자동완성에서 특히 중요합니다. 일반 텍스트와 달리 코드는 앞뒤 문맥이 모두 중요하기 때문입니다. 반환 타입, 후속 사용, 변수 스코프 등이 이미 정해져 있는 상태에서 중간을 채워야 하는 경우가 빈번합니다.
AI 코딩 어시스턴트의 핵심에는 코드에 특화된 대규모 언어 모델(Large Language Model, LLM)이 있습니다. 이 모델들이 어떻게 학습되는지 살펴보겠습니다.
코드 LLM은 대규모 코드 코퍼스(Corpus)로 학습됩니다. 주요 데이터 소스는 다음과 같습니다.
The Stack(더 스택)과 같은 데이터셋은 라이선스를 고려하여 허용된 코드만 포함합니다. 이는 이후 IP 및 라이선스 문제와도 연결됩니다.
| 모델 | 개발사 | 특징 |
|---|---|---|
| CodeLlama | Meta | Llama 기반, 코드 특화 파인튜닝 |
| StarCoder | BigCode | 600+ 언어, The Stack으로 학습 |
| DeepSeek Coder | DeepSeek | FIM 최적화, 높은 벤치마크 성능 |
| Claude | Anthropic | 범용 + 코드, 긴 컨텍스트 |
| GPT-4o | OpenAI | 범용 + 코드, 멀티모달 |
코드 전용 모델과 범용 모델의 차이는 흥미롭습니다. StarCoder나 DeepSeek Coder 같은 코드 전용 모델은 작은 파라미터 수로도 코드 생성에서 높은 성능을 보입니다. 반면 Claude나 GPT-4o 같은 범용 모델은 코드의 의도와 맥락을 이해하는 능력이 뛰어나, 복잡한 추론이 필요한 작업에서 강점을 보입니다.
코드 LLM의 학습은 일반적으로 세 단계로 이루어집니다.
1단계 사전 학습(Pre-training): 대규모 텍스트와 코드 데이터로 언어의 기본 구조를 학습합니다.
2단계 코드 특화 학습(Code-specific Training): 코드 코퍼스를 집중적으로 학습하며, FIM 목표를 포함합니다. 이 단계에서 코드의 구문, 패턴, 관용구를 깊이 있게 학습합니다.
3단계 정렬 학습(Alignment): 인간 피드백 기반 강화 학습(RLHF)이나 유사 기법을 통해, 인간의 의도에 맞는 코드를 생성하도록 조정합니다.
LLM은 텍스트를 토큰(Token) 단위로 처리합니다. 코드의 토큰화에는 자연어와 다른 특수한 고려사항이 있습니다.
Python처럼 들여쓰기가 문법적 의미를 가지는 언어에서는, 공백 토큰의 처리가 중요합니다. 일부 코드 특화 토크나이저는 들여쓰기 수준 자체를 하나의 토큰으로 인코딩합니다.
# 들여쓰기가 다르면 완전히 다른 코드
for item in items:
if item.valid:
process(item) # if 블록 내부
log(item) # for 블록 내부, if 밖프로그래밍에서는 getUserProfileData처럼 긴 식별자가 흔합니다. 토크나이저는 이를 get, User, Profile, Data처럼 의미 단위로 분할합니다. 이 분할이 적절해야 모델이 식별자의 의미를 파악할 수 있습니다.
같은 코드라도 언어에 따라 토큰 수가 크게 다릅니다. 일반적으로 Python이 가장 토큰 효율적이고, Java나 C++는 더 많은 토큰을 소비합니다. 이는 컨텍스트 윈도우 내에 담을 수 있는 코드의 양에 직접적인 영향을 줍니다.
컨텍스트 윈도우를 효율적으로 활용하려면, 불필요한 주석이나 빈 줄을 줄이고, 관련 코드만 선택적으로 포함하는 것이 좋습니다. 7장에서 이 주제를 더 깊이 다루겠습니다.
순수한 텍스트 기반 모델은 코드를 문자열로만 봅니다. 하지만 코드에는 추상 구문 트리(Abstract Syntax Tree, AST)라는 명확한 구조가 있습니다.
// 이 코드는
const result = a + b * c;
// AST로 표현하면
// VariableDeclaration
// └─ VariableDeclarator
// ├─ Identifier: result
// └─ BinaryExpression (+)
// ├─ Identifier: a
// └─ BinaryExpression (*)
// ├─ Identifier: b
// └─ Identifier: c최신 코드 LLM들은 AST 정보를 직접 또는 간접적으로 활용합니다. 이를 통해 다음과 같은 이점을 얻습니다.
AI 코딩 어시스턴트의 동작 모드는 기술적으로 세 가지로 구분됩니다.
가장 기본적인 모드입니다. 현재 커서 위치에서 다음 몇 줄의 코드를 예측합니다. FIM 기법을 사용하며, 지연 시간(Latency)이 핵심입니다. 보통 100~300ms 이내에 결과를 반환해야 개발자의 흐름을 방해하지 않습니다.
커서 위치 감지 → 주변 코드 수집 → FIM 형식 변환 → 모델 추론 → 결과 필터링 → 제안 표시이 모드에서는 빠른 응답을 위해 상대적으로 작은 모델을 사용하거나, 큰 모델의 추론을 최적화합니다. 추론 가속(Speculative Decoding) 같은 기법이 활용되기도 합니다.
채팅 인터페이스를 통해 더 큰 단위의 코드를 생성합니다. 함수, 클래스, 심지어 파일 전체를 생성할 수 있습니다. 응답 시간이 수 초 정도로 더 여유가 있어, 더 큰 모델과 더 많은 컨텍스트를 활용합니다.
가장 복잡한 모드입니다. AI가 자율적으로 여러 단계를 수행합니다.
에이전틱 실행에서는 모델이 도구(Tool)를 호출합니다. 파일 시스템 접근, 셸 명령 실행, 웹 검색 등의 도구를 사용하여 복잡한 작업을 수행합니다. Claude Code의 서브에이전트(Sub-agent) 시스템이나 Cursor의 Background Agents가 이 패턴의 대표적인 구현입니다.
에이전틱 실행은 가장 강력하지만, 가장 많은 컴퓨팅 자원을 소비합니다. 단순 자동완성에 에이전틱 실행을 사용하는 것은 과잉입니다. 작업의 복잡도에 따라 적절한 모드를 선택하는 것이 중요합니다.
같은 프롬프트라도 어떤 모델을 사용하느냐에 따라 결과가 크게 달라집니다. 모델 선택에 영향을 주는 요소들을 정리하면 다음과 같습니다.
파라미터 크기: 일반적으로 큰 모델이 더 정확하지만, 응답 속도가 느립니다. 자동완성에는 빠른 소형 모델을, 복잡한 생성에는 대형 모델을 사용하는 것이 일반적입니다.
컨텍스트 윈도우 크기: 200K 토큰과 1M 토큰의 차이는 단순히 양적 차이가 아닙니다. 더 많은 관련 파일을 포함할 수 있어, 프로젝트 전체의 일관성을 유지한 코드 생성이 가능해집니다.
코드 특화 정도: 코드 전용 모델은 구문적으로 올바른 코드를 생성하는 데 강하고, 범용 모델은 요구사항을 이해하고 적절한 설계를 선택하는 데 강합니다.
추론 능력: 복잡한 알고리즘 구현이나 디버깅에서는 추론 능력이 중요합니다. 단순한 보일러플레이트(Boilerplate) 생성에서는 큰 차이가 나지 않습니다.
이번 장에서는 AI 코딩 어시스턴트의 내부 동작 원리를 살펴보았습니다.
다음 장에서는 이러한 원리를 가장 널리 사용되는 도구에 적용하여, GitHub Copilot의 아키텍처와 기능을 심층 분석하겠습니다.
이 글이 도움이 되셨나요?
관련 주제 더 보기
GitHub Copilot의 아키텍처, 코드 컴플리션부터 Agent Mode까지의 기능 진화, VS Code/JetBrains/CLI 통합, 가격 플랜을 심층 분석합니다.
2026년 현재 84%의 개발자가 사용하는 AI 코딩 어시스턴트의 현황과 3가지 아키텍처 철학, 주요 도구 지도, 그리고 생산성 논쟁을 살펴봅니다.
Cursor의 아키텍처, Composer 멀티파일 편집, Background Agents, Tab 자동완성, .cursorrules, 자기 요약 기법까지 심층 분석합니다.