반응형

 

AI Agent 시대다.

AI Agent를 쉽게 만들 수 있는 Framework 가 생겨났다.

AI Agent 엔지니어라는 직업이 나올 수도 있다.

많이 사용하는 AI Agent Framework 대표적인 것 4개를 선정하고, QuickStart 로 AI Agent 를 만들어본다.

그리고 지극히 주관적인 나의 느낌을 담아 장/단점을 정리하겠다.

후보1) Langchain - 너무 유명해서

후보2) AWS Strands SDK - 내가 AWS 클라우드 환경에 익숙해서

 

후보3) CrewAI - 비기너에게 적합하다고 해서  

후보4) Autogen - 멀티에이전트 구현에 집중됨.

후보5) LangGraph - 그래프 기반으로 stateful, multi-agent 시스템에 접근하는 확장성있는 Framework

 

 

Framework 를 고르는데 중요한 요소 (Key Factor)

  • 복잡한 워크플로우 까지 구현이 가능한가. - 복잡한 워크플로우도 구현 가능해?
  • 데이터 통합 - 다양한 데이터 소스로 부터 데이터를 연동하고 반환이 가능해?
  • 멀티에이전트 콜라보 - 여러 에이전트와의 협업 성능이 좋은가?
  • 노 코드 VS 코드 친화적이냐 - 노코드로 에이전트를 만들수 있는가? 반면에 개발자들에게 조금 더 친숙한 개발 환경을 제공하는가

 

LangChain - 생태계 광범위, 큰 커뮤니티
- 다양한 통합 도구 지원
- 성숙하고 안정적인 프레임워크
- LangSmith 제공
- Chain/Agent/RAG 등 유연한 패턴
- 과도한 추상화로 학습 곡선 높음
- 다중 레이어로 성능 저하
- 메모리 모듈 불안정
- 잦은 API 변경으로 호환성 문제
- 모듈식 아키텍처
- RAG/문서 처리 강점
- 엔터프라이즈급 기능 지원
- 복잡한 RAG 시스템
- 외부 서비스 통합 필요
- 엔터프라이즈 환경
AWS Strands SDK - 모델 중심 접근
- 간단한 코드로 에이전트 구축
- AWS 네이티브 통합
- 프로덕션 검증 (Amazon Q 등)
- A2A 멀티 에이전트 지원
- MCP 네이티브 지원
- 2024년 출시, 커뮤니티 작음
- AWS 환경 의존
- 문서 및 자료 부족
- Model-driven 아키텍처
- 세션 관리/상태 지속성
- 비동기 및 스트리밍 지원
- 에이전트 간 도구 공유
- AWS 클라우드 개발
- 빠른 프로토타이핑/배포
- 최신 LLM 활용
- 엔터프라이즈급 확장
CrewAI - 쉬운 학습 곡선
- 직관적 역할 기반 팀워크
- 빠른 멀티에이전트 개발
- 우수한 문서와 예제
- 자연스러운 협업
- 높은 추상화로 세부 제어 어려움
- 로깅/디버깅 제한적
- 맞춤화 한계
- LangChain 의존성
- 스트리밍 미지원
- Agent, Crew, Task 구조
- 순차/병렬 처리 지원
- 역할 기반 협업
- 메모리 관리 내장
- 입문자용 멀티에이전트
- 빠른 프로토타입
- 단순한 팀 기반 워크플로우
- 내부 자동화
Autogen - 자연스러운 대화 중심
- 유연한 에이전트 토폴로지
- Docker 내 안전한 코드 실행
- AutoGen Studio 제공
- Microsoft 지원, 확장성 높음
- 수동 설정 복잡
- 대화 오케스트레이션 학습 필요
- 문서 불일치
- 고성능 LLM 필요
- 디버깅 난이도 높음
- 비동기 이벤트 루프 구조
- 다양한 에이전트 역할
- 대화 기반 작업 조정
- RPC 기반 분산 처리
- 동적 에이전트 대화
- 개발/코딩 어시스턴트
- R&D 환경
- 복잡한 멀티에이전트 실험
LangGraph - 그래프 기반 정밀 제어
- 뛰어난 상태 지속성 및 복구
- DAG 기반 시각화
- LangChain 통합
- 조건부 분기/오류 처리 강력
- 그래프/상태 관리 학습 곡선 높음
- 초기 구조 정의 필요
- 단순 작업에 과도
- LangChain 이슈 상속
- 문서 업데이트 지연
- DAG 아키텍처
- 조건부 엣지/분기 로직
- 상태 기반 워크플로우
- LangSmith 모니터링
- 복잡한 다단계 워크플로우
- 상태 관리 필수 시스템
- 결정적 프로세스
- 금융/헬스케어 등 규제 환경

 

 

