Posted in

Serverless 아키텍처로 구현한 인스타그램, 유튜브, 틱톡 등 콘텐츠 분석 AI Agent 운영 고도화

안녕하세요. 피처링에서 AIOps 엔지니어로 일하고 있는 Rocky입니다.

이전에 AWS 기술 블로그를 통해 저희가 Amazon Bedrock 기반으로 구축한 소셜 미디어 콘텐츠 분석 Multi-Agent 시스템을 소개해 드린 적이 있습니다.

이전 글: Amazon Bedrock을 활용한 피처링의 소셜 미디어 콘텐츠 분석 시스템 (AWS 기술 블로그)

해당 시스템을 프로덕션에서 운영한 지도 꽤 시간이 지났는데요. 운영을 하다 보니 초기 설계에서는 예상하지 못했던 문제들이 하나둘 드러나기 시작했습니다. 이번 글에서는 그 과정에서 마주한 한계들과, 이를 Amazon Bedrock AgentCore 기반으로 어떻게 개선해 나가고 있는지 공유드리려 합니다.

기존 시스템 간단 요약

자세한 내용은 이전 글을 참고해 주시면 되고, 간단히 정리하면 이렇습니다. ECS 기반 크롤러가 소셜 미디어 콘텐츠를 수집하고, Kinesis Data Streams를 통해 각 분석 에이전트(콘텐츠 분류, 광고 판별, 브랜드 정규화, 감성 분석)로 전달합니다. 각 에이전트는 AWS Lambda 위에서 독립적으로 동작하면서, Amazon Bedrock의 Claude Sonnet을 호출해 멀티모달 추론을 수행하는 구조입니다.

이 구조 덕분에 리포트 조회율 1.6배 향상, 광고 분석 활용 고객 65% 증가, 캠페인 분석 시간 약 70% 단축 같은 성과를 낼 수 있었습니다.

그런데 시스템이 커지면서, 기존 구조에서도 한계점들이 보이기 시작했습니다.

에이전트 내부 설계 원칙

이 시스템을 설계하면서 저희가 가장 중요하게 생각한 원칙은 각 구성요소의 독립성이었습니다. 이 원칙은 에이전트 간의 관계뿐 아니라, 에이전트 내부 설계에도 동일하게 적용했습니다.

저희는 에이전트 내부 워크플로우를 LangGraph로 구성하고 있습니다. 광고 분류 에이전트를 예로 들면, 콘텐츠가 들어오면 먼저 광고 여부를 판별하고, 광고라면 브랜드를 추출한 뒤 공식 명칭으로 정규화하고, 마지막으로 사람의 리뷰를 거쳐 최종 결과가 나가는 흐름입니다.

처음에는 광고 판별부터 브랜드 정규화까지 하나의 프롬프트에 구성하여 작업을 처리하려 했습니다. 그런데 작업들 간에 간섭이 생기면서 정확도가 눈에 띄게 떨어지는 현상이 발생했었습니다. 광고 여부를 판단하는 맥락과 브랜드를 정규화하는 맥락이 하나의 프롬프트 안에서 서로 영향을 주면서, 각각 따로 처리할 때보다 품질이 나빠진 겁니다.

그래서 노드별로 단일 책임을 부여하는 방식으로 내부 구성을 변경하였습니다. 각 노드가 하나의 태스크만 담당하고, 필요한 도구와 검증 기준도 독립적으로 갖도록 했습니다. Confidence Score, Pydantic Schema, Human-in-the-loop 등 노드마다 맞는 검증 방식을 적용하니, 각 단계의 품질을 개별적으로 추적하고 개선할 수 있게 되었습니다.

이 구조의 또 다른 장점은 확장이 쉽다는 거였는데요. human_review 노드는 사실 처음부터 있던 게 아니라 나중에 추가한 건데, 기존 로직을 건드리지 않고 이전 최종결과를 입력으로 받아 동작하도록 연결하기만 하면 됐습니다.

