AI가 만든 업무 흐름도, 일이 막히는 경우도 확인하기

AI가 만든 업무 흐름도에서 화살표가 끝까지 연결돼 있어도 일이 항상 끝나는 것은 아닙니다. 필요한 정보가 없거나 승인을 받지 못했을 때 어디서 멈추는지도 확인해야 합니다.

이 글에서는 접수부터 보관까지 다섯 단계로 된 가상 업무를 살펴봅니다. 정상 처리 한 건과 수량 누락·승인 대기·처리 실패 세 건을 비교하고, 마지막 단계부터 거꾸로 읽으며 앞 단계에서 필요한 확인이 빠지지 않았는지 점검합니다. 중복 접수를 막고 이전 기록을 보존하는 조건도 확인합니다.

흐름도와 처리 기록은 가상 예제입니다. 로컬 검사는 예제의 규칙만 확인하며 업무 자동화 서비스의 실행 결과를 검증하지 않습니다.

합성 업무 흐름의 접수 검증 초안 승인 보관 5단계, 정상 1건과 입력 대기·승인 대기·처리 실패 3건, 중복 중단, 접수·검증·초안·승인에서 잘린 끝 이벤트 4반례를 구분하는 설명용 도해
사람이 만든 합성 예제의 정상 경로와 중단 경로를 역검사한다. 접수·검증·초안·승인에서 끝난 4반례는 완료로 인정하지 않는다. 대기·실패의 True는 올바른 중단이며 업무 성공을 뜻하지 않는다. 실제 앱·LLM·업무 실행은 미검증이다.

정상 다섯 단계에 필요한 조건 먼저 적기

단계: 1 접수

  • 상태 표식: RECEIVED
  • 들어갈 조건: 요청ID·입력 버전·시도 번호 기록
  • 여기서 확정하면 안 되는 것: 접수됐다는 이유로 수량을 정상값으로 가정

단계: 2 검증

  • 상태 표식: VALIDATED
  • 들어갈 조건: 제품명 있음, 수량은 0보다 큰 정수, 중복 접수 아님
  • 여기서 확정하면 안 되는 것: 숫자 1과 참/거짓을 같은 자료형으로 취급

단계: 3 초안

  • 상태 표식: PROPOSED
  • 들어갈 조건: 검증 통과, 정한 처리 성공
  • 여기서 확정하면 안 되는 것: 초안 생성이 사람의 승인이라고 간주

단계: 4 승인

  • 상태 표식: APPROVED
  • 들어갈 조건: 지정 검토역이 바로 이 입력·초안ID를 승인
  • 여기서 확정하면 안 되는 것: 예전 입력이나 다른 시도의 승인 재사용

단계: 5 보관

  • 상태 표식: ARCHIVED
  • 들어갈 조건: 승인된 결과와 원본·상태 기록 연결
  • 여기서 확정하면 안 되는 것: 검증에서 보관으로 바로 이동

수량 0도 이 연습 정책에서는 입력 대기입니다. 실제 업무에서 0이 유효한 값이라면 정책과 기대값을 함께 바꿔야 합니다. 검토역-A는 합성 역할 이름이며 실제 사람의 승인 기록이 아닙니다. 아래 코드는 이 가상 승인표를 입력으로 읽을 뿐 누구에게 승인을 요청하거나 승인 버튼을 누르지 않습니다.

OpenAI 에이전트 안전 안내는 원치 않는 행동을 줄이기 위한 명확한 정책·예시, 도구 승인, 시험을 안내합니다. 본문은 그 원칙을 작은 상태 검사에 적용한 자체 설계입니다. 특정 업무 플랫폼이 이 상태 이름이나 복구를 자동 제공한다고 주장하지 않습니다.

흐름 원본의 두 가지 문제를 보존하기

다음이 사람이 만든 결함 있는 원본 flow-v1의 전체 연결입니다. 실제 AI 출력이라고 표시하지 않습니다.

flow-v1 연결 목록
RECEIVED -> VALIDATED
VALIDATED -> PROPOSED
PROPOSED -> APPROVED
APPROVED -> ARCHIVED
VALIDATED -> ARCHIVED  [잘못된 승인 생략 경로]

정상 경로만 그린 원본에는 수량 누락, 중복 접수, 처리 실패, 승인 대기 경로가 없습니다. 그리고 마지막 줄은 초안·승인을 생략하는 지름길입니다. 그 줄을 지우고 그림 제목만 바꿔서는 예외 경로가 완성되지 않습니다. 빠진 중단 상태와 재개 조건도 채워야 합니다.

