Function Calling 설계
메뉴
Moonshot Notes orbit notebook mark
Moonshot NotesAI 도구와 개발 워크플로우 기록하는 공간

AI Backend

Function Calling 설계

LLM이 내부 API를 호출하도록 만들 때 Function Calling을 어떻게 설계해야 하는지 tool boundary, 권한, 검증, 감사 로그, human approval 관점으로 정리합니다.

Function Calling 설계 hero image
Markdown약 1640 tokens

LLM과 내부 API의 경계를 어디에 둘 것인가

이 글에서는 Function Calling을 이용해 LLM과 내부 API를 연결할 때 어떤 경계를 잡아야 하는지 정리합니다.

Function Calling은 모델이 외부 시스템과 상호작용할 수 있게 해줍니다. 사용자의 질문에 답만 하는 것이 아니라, DB에서 데이터를 조회하고, 티켓을 만들고, 문서를 검색하고, 워크플로우를 실행할 수 있습니다.

하지만 여기서 중요한 질문이 생깁니다.

모델에게 어디까지 맡길 것인가?
어떤 API를 tool로 노출할 것인가?
권한 검사는 누가 할 것인가?
실패했을 때 어떻게 되돌릴 것인가?

분석 기준일: 2026-05-12
실습 기준 환경: OpenAI API, FastAPI, PostgreSQL
주요 참고자료: OpenAI Function Calling Docs, Structured Outputs Docs, AWS Idempotency

핵심 요약

  • Function Calling은 모델이 내부 API를 직접 실행하는 것이 아니라, 호출 의도를 구조화해서 백엔드에 전달하는 방식으로 이해해야 한다.
  • 실제 실행 권한은 백엔드 tool executor가 가져야 한다.
  • read-only tool과 mutating tool을 분리해야 한다.
  • 상태 변경 tool에는 idempotency, audit log, human approval이 필요할 수 있다.
  • tool schema는 내부 API 전체를 노출하지 말고 모델에게 필요한 최소 인터페이스만 제공해야 한다.

1. Function Calling을 어떻게 이해할 것인가

Function Calling은 모델이 함수를 “직접 실행”하는 기능으로 이해하면 위험합니다. 더 정확히는 모델이 어떤 함수를 어떤 인자로 호출해야 할지 구조화된 형태로 제안하는 기능입니다.

실제 실행은 백엔드가 해야 합니다.

# 예시입니다.User request→ LLM decides tool call→ Backend validates tool call→ Permission check→ Execute internal API→ Return tool result to model→ Generate final response

모델은 결정 보조자이고, 백엔드는 집행자입니다.

2. Tool Boundary란 무엇인가

Tool Boundary는 모델에게 노출되는 기능의 경계입니다.

나쁜 예:

# 예시입니다.execute_sql(query: string)

이 tool은 너무 강력합니다. 모델이 임의 SQL을 만들 수 있고, 권한과 안전성을 제어하기 어렵습니다.

좋은 예:

# 예시입니다.search_documents(query: string, scope: enum, limit: integer)get_document_summary(document_id: string)create_support_ticket(title: string, description: string, priority: enum)

모델에게 필요한 행동을 작은 도구로 제한해야 합니다.

3. Read Tool과 Write Tool 분리

Tool 유형예시위험도보호 장치
Read문서 검색, 상태 조회낮음~중간권한 필터, rate limit
Write티켓 생성, 이메일 발송중간~높음idempotency, approval
Destructive삭제, 환불, 권한 변경높음기본적으로 노출 금지 또는 강한 승인

초기 Function Calling은 read-only tool부터 시작하는 것이 안전합니다.

4. Tool Schema 설계

문서 검색 tool 예시:

// 예시 JSON 구조입니다.{  "name": "search_documents",  "description": "사용자가 접근 가능한 문서에서 관련 내용을 검색한다.",  "parameters": {    "type": "object",    "properties": {      "query": {        "type": "string",        "description": "검색할 자연어 질의"      },      "scope": {        "type": "string",        "enum": ["official_docs", "papers", "tech_blogs"]      },      "limit": {        "type": "integer",        "minimum": 1,        "maximum": 10      }    },    "required": ["query", "scope", "limit"],    "additionalProperties": false  }}

설계 포인트는 다음과 같습니다.

# 예시입니다.[ ] enum으로 범위를 제한한다.[ ] limit 최댓값을 둔다.[ ] 내부 ID나 권한 조건은 서버가 결정한다.[ ] 사용자의 원문 입력을 그대로 내부 API에 넘기지 않는다.

5. 권한과 인증

권한 검사는 모델이 아니라 서버가 해야 합니다.

# 예시입니다.사용자 A가 질문→ 모델이 search_documents 호출 제안→ 서버가 사용자 A의 문서 권한 확인→ 권한 있는 scope만 검색→ 결과 반환

모델에게 “이 사용자가 접근 가능한 문서만 검색해”라고 말하는 것만으로는 부족합니다. 실제 필터는 백엔드에서 강제해야 합니다.

6. 실행 전 검증과 Human Approval

상태 변경 tool은 실행 전 검증이 필요합니다.

# 예시입니다.LLM tool call 생성→ schema validation→ business rule validation→ permission check→ risk classification→ human approval if needed→ execute

예를 들어 이메일 발송, 티켓 생성, 고객 상태 변경은 사람이 승인해야 할 수 있습니다.