이렇게 독립성이라는 원칙은 시스템 레벨에서도, 에이전트 내부에서도 잘 작동했습니다. 하지만 시스템이 커지면서, 바로 이 원칙 때문에 생기는 새로운 종류의 문제들이 나타나기 시작했습니다.

독립성이 만든 새로운 문제: 운영에서 느낀 한계

에이전트를 독립적으로 잘 분리해 놨지만, 독립적인 에이전트가 많아질수록 오히려 통합 관리가 어려워지는 trade-off가 발생했습니다.

에이전트별 외부 도구 수동 통합

각 에이전트가 개별 Lambda에서 돌아가다 보니, 에이전트마다 필요한 외부 도구를 일일이 연결해줘야 했습니다. 브랜드 정규화 에이전트는 RDS 브랜드 DB 및 MCP 기반 외부 검색(Wikipedia, Google, DuckDuckGo)을 사용하고, 광고 분류 에이전트는 규칙 기반 신호 처리 로직이 필요하고, 콘텐츠 분류 에이전트는 Content Taxonomy 데이터를 참조하는 식인데요. 에이전트가 하나 늘어날 때마다 이 통합 작업이 반복되었고, 설정 불일치나 버전 관리가 점점 부담이 되어갔습니다.

상태 관리의 분산

에이전트 간 분석 결과에 의존성이 있는 경우, 저희는 SQS 기반 비동기 방식으로 결과를 전달하고 있습니다. 예를 들어 광고 분류 에이전트가 콘텐츠를 광고로 판별하면, 그 결과를 SQS를 통해 브랜드 분석 에이전트로 넘기는 식인데요. 문제는 이 과정에서 각 에이전트가 재시도 로직이나 실패 처리를 개별적으로 구현해야 한다는 점이었습니다. 특정 에이전트에서 처리가 실패하거나 지연이 발생했을 때, 전체 파이프라인에서 어디가 문제인지를 파악하려면 여러 Lambda의 로그와 SQS 메시지를 교차 확인해야 했고, 에이전트가 늘어날수록 이 디버깅 비용이 점점 커져갔습니다.

에이전트로의 피드백

가장 큰 문제는 에이전트의 판단 품질을 개선하는 과정이었습니다. 기존에는 분류 결과를 확인하고, 프롬프트를 디버깅한 다음, 새로운 프롬프트가 포함된 에이전트를 다시 배포해야 했습니다. 사소한 프롬프트 수정 하나에도 배포가 필요하니, 품질 개선을 위한 실험 자체가 규모가 커질수록 점점 더 부담스러워 집니다. 사람이 결과를 검토해서 피드백을 줘도, 그게 에이전트의 다음 판단에 실시간으로 자연스럽게 반영되는 구조가 아니었습니다.

정리하면, 개별 에이전트의 독립성은 여전히 유효한 설계 원칙이지만, 이 독립적인 에이전트들을 통합적으로 관리하고, 맥락을 공유하며, 사람의 피드백을 자연스럽게 반영할 수 있는 상위 계층이 필요하다는 결론에 이르렀습니다.

Amazon Bedrock AgentCore: 독립성과 통합 관리의 균형

여러 Agent 관련 기술을 조사한 끝에, Amazon Bedrock AgentCore가 저희 상황에 맞는 관리형 서비스라고 판단했습니다. 앞서 정리한 세 가지 한계에 각각 대응할 수 있었기 때문인데요.

첫째, Gateway를 통한 도구 통합입니다. 각 에이전트가 개별적으로 붙이던 외부 도구들을 AgentCore의 Gateway를 통해 한 곳에서 관리할 수 있게 됩니다. 기존에 Rest API나 AWS Lambda 형태로 구현한 내용을 쉽게 통합이 가능하며, 도구가 추가되거나 바뀌어도 각 에이전트를 다시 배포할 필요가 없어집니다.