Framework 별 간단한 Agent 구현

1) Langchain

"""
LangChain 커스텀 툴 - 에러 수정 버전

설치:
pip install langchain langchain-ollama
"""

from langchain.tools import tool
from langchain_ollama import OllamaLLM  # 새로운 import
from langchain.agents import AgentExecutor, create_react_agent
from langchain.prompts import PromptTemplate
from langchain import hub


# 간단한 덧셈 툴
@tool
def add_numbers(a: int, b: int) -> int:
    """두 숫자를 더합니다. a와 b는 정수여야 합니다."""
    result = a + b
    print(f"[툴 실행] {a} + {b} = {result}")
    return result


@tool
def multiply_numbers(a: int, b: int) -> int:
    """두 숫자를 곱합니다. a와 b는 정수여야 합니다."""
    result = a * b
    print(f"[툴 실행] {a} × {b} = {result}")
    return result


def main():
    print("=" * 70)
    print("LangChain 툴 연동 예제 (수정 버전)")
    print("=" * 70)
    
    # 툴 목록
    my_tools = [add_numbers, multiply_numbers]
    
    print("\n등록된 툴:")
    for tool in my_tools:
        print(f"  • {tool.name}: {tool.description}")
    
    # 1. 새로운 Ollama 클래스 사용
    llm = OllamaLLM(
        model="llama3.1:8b",
        temperature=0
    )
    
    # 2. PromptTemplate을 올바르게 생성
    # 방법 A: 직접 PromptTemplate 생성
    prompt = PromptTemplate.from_template("""
Answer the following questions as best you can. You have access to the following tools:

{tools}

Use the following format:

Question: the input question you must answer
Thought: you should always think about what to do
Action: the action to take, should be one of [{tool_names}]
Action Input: the input to the action in JSON format, e.g. {{"arg1": value1, "arg2": value2}}
Observation: the result of the action
... (this Thought/Action/Action Input/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question

IMPORTANT: Action Input must be valid JSON format with double quotes.
Example: {{"a": 5, "b": 3}}

Begin!

Question: {input}
Thought: {agent_scratchpad}
""")
    
    # 방법 B: LangChain Hub에서 기본 ReAct 프롬프트 가져오기 (권장)
    # prompt = hub.pull("hwchase17/react")
    
    # 3. Agent 생성
    agent = create_react_agent(
        llm=llm,
        tools=my_tools,
        prompt=prompt  # PromptTemplate 객체를 전달
    )
    
    # 4. AgentExecutor 생성
    agent_executor = AgentExecutor(
        agent=agent,
        tools=my_tools,
        verbose=True,
        handle_parsing_errors=True,
        max_iterations=5
    )
    
    # 5. 테스트 질문들
    questions = [
        "5와 3을 더하면?",
        "10과 7을 곱하면?",
        "12 더하기 8은 얼마인가요?",
    ]
    
    print("\n" + "=" * 70)
    print("Agent 실행 테스트")
    print("=" * 70)
    
    for i, question in enumerate(questions, 1):
        print(f"\n[질문 {i}] {question}")
        print("-" * 70)
        try:
            result = agent_executor.invoke({"input": question})
            print(f"\n✅ 최종 답변: {result['output']}")
        except Exception as e:
            print(f"❌ 오류: {e}")
        print("=" * 70)


# 간단한 툴 직접 테스트 (Agent 없이)
def simple_test():
    print("\n" + "=" * 70)
    print("툴 직접 테스트 (Agent 없이)")
    print("=" * 70)
    
    # 직접 호출
    result1 = add_numbers.invoke({"a": 10, "b": 20})
    print(f"\n결과 1: {result1}")
    
    result2 = multiply_numbers.invoke({"a": 5, "b": 6})
    print(f"결과 2: {result2}")
    
    print("\n" + "=" * 70)


if __name__ == "__main__":
    # 1. 먼저 툴만 간단히 테스트
    simple_test()
    
    print("\n\n")
    
    # 2. Agent와 함께 사용
    try:
        main()
    except Exception as e:
        print(f"\n❌ Agent 실행 오류: {e}")
        print("\n💡 Ollama가 실행 중인지 확인하세요: ollama serve")
        print("💡 모델이 설치되어 있는지 확인하세요: ollama pull llama3.1:8b")

2) Strands

from strands import Agent
from strands.models.ollama import OllamaModel
from strands import tool


