메인 콘텐츠로 건너뛰기

개요

@human_feedback 데코레이터는 CrewAI 버전 1.8.0 이상이 필요합니다. 이 기능을 사용하기 전에 설치를 업데이트하세요.
@human_feedback 데코레이터는 CrewAI Flow 내에서 직접 human-in-the-loop(HITL) 워크플로우를 가능하게 합니다. Flow 실행을 일시 중지하고, 인간에게 검토를 위해 출력을 제시하고, 피드백을 수집하고, 선택적으로 피드백 결과에 따라 다른 리스너로 라우팅할 수 있습니다. 이는 특히 다음과 같은 경우에 유용합니다:
  • 품질 보증: AI가 생성한 콘텐츠를 다운스트림에서 사용하기 전에 검토
  • 결정 게이트: 자동화된 워크플로우에서 인간이 중요한 결정을 내리도록 허용
  • 승인 워크플로우: 승인/거부/수정 패턴 구현
  • 대화형 개선: 출력을 반복적으로 개선하기 위해 피드백 수집

빠른 시작

Flow에 인간 피드백을 추가하는 가장 간단한 방법은 다음과 같습니다:
Code
이 Flow를 실행하면:
  1. generate_content를 실행하고 문자열을 반환합니다
  2. 요청 메시지와 함께 사용자에게 출력을 표시합니다
  3. 사용자가 피드백을 입력할 때까지 대기합니다 (또는 Enter를 눌러 건너뜁니다)
  4. HumanFeedbackResult 객체를 process_feedback에 전달합니다

@human_feedback 데코레이터

매개변수

기본 사용법 (라우팅 없음)

emit을 지정하지 않으면, 데코레이터는 단순히 피드백을 수집하고 다음 리스너에 HumanFeedbackResult를 전달합니다:
Code

emit을 사용한 라우팅

emit을 지정하면, 데코레이터는 라우터가 됩니다. 인간의 자유 형식 피드백이 LLM에 의해 해석되어 지정된 outcome 중 하나로 매핑됩니다:
Code
사용자가 “더 자세한 내용이 필요합니다”와 같이 말하면, LLM이 이를 "needs_revision"으로 매핑하고, or_()를 통해 review_content가 다시 트리거됩니다 — 수정 루프가 생성됩니다. outcome이 "approved" 또는 "rejected"가 될 때까지 루프가 계속됩니다.
LLM은 가능한 경우 구조화된 출력(function calling)을 사용하여 응답이 지정된 outcome 중 하나임을 보장합니다. 이로 인해 라우팅이 신뢰할 수 있고 예측 가능해집니다.
@start() 메서드는 flow 시작 시 한 번만 실행됩니다. 수정 루프가 필요한 경우, start 메서드를 review 메서드와 분리하고 review 메서드에 @listen(or_("trigger", "revision_outcome"))를 사용하여 self-loop을 활성화하세요.

HumanFeedbackResult

HumanFeedbackResult 데이터클래스는 인간 피드백 상호작용에 대한 모든 정보를 포함합니다:
Code

리스너에서 접근하기

emit이 있는 @human_feedback 메서드에 의해 리스너가 트리거되면, HumanFeedbackResult를 받습니다:
Code

피드백 히스토리 접근하기

Flow 클래스는 인간 피드백에 접근하기 위한 두 가지 속성을 제공합니다:

last_human_feedback

가장 최근의 HumanFeedbackResult를 반환합니다:
Code

human_feedback_history

Flow 동안 수집된 모든 HumanFeedbackResult 객체의 리스트입니다:
Code
HumanFeedbackResulthuman_feedback_history에 추가되므로, 여러 피드백 단계가 서로 덮어쓰지 않습니다. 이 리스트를 사용하여 Flow 동안 수집된 모든 피드백에 접근하세요.

완전한 예제: 콘텐츠 승인 워크플로우

콘텐츠 검토 및 승인 워크플로우를 구현하는 전체 예제입니다:

다른 데코레이터와 결합하기

@human_feedback 데코레이터는 @start(), @listen(), or_()와 함께 작동합니다. 데코레이터 순서는 두 가지 모두 동작합니다—프레임워크가 양방향으로 속성을 전파합니다—하지만 권장 패턴은 다음과 같습니다:
Code

Self-loop 패턴

수정 루프를 만들려면 or_()를 사용하여 검토 메서드가 상위 트리거자체 수정 outcome을 모두 리스닝해야 합니다:
Code
outcome이 "revise"이면 flow가 review로 다시 라우팅됩니다 (or_()를 통해 "revise"를 리스닝하기 때문). outcome이 "approved"이면 flow가 publish로 계속됩니다. flow 엔진이 라우터를 “한 번만 실행” 규칙에서 제외하여 각 루프 반복마다 재실행할 수 있기 때문에 이 패턴이 동작합니다.

체인된 라우터

한 라우터의 outcome으로 트리거된 리스너가 그 자체로 라우터가 될 수 있습니다:
Code

제한 사항

  • @start() 메서드는 한 번만 실행: @start() 메서드는 self-loop할 수 없습니다. 수정 주기가 필요하면 별도의 @start() 메서드를 진입점으로 사용하고 @listen() 메서드에 @human_feedback를 배치하세요.
  • 동일 메서드에 @start() + @listen() 불가: 이는 Flow 프레임워크 제약입니다. 메서드는 시작점이거나 리스너여야 하며, 둘 다일 수 없습니다.

모범 사례

1. 명확한 요청 메시지 작성

message 매개변수는 인간이 보는 것입니다. 실행 가능하게 만드세요:
Code

2. 의미 있는 Outcome 선택