둘째, 특정 프레임워크에 대한 의존성 제거입니다. 기존에는 LangGraph의 checkpointer와 thread_id로 직접 메모리를 구현하고 있었는데, 이러다 보니 LangGraph에 대한 의존도가 계속 높아지고 있었습니다. AgentCore의 session으로 매핑하면 이 부분을 서비스에 위임할 수 있어서, 프레임워크 교체나 업그레이드의 영향을 최소화할 수 있습니다.

셋째, 메모리 중앙 관리입니다. AgentCore Memory는 Short-term Memory(단일 세션 내 대화 기록)와 Long-term Memory(여러 세션에 걸친 인사이트 자동 추출) 두 가지를 제공하는데요. 기존에 LangGraph checkpointer로 직접 구현하던 메모리를 서비스에 위임할 수 있다는 것도 이점이지만, 저희에게 더 중요했던 건 이 Memory API를 활용해서 사람의 피드백을 에이전트에 자연스럽게 반영하는 구조를 만들 수 있다는 점이었습니다.

이 세 번째 이점, 메모리 중앙 관리가 바로 다음에 설명할 Human Review 시스템의 핵심 기반이 됩니다.

Human Review 시스템: 사람의 피드백이 에이전트를 개선하는 구조

AgentCore 전환에서 가장 공을 들이고 있는 부분이 Human Review 시스템입니다. 앞서 에이전트로의 피드백이 가장 큰 문제였다고 말씀드렸는데, AgentCore Memory를 활용하면 이 문제를 구조적으로 해결할 수 있습니다.

인플루언서별 세션 격리

인스타그램, 유튜브, 틱톡 등의 콘텐츠를 분석할 때 중요한 맥락 중 하나가 누가 올린 콘텐츠인가입니다. 동일한 텍스트와 이미지라도 해당 인플루언서의 과거 게시물 스타일이나 협업 이력, 활동 패턴에 따라 판단이 달라질 수 있거든요.

이를 반영하기 위해 AgentCore Memory를 생성할 때 Semantic Strategy의 namespace에 actor_id를 기준으로 분리되도록 설정합니다. 이후 세션을 만들 때 actor_id에 인플루언서의 고유 ID를 넣으면, 인플루언서마다 독립된 메모리 공간이 자동으로 생성됩니다. 수십만 인플루언서에 대해 별도의 DB 테이블이나 파티션을 설계할 필요 없이, AgentCore가 알아서 격리해주는 거죠.

AgentCore를 이용해 특정 ID를 기반으로 session을 생성하는 예시 코드는 아래와 같습니다.

influencer_id = "INF_824710"

# 같은 인플루언서에 대해 분석할 때마다 새 세션 생성
# Long-term Memory는 actor_id 기준으로 세션을 걸쳐 축적됨
session = session_manager.create_memory_session(
  actor_id=influencer_id, # 메모리 주체 = 인플루언서
  session_id=f"analysis-{uuid4()}" # 개별 분석 세션
)

모든 분석 세션에 걸쳐 공유될 Memory의 단위를 actor_id로 구분하고, 개별 분석의 대화 기록은 session_id 단위로 관리되는 구조입니다.

피드백이 반영되는 전체 흐름

전체 흐름을 단계별로 정리하면 이렇습니다.

① 분석 시작 — 콘텐츠가 들어오면 해당 인플루언서 ID를 actor_id로 AgentCore 세션을 생성합니다. 에이전트가 Bedrock Claude를 호출해 멀티모달 분석을 수행하고, 분석 요청과 결과가 Short-term Memory에 대화 단위로 기록됩니다.

② 1차 분석 결과 — 예를 들어 모던트커피 카페 리뷰 콘텐츠를 보고, 시스템이 자가 홍보 없음으로 판단해서 신뢰도 88%, organic으로 분류합니다.