@tool
def add_numbers(a:int, b:int) -> int:
    """
    add two numbers together
    Args:
        a: first number
        b: second number

    Returns:
        sum of a and b
    """
    return a+b

model = OllamaModel(
    model_id="llama3.1:8b",
    host="http://localhost:11434",
    temperature=0.0)

agent = Agent(model=model, tools=[add_numbers])

response = agent("1+2")
print(response)

 

3) crawAI

"""
CrewAI + Ollama를 사용한 커스텀 툴 예제

설치:
pip install crewai crewai-tools langchain-ollama
"""

from crewai import Agent, Task, Crew, Process
from crewai.tools import BaseTool  
from crewai import LLM
from typing import Type
from pydantic import BaseModel, Field


# 1. 덧셈 툴 생성
class AddNumbersInput(BaseModel):
    """덧셈 툴의 입력 스키마"""
    a: int = Field(..., description="첫 번째 숫자")
    b: int = Field(..., description="두 번째 숫자")


class AddNumbersTool(BaseTool):
    name: str = "add_numbers"
    description: str = "두 개의 숫자를 더합니다. 덧셈 계산이 필요할 때 사용하세요."
    args_schema: Type[BaseModel] = AddNumbersInput
    
    def _run(self, a: int, b: int) -> str:
        """덧셈 실행"""
        result = a + b
        return f"{a} + {b} = {result}"


def main():
    print("=" * 70)
    print("CrewAI + Ollama 3.1:8b + 커스텀 툴 예제")
    print("=" * 70)
    
    # Ollama 3.1:8b 모델 설정
    llm = LLM(
        model="ollama/llama3.1:8b",  # ⚠️ "ollama/" prefix 필수!
        base_url="http://localhost:11434"
    )
    # 툴 인스턴스 생성
    add_tool = AddNumbersTool()
    
    print("\n✅ 등록된 툴:")
    print(f"  • {add_tool.name}: {add_tool.description}")
    
    # Agent 생성 - 수학 전문가
    math_expert = Agent(
        role="수학 계산 전문가",
        goal="사용자의 계산 요청을 정확하게 처리합니다",
        backstory="""당신은 숫자 계산에 능숙한 수학 전문가입니다. 
        주어진 툴을 사용하여 정확한 계산 결과를 제공합니다.""",
        tools=[add_tool],
        llm=llm,
        verbose=True,
        allow_delegation=False
    )
    
    # Task 1: 덧셈 작업
    task1 = Task(
        description="15와 27을 더한 결과를 계산하세요.",
        expected_output="두 숫자의 덧셈 결과를 명확하게 제시",
        agent=math_expert
    )

    
    # Crew 생성 및 실행
        agents=[math_expert],
        tasks=[task1],
        process=Process.sequential,  # 순차적 실행
        verbose=True
    )
    
    print("\n" + "=" * 70)
    print("🚀 Crew 실행 시작")
    print("=" * 70)
    
    try:
        result = crew.kickoff()
        
        print("\n" + "=" * 70)
        print("✅ 최종 결과")
        print("=" * 70)
        print(result)
        
    except Exception as e:
        print(f"\n❌ 오류 발생: {e}")
        import traceback
        traceback.print_exc()


# 간단한 툴 테스트
def simple_tool_test():
    print("\n" + "=" * 70)
    print("툴 직접 테스트")
    print("=" * 70)
    
    add_tool = AddNumbersTool()
    
    # 덧셈 테스트
    result1 = add_tool._run(a=10, b=20)
    print(f"\n덧셈 결과: {result1}")

 

 

결론

  • 학습 난이도는 strands 가 가장 쉬웠고, 이해해야 할 요소가 적어서 빠르게 테스트 코드를 만들 수 있었지만 레퍼런스가 부족하고, 공식 도큐먼트의 양과 질이 아쉽다.
  • LangCahin 이 테스트 코드를 실행하는데 가장 많은 시간이 소요됐고, Agent 의 프롬프트를 하나 실행하는데도 더 많은 객체가 필요했다. (prompt 를 만들때도 PromptTemplate 객체를 만들어야 하는 점.)
  • crewAI 도 비교적 학습이 간단했지만, Task들을 객체로 만들어 요소에 넣어야 하는 특징이 있었다. Tasks 를 모아서 순차적으로 실행할 수 있고, 병렬로 실행할 수도 있으며, Crew 라는 객체 안에서 Multi Agent 의 다양한 패턴을 정의할 수 있는것이 특징이다.
  • 생산성 면에서는 Strands 가 가장 좋을 것 같다는 결론이다.
반응형

+ Recent posts