flow-v2 연결 목록
RECEIVED -> VALIDATED
RECEIVED -> WAIT_INPUT       [필수값·수량 형식 불충족]
RECEIVED -> STOP_DUPLICATE   [중복 접수, 자동 재처리 금지]
VALIDATED -> PROPOSED
VALIDATED -> PROCESSING_FAILED  [처리 실패, 승인·보관 금지]
PROPOSED -> APPROVED         [정확한 입력·초안에 대한 합성 승인표 일치]
PROPOSED -> WAIT_APPROVAL    [승인 없음·다른 검토역·다른 입력·다른 초안]
APPROVED -> ARCHIVED

복구 규칙
이전 입력·상태 기록은 그대로 보존한다.
입력 수정: 입력 버전과 시도 번호를 늘린 별도 기록에서 검증부터 다시 수행한다.
처리 재시도: 같은 입력을 유지해도 시도 번호와 초안ID를 새로 부여한다.
새 입력·초안은 그 대상에 대한 승인을 다시 확인한다.
대기·실패 상태에서 보관으로 직접 이동하지 않는다.
완료 검사의 허용 종착: ARCHIVED, WAIT_INPUT, WAIT_APPROVAL, PROCESSING_FAILED, STOP_DUPLICATE.
RECEIVED, VALIDATED, PROPOSED, APPROVED에서 끝난 prefix는 완료로 승인하지 않는다.

이 복구 규칙은 이전 기록을 새 정상 경로에 덧붙이지 않고 별도 시도 기록으로 남기는 방식입니다. 운영 시스템에 실제 재개 버튼이나 자동 재시도를 구현한 것이 아닙니다. 중복을 거절한 경우에는 새 ID를 만들어 몰래 우회하지 말고 이미 접수·보관된 건인지 사람이 확인합니다.

전체 합성 입력 네 건과 기대 경로

[
  {"name":"정상","request_id":"R01","revision":1,"attempt":1,"item":"파란 상자","qty":8,"approval":"해당 입력·초안에 대한 검토역-A 승인표 일치","processing":"성공"},
  {"name":"수량 누락","request_id":"R02","revision":1,"attempt":1,"item":"노란 봉투","qty":null,"approval":"없음","processing":"미수행"},
  {"name":"승인 없음","request_id":"R03","revision":1,"attempt":1,"item":"초록 카드","qty":3,"approval":"없음","processing":"성공"},
  {"name":"처리 실패","request_id":"R04","revision":1,"attempt":1,"item":"보라 표식","qty":2,"approval":"없음","processing":"실패"}
]

입력 해시는 요청ID·입력 버전·제품·수량을 정렬된 JSON으로 표현해 SHA-256을 계산합니다. 시도 번호는 이 입력 해시에서 제외하고 초안ID에 넣습니다. 예를 들어 R01의 첫 초안은 R01:v1:a1입니다. 같은 입력을 재시도한 R01:v1:a2는 입력 해시가 같아도 다른 초안이며 첫 초안의 승인을 자동 재사용하지 않습니다.

입력 정한 기대 경로 도달하면 실패인 상태
R01 정상 RECEIVED, VALIDATED, PROPOSED, APPROVED, ARCHIVED 승인 없이 ARCHIVED
R02 수량 없음 RECEIVED, WAIT_INPUT VALIDATED·PROPOSED·APPROVED·ARCHIVED
R03 승인 없음 RECEIVED, VALIDATED, PROPOSED, WAIT_APPROVAL APPROVED·ARCHIVED
R04 처리 실패 RECEIVED, VALIDATED, PROCESSING_FAILED PROPOSED·APPROVED·ARCHIVED

R02의 null을 0이나 평균 수량으로 채우면 복구가 아닙니다. 담당자가 실제로 확인한 값을 새 입력 버전으로 등록해야 합니다. R04의 처리 실패를 ‘완료’로 바꾸는 것도 실패입니다. 어느 단계에서 왜 멈췄는지 남겨야 재시도 결과와 비교할 수 있습니다.

