Agently: 생성형 AI 애플리케이션 구축을 돕는 에이전트 네이티브(Agent-native) 프레임워크

Agently 소개

Agently는 개발자가 LLM(Large Language Model)을 활용한 생성형 AI 애플리케이션을 빠르고 안정적으로 구축할 수 있도록 돕는 오픈소스 프레임워크입니다. Python 기반(Node.js 베타 지원)으로 동작하며, 단순히 모델과 대화하는 것을 넘어 실제 서비스 가능한 수준의 엔지니어링 경계(Engineering Boundary) 안으로 LLM의 불확실성을 끌어들이는 데 초점을 맞춥니다.

AI 애플리케이션 개발은 '데모(Demo)'와 '프로덕션(Production)' 사이에 거대한 간극이 존재합니다. 데모 단계에서는 모델이 똑똑하게 대답하는 것만으로 충분하지만, 실제 서비스 단계에서는 트래픽 부하, 데이터 검증, 외부 시스템과의 의존성 관리, 그리고 무엇보다 예측 가능한 출력이 필수적입니다. 예를 들어, JSON을 요청했는데 평문이 반환되어 파서가 깨지는 문제 또는 복잡해진 로우코드(Low-code) 워크플로우의 유지보수가 불가능해지는 문제 등에 직면합니다.

Agently는 이러한 문제를 해결하기 위해 탄생했습니다. 이 프레임워크는 AI 에이전트 개발을 위한 문법적 설탕(Syntactic Sugar)을 제공하는 것을 넘어, Contract 기반의 구조화된 출력(Contract-first structured outputs), 이벤트 기반의 워크플로우(TriggerFlow), 그리고 프레임워크 네이티브 도구 계획(Tool Planning) 등을 통해 개발자가 비즈니스 로직과 시스템 안정성에 집중할 수 있는 환경을 제공합니다. 개발자는 복잡한 프롬프트 엔지니어링이나 모델별 API 차이에 얽매이지 않고, 코드로 명확하게 정의된 에이전트 로직을 구현할 수 있습니다.

Agently vs. 유사 프레임워크 비교

먼저 Agently를 n8n, Dify, Coze 등과 같은 시각적 워크플로우 도구와 비교해보겠습니다. 최근 유행하는 노드 기반의 시각적 도구들은 초기 진입 장벽이 낮지만, 로직이 복잡해질수록 '스파게티 그래프'가 되어 유지보수가 급격히 어려워집니다. Agently는 이러한 시각적 그래프를 TriggerFlow라는 코드 기반의 이벤트 오케스트레이션으로 전환합니다. 이를 통해 개발자는 분기(Branching), 반복(Loop), 동시성 제어(Concurrency) 등을 Git과 같은 버전 관리 시스템으로 명확하게 관리할 수 있으며, 디버깅과 테스트가 훨씬 용이해집니다.

다음으로 Agently와 LangChain과 비교해보겠습니다. LangChain은 방대한 통합을 자랑하지만 추상화가 깊고 학습 곡선이 가파른 편입니다. 이에 비해 Agently는 개발자 경험(DX)을 최우선으로 하여, 직관적인 메서드 체이닝의 Fluent API를 채택했습니다. 즉, Agently는 복잡한 추상화 클래스를 상속받아 구현하기보다는, input().output().start()와 같이 자연어 흐름과 유사한 코드를 작성함으로써 개발 속도를 높이고 코드 가독성을 극대화하는 방향으로 설계되었습니다.

Agently의 주요 기능

Agently가 제공하는 기능들은 '어떻게 하면 LLM의 출력을 엔지니어링 적으로 통제할 것인가'에 집중되어 있습니다.

Contract 기반의 구조화된 출력 (Contract-first Structured Output)

Agently는 LLM의 출력을 단순 텍스트가 아닌, 애플리케이션이 즉시 사용할 수 있는 데이터로 취급합니다. 즉, 개발자는 .output() 메서드를 통해 데이터 스키마를 정의하고, Agently 프레임워크는 이를 준수하도록 모델을 제어합니다.

가장 강력한 점은 ensure_keys 기능과 자동 재시도(Retry) 메커니즘입니다. 배치 작업이나 파이프라인에서 필드 하나가 누락되면 전체 프로세스가 중단될 수 있는데, Agently는 필수 키가 누락되거나 형식이 잘못된 경우 프레임워크 차원에서 모델에 수정을 요청하거나 재시도(retry)를 수행하여 완전한 데이터 구조를 보장합니다.

