빌드

거절하는 도구 — 스키마는 약속이지 보장이 아니다

작성: makemind · 2026년 2월 20일

2편의 도구는 인자를 안 받았다. 이번엔 받는다. 그리고 받은 걸 안 믿는다.

스키마

inputSchema: const {
  'type': 'object',
  'properties': {
    'count': {'type': 'integer', 'description': 'How many to admit, 1 or more'},
  },
  'required': ['count'],
},

이걸 붙이면 부르는 쪽이 무엇을 보내야 하는지 안다. 모델이라면 여기 맞춰 인자를 만든다.

그런데 스키마는 보장이 아니다

'type': 'integer' 라고 적었다고 정수가 오는 게 아니다. 스키마는 부르는 쪽에 대한 안내이고, 그 쪽이 안 지킬 수도 있고 못 지킬 수도 있다.

그래서 핸들러가 다시 본다.

handler: (args) async {
  final n = args['count'];
  // The schema says integer; the caller may still send anything.
  if (n is! int || n < 1) {
    return CallToolResult(
      content: [TextContent(text: 'desk.admit: count must be 1 or more')],
      isError: true,
    );
  }
  // And the desk cannot admit people who are not there.
  if (n > waiting) {
    return CallToolResult(
      content: [TextContent(text: 'only $waiting waiting')],
      isError: true,
    );
  }
  waiting -= n;
  return CallToolResult(
    content: [TextContent(text: jsonEncode({'waiting': waiting}))],
  );
},

두 거절은 성질이 다르다

검사가 둘인데 이유가 다르다.

n < 1 — 값 자체가 말이 안 된다. 0명을 들여보내라는 건 언제나 틀렸다. 입력의 문제다.

n > waiting — 값은 멀쩡한데 지금 상태에서 불가능하다. 3명 대기 중에 99명을 들여보낼 수 없다. 하지만 100명이 대기 중이면 99는 정상이다. 상태의 문제다.

이걸 구분해야 하는 이유는 메시지 때문이다.

count must be 1 or more     ← 다시 보내도 똑같이 틀림
only 3 waiting              ← 3 이하로 보내면 됨

isError: true 로 뭉뚱그리면 부르는 쪽이 재시도할지 포기할지 모른다.

이 콘텐츠는 개발자 이상이 필요합니다

로그인 후 플랜을 업그레이드하면 계속 읽을 수 있습니다.

플랜 보기
Twitter