if 문, for 루프, 함수 호출과 같은 표준 언어 프리미티브를 사용하는 기존 코드에 이러한 기능을 통합하도록 설계되었습니다. 코드를 명시적인 파이프라인이나 DAG로 재구성해야 하는 많은 데이터 오케스트레이션 프레임워크와 달리, Functional API는 엄격한 실행 모델을 강제하지 않고도 이러한 기능을 통합할 수 있습니다.
Functional API는 두 가지 핵심 구성 요소를 사용합니다:
@entrypoint– 함수를 워크플로우의 시작점으로 표시하여 로직을 캡슐화하고 장기 실행 작업 및 interrupt 처리를 포함한 실행 흐름을 관리합니다.@task– API 호출이나 데이터 처리 단계와 같은 개별 작업 단위를 나타내며, entrypoint 내에서 비동기적으로 실행될 수 있습니다. Task는 await하거나 동기적으로 해결할 수 있는 future와 유사한 객체를 반환합니다.
Functional API 사용 방법에 대한 자세한 내용은 Functional API 사용하기를 참조하세요.
Functional API vs. Graph API
보다 선언적인 접근 방식을 선호하는 사용자를 위해 LangGraph의 Graph API를 사용하면 Graph 패러다임을 사용하여 워크플로우를 정의할 수 있습니다. 두 API는 동일한 기본 런타임을 공유하므로 동일한 애플리케이션에서 함께 사용할 수 있습니다. 주요 차이점은 다음과 같습니다:- 제어 흐름: Functional API는 그래프 구조에 대해 생각할 필요가 없습니다. 표준 Python 구조를 사용하여 워크플로우를 정의할 수 있습니다. 이는 일반적으로 작성해야 하는 코드의 양을 줄입니다.
- 단기 메모리: GraphAPI는 State를 선언해야 하며 그래프 상태에 대한 업데이트를 관리하기 위해 reducer를 정의해야 할 수 있습니다.
@entrypoint와@task는 상태가 함수에 범위가 지정되고 함수 간에 공유되지 않으므로 명시적인 상태 관리가 필요하지 않습니다. - Checkpointing: 두 API 모두 checkpoint를 생성하고 사용합니다. Graph API에서는 모든 superstep 후에 새로운 checkpoint가 생성됩니다. Functional API에서는 task가 실행될 때 새로운 checkpoint를 생성하는 대신 주어진 entrypoint와 연결된 기존 checkpoint에 결과가 저장됩니다.
- 시각화: Graph API를 사용하면 워크플로우를 그래프로 쉽게 시각화할 수 있어 디버깅, 워크플로우 이해 및 다른 사람과 공유하는 데 유용합니다. Functional API는 그래프가 런타임 중에 동적으로 생성되므로 시각화를 지원하지 않습니다.
예제
아래에서는 에세이를 작성하고 사람의 검토를 요청하기 위해 interrupt하는 간단한 애플리케이션을 보여줍니다.상세 설명
상세 설명
이 워크플로우는 “cat”이라는 주제에 대한 에세이를 작성한 다음 사람의 검토를 받기 위해 일시 중지됩니다. 워크플로우는 검토가 제공될 때까지 무기한으로 중단될 수 있습니다.워크플로우가 재개되면 처음부터 실행되지만 에세이가 작성되었고 검토 준비가 완료되었습니다. 검토가 제공되면 워크플로우를 재개할 수 있습니다:워크플로우가 완료되었고 검토가 에세이에 추가되었습니다.
writeEssay task의 결과가 이미 저장되었기 때문에 task 결과는 다시 계산되는 대신 checkpoint에서 로드됩니다.Entrypoint
@entrypoint 데코레이터를 사용하여 함수에서 워크플로우를 생성할 수 있습니다. 이는 워크플로우 로직을 캡슐화하고 장기 실행 작업 및 interrupt 처리를 포함한 실행 흐름을 관리합니다.
정의
entrypoint는@entrypoint 데코레이터로 함수를 장식하여 정의됩니다.
함수는 단일 위치 인수를 받아야 하며, 이는 워크플로우 입력으로 사용됩니다. 여러 데이터를 전달해야 하는 경우 첫 번째 인수의 입력 타입으로 딕셔너리를 사용하세요.
entrypoint로 함수를 장식하면 워크플로우 실행을 관리하는 데 도움이 되는 Pregel 인스턴스가 생성됩니다(예: 스트리밍, 재개 및 checkpointing 처리).
일반적으로 persistence를 활성화하고 human-in-the-loop와 같은 기능을 사용하려면 @entrypoint 데코레이터에 checkpointer를 전달해야 합니다.
- Sync
- Async
직렬화
entrypoint의 입력 및 출력은 checkpointing을 지원하기 위해 JSON 직렬화 가능해야 합니다. 자세한 내용은 직렬화 섹션을 참조하세요.
주입 가능한 매개변수
entrypoint를 선언할 때 런타임에 자동으로 주입될 추가 매개변수에 대한 액세스를 요청할 수 있습니다. 이러한 매개변수는 다음과 같습니다:
| 매개변수 | 설명 |
|---|---|
| previous | 주어진 thread에 대한 이전 checkpoint와 연결된 상태에 액세스합니다. 단기 메모리를 참조하세요. |
| store | [BaseStore][langgraph.store.base.BaseStore]의 인스턴스입니다. 장기 메모리에 유용합니다. |
| writer | Async Python < 3.11에서 작업할 때 StreamWriter에 액세스하는 데 사용합니다. 자세한 내용은 Functional API를 사용한 스트리밍을 참조하세요. |
| config | 런타임 구성에 액세스하기 위해 사용합니다. 자세한 내용은 RunnableConfig를 참조하세요. |
적절한 이름과 타입 어노테이션으로 매개변수를 선언하세요.
주입 가능한 매개변수 요청
주입 가능한 매개변수 요청
실행
@entrypoint를 사용하면 invoke, ainvoke, stream, astream 메서드를 사용하여 실행할 수 있는 Pregel 객체가 생성됩니다.
- Invoke
- Async Invoke
- Stream
- Async Stream
재개
interrupt 후 실행을 재개하려면Command 프리미티브에 resume 값을 전달하면 됩니다.
- Invoke
- Async Invoke
- Stream
- Async Stream
None과 동일한 thread id (config)로 entrypoint를 실행하세요.
이는 기본 오류가 해결되었고 실행이 성공적으로 진행될 수 있다고 가정합니다.
- Invoke
- Async Invoke
- Stream
- Async Stream
단기 메모리
entrypoint가 checkpointer로 정의되면 동일한 thread id에서 연속적인 호출 간에 정보를 checkpoint에 저장합니다.
이를 통해 previous 매개변수를 사용하여 이전 호출의 상태에 액세스할 수 있습니다.
기본적으로 previous 매개변수는 이전 호출의 반환 값입니다.
entrypoint.final
entrypoint.final은 entrypoint에서 반환할 수 있는 특수 프리미티브로, checkpoint에 저장되는 값과 entrypoint의 반환 값을 분리할 수 있습니다.
첫 번째 값은 entrypoint의 반환 값이고, 두 번째 값은 checkpoint에 저장될 값입니다. 타입 어노테이션은 entrypoint.final[return_type, save_type]입니다.
Task
task는 API 호출이나 데이터 처리 단계와 같은 개별 작업 단위를 나타냅니다. 두 가지 주요 특성이 있습니다:- 비동기 실행: Task는 비동기적으로 실행되도록 설계되어 여러 작업이 차단 없이 동시에 실행될 수 있습니다.
- Checkpointing: Task 결과는 checkpoint에 저장되어 마지막으로 저장된 상태에서 워크플로우를 재개할 수 있습니다. (자세한 내용은 persistence를 참조하세요).
정의
Task는 일반 Python 함수를 래핑하는@task 데코레이터를 사용하여 정의됩니다.
직렬화
task의 출력은 checkpointing을 지원하기 위해 JSON 직렬화 가능해야 합니다.
실행
Task는 entrypoint, 다른 task 또는 state graph node 내에서만 호출할 수 있습니다. Task는 메인 애플리케이션 코드에서 직접 호출할 수 없습니다. task를 호출하면 future 객체와 함께 즉시 반환됩니다. future는 나중에 사용할 수 있는 결과의 자리 표시자입니다. task의 결과를 얻으려면 동기적으로 대기(result() 사용)하거나 비동기적으로 await(await 사용)할 수 있습니다.
- 동기 호출
- 비동기 호출
Task를 사용해야 하는 경우
Task는 다음과 같은 시나리오에서 유용합니다:- Checkpointing: 장기 실행 작업의 결과를 checkpoint에 저장하여 워크플로우를 재개할 때 다시 계산할 필요가 없도록 해야 하는 경우.
- Human-in-the-loop: 사람의 개입이 필요한 워크플로우를 구축하는 경우, 워크플로우가 올바르게 재개될 수 있도록 모든 무작위성(예: API 호출)을 캡슐화하기 위해 task를 사용해야 합니다. 자세한 내용은 결정론 섹션을 참조하세요.
- 병렬 실행: I/O 바운드 작업의 경우 task는 병렬 실행을 가능하게 하여 여러 작업이 차단 없이 동시에 실행될 수 있습니다(예: 여러 API 호출).
- 관찰 가능성: 작업을 task로 래핑하면 워크플로우의 진행 상황을 추적하고 LangSmith를 사용하여 개별 작업의 실행을 모니터링할 수 있습니다.
- 재시도 가능한 작업: 실패나 불일치를 처리하기 위해 작업을 재시도해야 하는 경우 task는 재시도 로직을 캡슐화하고 관리하는 방법을 제공합니다.
직렬화
LangGraph의 직렬화에는 두 가지 주요 측면이 있습니다:entrypoint입력 및 출력은 JSON 직렬화 가능해야 합니다.task출력은 JSON 직렬화 가능해야 합니다.
결정론
human-in-the-loop와 같은 기능을 활용하려면 모든 무작위성을 task 내부에 캡슐화해야 합니다. 이렇게 하면 실행이 중단되고(예: human-in-the-loop) 재개될 때 task 결과가 비결정적이더라도 동일한 _단계 순서_를 따르게 됩니다. LangGraph는 task 및 subgraph 결과를 실행될 때 유지하여 이러한 동작을 달성합니다. 잘 설계된 워크플로우는 실행을 재개할 때 동일한 _단계 순서_를 따르도록 보장하여 이전에 계산된 결과를 다시 실행하지 않고 올바르게 검색할 수 있습니다. 이는 장기 실행 task 또는 비결정적 결과를 가진 task에 특히 유용합니다. 이전에 수행한 작업을 반복하지 않고 본질적으로 동일한 지점에서 재개할 수 있기 때문입니다. 워크플로우의 다른 실행은 다른 결과를 생성할 수 있지만, 특정 실행을 재개하면 항상 동일한 기록된 단계 순서를 따라야 합니다. 이를 통해 LangGraph는 그래프가 중단되기 전에 실행된 task 및 subgraph 결과를 효율적으로 조회하고 다시 계산하지 않을 수 있습니다.멱등성
멱등성은 동일한 작업을 여러 번 실행해도 동일한 결과를 생성하도록 보장합니다. 이는 실패로 인해 단계가 다시 실행되는 경우 중복 API 호출 및 중복 처리를 방지하는 데 도움이 됩니다. checkpointing을 위해 항상 API 호출을 task 함수 내부에 배치하고 재실행 시 멱등성을 갖도록 설계하세요. task가 시작되었지만 성공적으로 완료되지 않은 경우 재실행이 발생할 수 있습니다. 그런 다음 워크플로우가 재개되면 task가 다시 실행됩니다. 중복을 방지하려면 멱등성 키를 사용하거나 기존 결과를 확인하세요.일반적인 함정
부작용 처리
부작용(예: 파일에 쓰기, 이메일 보내기)을 task에 캡슐화하여 워크플로우를 재개할 때 여러 번 실행되지 않도록 하세요.- 잘못된 예
- 올바른 예
이 예제에서는 부작용(파일에 쓰기)이 워크플로우에 직접 포함되어 있으므로 워크플로우를 재개할 때 두 번째로 실행됩니다.
비결정적 제어 흐름
매번 다른 결과를 제공할 수 있는 작업(예: 현재 시간 가져오기 또는 난수)은 재개 시 동일한 결과가 반환되도록 task에 캡슐화해야 합니다.- task에서: 난수 가져오기 (5) → interrupt → 재개 → (5를 다시 반환) → …
- task가 아닌 경우: 난수 가져오기 (5) → interrupt → 재개 → 새 난수 가져오기 (7) → …
interrupt 호출이 잘못된 resume 값과 일치하여 잘못된 결과가 발생할 수 있습니다.
자세한 내용은 결정론 섹션을 참조하세요.
- 잘못된 예
- 올바른 예
이 예제에서는 워크플로우가 현재 시간을 사용하여 실행할 task를 결정합니다. 이는 워크플로우의 결과가 실행 시간에 따라 달라지므로 비결정적입니다.
Connect these docs programmatically to Claude, VSCode, and more via MCP for real-time answers.