이러한 구조는 특정 모델(OpenAI 등)의 JSON 모드에만 의존하는 것이 아니라 프레임워크 레벨에서 검증하므로, 모델을 교체해도 동일한 안정성을 유지합니다.

다음은 ensure_keys 파라미터를 사용하는 예시 코드입니다:

import Agently

agent_factory = Agently.AgentFactory()
agent = agent_factory.create_agent()

# 시나리오: 사용자 입력에서 '할 일 목록'을 추출하여 정형 데이터로 반환
result = (
    agent
    .input("내일 아침 9시에 팀 미팅 잡고, 오후 2시에는 보고서 작성해야 해. 그리고 퇴근길에 우유 사기.")
    .output({
        # 반환받고 싶은 데이터 구조 정의
        "todos": [
            {
                "task": ("str", "구체적인 할 일 내용"),
                "time": ("str", "시간 정보 (없으면 null)"),
                "category": ("str", "카테고리 (업무/개인/기타)")
            }
        ],
        "summary": ("str", "전체 일정 요약")
    })
    # ensure_keys: 'todos' 리스트 내의 모든 항목이 위 스키마를 따르도록 강제함
    .start(ensure_keys=["todos[*]"], max_retries=2)
)

print(result)
# 출력 결과 (Python Dict):
# {
#   'todos': [
#     {'task': '팀 미팅', 'time': '09:00', 'category': '업무'},
#     {'task': '보고서 작성', 'time': '14:00', 'category': '업무'},
#     {'task': '우유 사기', 'time': '퇴근길', 'category': '개인'}
#   ],
#   'summary': '내일은 업무 미팅과 보고서 작성이 있으며, 퇴근 후 개인 용무가 있습니다.'
# }

즉시 스트리밍 (Instant Streaming & Typed Delta)

일반적인 텍스트 스트리밍은 문자가 하나씩 찍히는 것에 불과하지만, Agently의 Instant Mode는 구조화된 데이터가 생성되는 즉시 이를 파싱하여 제공합니다.

예를 들어, "생각(Thinking)"과 "발화(Saying)", "행동(Action)"을 동시에 출력하는 에이전트를 가정해보겠습니다. Agently는 스트리밍되는 데이터 중 "생각" 필드는 로그로 남기고, "발화" 필드는 즉시 UI에 텍스트로 표시하며, "행동" 필드가 완성되는 순간 함수를 실행하도록 이벤트를 분리할 수 있습니다.

이러한 구조를 통해 사용자가 답변을 기다리는 체감 시간을 획기적으로 줄이고, 말하면서 행동하는 로봇과 같은 식의 더욱 동적인 사용자 경험을 구현할 수 있게 해줍니다. 다음은 이러한 스트리밍을 구현하는 예시 코드입니다:

# 시나리오: AI가 답변을 생성하는 과정(생각)과 실제 답변(발화)을 분리하여 스트리밍
response = (
    agent
    .input("AI 에이전트의 미래에 대해 짧게 설명해줘.")
    .output({
        "thinking_process": ("str", "답변을 작성하기 위한 논리적 사고 과정"),
        "final_answer": ("str", "사용자에게 보여줄 최종 답변")
    })
    .get_response()
)

# 'instant' 모드 제너레이터 사용
generator = response.get_generator(type="instant")

for data in generator:
    # delta: 새로 추가된 텍스트 조각 / value: 현재까지 완성된 값
    if data.path == "thinking_process" and data.delta:
        # 로그에는 사고 과정을 실시간으로 출력
        print(f"[Thinking] {data.delta}", end="", flush=True)
    
    elif data.path == "final_answer" and data.delta:
        # 사용자에게는 답변만 실시간으로 출력
        print(f"[Answer] {data.delta}", end="", flush=True)

# 실행 결과: [Thinking] 로그가 찍히다가 [Answer]가 나오면 즉시 UI 업데이트 가능

TriggerFlow: 코드 기반의 워크플로우 오케스트레이션

복잡한 에이전트 로직을 관리하기 위해 Agently는 TriggerFlow라는 이벤트 구동형(Event-driven) 엔진을 도입했습니다. 이는 "조건 A를 만족하면 B를 실행하고, C가 완료되면 D를 실행하라"와 같은 흐름을 명시적인 코드로 작성하게 해줍니다.

