이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.
- Context Engineering은 Prompt Engineering과 무엇이 다른가?
- RAG, tool result, 대화 이력, 사용자 권한은 어떤 순서로 조립해야 하는가?
- context window가 커져도 왜 컨텍스트 설계가 여전히 중요한가?
- 백엔드 서버에서는 context 조립 로직을 어떻게 테스트해야 하는가?
개요
Context Engineering은 모델에 넣을 정보를 선택하고, 정렬하고, 압축하고, 권한에 맞게 필터링하고, 출력 목적에 맞는 구조로 조립하는 일이다. Prompt Engineering이 “어떻게 지시할 것인가”에 집중한다면, Context Engineering은 “무엇을 근거로 답하게 할 것인가”에 집중한다.
LLM의 context window가 커져도 이 문제는 사라지지 않는다. 더 많은 정보를 넣을 수 있다는 것은 더 많은 오래된 정보, 중복 정보, 권한 없는 정보, 공격성 텍스트가 섞일 수 있다는 뜻이기도 하다.
왜 백엔드 개발자에게 중요한가
백엔드 개발자는 데이터 접근 경계와 권한 경계를 책임진다. AI 기능에서 context 조립은 이 경계를 모델 입력으로 변환하는 작업이다.
예를 들어 사내 문서 QA 기능을 만든다고 하자. 단순히 vector DB에서 top-5 chunk를 찾아 prompt에 넣으면 끝이 아니다.
- 사용자가 볼 수 없는 문서 chunk를 제거해야 한다.
- 삭제된 문서의 오래된 chunk가 index에 남아 있지 않아야 한다.
- 최신 정책 문서가 오래된 문서보다 우선되어야 한다.
- 동일 문서의 중복 chunk가 token budget을 낭비하지 않아야 한다.
- tool result에 포함된 지시문을 시스템 지시보다 우선하지 않게 해야 한다.
이것은 모델 문제가 아니라 백엔드 데이터 흐름 문제다.
핵심 원리
Context는 보통 다음 재료로 구성된다.
- system instruction
- developer instruction
- 사용자 질문
- 대화 이력
- RAG 검색 결과
- 사용자 프로필과 권한 정보
- tool 호출 결과
- 출력 schema
- 실패 시 행동 규칙
중요한 원칙은 신뢰도와 역할을 섞지 않는 것이다. 시스템 정책은 시스템 정책으로, 사용자 입력은 사용자 입력으로, 외부 문서와 tool 결과는 근거 자료로 구분해야 한다. 외부 문서 안에 “이전 지시를 무시하라”는 문장이 들어 있어도 그것은 지시가 아니라 인용된 데이터여야 한다.
컨텍스트 조립 순서
실전에서는 다음 순서가 안전하다.
- 사용자와 테넌트 권한을 먼저 확인한다.
- 요청 목적에 맞는 retrieval 전략을 고른다.
- 검색 결과에 metadata filter와 권한 필터를 적용한다.
- chunk를 최신성, 출처 신뢰도, 점수, 중복 기준으로 정렬한다.
- token budget에 맞게 압축하거나 일부를 제거한다.
- context block을 출처와 함께 구조화한다.
- prompt와 schema를 조립한다.
- 조립 결과의 token 수와 source id를 기록한다.
권한 필터는 모델에게 맡기지 않는다. “권한 없는 문서는 답하지 마”라고 프롬프트에 적는 것은 보조 장치일 뿐이다. 권한 없는 chunk는 애초에 context에 들어가면 안 된다.
코드로 이해하기
다음은 RAG context를 조립하는 단순 예시다. 핵심은 검색 후 바로 prompt에 붙이지 않고, 권한과 token budget을 통과시킨다는 점이다.
from dataclasses import dataclass
from typing import Iterable
@dataclass(frozen=True)
class Chunk:
source_id: str
text: str
score: float
updated_at: str
allowed_role: str
def estimate_tokens(text: str) -> int:
return max(1, len(text) // 4)
def build_context(
*,
chunks: Iterable[Chunk],
user_role: str,
token_budget: int,
) -> str:
selected: list[Chunk] = []
used_tokens = 0
seen_sources: set[str] = set()
visible_chunks = [
chunk for chunk in chunks
if chunk.allowed_role == user_role or chunk.allowed_role == "public"
]
ranked_chunks = sorted(
visible_chunks,
key=lambda chunk: (chunk.score, chunk.updated_at),
reverse=True,
)
for chunk in ranked_chunks:
if chunk.source_id in seen_sources:
continue
cost = estimate_tokens(chunk.text)
if used_tokens + cost > token_budget:
continue
selected.append(chunk)
seen_sources.add(chunk.source_id)
used_tokens += cost
return "\n\n".join(
f"[source_id={chunk.source_id}]\n{chunk.text}"
for chunk in selected
)이 코드는 단순하지만 중요한 운영 포인트를 가진다. 권한 없는 chunk를 제거하고, source 중복을 줄이며, token budget을 넘지 않는다. 실제 서비스에서는 여기에 문서 삭제 상태, 테넌트 id, 접근 제어 목록, reranking 결과, source 신뢰도까지 붙는다.
장애 상황과 대응
Context Engineering 실패는 다음 증상으로 드러난다.
- 검색 결과는 나왔는데 답변이 엉뚱하다.
- 같은 질문인데 사용자마다 보이면 안 되는 문서가 섞인다.
- 최신 문서를 올렸는데 오래된 정책으로 답한다.
- 긴 문서를 넣었더니 latency와 비용이 급증한다.
- tool 결과에 포함된 악성 문구를 모델이 지시로 따른다.
대응은 검색, 조립, 생성 단계를 분리해 관찰하는 것이다. trace에는 검색 query, top-k source id, 필터링 후 source id, token count, final prompt version, output validation result를 남긴다. source text 전문은 민감정보가 있을 수 있으므로 접근 제어와 샘플링이 필요하다.
인프라 협업 포인트
인프라팀은 context 조립에서 다음을 걱정한다.
- vector DB query latency와 tail latency
- metadata filter cardinality와 index 성능
- batch indexing이 online serving 리소스를 잠식하는 문제
- embedding 모델 변경 시 재색인 비용
- context token 증가로 인한 provider 비용
- 로그와 trace의 고카디널리티 비용
백엔드 개발자는 RAG 기능을 만들 때 “검색 한 번 추가”가 아니라 새로운 읽기 경로, 색인 경로, 권한 경로, 관측성 경로를 추가한다는 점을 공유해야 한다.
개인 프로젝트 최소 기준
- 문서마다 source id와 updated_at을 둔다.
- 검색 결과를 그대로 넣지 말고 중복 제거와 token budget 제한을 한다.
- private 문서와 public 문서를 구분한다.
- 문서 삭제 시 vector index에서도 제거하는 스크립트를 둔다.
- 답변에 사용한 source id를 보여준다.
기업 운영 수준 기준
- 권한 필터는 DB 권한 모델과 일치해야 한다.
- 문서 수집, chunking, embedding, indexing, serving을 분리해 모니터링한다.
- embedding 모델 변경 시 dual index 또는 재색인 계획을 둔다.
- context 조립 로직을 테스트하고, 권한 경계 테스트를 CI에 포함한다.
- source id, document version, prompt version, model version을 trace로 연결한다.
실전 팁
- context block에는 source id를 명시한다. 나중에 답변 근거와 로그를 연결할 수 있다.
- chunk 크기는 정답이 없다. 문서 구조, 질문 유형, 임베딩 모델, reranker 사용 여부에 따라 달라진다.
- 최신성이 중요한 문서는 score만으로 정렬하지 않는다. updated_at이나 version을 함께 본다.
- tool result는 “데이터”로 감싼다. tool 결과가 새로운 system instruction처럼 해석되지 않게 한다.
위험 신호!
- 권한 없는 문서를 prompt에 넣고 모델에게 답하지 말라고 지시한다.
- vector DB의 metadata filter가 실제 서비스 DB 권한과 다르게 관리된다.
- 문서 삭제 후 index에서 제거하는 절차가 없다.
- token budget 없이 검색 결과를 많이 넣는다.
- context 조립 로직에 테스트가 없다.
확인 질문
확인 질문
- Context Engineering의 핵심은 무엇인가?
- 모델이 답할 때 사용할 정보를 권한, 최신성, 목적, token budget에 맞게 선택하고 구조화하는 것이다.
- 권한 필터를 프롬프트에만 맡기면 안 되는 이유는 무엇인가?
- 권한 없는 데이터가 이미 모델 입력에 들어가면 유출 위험이 생기기 때문이다.
- context window가 커져도 조립 설계가 필요한 이유는 무엇인가?
- 많은 정보는 비용, latency, 충돌, 오래된 정보, 보안 위험을 함께 늘릴 수 있기 때문이다.
Spring AI 적용 연결
- Spring AI에서는 context 조립을
Advisor,ChatMemory, RAG retriever의 책임으로 나눠 본다. 구현 흐름은 05. Prompt Context Advisor Memory 설계에서 이어서 확인한다. - context 품질을 회귀 테스트로 묶는 방법은 10. Evaluation Testing Regression과 함께 본다.