Post

프롬프트에 API 50개를 때려 넣었다고요? 에이전트 스킬 레지스트리가 필요한 진짜 이유

프롬프트에 API 50개를 때려 넣었다고요? 에이전트 스킬 레지스트리가 필요한 진짜 이유

[Metadata & References]

1. The Hook: 프롬프트에 API 50개를 때려 넣는 미련한 짓

솔직히 까놓고 얘기해 봅시다. 10년 넘게 이 바닥에서 구르면서 온갖 프레임워크와 아키텍처의 흥망성쇠를 지켜봤지만, 최근 AI 에이전트(Agent) 열풍만큼 개발자들을 단체로 끔찍한 삽질의 늪으로 몰아넣는 트렌드도 드문 것 같습니다. 다들 PoC(개념 증명) 단계에서는 환호합니다. LLM에 사내 API 2~3개 연동해서 ‘오늘 매출 데이터 뽑아줘’ 같은 데모를 보여주면 임원진은 기립박수를 치죠.

하지만 진짜 악몽은 이 시스템을 프로덕션(Production) 레벨로 올리는 순간 시작됩니다.

“유저가 무슨 질문을 할지 모르니까, 일단 우리가 가진 API 50개의 스펙을 전부 JSON Schema로 변환해서 System Prompt의 tools 배열에 다 때려 넣자!”

현업에서 이 문제를 마주해 본 분들이라면 아실 겁니다. 이게 얼마나 시스템을 갉아먹는 짓인지요. 컨텍스트 윈도우(Context Window)는 순식간에 터져나가고, 토큰 비용은 CFO가 뒷목을 잡을 만큼 폭발합니다. 무엇보다 치명적인 것은 에이전트의 ‘지능 저하’입니다. 수십 개의 도구 속에서 길을 잃은 LLM은 환각(Hallucination)을 일으키며 “배송 조회”를 해야 할 타이밍에 엉뚱하게 “회원 탈퇴” API를 호출해버리는 대형 사고를 칩니다. 우리는 지금 거대한 비효율의 늪에서 허우적대고 있습니다.

2. TL;DR (The Core)

“에이전트 스킬 레지스트리(Agent Skills Registry)는 프롬프트 하드코딩의 저주를 끊어낼, AI 에이전트를 위한 동적 패키지 매니저(npm, pip)이자 지능형 서비스 디스커버리(Service Discovery) 시스템입니다.”

3. Deep Dive: Under the Hood (RAG-for-Tools 아키텍처의 민낯)

이 레지스트리는 단순히 도구들을 모아둔 DB가 아닙니다. 핵심은 에이전트가 도구를 인식하고 사용하는 패러다임을 정적(Static)에서 동적(Dynamic)으로 전환하는 데 있습니다. 저는 이를 ‘RAG-for-Tools’라고 부릅니다. 텍스트 문서를 검색해 RAG(검색 증강 생성)를 하듯, ‘실행 가능한 함수’를 검색해서 LLM의 컨텍스트에 런타임으로 먹여주는 겁니다.

기존 아키텍처와 레지스트리 기반 아키텍처의 차이를 한눈에 비교해 볼까요?

비교 항목Monolithic Prompting (기존)Agent Skills Registry (도입 후)
도구 주입 방식프롬프트 내 하드코딩 (무조건 전체 주입)유저 의도 기반 런타임 동적 주입 (On-demand)
토큰 소모량O(N) - 도구 개수에 비례해 기하급수적 증가O(k) - 검색된 상위 k개의 스키마만 소모
에이전트 환각률매우 높음 (유사 API 간 심각한 혼동 발생)매우 낮음 (컨텍스트 내 선택지가 극도로 압축됨)
유지보수성최악 (API 하나 바뀔 때마다 프롬프트/코드 수정)우수 (레지스트리 내 개별 스키마만 독립적 업데이트)

작동 원리는 이렇습니다. 먼저 모든 사내 API 스펙과 설명을 Vector DB(Qdrant, Pinecone 등)에 임베딩하여 저장합니다. 유저의 요청이 들어오면 LLM에 바로 넘기는 게 아니라, 오케스트레이터(Orchestrator)가 먼저 유저의 의도를 벡터로 변환해 가장 적합한 스킬 Top-k를 레지스트리에서 검색(Retrieval)합니다.