emit을 사용할 때, 인간의 응답에 자연스럽게 매핑되는 outcome을 선택하세요:
Code

3. 항상 기본 Outcome 제공

사용자가 입력 없이 Enter를 누르는 경우를 처리하기 위해 default_outcome을 사용하세요:
Code

4. 감사 추적을 위한 피드백 히스토리 사용

감사 로그를 생성하기 위해 human_feedback_history에 접근하세요:
Code

5. 라우팅된 피드백과 라우팅되지 않은 피드백 모두 처리

Flow를 설계할 때, 라우팅이 필요한지 고려하세요:

비동기 인간 피드백 (논블로킹)

기본적으로 @human_feedback은 콘솔 입력을 기다리며 실행을 차단합니다. 프로덕션 애플리케이션에서는 Slack, 이메일, 웹훅 또는 API와 같은 외부 시스템과 통합되는 비동기/논블로킹 피드백이 필요할 수 있습니다.

Provider 추상화

커스텀 피드백 수집 전략을 지정하려면 provider 매개변수를 사용하세요:
Code
Flow 프레임워크는 HumanFeedbackPending이 발생하면 자동으로 상태를 영속화합니다. Provider는 외부 시스템에 알리고 예외를 발생시키기만 하면 됩니다—수동 영속성 호출이 필요하지 않습니다.

일시 중지된 Flow 처리

비동기 provider를 사용하면 kickoff()는 예외를 발생시키는 대신 HumanFeedbackPending 객체를 반환합니다:
Code

일시 중지된 Flow 재개

피드백이 도착하면 (예: 웹훅을 통해) Flow를 재개합니다:
Code

주요 타입

PendingFeedbackContext

컨텍스트는 재개에 필요한 모든 것을 포함합니다:
Code

완전한 비동기 Flow 예제

Code
비동기 웹 프레임워크(FastAPI, aiohttp, Slack Bolt 비동기 모드)를 사용하는 경우 flow.resume() 대신 await flow.resume_async()를 사용하세요. 실행 중인 이벤트 루프 내에서 resume()을 호출하면 RuntimeError가 발생합니다.

비동기 피드백 모범 사례

  1. 반환 타입 확인: kickoff()는 일시 중지되면 HumanFeedbackPending을 반환합니다—try/except가 필요하지 않습니다
  2. 올바른 resume 메서드 사용: 동기 코드에서는 resume(), 비동기 코드에서는 await resume_async() 사용
  3. 콜백 정보 저장: callback_info를 사용하여 웹훅 URL, 티켓 ID 등을 저장
  4. 멱등성 구현: 안전을 위해 resume 핸들러는 멱등해야 합니다
  5. 자동 영속성: HumanFeedbackPending이 발생하면 상태가 자동으로 저장되며 기본적으로 SQLiteFlowPersistence 사용
  6. 커스텀 영속성: 필요한 경우 from_pending()에 커스텀 영속성 인스턴스 전달

피드백에서 학습하기

learn=True 매개변수는 인간 검토자와 메모리 시스템 간의 피드백 루프를 활성화합니다. 활성화되면 시스템은 과거 인간의 수정 사항에서 학습하여 출력을 점진적으로 개선합니다.

작동 방식

  1. 피드백 후: LLM이 출력 + 피드백에서 일반화 가능한 교훈을 추출하고 source="hitl"로 메모리에 저장합니다. 피드백이 단순한 승인(예: “좋아 보입니다”)인 경우 아무것도 저장하지 않습니다.
  2. 다음 검토 전: 과거 HITL 교훈을 메모리에서 불러와 LLM이 인간이 보기 전에 출력을 개선하는 데 적용합니다.
시간이 지남에 따라 각 수정 사항이 향후 검토에 반영되므로 인간은 점진적으로 더 나은 사전 검토된 출력을 보게 됩니다.

예제

Code
첫 번째 실행: 인간이 원시 출력을 보고 “사실에 대한 주장에는 항상 인용을 포함하세요.”라고 말합니다. 교훈이 추출되어 메모리에 저장됩니다. 두 번째 실행: 시스템이 인용 교훈을 불러와 출력을 사전 검토하여 인용을 추가한 후 개선된 버전을 표시합니다. 인간의 역할이 “모든 것을 수정”에서 “시스템이 놓친 것을 찾기”로 전환됩니다.

구성

주요 설계 결정

  • 모든 것에 동일한 LLM 사용: 데코레이터의 llm 매개변수는 outcome 매핑, 교훈 추출, 사전 검토에 공유됩니다. 여러 모델을 구성할 필요가 없습니다.
  • 구조화된 출력: 추출과 사전 검토 모두 LLM이 지원하는 경우 Pydantic 모델과 함께 function calling을 사용하고, 그렇지 않으면 텍스트 파싱으로 폴백합니다.
  • 논블로킹 저장: 교훈은 백그라운드 스레드에서 실행되는 remember_many()를 통해 저장됩니다 — Flow는 즉시 계속됩니다.
  • 우아한 저하: 추출 중 LLM이 실패하면 아무것도 저장하지 않습니다. 사전 검토 중 실패하면 원시 출력이 표시됩니다. 어느 쪽의 실패도 Flow를 차단하지 않습니다.
  • 범위/카테고리 불필요: 교훈을 저장할 때 source만 전달됩니다. 인코딩 파이프라인이 범위, 카테고리, 중요도를 자동으로 추론합니다.
learn=True는 Flow에 메모리가 사용 가능해야 합니다. Flow는 기본적으로 자동으로 메모리를 얻지만, _skip_auto_memory로 비활성화한 경우 HITL 학습은 조용히 건너뜁니다.

관련 문서