FastAPI 에이전트 템플릿은 작업 소유권이 모든 계층을 관통하기 전까지는 프로덕션 준비가 되지 않았다
요약
Vercel의 FastAPI 기반 OpenAI Agents SDK 템플릿을 활용할 때, 프로덕션 환경에서 필수적인 '작업 소유권(Task ownership)' 관리 전략을 다룹니다. 데이터베이스부터 UI까지 모든 계층에서 일관된 권한 부여와 상태 관리가 이루어져야 함을 강조합니다.
핵심 포인트
- 모든 계층(DB, API, UI)에서 동일한 작업 소유권 및 상태 계약을 유지해야 함
- 브라우저 필드가 아닌 서버 측 인증된 주체를 기반으로 소유권을 관리할 것
- 이벤트 스트리밍 엔드포인트에도 API와 동일한 권한 부여 로직을 적용할 것
- 경합 상태를 방지하기 위해 취소 작업 시 Compare-and-Set 패턴을 사용할 것
Vercel은 2026년 7월 17일에 FastAPI를 사용한 OpenAI Agents SDK 템플릿을 공개했습니다. 템플릿은 설정 작업을 줄여줄 수 있지만, 성공적인 생성(generation)이 보통 문제가 발생하는 프로덕션의 경계선은 아닙니다. 작업 소유권(Task ownership)이 바로 그 경계입니다.
주요 출처: Vercel template, “OpenAI Agents SDK with FastAPI”.
어떤 에이전트 스타터(starter)를 채택하기 전에, 저는 한 가지 수직 테스트(vertical test)를 추가하겠습니다: Alice는 자신의 작업을 생성하고 취소할 수 있어야 합니다; Bob은 설령 작업 ID를 추측하더라도 해당 작업을 읽거나, 스트리밍하거나, 취소할 수 없어야 합니다.
계층 간 계약(cross-layer contract) 명시
UI -> POST /tasks -> ownership row -> worker
UI <- GET /tasks/:id <- authorization <- state
UI <- event stream <- authorization <- events
...
명시적인 상태(states)를 사용하세요:
queued -> running -> succeeded
-> failed
queued|running -> cancelling -> cancelled
데이터베이스, API 응답, 스트림(stream), 그리고 UI는 동일한 작업과 소유자에 대해 일치해야 합니다.
최소 스키마(Minimal schema)
create table tasks (
id text primary key,
owner_id text not null,
...
브라우저가 제공하는 필드로부터 소유권을 유도하지 마세요. 서버에서 인증된 주체(authenticated principal)를 확인하고 작업을 생성할 때 이를 저장하십시오.
FastAPI 권한 부여 접점(authorization seam)
from fastapi import Depends, FastAPI, HTTPException
app = FastAPI()
...
동일한 의존성(dependency)이 이벤트 히스토리와 스트리밍 엔드포인트(endpoints)를 보호해야 합니다. /tasks/{id}/events를 열어둔 채로 GET /tasks/{id}만 보안 조치를 취하는 것은 프롬프트(prompts)와 출력(outputs)을 여전히 유출하게 됩니다.
계층 간 실패 테스트(Cross-layer failure test)
def test_bob_cannot_observe_or_cancel_alices_task(client, alice, bob):
created = client.post("/tasks", headers=alice, json={"prompt": "demo"})
task_id = created.json()["id"]
...
첫 번째 이벤트를 보내기 전에 인증을 수행하는 스트림 전용 테스트를 추가하십시오. 늦은 권한 부여 확인(late authorization check)은 초기 메타데이터를 유출할 수 있습니다.
취소에는 비교 후 설정(compare-and-set)이 필요합니다
두 개의 취소 요청이 발생하거나, 작업 완료와 취소가 경합(racing)하는 상황에서도 불가능한 상태 전이(impossible transitions)가 발생해서는 안 됩니다.
update tasks
set state = 'cancelling', revision = revision + 1
where id = :id
...
업데이트된 행(rows)이 0개라는 것은 "취소가 성공한 척"하는 것이 아니라 "다시 로드하여 결정(reload and decide)"해야 함을 의미합니다. 워커(worker)는 중요한 도구 호출(tool call)을 수행하기 전에 영구적인 취소 상태(durable cancellation state)를 확인해야 합니다.
UI 상태는 계약(contract)의 일부입니다
취소 버튼은 다음과 같이 동작해야 합니다:
queued또는running상태일 때만 표시되어야 합니다.- API가 상태 전이를 수락한 후에는 "취소 중...(Cancelling...)"으로 전환되어야 합니다.
- 최종 이벤트(terminal event)를 기다리는 동안에는 비활성화 상태를 유지해야 합니다.
- 작업이 완료된 경우가 아닌, 전송 실패(transport failure) 시에만 재시도(retry)를 표시해야 합니다.
- 취소 후에는 상태 헤딩(status heading)으로 포커스를 복구해야 합니다.
서버가 cancelling 상태만을 기록했을 때, 낙관적으로 작업을 cancelled라고 표시하지 마십시오.
프로덕션 주의사항 및 롤백(rollback)
제공된 코드 스니펫에는 실제 ID 제공자(identity provider), 큐(queue), 데이터베이스 구현, 속도 제한(rate limits), 샌드박스 정책(sandbox policy), 그리고 비밀 관리(secret management)가 생략되어 있습니다. 템플릿을 평가하기 전에 템플릿 리비전(revision)과 의존성(dependencies)을 고정(pin)하십시오.
롤백 체크리스트:
[ ] 새 작업 생성 비활성화
[ ] 워커 도구 자격 증명(credentials) 취소
[ ] 작업 상태 읽기 전용 허용
...
스타터(starter)는 해피 패스(happy path)가 부팅될 수 있음을 증명합니다. 소유권 슬라이스(ownership slice)는 그보다 더 가치 있는 것을 증명합니다. 즉, 동일한 보안 불변성(security invariant)이 UI, API, 영속성(persistence), 워커(worker), 스트림(stream), 그리고 취소 동작(cancellation behavior) 전반에 걸쳐 유지된다는 점입니다.
귀하의 에이전트 스택 중 어떤 엔드포인트(endpoint)가 소유권 확인(ownership check)을 누락할 가능성이 가장 높습니까: 이벤트(events), 아티팩트(artifacts), 아니면 취소(cancellation)입니까?
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기