// 예시 JSON 구조입니다.{  "tool": "create_support_ticket",  "arguments": {    "title": "Redis cache issue",    "description": "사용자가 Redis cache miss 문제를 보고했습니다.",    "priority": "medium"  },  "requires_approval": true}

7. 감사 로그와 재현성

Function Calling은 반드시 감사 로그를 남겨야 합니다.

로그 항목이유
user_id누가 요청했는지
tool_name어떤 tool이 호출됐는지
tool_arguments어떤 인자가 사용됐는지
validation_result검증 통과 여부
execution_result실행 결과
trace_id장애 분석
prompt_version재현성
model품질 분석

단, 민감정보는 마스킹해야 합니다.

8. 실패와 rollback

Tool 실행은 실패할 수 있습니다.

실패 유형대응
schema validation 실패모델 재시도 또는 fallback
권한 없음tool 실행 거부
내부 API timeoutretry 또는 사용자 안내
중복 요청idempotency key로 기존 결과 반환
잘못된 상태 변경rollback 또는 보상 트랜잭션

상태 변경 tool은 rollback 계획이 없으면 노출하지 않는 편이 안전합니다.

9. 실무 체크리스트

# 예시입니다.[ ] read tool과 write tool을 분리했는가?[ ] tool schema가 최소 권한 원칙을 따르는가?[ ] enum, max limit 등 입력 제한이 있는가?[ ] 권한 검사를 서버에서 강제하는가?[ ] 상태 변경 tool에 idempotency key가 있는가?[ ] 위험 작업에 human approval이 있는가?[ ] 모든 tool call이 audit log로 남는가?[ ] 실패 시 사용자에게 설명 가능한 응답이 있는가?

실패 사례: 내부 API를 그대로 tool로 공개한 경우

Function Calling에서 자주 보는 실수는 이미 존재하는 backend API를 거의 그대로 tool로 노출하는 것입니다. 예를 들어 POST /tickets, PATCH /users/:id, DELETE /documents/:id 같은 endpoint를 모델이 호출할 수 있게 만들면 구현은 빠릅니다. 하지만 이 API들은 사람 또는 서버가 명시적으로 호출한다는 전제로 설계되어 있습니다. 모델에게 그대로 주면 인자 범위, 권한, 승인, 재시도 의미가 너무 넓습니다.

특히 write API는 idempotency가 없으면 위험합니다. 모델이 timeout을 보고 같은 tool call을 다시 시도했는데 실제로는 첫 요청이 성공했다면 티켓이 두 개 생길 수 있습니다. 사용자에게 확인받아야 하는 작업도 tool description에 "주의해서 호출"이라고 쓰는 것만으로는 충분하지 않습니다. 최종 실행 전 서버가 approval state를 확인해야 합니다.

구현 예시: 모델용 command API 만들기

내부 API를 감싸는 좁은 command를 두면 boundary가 선명해집니다.

type CreateTicketCommand = {  kind: "create_support_ticket";  idempotencyKey: string;  title: string;  summary: string;  priority: "low" | "normal" | "high";  requiresHumanApproval: true;};

이 command는 내부 ticket API보다 의도적으로 작습니다. assignee, internal label, billing field 같은 값은 모델이 고르지 못하게 서버에서 채웁니다. 모델은 "티켓을 만들어야 한다"는 제안을 구조화하고, backend는 권한과 approval을 확인한 뒤 내부 API를 호출합니다.

공식 사실과 설계 해석 분리

공식 문서가 제공하는 사실은 "모델이 structured tool call을 만들 수 있다"는 수준입니다. 하지만 "어떤 내부 API를 tool로 노출할 것인가", "어떤 작업을 approval 뒤로 보낼 것인가", "어떤 field를 서버가 계산할 것인가"는 제품 설계 해석입니다. 이 둘을 섞으면 tool 지원 기능이 곧 운영 안전성이라고 착각하기 쉽습니다.

결정공식 기능제품 설계 책임
schematool input 형식 지정field 최소화와 versioning
executiontool call 수신권한, 승인, idempotency
error실패 응답 전달재시도 가능 여부와 사용자 문구
audit호출 정보 확보 가능누가, 왜, 무엇을 실행했는지 저장

이렇게 분리하면 Function Calling은 모델 기능이 아니라 backend boundary로 다룰 수 있습니다.

10. Q&A

Q1. 내부 API를 그대로 tool로 노출해도 되나요?

권장하지 않습니다. 모델용 tool은 내부 API보다 더 작고 제한적인 인터페이스여야 합니다.

Q2. 모델이 잘못된 tool을 고르면 어떻게 하나요?

서버가 tool call을 검증하고 거부해야 합니다. 모델 판단은 제안일 뿐입니다.

Q3. Function Calling은 Agent와 같은 건가요?

Agent를 구성하는 요소가 될 수 있지만 동일하지는 않습니다. Function Calling은 외부 기능 호출을 구조화하는 인터페이스입니다.

11. 참고자료와 불확실성

참고자료

불확실성

  • Function Calling의 세부 API와 지원 모델은 시점에 따라 달라질 수 있습니다.
  • 실제 tool approval 기준은 조직의 보안·운영 정책에 맞춰야 합니다.

댓글

GitHub 계정으로 로그인하면 댓글을 남길 수 있습니다. 댓글은 GitHub Discussions를 통해 운영됩니다.

TOP