*회사 하네스를 어떻게 구축할까요?
저희는 LangChain 내부에서 마케팅, 영업, 엔지니어링 부서에 걸쳐 자체 에이전트(internal agents)를 구축했으며, 이는 해당 팀들의 업무 방식을 완전히 변화시켰습니다. 하지만 이를 제대로 구현하는 것은 쉽지 않았습니다. 저희는 멀티플레이어 하네스(multiplayer harness)와 관련된 문제들을 해결하는 데 많은 시간을 할애했고, 모든 팀은 동일한 핵심 기본 요소들(core primitives)에 도달했습니다:
- 사람들이 이미 작업하는 곳에서 작동한다 (저희의 경우 Slack)
- 누가 요청했는지 알고 있으며, 일부 서비스에 대해서는 해당 사람을 대신하여 행동하고 다른 서비스에 대해서는 자체적인 ID를 가지고 행동한다
- 메모리를 가지며, 전역적으로 또는 사용자 수준에서 범위가 지정된다
- 샌드박스(sandbox) 내에서 코드가 실행되며 인증이 필요한 서비스로 요청을 보낼 수 있다
- 실행의 큰 비율이 누군가에 의해 명시적으로 호출되기보다는 스케줄링된다 (앰비언트 에이전트!!)
본 블로그 작성을 돕기 위해 @caspar_br님께 감사드립니다.
LangChain 내부 에이전트
이 논의를 뒷받침하기 위해, LangChain에 있는 세 가지 주요 에이전트에 대한 간략한 개요를 제공합니다:
GTM Agent: GTM(Go-To-Market) 활동을 지원하는 능동적이고 항상 작동하는 에이전트. 이메일을 모니터링하고 응답하며, 새로운 자격 있는 리드에게 보내고, 일일 브리프를 전송할 수 있으며, 계정에 대한 질문에 답변하고, 아웃바운드 작업을 수행할 수 있습니다.
OpenSWE: 저희의 엔지니어링 에이전트로, PR(Pull Request)을 작업하고 초안 작성할 수 있을 뿐만 아니라 모든 PR에 대해 코드 리뷰도 수행합니다.
Content Studio: 저희의 마케팅 에이전트로, 저희 스타일과 포지셔닝 지식을 가지고 자산(블로그, 이미지, PowerPoint, 비디오 등)을 초안 작성할 수 있습니다.
이러한 모든 에이전트들은 동일한 방식으로 구축되었습니다. 저희는 이것이 회사 하네스를 구축하기 위한 일반적인 레시피라고 생각합니다.
문제점: 사용자 경험(User Experience)
저희의 모든 에이전트는 사람들이 이미 작업하는 곳, 즉 Slack에 존재합니다. 각 에이전트는 자체 Slack 앱을 가지고 있으며, DM되거나 채널에서 태그될 수 있습니다. 이러한 에이전트들을 채널에서 사용한다는 것의 한 가지 이점은 다른 사람들이 사람들이 그것을 어떻게 사용하는지 볼 수 있다는 것입니다.
우리가 추가한 좋은 기능 중 하나는 Slack에서 대화를 “분리(breaking)”하는 개념이었습니다. 종종 훌륭한 대화가 진행되고 있을 때, 에이전트에게 의견을 얻거나 무언가를 요청하고 싶을 수 있습니다. 하지만 만약 그 내용이 해당 스레드에 포함되면 인간의 대화 흐름을 방해하고 산만하게 만들 수 있습니다. 그래서 우리는 에이전트가 채널 내에서 자신만의 별도 스레드로 “분리(breakout)”할 수 있는 쉬운 방법을 추가했습니다.
Slack에서는 진행하기에 적합하지 않은 사용자 경험들이 일부 존재합니다. 예를 들어, GTM Agent가 제가 보내기를 원하는 이메일을 검토하는 경우, Slack에서 일회성으로 처리하는 것은 괜찮지만, 백로그(backlog)가 많다면 Slack 메시지에서 이를 추적하는 것은 전혀 재미있는 경험이 아닙니다. 이러한 경험들을 위해 우리는 결국 커스텀 UI를 구축하게 되었습니다.
문제점: 신원(Identity)
우리가 다룬 가장 까다롭고 어려운 문제는 바로 '신원'이었습니다. 구체적으로, 이 에이전트들이 행동을 취할 때, 그들은 누구를 대신하여 행동하는 것일까요?
업계에서는 이 문제를 처리하는 두 가지 주요 방식이 있습니다:
- 대리(On-behalf-of): 에이전트가 에이전트를 호출한 사용자를 대신하여 행동합니다.
고정 자격 증명(Fixed credentials): 누가 호출하든 상관없이 에이전트가 사용하는 고정된 자격 증명이 있습니다 (예: 서비스 계정).
우리는 각 에이전트에 대해 다음과 같이 처리했습니다 (문서 참고: Managed Deep Agents에 신원 추가, 연결 관리):
OpenSWE:
- 사용자로부터 메시지를 받으면, 사용자를 대신하여 행동합니다 (예: GitHub 핸들로 PR을 열어줍니다).
- 백그라운드에서 실행될 때(예: 코드 검토 에이전트로서)는 자체 신원(GitHub 앱)으로 행동합니다.
GTM Agent:
- 고정된 신원을 사용하는 도구(예: Salesforce 접근)가 있어 모든 사람이 로그인할 필요가 없습니다.
- 사용자 호출자를 대신하여 행동하는 도구(예: 이메일)도 있습니다. 이러한 도구는 DMs에서만 사용 가능하며, 공유 채널에서는 사용할 수 없습니다.
Content Studio:
- 에이전트를 호출하는 사용자를 대신하여 작동하는 도구(예: Notion)가 있습니다.
- 고정된 자격 증명 세트(credentials)를 사용하는 도구(예: Twitter)도 있습니다. 이 경우, 저희 회사 트위터 계정을 사용합니다. 다만, 특정 작업을 호출할 수 있는 사용자는 화이트리스트로 지정된 사용자만 가능하며, 예를 들어 모든 사람이 트위터에 게시물을 올릴 수는 없고 (읽기/초안 작성만 가능할 수 있음) 제한됩니다.
문제점: 메모리(Memory)
모든 에이전트는 두 가지 계층의 메모리를 가지고 있습니다:
- 글로벌 메모리 (Global memory): 모든 사용자에게 적용되는 메모리입니다.
- 사용자 메모리 (User memory): 특정 사용자에게만 적용되는 메모리입니다.
에이전트는 어떤 사실을 어느 수준의 메모리에 저장할지 결정합니다. 이는 아마도 지금까지 가장 덜 탐구된 영역일 것입니다. 저희가 여기서 하고 싶은 작업이 많습니다!
문제점: 코드 실행(Code Execution)
저희의 세 에이전트 모두 코드를 작성하고 실행할 수 있으며, 작업을 완수하기 위해 종종 이를 필요로 합니다. 이들은 모두 샌드박스(sandbox) 외부에서 실행되는 패턴을 따르지만, 그 안에 연결하여 코드를 실행합니다. 이들은 모두 서로 다른 종속성(dependencies)을 가진 약간씩 다른 기본 이미지(base image)를 가지고 있습니다. OpenSWE(코딩 관련 에이전트 중 가장 전문적인 에이전트)는 어떤 기본 이미지를 구동할지 지능적으로 판단합니다 (채널/사용자에 따라 다름). 이들은 모두 LangSmith Sandbox의 비밀 프록시를 활용하여 에이전트가 샌드박스 내부에서 서비스에 안전하고 보안적인 방식으로 연결할 수 있도록 합니다 (Managed Deep Agents에 샌드박스 추가 참조).
문제점: 예약 실행(Scheduled Runs)
실행되는 횟수의 상당 부분은 사용자에 의해 직접 시작되기보다는 이벤트에 의해 예약되거나 백그라운드에서 트리거됩니다.
이 중 일부는 에이전트 개발자에 의해 설정됩니다. 예를 들어, OpenSWE는 PR(Pull Request)을 감지하며, 새 PR이 생성되면 이를 검토합니다.
다른 일부는 사용자가 에이전트에게 요청하여 설정됩니다. 예를 들어, 저는 GTM 에이전트에게 일일 브리핑을 보내달라고 요청했고, 에이전트는 이를 위해 자체 크론(cron) 작업을 생성했습니다.
모든 것이 Managed Deep Agents를 기반으로 구축되었습니다.
이 모든 에이전트는 오픈 소스 Deep Agents 하네스를 기반으로 하는 관리형 Deep Agents(Managed Deep Agents)를 통해 구축됩니다. 이는 필요한 경우 에이전트 동작을 맞춤 설정할 수 있는 충분한 유연성을 제공하는 동시에, 이러한 모든 문제들(채널(channels), 크론(crons), 샌드박스(sandboxes), 메모리(memory), 아이덴티티(identity))을 해결하기 위한 인프라를 제공합니다. 오늘 퀵스타트(quickstart)로 직접 사용해 보세요!