런 vs. 스레드: 언제 어떤 것을 사용해야 할까
Source: Dev.to

Crewship에는 배포된 크루를 실행하는 두 가지 방법이 있습니다: Run API와 Thread API. 플랫폼을 한 번이라도 사용해봤다면, 이미 런(Run)을 사용한 것입니다. 스레드는 더 새롭고 덜 직관적이며, 우리가 계속 듣는 질문은: 어떤 경우에 어떤 것을 사용해야 할까요?
런은 일회성 작업을 위해 사용됩니다. 스레드는 대화를 위해 사용됩니다. 이것이 간단히 말한 버전입니다. 나머지 포스트는 자세한 버전입니다.
실행: 기본값
실행(run) 은 여러분의 크루가 한 번 실행되는 것을 의미합니다. 입력을 보내면 크루가 작업을 수행하고, 결과를 반환합니다. 각 실행은 자체 컨테이너를 할당받으며 다른 실행과는 아무것도 공유하지 않고, 실행이 끝나면 환경이 파기됩니다.
crewship invoke --input '{"topic": "AI agents in logistics"}'
또는 API를 통해:
curl -X POST https://api.crewship.dev/v1/runs \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"deployment_id": "dep_abc123", "input": {"topic": "AI agents in logistics"}}'
실행 ID가 반환됩니다. 실행은 pending → running → succeeded/failed/canceled 순서로 진행됩니다. 실시간으로 이벤트를 스트리밍해서 에이전트가 작업하는 모습을 볼 수도 있고, 결과만 폴링(poll)해서 확인할 수도 있습니다.
설정도, 정리도, 관리해야 할 상태도 없습니다.
실행이 적합한 경우
다음과 같이 크루의 작업이 단일 실행 안에서 시작하고 끝나는 경우에 실행이 적합합니다:
- “X에 대한 블로그 포스트 작성” – 입력을 주면 콘텐츠가 출력되고 끝납니다.
- “이 데이터셋을 분석하고 보고서 생성” – 동일한 흐름.
- 항목 리스트를 독립적으로 처리하는 배치 작업.
- 웹훅이나 크론 스케줄에 의해 트리거되는 백그라운드 작업.
- 전체 워크플로우에서 크루가 하나의 단계가 되는 파이프라인 단계.
공통 패턴: 크루가 추가적인 질문을 할 필요가 없고, 이전에 무슨 일이 있었는지 기억할 필요도 없습니다. 입력을 받고 출력을 생성하면 그게 전부입니다.
실행이 할 수 없는 것
실행은 무상태(stateless) 입니다. 실행이 끝나면 그 실행은 사라집니다. 같은 배포를 사용해 또 다른 실행을 시작해도 이전 실행에 대한 컨텍스트가 전혀 없습니다. 5분 전에 약간 다른 입력으로 실행했었다는 사실이나, 마지막 출력이 거의 맞았지만 약간 수정이 필요했다는 정보도 알 수 없습니다.
많은 워크로드에서는 바로 이것이 원하는 동작이지만, 경우에 따라서는 문제가 될 수도 있습니다.
Source: …
스레드: 메모리가 필요할 때
스레드는 배포에 범위가 지정된 지속적인 대화 컨텍스트입니다. 한 번 생성하면, 필요에 따라 그 안에서 크루를 여러 번 실행할 수 있습니다. 각 실행은 스레드의 현재 상태를 받고, 실행이 끝나면 그 상태를 업데이트할 수 있습니다. 다음 실행은 이전 실행이 남긴 지점부터 이어서 진행됩니다.
# 스레드 생성
crewship thread create dep_abc123
# 스레드 안에서 실행
crewship invoke dep_abc123 --thread thr_xyz789 -i '{"message": "Research AI agents in healthcare"}'
# 후속 실행 – 크루가 첫 번째 메시지를 기억함
crewship invoke dep_abc123 --thread thr_xyz789 -i '{"message": "Now focus on diagnostic applications"}'
API를 통한 방법:
# 스레드 생성
curl -X POST https://api.crewship.dev/v1/threads \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"deployment_id": "dep_abc123"}'
# 스레드 안에서 실행
curl -X POST https://api.crewship.dev/v1/threads/thr_xyz789/runs \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"input": {"message": "Research AI agents in healthcare"}}'
스레드는 values 필드—크루가 읽고 쓸 수 있는 JSON 객체—를 통해 상태를 추적합니다. 각 실행이 끝난 후, Crewship은 체크포인트를 저장하여 시간이 흐름에 따라 상태가 어떻게 변했는지 전체 히스토리를 제공합니다.
스레드 수명 주기
스레드에는 자체 상태가 있습니다:
| 상태 | 의미 |
|---|---|
idle | 새로운 실행을 받을 준비가 된 상태 |
busy | 실행 중; 새로운 실행 요청은 종료될 때까지 409 응답을 받음 |
interrupted | 실행이 중단됨 |
error | 마지막 실행이 실패했지만, 스레드는 여전히 새로운 실행을 받을 수 있음 |
한 번에 하나의 실행만 스레드에서 실행될 수 있습니다. 이 설계는 상태 일관성을 유지하고, 동시에 실행되는 작업이 서로의 업데이트를 방해하지 않도록 합니다.
스레드가 유용한 경우
스레드는 컨텍스트가 상호작용 사이에 이어지는 모든 상황에서 빛을 발합니다:
- 대화형 에이전트 – 각 사용자 메시지가 이전 교환을 기반으로 하는 챗봇이나 지원 어시스턴트.
- 반복적인 정교화 – 예: “마케팅 플랜을 생성해 주세요”, 그 다음 “예산 섹션을 더 자세히 만들어 주세요”, 다시 “타임라인을 추가해 주세요”. 각 실행이 이전 출력 위에 구축됩니다.
- 인간 승인 단계가 포함된 다단계 워크플로 – 크루가 조사하고, 결과를 제시하고, 사용자 지시를 기다린 뒤 진행합니다. 스레드는 중간 상태를 보관하므로 별도로 관리할 필요가 없습니다.
체크포인트
스레드 안에서 실행이 끝날 때마다 Crewship은 해당 시점의 스레드 values를 기록한 체크포인트를 생성합니다. 전체 체크포인트 히스토리를 조회하면 다음을 할 수 있습니다:
- 상태가 어떻게 변했는지 감사하기.
- 필요 시 이전 상태로 롤백하기.
- 과거 값을 검사해 예기치 않은 동작을 디버깅하기.
TL;DR
- Runs = 일회성, 무상태 실행. 이전 실행에 대한 기억이 필요 없는 격리된 작업, 배치 작업, 또는 그런 상황에 사용하세요.
- Threads = 상태를 유지하는 순차 실행. 대화, 반복 작업, 또는 여러 호출에 걸쳐 컨텍스트를 보존해야 하는 워크플로에 사용하세요.
작업에 맞는 도구를 선택하고, Crewship이 무거운 작업을 처리하도록 하세요!
체크포인트
Crewship은 체크포인트를 저장합니다 — 해당 시점의 스레드 상태를 스냅샷으로 기록합니다.
curl https://api.crewship.dev/v1/threads/thr_xyz789/history \
-H "Authorization: Bearer YOUR_API_KEY"
이렇게 하면 감사 로그를 얻을 수 있습니다. 또한 디버깅에 유용합니다: 크루의 응답이 5번째 턴에서 엉켰다면, 4번째 턴의 체크포인트를 살펴보아 어떤 상태에서 작업했는지 확인할 수 있습니다.
Threads support a metadata field that’s separate from the conversation state. Use it for things like user IDs, channels, tags — anything you want to filter or search by later:
curl -X POST https://api.crewship.dev/v1/threads \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"deployment_id": "dep_abc123",
"metadata": {
"user_id": "user_42",
"channel": "web",
"priority": "high"
}
}'
이것은 다양한 사용자와 사용 사례에 걸쳐 수백 개의 스레드가 있을 때 중요합니다.
나란히 비교
| 기능 | 실행 | 스레드 |
|---|---|---|
| 상태 | 없음 — 각 실행이 독립적 | values를 통해 실행 간에 지속 |
| 수명 주기 | pending → running → 종료 | idle → busy → idle (반복) |
| 동시성 | 무제한 병렬 실행 | 스레드당 한 번에 하나의 실행 |
| 히스토리 | 개별 실행 기록 | 각 실행 후 체크포인트 |
| 설정 | 없음 — 실행만 생성 | 먼저 스레드를 생성하고, 그 안에서 실행 |
| 정리 | 자동 | 수동 — 완료 시 스레드 삭제 |
| 비용 프로필 | 실행당 예측 가능 | 대화 길이에 따라 증가 |
다른 플랫폼은 어떻게 처리할까
다른 에이전트 플랫폼을 사용해 본 적이 있다면, 이 구분을 익숙하게 느낄 것입니다. OpenAI의 Assistants API는 Threads와 Runs라는 이름을 사용했는데, 문자 그대로 같은 이름이었습니다. 이후 Responses API와 Conversations로 대체했지만 개념은 동일합니다: 상태가 없는 실행 원시 요소와 선택적인 지속성 레이어.
- LangGraph – 한 번에 실행하려면
graph.invoke()를 호출합니다.thread_id를 전달하면 지속성, 체크포인트 및 어느 시점에서든 재개할 수 있는 기능을 얻을 수 있습니다. - CrewAI –
kickoff()이 한 번에 실행하는 방법이며, 별도의 대화 모드가 다중 턴 상호작용을 제공합니다.
이들 모두에서 공통된 패턴은 다음과 같습니다: runs는 실행 원시 요소이며, threads(또는 그에 상응하는 것)는 선택적으로 공유 상태와 함께 runs를 연결합니다. 필요할 때까지 threads를 사용할 필요는 없습니다.
어느 것을 사용해야 할까요?
하나의 질문이 대부분을 해결합니다: 크루가 이전 실행에서 어떤 것을 기억해야 합니까?
| 답변 | 추천 |
|---|---|
| 아니오 | run을 사용하세요. 스레드를 추가하면 불필요한 복잡성만 늘어납니다. |
| 예 | thread를 사용하세요. 이전 컨텍스트를 run 입력에 억지로 넣어 상태를 흉내 내려고 하면 금방 엉망이 되고, 체크포인트, 히스토리, 그리고 스레드가 제공하는 동시성 보장을 잃게 됩니다. |
스레드 사용을 시사하는 신호
- 사용자는 세션당 여러 번 크루와 상호작용합니다.
- 크루의 출력은 현재 입력만이 아니라 대화 기록에 따라 달라집니다.
- 시간에 따라 상태가 어떻게 변했는지에 대한 감사 추적이 필요합니다.
런 사용을 시사하는 신호
- 크루가 단일 입력 세트만으로 작업을 수행할 수 있습니다.
- 여러 실행을 병렬로 시작하고 싶습니다.
- 워크로드가 사람의 메시지가 아니라 자동화 시스템에 의해 트리거됩니다.
스레드 시작하기
런을 사용해 왔고 스레드를 시도해 보고 싶다면 배포에 대해 바꿀 것이 없습니다. 스레드는 어떤 배포된 크루와도 작동합니다 — CrewAI, LangGraph Python, 또는 LangGraph JS.
# 스레드 생성
crewship thread create dep_abc123 --metadata '{"user_id": "demo"}'
# 첫 번째 턴
crewship invoke dep_abc123 --thread thr_xyz789 \
-i '{"message": "What can you help me with?"}'
# 두 번째 턴 — 크루가 첫 번째 턴의 컨텍스트를 받음
crewship invoke dep_abc123 --thread thr_xyz789 \
-i '{"message": "Tell me more about option 2"}'
# 히스토리 확인
crewship thread history thr_xyz789
전체 API 참조는 스레드 문서에 있습니다.
런, 스레드, 혹은 기타 사항에 대한 질문이 있나요? 문서를 확인하거나 언제든지 연락 주세요.
