휴먼 인풋 API 통합 흐름

휴먼 인풋 API 통합 흐름

워크플로가 Human Input 노드에 도달하면 일시정지되고, 스트리밍 응답에 human_input_required 이벤트를 띄워요. 이 이벤트에는 form_token이 실려 있는데, 워크플로가 재개될 때까지 폼 라이프사이클을 몰고 가는 역할을 해요.

출처: 공식문서

단계

아래 순서는 Workflow 앱과 Chatflow 앱 모두에 적용돼요. 1단계의 진입 엔드포인트만 둘 사이에서 달라집니다.

1단계: 스트리밍 모드로 앱 시작

  1. Run Workflow(Workflow 앱) 또는 Send Chat Message(Chatflow 앱)를 호출하되, 최종 사용자의 user 식별자를 넘겨요.

  2. SSE 스트림에서 human_input_required 이벤트를 지켜보고, 그 form_token을 잡아요.

    form_tokennull이면 폼이 Email 전달 방식을 쓰는 거라 API로는 다룰 수 없어요(아래 전달 방식 요건 참고).

    human_input_required 이벤트는 실행의 workflow_run_id도 함께 실어 보내요. 5단계에서 리슨을 재개해야 할 때를 대비해 보관해 두세요.

2단계: 폼 정의 가져오기

form_token으로 Get Human Input Form을 호출해요. 응답에는 렌더링된 Markdown, 입력 필드 정의, 사용 가능한 액션, 미리 채워진 기본값, 그리고 제출 가능한 시한인 expiration_time이 포함돼요. 이 폼을 수신자에게 렌더링합니다.

제출 전에 폼이 만료되면, 일시정지된 실행은 노드 설정의 타임아웃 동작을 따르고, 재개된 스트림에는 human_input_form_filled 대신 human_input_form_timeout이 실려 와요.

3단계: (파일 입력만 해당) 로컬 파일 업로드

수신자가 file 또는 file-list 입력에 로컬 파일을 붙인다면, 먼저 Upload File로 업로드해요. 그러면 id가 돌아오는데, 제출 페이로드에서 upload_file_id로 참조해요. 실행·업로드·제출 호출 전체에 일관된 user 하나를 쓰세요(자세한 건 엔드 유저 식별자).

원격 파일은 업로드 단계가 필요 없어요. 제출 때 {transfer_method: remote_url, url} 매핑으로 인라인으로 붙이면 됩니다.

4단계: 응답 제출

수신자가 입력한 값과 선택한 action, 그리고 user를 담아 Submit Human Input Form을 호출해요. action은 2단계에서 받은 폼 정의의 액션 중 하나여야 해요.

파일 입력은 3단계의 {transfer_method: local_file, upload_file_id} 매핑 또는 인라인 {transfer_method: remote_url, url} 매핑을 받아요. 두 방식의 트레이드오프는 아래 업로드 우선 vs 인라인 원격 URL에서 설명할게요.

  • 성공한 제출은 최종적이에요. 폼을 닫고 그에 맞는 액션 분기로 실행을 재개하므로, 같은 form_token으로 다시 제출할 수 없어요.
  • 거부된 제출(잘못된 action, 필수 입력 누락, 원격 파일 fetch 실패)은 폼을 그대로 두어요. 입력을 고쳐 같은 form_token으로 재제출하면 됩니다.

5단계: 워크플로 리슨 재개

원래 SSE 스트림이 닫혔다면 Stream Workflow Events로 다시 여는데, 1단계의 workflow_run_id와 실행을 시작한 것과 **같은 user**를 넘겨요. 다른 user면 404가 나요.

재개된 스트림에는 human_input_form_filled(제출 확인) 또는 human_input_form_timeout(폼 만료)이 담기고, 이어서 나머지 노드 이벤트가 완료까지 전달돼요. 일시정지가 없었던 실행처럼요.

include_state_snapshot=true를 추가하면 이미 실행된 노드 상태를 먼저 재생해 줘요. 워크플로에 Human Input 노드가 여러 개 순차로 있다면 기본적으로 일시정지 때마다 스트림이 닫히는데, continue_on_pause=true를 넘기면 전부를 관통하는 스트림 하나를 유지할 수 있어요.

업로드 우선 vs 인라인 원격 URL

파일 입력에는 두 패턴 모두 동작해요.

  • 선업로드 후 upload_file_id 참조 (권장)

    Upload File이 업로드 시점에 파일 크기 제한을 적용하므로, 수신자는 즉시 피드백을 받고 전체 제출을 확정하기 전에 재시도할 수 있어요.

  • transfer_method: remote_url로 인라인 제출

    백엔드가 제출 시점에 파일을 가져와요. 통합은 더 빠르지만, 크기·유형·fetch 실패 어느 하나라도 나면 전체 제출이 거부돼서 수신자가 다른 필드를 처음부터 다시 채워야 해요.

💡 상호작용 폼처럼 수신자 피드백이 필요한 경우엔 선업로드 패턴이 낫습니다. 이 트레이드오프는 통합이 완전히 프로그래밍 방식이고 사람이 다시 입력할 일이 없을 때만 유리해요.

전달 방식 요건

Human Input API는 Human Input 노드의 웹 앱 방식으로 전달되는 폼에서만 동작해요. Email 전용 전달form_token을 노출하지 않습니다.

예시: 파일 첨부 제출

이 예시는 feedback 문단 입력, attachments 파일 목록 입력, 그리고 approve/reject 액션이 있는 폼을 사용해요.

  1. Get Human Input Form을 호출해 폼 정의를 받아요.

    GET /form/human_input/<form_token>
    Authorization: Bearer ***
    

    폼 정의가 돌아옵니다.

    {
      "form_content": "Please review the draft and confirm or request changes.",
      "inputs": [
        {
          "type": "paragraph",
          "output_variable_name": "feedback",
          "default": {
            "type": "constant",
            "selector": [],
            "value": ""
          }
        },
        {
          "type": "file-list",
          "output_variable_name": "attachments",
          "allowed_file_types": [
            "image",
            "document"
          ],
          "allowed_file_extensions": [],
          "allowed_file_upload_methods": [
            "local_file",
            "remote_url"
          ],
          "number_limits": 5
        }
      ],
      "resolved_default_values": {},
      "user_actions": [
        {
          "id": "approve",
          "title": "Approve",
          "button_style": "primary"
        },
        {
          "id": "reject",
          "title": "Request changes",
          "button_style": "default"
        }
      ],
      "expiration_time": 1745510400
    }
    
  2. 로컬 파일마다 Upload File을 호출해요.

    POST /files/upload
    Authorization: Bearer ***
    Content-Type: multipart/form-data
    
    file=<binary>
    user=abc-123
    

    {"id": "1a77f0df-...", ...}가 돌아옵니다.

  3. 수신자의 입력과 선택한 액션으로 Submit Human Input Form을 호출해요.

    POST /form/human_input/<form_token>
    Authorization: Bearer ***
    Content-Type: application/json
    
    {
      "inputs": {
        "feedback": "Looks good to ship",
        "attachments": [
          {"transfer_method": "local_file", "upload_file_id": "1a77f0df-..."}
        ]
      },
      "action": "approve",
      "user": "abc-123"
    }
    

    {}가 돌아오고, 워크플로는 approve 분기를 따라 재개돼요.

  4. Stream Workflow Events로 실행 스트림에 재연결해 완료까지 따라가요. 위 순서의 5단계와 같습니다.

더 알아보기 (Learn more)