
도구가 왜 필요할까
LLM은 학습한 내용 안에서만 답할 수 있다. 그래서 이런 질문에는 답하지 못한다.
- 지금 몇 시야? → 현재 시각을 모름
- 이 웹페이지에 뭐 있어? → 인터넷에 접속 못 함
- 우리 DB에 이번 달 데이터 몇 건이야? → 내 시스템에 접근 못 함
이 한계를 넘게 해주는 게 도구(Tool)다. 내가 만든 파이썬 함수를 LLM이 필요할 때 불러 쓸 수 있게 해주는 기능이고, OpenAI에서는 Function Calling이라고 부른다.
가장 중요한 사실: LLM은 도구를 직접 실행하지 않는다
LLM은 OpenAI 서버에서 돌고, 내 함수는 내 컴퓨터에 있다. LLM은 내 코드를 볼 수도, 실행할 수도 없다.
LLM이 하는 일은 "이 도구를 이 값으로 실행해줘"라는 요청서를 돌려주는 것까지다. 실제 실행은 내 파이썬 코드가 한다. 그래서 API를 두 번 호출하게 된다.
[1차 호출] 나 → LLM : "지금 몇 시야?" + 도구 목록
LLM → 나 : "get_current_time 실행해줘" (답변은 비어 있음)
[실행] 내 파이썬 코드가 get_current_time() 실행 → "2026-09-28 14:30"
[2차 호출] 나 → LLM : 지금까지 대화 + 도구 실행 결과
LLM → 나 : "지금은 오후 2시 30분입니다."
왜 응답을 확인하고 다시 요청할까
1. 1차 응답에서 tool_calls를 확인하는 이유
LLM이 도구가 필요 없다고 판단하면 바로 답을 준다. 필요하다고 판단하면 답 대신 요청서(tool_calls)를 준다. 어느 쪽인지 확인해야 다음 행동을 정할 수 있다. 도구를 쓸지 말지는 LLM이 스스로 판단한다. "수도가 어디야?"는 바로 답하고, "지금 몇 시야?"는 도구를 요청한다.
2. 실행 결과를 들고 다시 요청하는 이유
LLM은 기억력이 없다. 매 호출이 독립적이라서, 도구 결과를 알려주려면 지금까지의 대화 + 도구 결과를 통째로 다시 보내야 한다. 그래야 LLM이 결과를 읽고 사람이 읽을 수 있는 최종 답을 만든다.
도구 등록에 필요한 3가지
① 실제 함수
평범한 파이썬 함수다.
from datetime import datetime
def get_current_time():
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
② 도구 설명서 (JSON 스키마)
LLM은 코드를 볼 수 없으니, 이 함수가 뭔지 글로 설명해줘야 한다.
tools = [
{
"type": "function",
"function": {
"name": "get_current_time",
"description": "현재 날짜와 시각을 알려준다.",
"parameters": {
"type": "object",
"properties": {}
}
}
}
]
| 항목 | 역할 |
|---|---|
| name | LLM이 요청서에 적을 도구 이름 |
| description | LLM이 도구를 고르는 유일한 근거. 대충 쓰면 엉뚱할 때 쓰거나 안 씀 |
| parameters | 도구에 넘길 값의 이름·타입·설명. LLM이 여기에 맞춰 값을 채워 보냄 |
③ 이름 → 함수 연결표
LLM은 "get_current_time"이라는 문자열로 요청한다. 이 문자열을 실제 함수와 연결해줘야 실행할 수 있다.
available_functions = {
"get_current_time": get_current_time,
}
전체 흐름 코드
import json
from openai import OpenAI
client = OpenAI()
messages = [{"role": "user", "content": "지금 몇 시야?"}]
# 1차 호출: 도구 목록과 함께 질문
response = client.chat.completions.create(
model="gpt-4o", messages=messages, tools=tools
)
msg = response.choices[0].message
# 도구 요청이 있으면 실행
if msg.tool_calls:
messages.append(msg) # LLM의 요청서도 대화 기록에 남김
for call in msg.tool_calls:
func = available_functions[call.function.name]
args = json.loads(call.function.arguments)
result = func(**args)
messages.append({
"role": "tool",
"tool_call_id": call.id, # 어느 요청에 대한 결과인지 짝 맞추기
"content": str(result)
})
# 2차 호출: 결과를 보고 최종 답변
response = client.chat.completions.create(
model="gpt-4o", messages=messages, tools=tools
)
msg = response.choices[0].message
print(msg.content)
자주 하는 실수
- 1차 응답만 출력하고 끝냄: 도구를 요청한 응답은 content가 None이다. 실행하고 다시 호출해야 답이 나온다.
- LLM의 요청서(msg)를 기록에 안 넣음: tool 메시지만 넣으면 짝이 안 맞아 에러가 난다.
- tool_call_id 누락: 어떤 요청의 결과인지 알 수 없어 에러가 난다.
- description을 대충 씀: LLM이 도구를 제대로 고르지 못한다.
정리
- 도구 = LLM이 요청하고, 내 코드가 실행하는 함수
- 흐름 = 1차 호출(요청서 받기) → 실행 → 2차 호출(결과 주고 답 받기)
- 등록 = 함수 + 설명서 + 연결표
이 한 바퀴가 "AI 에이전트"의 가장 기본 단위다. 여기서 도구를 늘리고, 이 과정을 여러 번 반복하게 만들면 에이전트가 된다.

'AI' 카테고리의 다른 글
| 태태코딩 - SelfAttetnion, densevector에 대하여 (0) | 2026.09.26 |
|---|---|
| 태태개발일지 - LLM(Prompting) (1) | 2026.05.17 |
| 태태개발일지 - 클러스터링 (0) | 2026.05.17 |
| 태태개발일지 - Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks 리뷰 (0) | 2026.05.17 |
| 태태개발일지 - lang smith 분석법 (0) | 2026.05.08 |