아래는 실제 레지스트리에 저장되는 스킬의 JSON 스키마 예시와, 이를 동적으로 가져오는 파이썬 의사코드(Pseudo-code)입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
  "skill_id": "com.corp.order.refund",
  "name": "process_refund",
  "description": "사용자의 주문 번호를 기반으로 환불 절차를 진행합니다. 이 스킬은 결제 취소 및 재고 복구 로직을 포함합니다.",
  "parameters": {
    "type": "object",
    "properties": {
      "order_id": {"type": "string", "description": "환불할 주문의 고유 ID (예: ORD-12345)"},
      "reason": {"type": "string", "description": "환불 사유 카테고리"}
    },
    "required": ["order_id"]
  },
  "metadata": {
    "auth_level": "admin_only",
    "endpoint": "https://api.internal.corp/v1/orders/refund"
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 의사코드: 사용자 의도를 기반으로 Registry에서 동적 스킬 획득 및 주입
def orchestrate_agent(user_query, user_role="user"):
    # 1. 사용자 쿼리 임베딩 처리
    query_embedding = embed_model.embed(user_query)

    # 2. Agent Skills Registry에서 관련 스킬 검색 (RBAC 메타데이터 필터링 적용!)
    relevant_skills = registry_db.similarity_search(
        query_embedding,
        k=2,
        filter={"auth_level": {"$in": ["public", user_role]}}
    )

    # 3. 검색된 스킬 객체들을 LLM이 이해할 수 있는 도구 스키마로 변환
    dynamic_tools = [skill.to_openai_schema() for skill in relevant_skills]

    # 4. 압축되고 가벼워진 컨텍스트로 LLM 호출
    response = llm.invoke(
        prompt=user_query,
        tools=dynamic_tools
    )
    return response

여기서 실무적으로 가장 주목해야 할 점은 바로 메타데이터 필터링(Metadata Filtering)입니다. 위 코드처럼 권한(RBAC) 필터를 레지스트리 조회 단계에 하드하게 걸어버리면, 일반 유저가 “모든 유저 데이터 삭제해줘”라고 명령해도 LLM의 도구 상자에는 애초에 ‘삭제 API’가 제공되지 않습니다. LLM이 환각을 일으키고 싶어도 도구가 없어서 못 하는 겁니다. 보안 및 컴플라이언스 관점에서 원천적인 방어가 가능해진다는 뜻이죠. 이거, 엔터프라이즈 환경에서는 진짜 피눈물 흘려가며 깨닫는 핵심입니다.

4. Pragmatic Use Cases (현업 실무 적용 시나리오)

상상해 봅시다. 10년 된 Spring Boot 기반의 SOAP 레거시와 최신 Node.js 마이크로서비스(MSA)가 혼재된 거대한 e-commerce 플랫폼입니다. 당신은 이 혼돈의 백엔드 위에 고객센터 챗봇을 올려야 합니다. 조회, 취소, 환불, 배송 추적, 리뷰 작성 등 연결해야 할 API만 150개가 넘습니다.

기존 방식이라면 트래픽 스파이크가 칠 때마다 150개의 API 스키마를 담은 거대한 JSON 페이로드가 OpenAI 서버를 오가며 네트워크 대역폭과 회사 지갑을 동시에 박살냈을 겁니다. 하지만 Registry를 도입하면 이 시스템은 LLM을 위한 지능형 API Gateway로 진화합니다.

사용자가 “나 어제 산 신발 사이즈 270으로 바꿀 수 있어?”라고 물으면, 오케스트레이터는 Registry에서 check_inventory(재고 확인)와 exchange_order(교환 처리) 두 개의 스킬만 쏙 뽑아옵니다. LLM은 자신이 세상에 단 2개의 도구만 존재하는 것처럼 완벽하게 집중하여 파라미터를 추출합니다. 결과적으로 토큰 비용은 1/50 수준으로 급감하고, LLM의 추론 속도(TTFT)는 대폭 상승하며, 레거시 시스템에 잘못된 API 콜을 날려 트랜잭션이 꼬이는 대형 사고 리스크는 제로(0)에 수렴하게 됩니다.

더 나아가, 이 Registry는 상태(State)를 가지는 워크플로우에도 적용됩니다. 예를 들어 ‘환불 절차’는 단순 단일 API 호출이 아니라, 결제 취소 -> 재고 복구 -> 고객 알림을 순차적으로 수행해야 하는 복합 스킬(Composite Skill)일 수 있습니다. 이럴 때 Registry에 LangGraph 기반의 서브 에이전트(Sub-agent) 자체를 하나의 ‘스킬’로 등록해버리면 됩니다. 메인 에이전트는 그저 ‘환불 마이크로 에이전트’를 호출하기만 하면 되죠. 이게 바로 에이전틱(Agentic) 아키텍처가 무한대의 확장성을 가지는 진짜 비결입니다.

5. Honest Review & Trade-offs (시니어의 깐깐한 시선으로 본 한계)

물론, 세상에 은탄환(Silver Bullet)은 없고 장밋빛 미래만 있는 것도 아닙니다. 아키텍처 다이어그램에 박스를 하나 더 얹는다는 건 필연적으로 뼈아픈 트레이드오프를 동반하죠.

첫째, Latency Hop (지연 시간 증가)입니다. LLM에 도달하기 전, Registry(Vector DB)를 찌르고 오는 네트워크 홉이 무조건 추가됩니다. 내부망에서 gRPC로 촘촘하게 묶어 밀리초(ms) 단위로 최적화하지 않으면, 사용자 입장에서는 챗봇이 평소보다 한 박자 늦게 생각하고 대답한다고 느낄 수밖에 없습니다.

둘째, Semantic Search의 치명적 한계입니다. 사용자의 발화가 너무 짧거나 모호할 때, Registry가 엉뚱한 스킬을 반환(False Positive)하거나 필수 스킬을 누락(False Negative)해버리면, LLM은 그 잘못 쥐어진 도구 안에서 어떻게든 답을 내려고 발악하다가 장렬하게 에러를 뱉습니다. 결국 Tool Embedding 모델의 품질과 Description의 디테일이 전체 시스템의 명운을 가르게 됩니다. 단순 텍스트 임베딩을 넘어서서 BM25 기반의 키워드 하이브리드 검색(Hybrid Search)을 섞어 써야만 하는 이유가 여기에 있습니다. 결국 우리는 “프롬프트 깎는 노인”에서 “스킬 Description 깎는 노인”으로 직무만 바뀔 뿐입니다.

셋째, 버전 관리의 지옥(Versioning Hell)입니다. 백엔드 팀에서 API 파라미터를 orderId에서 order_id로 슬쩍 바꿨는데 Registry 스키마 업데이트를 깜빡했다면? LLM은 구버전 스키마를 보고 낡은 파라미터로 API를 찌르고 HTTP 400 Bad Request 폭탄을 맞게 됩니다. 이를 방지하려면 백엔드 개발자가 OpenAPI(Swagger) 스펙을 깃허브에 푸시(Push)할 때, GitHub Actions 등을 통해 자동으로 Registry의 벡터 DB와 JSON 스키마를 덮어쓰기(Upsert)하는 빡센 CI/CD 파이프라인 구축이 필수적입니다. AI 팀과 백엔드 팀 간의 완벽한 DevOps적 결합 없이는 이 시스템은 금방 레거시 쓰레기통이 되어버릴 겁니다.

6. Closing Thoughts: 프롬프트의 시대는 저물고, 마이크로 스킬의 시대가 온다

“모든 것을 할 줄 아는 거대한 신(God) 같은 단일 프롬프트를 깎는 시대는 끝났습니다.”

이제 AI 에이전트 설계의 핵심은 무식한 컨텍스트 구겨넣기가 아닙니다. ‘필요한 순간에 필요한 도구만 정확하고 안전하게 쥐어주는’ 정교한 오케스트레이션에 있습니다. Agent Skills Registry는 단순한 도구 저장소를 넘어, 통제 불가능할 정도로 똑똑해지는 AI 에이전트와 엄격한 엔터프라이즈 레거시 시스템을 안전하게 연결해 주는 필수 미들웨어(Middleware)로 자리 잡을 것입니다.

아직도 수십 개의 API 스키마를 tools 배열에 하드코딩하며 밤잠을 설치고 계신가요? 시스템이 이따금씩 엉뚱한 API를 호출할 때마다 temperature 값이나 조절하며 기도하고 계시진 않나요? 지금 당장 그 하드코딩된 코드 블록을 지우고, 작지만 강력한 스킬 레지스트리 구축을 시작해야 할 때입니다. 진정한 에이전트의 자율성은, 역설적이게도 완벽하게 통제되고 큐레이션 된 도구의 제공에서 비로소 시작되니까요.

References

  • https://modelcontextprotocol.io/
  • https://python.langchain.com/docs/modules/agents/
  • https://platform.openai.com/docs/guides/function-calling
This post is licensed under CC BY 4.0 by the author.