오른쪽에서 왼쪽으로 확인하는 질문

  1. ARCHIVED에서 출발합니다. 같은 입력 해시·초안ID를 승인한 검토역이 있는가? 바로 앞 상태가 APPROVED인가?
  2. APPROVED에서 출발합니다. 승인 대상이 현재 PROPOSED 결과인가? 초안 생성 전이나 입력 수정 전 승인을 가져온 것은 아닌가?
  3. PROPOSED에서 출발합니다. 입력 검증과 처리가 모두 성공했는가? 처리 실패가 정상 초안으로 연결되지 않았는가?
  4. WAIT_APPROVAL·WAIT_INPUT·PROCESSING_FAILED에서 출발합니다. 이후 승인·보관이 없는가? 필요한 복구 행동과 책임자가 적혀 있는가?
  5. 각 상태에서 입력ID·버전·시도번호·순서번호가 일치하는지 확인합니다. 상태만 같고 다른 입력의 기록이 섞인 것은 아닌가?

화살표 그림만으로 입력 값과 승인 대상을 확인할 수 없으면 표나 상태 기록을 추가해야 합니다. 아래 복사 요청문은 설명의 빈 곳을 찾는 요청이며 실제 업무 접수·승인·재처리 권한을 주지 않습니다.

위 flow-v1, flow-v2 연결 목록과 네 합성 입력만 검토한다.
정상 5단계와 WAIT_INPUT, WAIT_APPROVAL, PROCESSING_FAILED, STOP_DUPLICATE를 구분한다.
각 종착 상태에서 선행 조건을 거꾸로 검사한다.
flow-v1의 빠진 4경로와 VALIDATED->ARCHIVED 승인 생략을 표시한다.
R01~R04의 예상 상태 순서를 한 줄씩 출력하고, 실패 입력을 보관하지 않는다.
완료 검사는 허용 종착 다섯 상태만 인정하고 정상 경로의 끝 이벤트 누락도 거절한다.
원본 입력·흐름·실패 기록을 덮어쓰지 않는다.
입력 수정은 새 버전, 처리 재시도는 새 시도/초안ID로 구분한다.
이전 승인과 새 대상의 일치 여부를 검토하고 없으면 승인 대기로 남긴다.
실제 파일 변경·접수 전송·승인·보관·자동 재시도는 하지 않는다.
확인할 수 없는 항목은 미관찰로 남긴다.

간단한 역검사 코드 실행하기

다음은 경로·입력·승인의 필수 조건을 읽는 Python 3.12 예제입니다. 내부 승인표는 사람이 만든 합성 기준일 뿐 실제 승인 근거가 아닙니다. qty의 불리언을 정수로 통과시키지 않으며 승인 누락·경로 누락도 확인합니다.

normal = ["RECEIVED", "VALIDATED", "PROPOSED", "APPROVED", "ARCHIVED"]
allowed = {
    ("RECEIVED", "VALIDATED"), ("RECEIVED", "WAIT_INPUT"),
    ("RECEIVED", "STOP_DUPLICATE"), ("VALIDATED", "PROPOSED"),
    ("VALIDATED", "PROCESSING_FAILED"), ("PROPOSED", "APPROVED"),
    ("PROPOSED", "WAIT_APPROVAL"), ("APPROVED", "ARCHIVED")
}
complete_terminals = {"ARCHIVED", "WAIT_INPUT", "WAIT_APPROVAL", "PROCESSING_FAILED", "STOP_DUPLICATE"}
def reverse_check(qty, states, matching_approval):
    if not states or states[0] != "RECEIVED": return False
    if states[-1] not in complete_terminals: return False
    if any((a, b) not in allowed for a, b in zip(states, states[1:])):
        return False
    if "VALIDATED" in states and (type(qty) is not int or qty <= 0):
        return False
    if "APPROVED" in states and not matching_approval: return False
    if states[-1] == "ARCHIVED" and states != normal: return False
    return True
cases = [
    ("R01", 8, normal, True),
    ("R02", None, ["RECEIVED", "WAIT_INPUT"], False),
    ("R03", 3, ["RECEIVED", "VALIDATED", "PROPOSED", "WAIT_APPROVAL"], False),
    ("R04", 2, ["RECEIVED", "VALIDATED", "PROCESSING_FAILED"], False),
    ("승인생략", 8, ["RECEIVED", "VALIDATED", "ARCHIVED"], False),
    ("누락이벤트", 8, ["RECEIVED", "VALIDATED", "APPROVED", "ARCHIVED"], True),
    ("중복이벤트", 8, ["RECEIVED", "VALIDATED", "VALIDATED", "PROPOSED", "APPROVED", "ARCHIVED"], True),
    ("끝누락_RECEIVED", 8, normal[:1], True),
    ("끝누락_VALIDATED", 8, normal[:2], True),
    ("끝누락_PROPOSED", 8, normal[:3], True),
    ("끝누락_APPROVED", 8, normal[:4], True)
]
for name, qty, states, approval in cases:
    print(name, reverse_check(qty, states, approval))