TriggerFlow는 작업 흐름을 제어하기 위해 when(조건), if_condition(분기), batch/for_each(동시성 제어), emit(이벤트 발생) 과 같은 다양한 기능들을 제공합니다. 또한, TriggerFlow를 사용하면 시각적 도구에서나 가능했던 복잡한 그래프 로직을 Python 코드로 깔끔하게 구현할 수 있으며, Auto Loop 기능과 결합하여 목표를 달성할 때까지 스스로 판단하고 반복하는 자율 에이전트도 쉽게 만들 수 있습니다.

다음은 TriggerFlow를 사용하는 예시 코드입니다. 실제 활용 시에는 람다 함수 대신 agent.start()를 호출하여 에이전트의 응답을 다음 단계로 넘기는 방식으로 사용합니다:

from Agently import TriggerFlow

# 워크플로우 인스턴스 생성
flow = TriggerFlow()

# 단계별 로직 정의 (체이닝 방식)
# Start -> Step 1 -> Step 2 -> End
(
    flow.start("User Input Data") # 시작 데이터 주입
    .to(lambda data: f"Step 1 Processed: {data}") # 첫 번째 처리
    .to(lambda data: f"Step 2 Processed: {data}") # 두 번째 처리
    .end()
)

# 워크플로우 실행 및 결과 확인
result = flow.start_flow("Hello Agently")
print(result) 
# 출력: Step 2 Processed: Step 1 Processed: Hello Agently


TriggerFlow와 관련한 다양한 예시는 Agently GitHub 저장소의 examples/step_by_step 디렉토리에서 11-triggerflow-로 시작하는 12개의 예시 파일들에서 확인하실 수 있습니다.

TriggerFlow 관련 예시 파일들

프레임워크 네이티브 도구 계획 (Framework-Native Tool Planning)

많은 프레임워크가 모델(OpenAI 등)이 제공하는 함수 호출(Function Calling) 기능에 전적으로 의존합니다. 하지만 이 경우 모델을 바꾸면 도구 호출 성능이 떨어지거나 동작하지 않을 수 있습니다.

Agently는 도구 사용 여부 결정, 도구 선택, 파라미터 생성을 프레임워크 내부의 계획 단계(Planning Step) 로 내재화했습니다. 즉, Function Calling을 지원하지 않는 모델을 사용하더라도 Agently가 프롬프트 레벨에서 도구 사용을 유도하고 결과를 파싱합니다. 또한, 모든 도구 실행 내역은 extra 로그에 투명하게 기록되므로, 디버깅과 감사가 용이합니다.

Agently에서 자체적으로 제공하는 도구 계획 기능은 다음과 같이 사용할 수 있습니다:

# 1. 사용할 도구(함수) 정의
def get_current_weather(location: str):
    """
    특정 지역의 날씨를 반환합니다.
    """
    # 실제로는 외부 날씨 API를 호출하는 코드가 들어감
    return f"{location}의 날씨는 맑음, 기온은 25도입니다."

# 2. 에이전트에 도구 등록 (Global Tool Manager 사용 가능)
agent.use_tools([
    {
        "name_for_model": "get_weather",
        "description_for_model": "Get weather info by location name",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {"type": "string", "description": "City name"}
            },
            "required": ["location"]
        },
        "func": get_current_weather
    }
])

# 3. 에이전트 실행 (도구 사용 여부를 스스로 판단)
response = (
    agent
    .input("지금 서울 날씨 어때?")
    .start()
)

print(response)
# 내부 동작:
# 1. 에이전트가 'get_weather(location="서울")' 호출 필요성을 판단
# 2. Agently가 함수 실행
# 3. 실행 결과("서울의 날씨는...")를 바탕으로 최종 자연어 답변 생성

모델 독립성 (AnyModel Architecture)

Agently는 OpenAICompatible 설정을 표준으로 채택하여, 코드 변경 없이 설정값 수정만으로 모델을 교체할 수 있습니다. OpenAI를 비롯하여 Anthropic(Claude), Google(Gemini), DeepSeek 등 상용 모델뿐만 아니라, 로컬에서 구동되는 Llama, Mistral 모델과도 매끄럽게 연동됩니다.

