어텐션 메커니즘과 위치 편향을 이해하고, 정보 배치 전략과 XML/마크다운/JSON 포맷 비교를 통해 컨텍스트 구조를 최적화합니다.
동일한 정보라도 컨텍스트 내 위치에 따라 모델의 주의력(Attention)이 달라집니다. 이는 트랜스포머(Transformer) 아키텍처의 어텐션 메커니즘에서 기인합니다.
연구에서 반복적으로 확인된 패턴은 다음과 같습니다.
| 위치 | 주의력 수준 | 적합한 정보 |
|---|---|---|
| 컨텍스트 시작 | 높음 (프라이머시 효과) | 시스템 프롬프트, 핵심 규칙 |
| 컨텍스트 중간 | 낮음 ("Lost in the Middle") | 참조용 코드, 보조 정보 |
| 컨텍스트 끝 | 높음 (리센시 효과) | 현재 작업, 사용자 요청 |
"Lost in the Middle"은 2023년 Stanford 연구에서 명명된 현상으로, 긴 컨텍스트의 중간에 위치한 정보를 모델이 놓치는 경향을 가리킵니다. 이후 모델들이 개선되었지만, 이 경향은 완전히 사라지지 않았습니다.
1M 토큰 컨텍스트를 지원하는 최신 모델들도 위치 편향에서 완전히 자유롭지 않습니다. "Needle in a Haystack" 벤치마크에서 높은 점수를 기록하더라도, 실제 복잡한 작업에서는 위치에 따른 성능 차이가 관찰됩니다.
위치 편향을 고려한 최적 배치는 U자형입니다: 가장 중요한 정보를 시작과 끝에, 덜 중요한 정보를 중간에 배치합니다.
interface ContextBlock {
content: string;
priority: "critical" | "high" | "medium" | "low";
type: "system" | "code" | "reference" | "task";
}
function orderContextBlocks(blocks: ContextBlock[]): ContextBlock[] {
const critical = blocks.filter(b => b.priority === "critical");
const high = blocks.filter(b => b.priority === "high");
const medium = blocks.filter(b => b.priority === "medium");
const low = blocks.filter(b => b.priority === "low");
return [
...critical, // 시작: 핵심 규칙, 시스템 프롬프트
...low, // 중간 시작: 낮은 우선순위
...medium, // 중간: 참조 코드
...high, // 끝 근처: 중요 컨텍스트
// 사용자 요청은 항상 맨 마지막
];
}AI 코딩 에이전트의 컨텍스트를 배치하는 권장 순서입니다.
주목할 점은 현재 작업 대상 코드가 사용자 요청 바로 앞에 위치한다는 것입니다. 모델이 요청을 처리할 때 가장 가까이에 있는 코드를 먼저 참조하므로, 작업 대상 코드와 요청의 물리적 거리를 최소화합니다.
정보를 어떤 형식으로 구조화하느냐에 따라 모델의 파싱 효율이 달라집니다.
<context>
<project-rules>
<rule priority="critical">TypeScript strict mode, no 'any' type</rule>
<rule priority="critical">Function declarations for components</rule>
<rule priority="high">Use cn() for className composition</rule>
</project-rules>
<current-file path="src/auth/middleware.ts">
<code language="typescript">
export function verifyToken(req: Request): Promise<User> {
// ...
}
</code>
</current-file>
<related-files>
<file path="src/auth/types.ts" summary="User, Role, AuthConfig types" />
<file path="src/auth/jwt.ts" summary="JWT sign/verify utilities" />
</related-files>
</context>장점: 명확한 계층 구조, 메타데이터(속성) 표현 용이, 여는/닫는 태그로 경계가 명확합니다.
단점: 태그 자체가 토큰을 소모하며, 코드 내 <, > 기호와 충돌할 수 있습니다.
## Project Rules
- **[CRITICAL]** TypeScript strict mode, no 'any' type
- **[CRITICAL]** Function declarations for components
- **[HIGH]** Use cn() for className composition
## Current File: src/auth/middleware.ts
export function verifyToken(req: Request): Promise<User> {
// ...
}
## Related Files
| File | Summary |
|---|---|
| src/auth/types.ts | User, Role, AuthConfig types |
| src/auth/jwt.ts | JWT sign/verify utilities |장점: 사람도 읽기 쉬움, 대부분의 모델이 마크다운에 익숙, 코드 블록 자연스러움.
단점: 중첩 구조 표현이 제한적, 메타데이터 표현이 어색합니다.
{
"projectRules": [
{ "rule": "TypeScript strict mode, no any", "priority": "critical" },
{ "rule": "Function declarations for components", "priority": "critical" },
{ "rule": "Use cn() for className", "priority": "high" }
],
"currentFile": {
"path": "src/auth/middleware.ts",
"code": "export function verifyToken(req: Request): Promise<User> { ... }"
},
"relatedFiles": [
{ "path": "src/auth/types.ts", "summary": "User, Role, AuthConfig types" },
{ "path": "src/auth/jwt.ts", "summary": "JWT sign/verify utilities" }
]
}장점: 구조화된 데이터에 최적, 프로그래밍적 생성이 용이, 파싱이 명확합니다.
단점: 토큰 효율이 낮음(따옴표, 중괄호 등), 긴 코드 포함 시 이스케이프가 복잡합니다.
| 측면 | XML | 마크다운 | JSON |
|---|---|---|---|
| 토큰 효율 | 중간 | 높음 | 낮음 |
| 구조 표현력 | 높음 | 중간 | 높음 |
| 코드 포함 용이성 | 낮음 (이스케이프) | 높음 (코드 블록) | 낮음 (이스케이프) |
| 모델 친화도 | 높음 (Claude) | 높음 (범용) | 중간 |
| 사람 가독성 | 중간 | 높음 | 중간 |
Anthropic의 공식 가이드에 따르면, Claude는 XML 태그를 사용한 구조화에 특히 잘 반응합니다. 시스템 프롬프트와 메타데이터에는 XML을, 코드와 설명에는 마크다운을 사용하는 하이브리드 포맷이 실전에서 효과적입니다.
코드와 그에 대한 설명을 어떻게 배치할 것인가도 중요한 포맷 결정입니다.
## 설명
UserService는 사용자 CRUD를 담당합니다. findById는 캐시를 먼저 확인하고,
없으면 DB에서 조회합니다. create는 이메일 중복을 검사합니다.
## 코드
class UserService {
async findById(id: string): Promise<User | null> { ... }
async create(data: CreateUserDTO): Promise<User> { ... }
}## UserService
사용자 CRUD를 담당하는 서비스입니다.
### findById
캐시를 먼저 확인하고, 없으면 DB에서 조회합니다.
async findById(id: string): Promise<User | null> { ... }
### create
이메일 중복을 검사한 후 사용자를 생성합니다.
async create(data: CreateUserDTO): Promise<User> { ... }인터리빙 방식이 더 효과적인 이유는 설명과 코드의 물리적 거리가 가까울수록 모델이 둘을 연결하여 이해하기 쉽기 때문입니다. 분리 배치에서는 설명을 읽은 후 코드를 찾아가야 하므로, 어텐션이 분산됩니다.
반복적인 작업에서 일관된 컨텍스트 구조를 유지하기 위한 템플릿입니다.
<context>
<task-type>code-modification</task-type>
<project-context>
<!-- CLAUDE.md 핵심 규칙 -->
</project-context>
<target-file path="...">
<!-- 수정 대상 전체 코드 -->
</target-file>
<dependencies>
<!-- 의존하는 타입/인터페이스 (압축) -->
</dependencies>
<related-tests path="...">
<!-- 관련 테스트 코드 -->
</related-tests>
<similar-implementations>
<!-- 프로젝트 내 유사한 구현 예시 -->
</similar-implementations>
<user-request>
<!-- 사용자의 구체적 요청 -->
</user-request>
</context><context>
<task-type>bug-fix</task-type>
<error-info>
<error-message><!-- 에러 메시지 --></error-message>
<stack-trace><!-- 스택 트레이스 --></stack-trace>
<reproduction-steps><!-- 재현 단계 --></reproduction-steps>
</error-info>
<suspected-files>
<!-- 에러와 관련된 파일들 (전체 코드) -->
</suspected-files>
<call-chain>
<!-- 에러 발생 경로의 호출 체인 -->
</call-chain>
<recent-changes>
<!-- 최근 변경사항 (git diff) -->
</recent-changes>
</context>이런 템플릿을 사전에 정의해두면, 작업 유형에 따라 자동으로 적절한 컨텍스트를 조립할 수 있습니다.
컨텍스트를 구성할 때 확인해야 할 항목들입니다.
배치 순서
포맷 선택
정보 밀도
컨텍스트의 정렬과 포맷은 동일한 정보라도 모델의 이해도와 활용도를 크게 바꿀 수 있는 전략입니다. "Lost in the Middle" 현상을 고려하여 중요 정보를 시작과 끝에 배치하는 U자형 전략이 기본이며, XML과 마크다운의 하이브리드 포맷이 코드 작업에 효과적입니다.
코드와 설명은 인터리빙으로 배치하고, 작업 유형별 컨텍스트 템플릿을 사전에 정의하면 일관된 품질을 유지할 수 있습니다.
다음 장에서는 멀티에이전트 환경에서의 컨텍스트 격리 전략을 다룹니다. 에이전트별로 격리된 컨텍스트 윈도우를 설계하고, 크로스 오염을 방지하며, 공유 컨텍스트를 관리하는 방법을 살펴봅니다.
이 글이 도움이 되셨나요?
관련 주제 더 보기
멀티에이전트 시스템에서 에이전트별 컨텍스트를 격리하고, 크로스 오염을 방지하며, 공유 컨텍스트를 효과적으로 관리하는 전략을 다룹니다.
토큰 한계와 비용을 최적화하면서 핵심 의미를 보존하는 컨텍스트 압축 기법을 다룹니다. 코드 요약, 인터페이스 추출, 트리 구조 압축 등을 분석합니다.
Claude Code, Cursor, GitHub Copilot에서 컨텍스트를 최적화하는 구체적 방법과, MCP 서버를 통한 동적 컨텍스트 확장 기법을 다룹니다.