③ Human Review 피드백 — 리뷰어가 “이 인플루언서는 모던트커피 앰버서더로 활동 중”이라는 피드백을 제출합니다. 이 피드백이 동일 세션의 이벤트로 기록되면, Semantic Strategy가 동작하면서 “INF_824710은 모던트커피 앰버서더”라는 핵심 팩트를 Long-term Memory 레코드로 자동 추출합니다.

④ 재분석 — 재분석을 요청하면 에이전트는 Long-term Memory를 시맨틱 검색해서 기존 맥락을 가져옵니다. 앰버서더 정보를 참고해 판단 근거가 업데이트되고, 외부 홍보 있음, ambassador로 재분류되면서 신뢰도도 92%로 올라갑니다.

⑤ 이후 세션 자동 반영 — 2주 뒤 같은 인플루언서가 모던트커피의 새 메뉴를 소개하는 콘텐츠를 올려도, 에이전트는 Long-term Memory에서 앰버서더 정보를 자동으로 참조해서 처음부터 적절한 분류를 수행합니다. 리뷰어가 매번 같은 피드백을 반복할 필요가 없어지는 거죠.

기존 LangGraph 메모리에서 무엇이 달라졌나

기존에는 LangGraph의 checkpointer에 사용할 DB를 직접 선택하고 운영해야 했고, thread_id 기반으로 세션을 수동 관리했습니다. 장기 메모리에서 인사이트를 추출하려면 별도 로직을 직접 구현해야 했고, 인플루언서 간 메모리 격리도 애플리케이션 레벨에서 직접 처리해야 했습니다.

AgentCore Memory에서는 이 모든 게 서비스 레벨에서 처리됩니다. DB 인프라 운영이 필요 없고, actor_id 기반으로 자동 격리되며, Semantic Strategy가 장기 메모리 추출을 알아서 해줍니다. 저희 입장에서는 “어떤 정보를 기록하고, 어떤 질문으로 검색할 것인가”에만 집중하면 되는 구조가 됩니다.

앞으로의 계획

현재는 AgentCore의 Memory 기반 인플루언서 Context 관리가 실제로 분석 품질 향상에 유효한지 검증하는 단계에 있습니다. 이 검증이 끝나면 몇 가지 다음 단계를 진행하려고 합니다.

먼저 인플루언서별 Memory Life Cycle 관리입니다. 수십만 인플루언서에 대한 Memory가 쌓이면, 오래된 맥락 정보의 만료 정책이나 용량 관리가 필요해지거든요. 이 부분에 대한 전략을 수립하고 있습니다.

그리고 분석 정확도 고도화입니다. Human Review를 통해 쌓인 피드백 데이터를 기반으로 에이전트별 프롬프트 최적화와 신뢰도 임계값 조정을 반복적으로 수행할 계획입니다.

마지막으로 글로벌 확장도 준비 중입니다. Claude Sonnet의 다국어 지원 역량을 활용해서 일본어, 영어권 콘텐츠로 범위를 넓혀나갈 예정입니다.

마치며

이번 글을 한 문장으로 요약하면, 독립성은 유지하되 통합 관리가 가능한 상위 계층을 도입하는 과정이었습니다.

처음 시스템을 설계할 때 세웠던 에이전트의 독립성이라는 원칙은 에이전트 내부 노드 설계에서도, 시스템 전체 아키텍처에서도 잘 작동했습니다. 하지만 독립적인 에이전트들이 늘어나면서, 이걸 통합적으로 관리하고 맥락을 공유하며 사람의 피드백을 자연스럽게 반영할 수 있는 계층이 필요해졌고, AgentCore가 그 역할을 해주고 있습니다.

AgentCore 도입은 아직 진행 중인 여정이고, 앞으로도 운영하면서 새로운 도전과 배움이 이어질 것 같습니다. 저희와 비슷한 구조를 고민하고 계신 분들께 조금이라도 참고가 되었으면 좋겠습니다. 그 과정도 계속 공유해 나가겠습니다.