create_agent 미들웨어 데코레이터 패턴
LangChain의 create_agent가 제공하는 미들웨어 데코레이터는 LLM 호출의 전후 처리를 중앙화하는 아키텍처 패턴이다.
4가지 데코레이터 타입
1. @wrap_model_call
용도: LLM 입출력 스키마 변환 및 응답 후처리
LLM의 원본 응답을 비즈니스 로직에 맞는 스키마로 변환한다. 예를 들어:
- 토큰 수 추출
- 응답 구조 정규화
- 메타데이터 추가
2. @before_model
용도: 모델 호출 전 프롬프트 수정
LLM으로 보내기 전에 프롬프트를 동적으로 수정한다.
3. @dynamic_prompt
용도: 실행 시점 변수 기반 프롬프트 조정
프롬프트 템플릿에서 실행 시점의 변수를 주입한다. 템플릿 문자열의 정적 부분과 동적 부분을 분리하는 데 유용하다.
4. @before_agent
용도: 에이전트 실행 전 보안 검증
에이전트가 LLM 호출을 수행하기 전에 프롬프트를 검증한다. 특히 프롬프트 인젝션 방어에 사용된다.
설계 원칙
단일 책임 원칙 (SRP)
각 데코레이터는 하나의 책임만 가져야 한다:
- 스키마 변환은 @wrap_model_call에서만
- 보안 검증은 @before_agent에서만
- 동적 조정은 @dynamic_prompt에서만
이렇게 분리하면 각 미들웨어를 독립적으로 테스트하고 조합할 수 있다.
중앙화의 장점
분산된 검증 로직 중앙화된 미들웨어
├─ API 엔드포인트1 @wrap_model_call
├─ API 엔드포인트2 @before_model
├─ API 엔드포인트3 @dynamic_prompt
└─ ... @before_agent
(중복된 코드) (일관된 정책)
실전 패턴
패턴 1: 응답 스키마 정규화
@wrap_model_call
def normalize_response(response):
return {
"content": response.content,
"finish_reason": response.finish_reason,
"tokens_used": response.usage.total_tokens
}패턴 2: 프롬프트 인젝션 차단
@before_agent
def block_injections(prompt: str) -> str:
dangerous = [r"'; DROP", r"<script>", r"__import__"]
for pattern in dangerous:
if re.search(pattern, prompt, re.IGNORECASE):
raise SecurityError(f"Blocked: {pattern}")
return prompt패턴 3: 문맥 주입
@dynamic_prompt
def add_context(prompt: str, user_id: str) -> str:
return f"[User: {user_id}]\n{prompt}"