langgraph의 공식문서를 번역해 놓은 자료입니다. 문제가 되면 삭제하겠습니다.
https://langchain-ai.github.io/langgraph/concepts/agentic_concepts/
많은 LLM 애플리케이션은 LLM 호출 전후에 특정한 제어 흐름을 구현한다. 예를 들어, RAG
는 질문과 관련된 문서를 검색하고, 그 문서를 LLM에 전달하여 모델의 응답을 구체화한다.
고정된 제어 흐름을 하드 코딩하는 대신, 때때로 더 복잡한 문제를 해결하기 위해 스스로 제어 흐름을 선택할 수 있는 LLM 시스템을 원한다. 이것이 에이전트(agent)의 정의이다. 에이전트는 LLM을 사용하여 애플리케이션의 제어 흐름을 결정하는 시스템이다. LLM이 애플리케이션을 제어할 수 있는 방법은 여러 가지가 있다.
- LLM은 두 가지 잠재적인 경로 간에 라우팅할 수 있다.
- LLM은 호출할 많은 도구 중에서 선택할 수 있다.
- LLM은 생성된 답변이 충분한지, 아니면 더 많은 작업이 필요한지 결정할 수 있다.
그 결과, 다양한 수준의 제어를 LLM에 제공하는 여러 가지 에이전트 아키텍처(agent architectures)가 존재한다.
Router
라우터는 LLM이 지정된 옵션 집합에서 하나의 단계를 선택할 수 있도록 한다. 이는 LLM이 일반적으로 하나의 결정을 내리고 좁은 범위의 출력을 반환할 수 있기 때문에 상대적으로 제한된 수준의 제어를 나타내는 에이전트 아키텍처이다. 라우터는 일반적으로 이를 달성하기 위해 몇 가지 다른 개념을 사용한다.
Structured Output
LLM의 구조화된 출력은 LLM이 응답에서 따라야 할 특정 형식이나 스키마를 제공하여 동작한다. 이는 도구 호출과 유사하지만 더 일반적이다. 도구 호출이 일반적으로 미리 정의된 함수를 선택하고 사용하는 것인 반면, 구조화된 출력은 모든 유형의 형식화된 응답에 사용할 수 있다. 구조화된 출력을 하기 위한 일반적인 방법은 다음과 같다.
- 프롬프트 엔지니어링: LLM에게 특정 형식으로 응답하도록 지시하기.
- 출력 파서: 후처리를 사용하여 LLM 응답에서 구조화된 데이터를 추출하기.
- 도구 호출: 일부 LLM의 내장 도구 호출 기능을 활용하여 구조화된 출력을 생성하기.
구조화된 출력은 LLM의 결정을 시스템에서 신뢰할 수 있게 해석하고 행동할 수 있도록 보장하기 때문에 라우팅에 매우 중요하다. 구조화된 출력에 대한 자세한 내용은 이 방법 안내서를 참조하자.
Tool calling agent
라우터가 LLM이 하나의 결정을 내리도록 하는 반면, 더 복잡한 에이전트 아키텍처는 LLM의 제어를 두 가지 주요 방식으로 확장한다.
- 다단계 의사 결정: LLM이 단순히 하나의 결정이 아닌 일련의 결정을 제어할 수 있다.
- 도구 접근: LLM이 다양한 도구 중 선택 및 사용하여 작업을 수행할 수 있다.
ReAct는 이러한 확장을 결합한 인기 있는 범용 에이전트 아키텍처로, 세 가지 핵심 개념을 통합한다.
- 도구 호출: LLM이 필요에 따라 다양한 도구를 선택하고 사용할 수 있도록 한다.
- 메모리: 에이전트가 이전 단계의 정보를 유지하고 이를 사용할 수 있게 한다.
- 계획: LLM이 목표를 달성하기 위해 다단계 계획을 생성하고 따를 수 있도록 한다.
이 아키텍처는 단순한 라우팅을 넘어 여러 단계에 걸쳐 동적인 문제 해결을 가능하게 하는 더 복잡하고 유연한 에이전트 행동을 허용한다. 이 기능은 create_react_agent
와 함께 사용할 수 있다.
Tool calling
도구는 에이전트가 외부 시스템과 상호작용할 때 유용하다. 외부 시스템(예: API)은 종종 자연어가 아닌 특정 입력 스키마나 페이로드를 요구한다. 예를 들어, API를 도구로 바인딩할 때 모델에게 필요한 입력 스키마를 제공한다. 모델은 사용자로부터 받은 자연어 입력을 기반으로 도구를 호출할 것이며, 도구의 스키마에 맞는 출력을 반환한다.
많은 LLM 제공업체가 도구 호출을 지원하며, LangChain의 도구 호출 인터페이스는 간단하다.ChatModel.bind_tools(function)
을 사용하여 어떤 Python 함수도 쉽게 전달할 수 있다.
Memory
메모리는 에이전트에게 매우 중요하며, 문제 해결의 여러 단계에서 정보를 유지하고 활용할 수 있게 해준다. 메모리는 다양한 규모로 작동한다.
- 단기 메모리: 에이전트가 특정 단계에서 획득한 정보에 접근할 수 있게 한다.
- 장기 메모리: 에이전트가 이전 정보를 기억할 수 있게 하며, 예를 들어 대화 중 과거 메시지를 기억한다.
LangGraph는 메모리 구현에 대한 완전한 제어를 제공한다.
- 상태(State): 유지할 메모리의 정확한 구조를 지정하는 사용자 정의 스키마이다.
- 체크포인터(Checkpointers): 서로 다른 상호작용에서 매 단계의 상태를 저장하는 메커니즘이다.
이 유연한 접근 방식은 특정 에이전트 아키텍처의 필요에 맞게 메모리 시스템을 조정할 수 있게 해준다. 그래프에 메모리를 추가하는 방법에 대한 실질적인 가이드는 이 튜토리얼을 참조하자.
효과적인 메모리 관리는 에이전트가 맥락(Context)을 유지하고, 과거 경험에서 학습하며, 시간이 지남에 따라 더 나은 결정을 내릴 수 있는 능력을 향상시킨다.
Planning
ReAct 아키텍처에서는 LLM이 반복적으로 호출된다. 각 단계에서 에이전트는 어떤 도구를 호출할지, 그리고 해당 도구에 대한 입력이 무엇이어야 할지를 결정한다. 그런 다음 그 도구가 실행되고, 출력이 관찰값(observations)으로 LLM에 피드백된다. 에이전트가 더 이상 도구를 호출할 가치가 없다고 결정할 때 while 루프가 종료된다.
ReAct 구현
이 논문과 사전 구축된 create_react_agent
구현 간에는 몇 가지 차이점이 있다.
첫째, 우리는 LLM이 도구를 호출하도록 하기 위해 도구 호출을 사용하지만, 논문에서는 프롬프트와 원시 출력을 파싱하는 방식을 사용했다. 이는 논문이 작성될 당시 도구 호출이 존재하지 않았기 때문이며, 일반적으로 도구 호출이 더 좋고 신뢰할 수 있다.
둘째, 우리는 LLM을 프롬프트하기 위해 메시지를 사용하지만, 논문에서는 문자열 포매팅을 사용했다. 이는 당시 LLM이 메시지 기반 인터페이스를 제공하지 않았기 때문이며, 현재는 메시지 기반 인터페이스만을 제공하고 있다.
셋째, 논문은 도구에 대한 모든 입력이 단일 문자열이어야 한다. 이는 당시 LLM의 성능이 제한적이었고 실제로 단일 입력만 생성할 수 있었기 때문이다. 실제 구현은 여러 입력을 요구하는 도구를 사용할 수 있도록 허용한다.
넷째, 논문은 한 번에 단일 도구만 호출하는 것을 다루었다. 이는 당시 LLM의 성능 제한 때문이다. 실제 구현은 여러 도구를 동시에 호출할 수 있다.
마지막으로, 논문에서는 LLM에게 호출할 도구를 결정하기 전에 명시적으로 "생각(Thought)" 단계를 생성하도록 요청했다. 이것이 "ReAct"의 "추론(Reasoning)" 부분이다. 실제 구현은 기본적으로 이 과정을 수행하지 않으며, 이는 LLM이 많이 개선되었기 때문이다. 물론, 그렇게 하도록 프롬프트를 작성할 수도 있다.
Custom agent 아키텍처
라우터와 도구 호출 에이전트(예: ReAct)는 일반적이지만, 에이전트 아키텍처를 커스트마이징하면 특정 작업에 대해 더 나은 성능을 얻을 수 있다. LangGraph는 맞춤형 에이전트 시스템을 구축하기 위한 여러가지 강력한 기능을 제공한다.
Human-in-the-loop
사람이 개입하는 방식은 특히 민감한 작업에서 에이전트의 신뢰성을 크게 향상시킬 수 있다. 이는 다음과 같은 것들을 포함할 수 있다.
- 특정 작업 승인
- 에이전트의 상태를 업데이트하기 위한 피드백 제공
- 복잡한 의사결정 과정에서의 안내 제공
전체 자동화가 불가능하거나 바람직하지 않은 경우, 사람이 개입하는 패턴은 매우 중요하다. 우리의 사람이 개입하는 방식 가이드에서 더 자세히 알아보자.
병렬처리
병렬 처리는 효율적인 다중 에이전트 시스템과 복잡한 작업에 필수적이다. LangGraph는 Send API를 통해 병렬 처리를 지원하여 다음을 가능하게 한다.
- 여러 상태의 동시 처리
- 맵-리듀스와 유사한 작업의 구현
- 독립적인 하위 작업의 효율적인 처리
실제 구현을 원하면 맵-리듀스 튜토리얼을 참고하자.
서브 그래프 (Sub-graphs)
서브 그래프는 복잡한 에이전트 아키텍처, 특히 다중 에이전트 시스템을 관리하는 데 필수적이다. 이것은 다음을 가능하게 한다.
- 개별 에이전트를 위한 독립적인 상태 관리
- 에이전트 팀의 계층적 조직
- 에이전트와 메인 시스템 간의 제어된 통신
서브 그래프는 상태 스키마의 겹치는 키를 통해 부모 그래프와 통신한다. 이를 통해 유연하고 모듈화된 에이전트 설계가 가능하다. 구현 세부사항은 서브 그래프 튜토리얼을 참조하자.
반영 (Reflection)
반영 메커니즘은 다음과 같이 에이전트의 신뢰성을 크게 향상시킬 수 있다.
- 작업 완료 및 정확성 평가
- 반복적 개선을 위한 피드백 제공
- 자기 교정 및 학습 가능
반영은 종종 LLM 기반이지만, 결정론적 방법도 사용할 수 있다. 예를 들어, 코딩 작업에서 컴파일 오류는 피드백 역할을 할 수 있다. 이 접근 방식은 LangGraph를 사용한 자기 교정 코드 생성에 대한 비디오에서 시연된다.
이러한 기능을 활용함으로써 LangGraph는 복잡한 워크플로를 처리하고 효과적으로 협력하며 지속적으로 성능을 향상시킬 수 있는 정교하고 작업별 에이전트 아키텍처의 생성을 가능하게 한다.