
내 AI 에이전트가 정체성 혼란을 겪고 있었다 — 해결 방법은 다음과 같습니다
요약
AI 에이전트가 이름이나 컨텍스트를 바탕으로 잘못된 역할을 수행하는 '정체성 드리프트(Identity Drift)' 현상을 분석합니다. 시스템 프롬프트에 에이전트의 정체성을 명시하지 않을 때 발생하는 조용한 실패의 원인과 해결책을 다룹니다.
핵심 포인트
- 정체성 드리프트는 에러 없이 발생하는 조용한 실패임
- LLM은 호출 시마다 컨텍스트에 의존하여 역할을 추측함
- 에이전트 이름이 모델의 패턴 매칭에 영향을 줄 수 있음
- 시스템 프롬프트에 명확한 정체성(Anchor)을 정의해야 함
한동안 ShipStack은 계속해서 제 택배 추적을 도와주려고 했습니다.
비유적인 표현이 아닙니다. 기사를 작성하고, 메모리를 관리하며, 비즈니스 파이프라인을 실행하기 위해 제가 만든 콘텐츠 및 자동화 에이전트(agent)가 가끔씩 마치 운송 회사의 고객 지원팀처럼 응답하곤 했습니다. 배송 상태를 확인해 주겠다고 제안하거나, 운송업체에 문의하라고 권하기도 했습니다.
저는 그것의 이름을 ShipStack이라고 지었습니다. Claude는 "ship"이라는 단어를 보고 우리가 물류 사업을 하고 있다고 판단한 모양입니다.
이것이 실제 에이전트에서 발생하는 정체성 드리프트(identity drift)의 모습입니다. 이는 극적으로 나타나지 않습니다. 에러를 발생시키지도 않습니다. 에이전트는 단지 당신이 만든 목적대로 작동하는 것을 서서히 멈출 뿐이며, 주의 깊게 관찰하지 않는다면 완전히 잘못된 행동을 하기 전까지는 알아차리지 못할 것입니다.
이 현상의 원인과 제가 이를 발견한 방법, 그리고 구현하는 데 약 5분밖에 걸리지 않았던 해결책을 소개합니다.
정체성 드리프트(Identity Drift)란 정확히 무엇인가
AI 에이전트는 본질적으로 하나의 루프(loop)입니다. 사용자가 메시지를 보냅니다. 에이전트가 이를 읽습니다. 에이전트가 LLM(대규모 언어 모델)을 호출합니다. LLM이 응답합니다. 에이전트가 그 응답에 따라 행동합니다. 이 과정이 반복됩니다.
문제는 LLM이 호출 간에 자신이 누구인지에 대한 지속적인 감각을 가지고 있지 않다는 점입니다. 에이전트가 Claude를 호출할 때마다, 매번 새롭게 시작하는 것과 같습니다. 해당 호출에서 전달하는 모든 컨텍스트(context)가 Claude가 상황에 대해 알고 있는 정보의 "전부"가 됩니다.
만약 당신이 Claude에게 자신이 누구인지 말해주지 않는다면, 모델은 추측을 합니다. 그리고 에이전트의 이름을 포함하여 사용 가능한 모든 신호(signal)를 바탕으로 추측을 수행합니다.
ShipStack. Ship. Stack. Shipping stack. Logistics platform. Package tracking.
이런 일이 어떻게 발생하는지 이해하실 수 있을 것입니다. 모델은 자신이 어떤 역할을 수행하고 있는지 파악하기 위해 학습 데이터와 패턴 매칭(pattern matching)을 수행하며, 정확히 해야 할 일을 하고 있는 것입니다. 정체성을 고정해 줄 지속적인 닻(anchor)이 없었기에, 모델은 불완전한 정보로 작업하며 그 공백을 그럴듯한 내용으로 채워 넣었던 것입니다.
좌절스러운 부분은 이것이 "조용한" 실패라는 점입니다. 에러도 없고, 경고도 없습니다. 그저 시간이 지남에 따라 누적되는 미묘하게 잘못된 행동이 있을 뿐입니다.
제가 실제로 알아차린 순간
저는 Telegram 명령어를 테스트하고 있었습니다. ShipStack에게 새로운 주제로 Article Factory 파이프라인을 실행하도록 요청하는 것이었습니다. 응답은 대체로 괜찮았지만, 그 안에 문맥상 전혀 맞지 않는 "배송 일정 (shipping timelines)"에 관한 문장이 포함되어 있었습니다.
저는 로그를 거슬러 올라가며 살펴보았습니다. 아니나 다를까, 지난 한 주 동안 약 12번의 상호작용에 걸쳐 ShipStack의 언어가 물류(logistics)와 풀필먼트(fulfillment) 쪽으로 미묘하게 흘러가는 순간들이 산발적으로 나타났습니다. 파멸적인 수준은 아니었습니다. 그저... 잘못되었을 뿐입니다. 마치 제가 쓰지도 않은 캐릭터를 연기하고 있는 것 같았습니다.
저는 실행기(executor) 코드를 불러와 LLM 호출에 실제로 무엇이 들어가는지 확인했습니다.
시스템 프롬프트(system prompt)는 전적으로 작업 실행에만 집중되어 있었습니다. '사용자가 X를 요청할 때 수행할 작업', '사용 가능한 도구들', '출력 형식' 같은 내용 말이죠. 하지만 Claude에게 ShipStack이 무엇인지 알려주는 내용은 단 한 줄도 없었습니다.
저는 문맥(context)을 보면 명확해질 것이라고 가정했습니다. 도구 이름, 파이프라인 설명, 명령어 구조 등을 통해 명확한 정체성이 형성될 것이라고 생각했습니다.
하지만 그렇지 않았습니다. Claude는 이름과 대화 문맥에 남아 있는 잔여물로부터 자신이 누구인지 추론하고 있었습니다. 그것은 정체성이 아닙니다. 그것은 추측일 뿐입니다.
해결책: AGENT_IDENTITY
해결책은 너무 간단해서, 이걸 추가하는 데 왜 이렇게 오래 걸렸나 싶어 민망할 정도였습니다.
저는 agent.py에 AGENT_IDENTITY라는 상수를 만들었습니다. 단 한 단락입니다. 여기에는 ShipStack이 무엇인지, 무엇을 하는지, 그리고 무엇을 명시적으로 거부하는지가 정의되어 있습니다.
AGENT_IDENTITY = """
당신은 개인용 AI 콘텐츠 자동화 에이전트인 ShipStack입니다. 당신은 Morning Brief,
Repo Triage, Ship Product, Article Factory, 그리고 Memory라는 다섯 가지 프로덕션 파이프라인을 실행합니다. 당신은 ...
그다음 저는 모든 실행기(executor) 호출과 모든 응답자(responder) 호출의 맨 앞에 이를 추가했습니다. 다른 어떤 지침보다도, 어떤 작업 컨텍스트(task context)보다도, 그 무엇보다도 앞서 말이죠:
system_prompt = AGENT_IDENTITY + "\n\n" + task_specific_instructions
그게 전부입니다. 코드베이스 전체에 걸쳐 단 두 줄의 변경만 이루어졌습니다.
이 코드가 적용된 순간, 정체성 표류(identity drift)가 완전히 멈췄습니다. ShipStack은 더 이상 "ship"이라는 단어에 맞춰 패턴 매칭을 하지 않고, 제가 실제로 구축한 대상처럼 행동하기 시작했습니다.
이것이 작동하는 이유 (비기술적 버전)
이렇게 생각해보세요. 에이전트가 LLM을 호출할 때마다, 그것은 마치 하루짜리 일을 위해 계약직 직원을 고용하는 것과 같습니다. 그 직원은 당신과 이전에 일했던 기억이 전혀 없는 상태로 나타납니다. 당신은 그들에게 사전에 상세한 브리핑(brief)을 전달할 수 있습니다. 당신이 누구인지, 이 프로젝트가 무엇인지, 범위(scope) 내에 포함되는 것과 제외되는 것은 무엇인지 말이죠. 아니면 그냥 작업 지시서(work order)만 보여주고 그들이 문맥(context)을 스스로 파악하기를 바랄 수도 있습니다.
작업 지시서는 명확할 수도 있습니다. 하지만 브리핑이 없다면, 그들은 추측을 하게 됩니다. 그리고 그 추측은 눈덩이처럼 불어납니다.
AGENT_IDENTITY는 바로 그 브리핑입니다. Claude가 모든 호출에서 가장 먼저 읽는 내용입니다. 가끔이 아닙니다. 작업이 모호해 보일 때만 하는 것도 아닙니다. 모든 호출에서, 매번 수행합니다.
비용은 기본적으로 거의 들지 않습니다. 텍스트 한 단락은 각 호출에 약 80개의 토큰(tokens)을 추가할 뿐입니다. Claude Haiku 가격 기준으로 이는 1센트의 아주 작은 일부에 불과합니다. 이점은 당신의 에이전트가 사용자가 무엇을 말했는지 또는 작업이 어떻게 생겼는지에 의존하지 않는 안정적인 자아 정체성을 갖게 된다는 것입니다.
AGENT_IDENTITY에 들어가야 할 내용
제 것을 반복해서 수정해 본 결과, 세 가지 요소를 다루는 구조로 정착했습니다.
그것이 무엇인가. 이름, 목적, 누가 만들었는지, 무엇을 위한 것인지. 한두 문장이면 충분합니다.
그것이 무엇을 하는가. 구체적인 명칭으로 명시된 실제 기능들입니다. ShipStack의 경우, 다섯 가지 파이프라인의 이름을 명시하는 것을 의미합니다. 당신의 에이전트라면 도구(tools), 워크플로(workflows), 통합(integrations) 등이 될 수 있습니다.
그것이 거부하는 것. 이 부분은 과소평가되어 있습니다. 에이전트가 무엇을 _하지 않는지_를 Claude에게 명시적으로 알려주는 것은 무엇을 하는지 알려주는 것만큼이나 중요합니다. 이는 제가 목격했던 바로 그 종류의 드리프트 (drift)를 방지하는 명확한 경계선을 만들어 줍니다.
짧게 유지하세요. 한 페이지 분량보다는 응축된 한 단락이 더 낫습니다. 정체성을 고정(anchor)해야 하며, 뒤따르는 실제 작업 지침 (task instructions)을 압도해서는 안 됩니다.
더 큰 교훈
정체성 드리프트 (Identity drift)는 명백한 방식으로 무언가를 망가뜨리지 않기 때문에 놓치기 쉬운 실패 모드 (failure modes) 중 하나입니다. 에이전트는 여전히 작동합니다. 파이프라인 (pipelines)도 여전히 실행됩니다. 출력값 (outputs)이 그저... 약간 어긋나 있을 뿐입니다. 충분히 많은 출력값을 살펴보기 전까지는 짚어내기 어려운 방식으로 잘못되어 있습니다.
저는 엔터프라이즈 보안 (enterprise security) 분야에서 이 문제를 훨씬 더 큰 규모로 논의하기 시작하는 것을 보았습니다. 조직들이 어떤 에이전트가 무엇을 했는지, 또는 에이전트가 의도된 역할에 따라 행동하고 있는지 추적할 수 있는 신뢰할 만한 방법 없이 수십 개의 에이전트를 배포하고 있습니다. 현재 에이전트를 위한 거버넌스 (governance) 및 정체성 인프라 (identity infrastructure)에 실제로 많은 비용이 투입되고 있습니다. 제가 상수 파일 (constants file)의 한 단락으로 해결한 문제는, 규모가 커지면 심각한 조직적 과제가 됩니다.
하지만 현재 저의 상황 — 하나의 에이전트, 한 명의 개발자, 하나의 Telegram 인터페이스 — 에서는 AGENT_IDENTITY가 이를 완벽하게 해결했습니다.
구현 방식은 다르더라도 원칙은 확장 가능합니다. 지속적인 정체성이 없는 에이전트는 진정한 에이전트가 아닙니다. 그것은 호출될 때마다 자신이 누구인지 추측하는 상태가 없는 함수 (stateless function)일 뿐입니다. 그 추측은 때때로 맞을 것입니다. 그리고 때로는 당신의 패키지를 추적하려고 시도할 것입니다.
이제 막 시작하는 사람에게 해주고 싶은 말
첫 번째 파이프라인을 구축하기 전에, 첫 번째 도구 (tool)를 연결하기 전에, 당신의 에이전트가 무엇인지 정의하는 한 단락을 작성하세요. 그것을 상수에 넣으세요. 당신이 수행하는 모든 LLM 호출 (LLM call) 앞에 그것을 붙이세요.
이 결정의 영향은 그것 없이는 무언가 잘못될 때까지는 느끼지 못할 것입니다. 그리고 그때가 되면, 무슨 일이 일어났는지 파악하기 위해 약간 이상했던 출력값들을 일주일 치나 거슬러 올라가며 살펴봐야 할 것입니다.
이제 5분이면 됩니다. 많은 디버깅(debugging)을 거친 후의 결과입니다.
그 절충안(trade-off)은 돌이켜보면 명백합니다. 대부분의 일들이 그렇듯이 말입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기