즉, 비즈니스 로직 코드를 수정하지 않고 설정값 변경만으로 백엔드 모델을 교체할 수 있습니다. 이는 개발 단계에서는 저렴한 모델을 쓰고, 운영 단계에서는 고성능 모델을 쓰거나, 유사시 백업 모델로 자동 전환하는 구성을 가능하게 합니다.

import Agently

# 설정만 바꾸면 코드 로직은 그대로 사용 가능

# Case A: OpenAI GPT-4 사용 시
Agently.set_settings("current_model", "OpenAI")
Agently.set_settings("model.OpenAI.auth", { "api_key": "sk-..." })
Agently.set_settings("model.OpenAI.options", { "model": "gpt-4" })

# Case B: Google Gemini로 전환 시 (위 코드 대신 아래 설정만 적용)
# Agently.set_settings("current_model", "Google")
# Agently.set_settings("model.Google.auth", { "api_key": "AIza..." })

agent = Agently.create_agent()
# 아래 코드는 모델이 바뀌어도 수정할 필요가 없음
agent.input("Hello").start()

또한 인증 정보, 엔드포인트 URL(Endpoint URL), 프록시 설정 등을 유연하게 주입할 수 있어 기업 내부망(Private Cloud) 환경에서 사용하기에도 적합합니다.

RAG 및 지식베이스 (Knowledge Base) 통합

Agently는 LLM의 환각(Hallucination)을 줄이기 위해 외부 지식을 참조하는 RAG(Retrieval-Augmented Generation) 시스템 구축을 지원합니다. ChromaDB 등과 같은 벡터 데이터베이스(Vector DB)와의 통합을 쉽게 구현할 수 있는 인터페이스를 제공합니다. 또한, 문서를 임베딩하고 검색 시 검색된 정보의 메타데이터(문서 ID, 출처)를 답변과 함께 구조화하여 반환함으로써, 단순한 검색을 넘어 인용 가능한 답변(출처 확인이 가능한 답변)을 만들 수 있도록 지원합니다.

다음은 Agently를 사용한 RAG 기능을 구현하는 예시 코드입니다:

from Agently.integrations.chromadb import ChromaCollection

# 1. 지식베이스(컬렉션) 생성 및 임베딩 모델 설정
kb = ChromaCollection(
    collection_name="my_knowledge_base",
    embedding_agent=agent # 임베딩에 사용할 에이전트 (또는 별도 임베딩 모델)
)

# 2. 문서 데이터 추가 (임베딩 자동 수행)
kb.add([
    {
        "document": "Agently는 AI 에이전트 개발을 위한 파이썬 프레임워크입니다.",
        "metadata": { "source": "official_docs", "page": 1 }
    }
])

# 3. 질문에 대한 관련 문서 검색 및 답변 생성
query = "Agently가 뭐야?"
# 관련 문서 검색
retrieved_docs = kb.query(query, n_results=1)

# 검색된 문맥을 에이전트에 주입하여 답변 요청
response = (
    agent
    .input(query)
    .info(f"참고 문서: {retrieved_docs}") # 검색된 지식 주입
    .instruct("참고 문서를 바탕으로 답변해줘.")
    .start()
)

# 답변 출력
print(response)

라이선스

Agently 프로젝트는 Apache License 2.0으로 배포되고 있습니다. 이는 개인 및 기업의 상업적 이용, 수정, 배포가 자유로운 오픈소스 라이선스입니다.

:house: Agently 공식 홈페이지 (중국어)

:books: Agently 공식 문서 사이트

:github: Agently 프로젝트 GitHub 저장소

더 읽어보기




이 글은 GPT 모델로 정리한 글을 바탕으로 한 것으로, 원문의 내용 또는 의도와 다르게 정리된 내용이 있을 수 있습니다. 관심있는 내용이시라면 원문도 함께 참고해주세요! 읽으시면서 어색하거나 잘못된 내용을 발견하시면 덧글로 알려주시기를 부탁드립니다. :hugs:

:pytorch:파이토치 한국 사용자 모임:south_korea:이 정리한 이 글이 유용하셨나요? 회원으로 가입하시면 주요 글들을 이메일:love_letter:로 보내드립니다! (기본은 Weekly지만 Daily로 변경도 가능합니다.)

:wrapped_gift: 아래:down_right_arrow:쪽에 좋아요:+1:를 눌러주시면 새로운 소식들을 정리하고 공유하는데 힘이 됩니다~ :star_struck:

2개의 좋아요