당신의 API 다음 소비자는 LLM입니다. LLM은 명세서의 모든 모호함을 찾아낼 것입니다.
요약
LLM 기반 에이전트가 API를 호출하는 환경에서는 인간 개발자와 달리 모호함을 참지 못하고 잘못된 값을 생성하거나 무한 루프를 돌 수 있습니다. 따라서 에이전트가 안정적으로 동작할 수 있도록 명세(spec)를 더욱 상세하고 의미론적으로 작성해야 합니다.
핵심 포인트
- 모든 필드와 파라미터에 완전한 문장 형태의 의미론적 설명 추가
- 에이전트의 오작동을 방지하기 위한 Idempotency-Key 헤더 필수 적용
- 파괴적인 작업에 대해 dry_run 옵션을 기본적으로 제공
- 열거형(enums) 사용 시 각 상태의 의미와 전환 규칙을 명시
대부분의 API 명세(spec)는 문서를 주의 깊게 읽고, 문맥에서 의도를 추론하며, 위험해 보이는 부분에서 잠시 멈출 줄 아는 사람, 즉 인간 개발자를 위해 작성되었습니다.
에이전트형 클라이언트(Agentic clients)는 그 중 어느 것도 하지 않습니다. 만약 당신의 명세가 사려 깊은 인간 독자를 가정한다면, LLM 기반 에이전트는 그 모호함을 찾아내어 곧장 실행해 버릴 것입니다. 그것도 400번이나, 루프(loop)를 돌며, 망설임 없이 말이죠.
저는 지난 분기에 에이전트 통합 과정에서 에이전트가 제어 불능의 루프에 빠져 DELETE /projects/{id} 엔드포인트를 400번 호출하는 상황을 겪으며 이를 뼈아프게 배웠습니다. 여기 기계 호출자(machine callers)가 API를 안정적으로 사용할 수 있도록, 코드가 아닌 '명세(spec)'에서 제가 변경한 내용이 있습니다.
호출자는 더 이상 사람이 아닙니다
저는 10년 동안 인간을 위한 API 문서를 작성하며 시간을 보냈습니다. id라는 필드는 괜찮았습니다. 어떤 개발자라도 curl 예시 하나를 따라 해보면 형식을 파악할 수 있었기 때문입니다.
하지만 에이전트 앞에 동일한 필드를 두면, 처음 10번의 호출 내에 세 가지 서로 다른 환각(hallucination) 형태가 나타납니다. UUID, 정수(integers), 혹은 모델이 리소스 이름으로부터 추론한 이메일 주소 같은 것들 말이죠. 호출자는 추측하는 것에 대해 부끄러움을 느끼지 않는 통계적 패턴 매처(statistical pattern matcher)입니다.
그래서 저는 이제 모든 파라미터가 설명이 빈약할 경우 자신 있게 값을 지어낼 무언가에 의해 읽힐 것이라고 가정합니다. 이러한 가정은 페이지에 담기는 내용을 재구성합니다.
설명(Description)이 계약의 전부를 담습니다
제가 적용한 가장 큰 개선 사항은 모든 필드, 파라미터, 그리고 작업(operation)에 대해 하나의 완전한 문장으로 된 의미론적 설명(semantic description)을 추가한 것입니다.
쓸모없는 예:
customer_id: string
사용 가능한 예:
customer_id: >
Stripe 고객 ID, 형식은 cus_XXXX, 대소문자 구분,
접두사 뒤에 14-18자; /customers.list를 통해 획득할 것,
...
"절대 조작하지 말 것"이라는 부분은 단순히 보여주기식(theater)이 아닙니다. 에이전트는 해당 지침을 읽고 예상보다 더 자주 이를 준수합니다. 특히 설명에서 값의 상위 소스(upstream source)를 명시할 때 더욱 그렇습니다.
열거형(enums)도 같은 원칙이 적용됩니다. 단순히 ["active", "pending", "cancelled"]를 나열하는 것으로 끝나지 마세요. 각 상태가 무엇을 의미하는지, 그리고 어떤 전환(transition)이 합법적인지를 설명해야 합니다. 모델은 당신이 말로 설명해 주면 올바른 값으로 라우팅합니다.
이제 Idempotency는 선택 사항이 아닙니다
사람 고객들은 한 번, 어쩌면 두 번 재시도한 후 담당자에게 에스컬레이션(escalate)합니다. 하지만 에이전트들은 공격적으로 재시도하며, 성공으로 간주했어야 할 모호한 응답에 대해서도 자주 그렇습니다.
저는 이제 모든 non-GET 엔드포인트에서 Idempotency-Key 헤더를 요구하고, 이 키가 없는 요청은 거부합니다. 서버는 첫 번째 응답을 24시간 동안 저장했다가 중복된 요청이 오면 이를 재전송(replay)합니다.
이것은 에이전트 기능이 아닙니다. 일종의 자기 방어 메커니즘입니다. 이것 없이는, 단 한 번 잘못 읽힌 502 오류가 세 건의 중복 청구와 환불 티켓으로 이어질 수 있습니다.
파괴적인 작업에는 기본적으로 Dry-run을 적용합니다
모든 파괴적(destructive) 작업은 ?dry_run=true를 받습니다. 응답 형태는 실제 호출과 동일하지만, `
{
"error_code": "payment.card_declined.insufficient_funds",
"category": "permanent",
...
suggested_fix는 에이전트에게 무엇이 잘못되었는지 알려줍니다. 하지만 실제로 비용을 절감해 주는 필드는 category입니다. 클라이언트는 특정 코드를 인식하지 못할 때 이 필드를 기준으로 분기 처리를 합니다. HTTP 상태 코드(HTTP status)는 도움이 되지 않습니다. 400은 잘못된 페이로드(payload)일 수도 있고 카드 거절일 수도 있으며, 500은 재시도 시 해결될 수도 있고 다음 47번의 시도 동안 동일하게 실패할 수도 있습니다.
여덟 개의 폐쇄형 카테고리(closed categories)가 모든 것을 다룹니다:
| category | 에이전트가 수행해야 할 작업 |
|---|---|
auth_required | 자격 증명(credentials) 갱신, 1회 재시도 |
| ... |
이 방식이 유지되려면 두 가지 규칙이 필요합니다. 첫째, error_code 문자열은 한 번 게시되면 고정되어야 합니다(사용 중단(deprecate)은 가능하지만, 이름을 변경해서는 안 됩니다). 둘째, 기계가 실행 가능한 상세 정보(machine-actionable detail)는 구조화된 details 객체에 담겨야 하며, 절대 산문(prose) 형태로 제공되어서는 안 됩니다.
기능(capabilities)을 발견 가능하게 만들기
에이전트는 당신의 문서 사이트를 브라우징하지 않습니다. 에이전트는 시스템 프롬프트(system prompt)가 가리키는 곳을 로드합니다.
- 저는 사용 가능한 작업(operations), 호출 주체에 대한 현재 속도 제한(rate limits), 호출당 비용을 반환하는
/_capabilities엔드포인트를 노출합니다. 이를 먼저 확인하는 에이전트는 잘못된 호출을 극적으로 줄입니다. operationId값은 동사_명사(list_projects,archive_project) 형태를 따릅니다. 이것이 모델이 도구 목록(tool list)에서 실제로 보게 되는 이름입니다.- 모든 응답은 문서화된 계약(contract)으로서
X-RateLimit-Remaining및X-RateLimit-Reset을 부수적인 헤더가 아닌 필수 항목으로 포함합니다. 에이전트가 남은 호출 횟수가 4회임을 확인할 수 있다면, 스스로 속도를 조절(back off)합니다. 확인할 수 없다면, 조절하지 못합니다.
에이전트 식별자별로 세 가지 숫자 주시하기
모든 요청에는 필수적으로 X-Agent-ID 헤더가 포함되며, 저는 식별자별로 다음 항목을 기록합니다: 드라이 런(dry-run) 비율, 확인 토큰(confirmation-token) 소모율, 그리고 재시도 횟수(retry count).
건강한 에이전트 통합은 탐색(exploration) 단계에서 30~60%의 드라이 런을 실행하고, 안정 상태(steady state)에서는 10% 미만으로 떨어지며, 확인의 두 번째 단계에서 거의 실패하지 않습니다. 이 범위를 벗어나는 모든 것은 장애(incident)로 이어지기 전에 면밀히 살펴봐야 합니다.
불편한 요약
이 중 어느 것도 생소한 엔지니어링이 아닙니다. 멱등성 키 (Idempotency keys), 드라이 런 (dry runs), 구조화된 에러 (structured errors) — 우리는 이것들을 수년 동안 알고 있었습니다. 변한 것은, 우리의 명세서(spec) 간극을 메워주던 관대하고 문맥을 파악하는 인간 독자가 사라졌다는 점입니다.
이제 명세서가 인터페이스 그 자체입니다. 독자가 명세서에 적힌 그대로 정확히 수행할 것이라고 가정하고 작성하십시오. 왜냐하면 이 독자는 실제로 그렇게 할 것이기 때문입니다.
저는 spec-coding.dev에서 명세서 우선 전달 (spec-first delivery), API 계약 (API contracts), 그리고 AI 지원 엔지니어링 (AI-assisted engineering)에 대해 글을 씁니다. 이 가이드의 전체 버전 (에이전트 클라이언트 (agentic clients)를 위한 버전 관리 및 폐기 패턴 포함)은 spec-coding.dev/blog/designing-api-specs-for-agentic-clients에서 확인하실 수 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기