R01 True
R02 True
R03 True
R04 True
승인생략 False
누락이벤트 False
중복이벤트 False
끝누락_RECEIVED False
끝누락_VALIDATED False
끝누락_PROPOSED False
끝누락_APPROVED False

이 코드는 완료·중단 결과의 검사입니다. 허용 종착은 ARCHIVED·WAIT_INPUT·WAIT_APPROVAL·PROCESSING_FAILED·STOP_DUPLICATE뿐입니다. RECEIVED·VALIDATED·PROPOSED·APPROVED로 끝난 기록은 아직 진행중이거나 끝 이벤트가 누락된 상태라 이 완료 검사에서 거절합니다. 진행중 관찰이 필요하면 별도 상태로 보존하고 완료 판정과 구분하세요.

True는 이 예제의 경로 계약에 맞다는 뜻입니다. R02·R03·R04의 True를 접수 처리 성공으로 읽지 마세요. 입력 대기·승인 대기·처리 실패가 올바른 위치에서 중단됐다는 판정입니다. 짧은 코드는 matching_approval의 진위를 스스로 확인하지 않습니다. 확장 검증기는 입력 해시·초안ID·검토역을 직접 비교했습니다.

로컬 Python 3.12.14에서 본문 코드와 확장 상태 검증기의 19개 검사를 실행해 모두 통과했습니다. 결함 원본에서는 중단 분기 4개 누락과 승인 생략 경로 1개를 찾았고, 수정본은 고정 연결 계약에 맞았습니다. 중복 요청·수량 누락·불리언 수량·다른 검토역·이전 입력 승인·이전 시도 승인·위조 보관·검증되지 않은 입력·이벤트 누락·중복과 두 복구 경로도 검사했습니다. 또한 정상 경로를 RECEIVED·VALIDATED·PROPOSED·APPROVED에서 잘라 종착으로 표시한 네 반례는 모두 거절했습니다. 실제 AI 호출과 업무 시스템 실행은 0회입니다.

원본·수정본·복구 시도를 따로 보관하기

기록 원본 상태 복구 사본 확인할 기대값
R02 입력 수정 v1/a1, qty=null, WAIT_INPUT v2/a2, qty=3 새 입력 해시, 새 초안ID, 그 대상의 합성 승인표가 있어야 ARCHIVED
R04 처리 재시도 v1/a1, qty=2, PROCESSING_FAILED v1/a2, qty=2 입력 해시 유지, 초안ID 변경, 새 초안에 대한 합성 승인표 필요

검증기는 원본 흐름·수정 흐름을 별도 JSON으로 읽고 각 입력의 사본·해시·초안ID·순서번호를 담은 상태 기록을 작성했습니다. R02의 이전 null과 WAIT_INPUT, R04의 이전 PROCESSING_FAILED는 복구 후에도 남았습니다. 업무 시스템의 저장소나 동시 접수·재시도 잠금까지 구현한 것은 아닙니다.

흐름 역검사·중단 기록
흐름 원본 버전 / 수정 버전 / 변경한 연결:
요청ID / 입력 버전 / 시도번호 / 원본 입력 해시:
초안ID / 검토역 / 승인 대상 해시·초안ID / 승인 시각 또는 미관찰:
상태 순서와 순서번호:
종착 상태 / 정상·대기·실패의 구분:
역검사에서 빠진 선행 조건:
중단한 후속 단계:
복구 담당자 / 승인된 복구 행동:
복구 사본의 버전·시도번호 / 새 관찰:
원본 보존 위치 / 재개 결정:

검사를 통과해도 남는 한계

Python unittest 공식 문서의 테스트 기능으로 이 합성 계약의 반례를 실행했습니다. 테스트 통과는 정한 입력과 상태를 코드가 예상대로 다뤘다는 증거이지 실제 업무 처리의 성공·안전·승인 진위를 증명하는 것은 아닙니다. 운영 시스템에는 실제 권한, 상태 저장, 중복 방지 키, 장애 시 데이터 일관성, 동시 실행과 사용자 취소 정책을 따로 설계해야 합니다.

원문·제안·사람이 고른 승인값의 보관이 필요하면 엑셀 AI 결과 승인대장을 함께 읽으세요. 그 글의 승인 정보와 이 글의 상태 경로를 연결할 수 있지만, 승인 표시가 있다고 중단 조건을 건너뛰거나 예전 승인으로 새 초안을 보관하면 안 됩니다.

작성자 소개