[IT도서리뷰📘]Do it! LLM을 활용한 AI 에이전트 개발 입문(4/10)/ai_message.tool_calls
GPT는 말은 잘하지만, 직접 뭔가를 실행할 순 없다.
펑션 콜링 기능을 쓰려니 코드엔 자연스럽게 tools가 들어가 있다. 펑션 콜링은 사실 툴 콜링이었던 것이다. 알아보기 쉽게 펑션 툴 콜링이라고 했으면 좋았겠지만, 펑션 콜링이라고 부른 것에는 이유가 있지 않을까싶다.
7장은 실행 결과를 잘 봐야 한다. 기존 response.choices[0].message.content에서 ai_response.choices[0].message로 바뀌었기 때문이다. 텍스트뿐만 아니라 GPT가 출력한 전체 메시지 객체 (role, content, function_call, tool_calls 등 포함 가능)가 같이 출력된다. 그렇기에 출력 결과를 보고 어떤 기능이 적용되었는지 확인하는 것이 빠르게 이해하는 것을 돕는다.
사용자 : 도쿄, 서울, 런던, 파리, 베를린 시간 알려줘.
ChatCompletionMessage(content=None, refusal=None, role='assistant', audio=None, function_call=None, tool_calls=
[ChatCompletionMessageToolCall(id='call_MlsmB4TL6z73hK892t7lWytF', function=Function(arguments='{"timezone": "Asia/Tokyo"}', name='get_current_time'), type='function'), ChatCompletionMessageToolCall(id='call_uCJMPXMNUOHBb8FJ5K7R5mIM', function=Function(arguments='{"timezone": "Asia/Seoul"}', name='get_current_time'), type='function'), ChatCompletionMessageToolCall(id='call_xGgnOb0Kud2RiH22MEMMTCYm', function=Function(arguments='{"timezone": "Europe/London"}', name='get_current_time'), type='function'), ChatCompletionMessageToolCall(id='call_QBKTDO4PSLydVbYGw8dBjuwV', function=Function(arguments='{"timezone": "Europe/Paris"}', name='get_current_time'), type='function'), ChatCompletionMessageToolCall(id='call_hHpf4IGhPnKdy7sIFHtcNxiV', function=Function(arguments='{"timezone": "Europe/Berlin"}', name='get_current_time'), type='function')], annotations=[])
2025-05-14 21:46:59 Asia/Tokyo
2025-05-14 21:46:59 Asia/Seoul
2025-05-14 13:46:59 Europe/London
2025-05-14 14:46:59 Europe/Paris
2025-05-14 14:46:59 Europe/Berlin
AI : 현재 시간은 다음과 같습니다:
- 도쿄: 2025년 5월 14일 오후 9시 46분
- 서울: 2025년 5월 14일 오후 9시 46분
- 런던: 2025년 5월 14일 오후 1시 46분
- 파리: 2025년 5월 14일 오후 2시 46분
- 베를린: 2025년 5월 14일 오후 2시 46분
일단 빨간색 표시한 tool_calls와 timezone을 기억하자.
datetime | datetime + pytz(타임존) |
get_current_time(): | get_current_time(timezone: str = 'Asia/Seoul'): |
tools = [ { "type": "function", "function": { "name": "get_current_time", "description": "현재 날짜와 시간을 반환합니다.", } }, ] |
tools = [ { "type": "function", "function": { "name": "get_current_time", "description": "해당 타임존의 날짜와 시간을 반환합니다.", "parameters": { "type": "object", "properties": { 'timezone': { 'type': 'string', 'description': '현재 날짜와 시간을 반환할 타임존을 입력하세요. (예: Asia/Seoul)', }, }, "required": ['timezone'], }, } }, ] |
ai_response = get_ai_response(messages, tools=tools) ai_message = ai_response.choices[0].message tool_calls = ai_message.tool_calls |
import json ai_response = get_ai_response(messages, tools=tools) ai_message = ai_response.choices[0].message tool_calls = ai_message.tool_calls arguments = json.loads(tool_call.function.arguments) |
"content": get_current_time(), | "content": get_current_time(timezone=arguments['timezone']) |
get_current_time 함수를 통해 얻은 시각이 그리니치 표준시인 UTC 기준이라고 판단해 그 시간을 기준으로 뉴욕이 몇 시인지 계산하기 때문입니다. 하지만 19시 9분은 그리니치 표준시가 아닌 서울의 시간이므로 맞지 않는 답변입니다.
pytz 라이브러리로 'Asia/Seoul','America/New_York'과 같은 형식으로 타임존 정보를 입력하면 지역별 시간을 활용할 수 있습니다.
🎯 비유로 정리
함수 호출을 **"택배 보내기"**라고 생각하면:
- 바깥 type: "function"은 “이건 택배 서비스야!”
- 안쪽 parameters.type: "object"는 “보낼 물건은 박스(객체)에 담겨 있어요”
- 그 properties 안의 type들은 박스 안의 물건 각각의 종류를 설명하는 거예요
오키, tool의 역할은 잘 알았다.
서울의 시간대로 다른 나라의 실시간 시간을 알고 싶으면, get_current_time에 그에 대한 요청이 들어가야함도 알았다.
ai_message.tool_calls가 그 요쳥을 정하는 것 같아보인다. gpt에게 물어봤다.
ai_response = get_ai_response(messages, tools=tools)
ai_message = ai_response.choices[0].message
tool_calls = ai_message.tool_calls
arguments = json.loads(tool_call.function.arguments)
ai_message.tool_calls의 처리 과정
🔧 이 "arguments": "{\"timezone\": \"Asia/Seoul\"}"는 GPT(AI)가 자동으로 생성합니다.
💡 어떻게 형성되냐면:
1. 먼저, 당신이 GPT에게 tool들을 줍니다:
tools = [
{
"type": "function",
"function": {
"name": "get_current_time",
"description": "...",
"parameters": {
"type": "object",
"properties": {
"timezone": {
"type": "string",
"description": "타임존 이름 (예: Asia/Seoul)"
}
},
"required": ["timezone"]
}
}
},
...
]
이걸 통해 GPT는 **“내가 사용할 수 있는 함수들”**을 미리 배워요.
즉, GPT 머릿속에 "아, 내가 get_current_time()이라는 툴을 사용할 수 있고, timezone이라는 string 타입 인자를 받아야 하네?" 라는 정보가 들어갑니다.
2. 사용자가 질문하면:
messages = [
{"role": "user", "content": "지금 서울 시간 알려줘"}
]
3. GPT는 내부적으로 툴과 매칭 → tool_calls 생성:
이때 GPT는 자연어를 읽고, 그에 적절한 툴 호출을 구성해요.
결과 예시:
"tool_calls": [
{
"id": "call_xyz123",
"type": "function",
"function": {
"name": "get_current_time",
"arguments": "{\"timezone\": \"Asia/Seoul\"}"
}
}
]
✅ 포인트:
- "arguments"는 GPT가 자동 생성합니다.
- JSON처럼 생겼지만 사실은 문자열입니다. (str)
- 그 이유는 → GPT는 툴 파라미터를 문자열 형태의 JSON으로 넘겨줘야 하기 때문이에요.
즉, 딕셔너리 아님! 문자열임!
4. 그 다음은 당신이 처리:
개발자는 이 문자열을 받아서 실제로 파싱해야 합니다:
arguments = json.loads(tool_call.function.arguments)
# 결과: {"timezone": "Asia/Seoul"} ← 진짜 딕셔너리로 변환됨
🧠 GPT는 어떻게 그걸 정확히 생성할 수 있을까?
GPT는 다음을 바탕으로 arguments를 생성합니다:
- 자연어 질문 ("서울 시간 알려줘")
- tool 정의 (name, parameters 구조 등)
- 사용자가 제공한 example schema (parameters 안의 type, properties, required, description 등)
그래서 tools 정의가 없으면 GPT는 절대 이걸 정확히 생성할 수 없습니다.
👉 따라서 "tools" 파라미터는 필수예요. 그게 있어야 tool_call 생성도 가능합니다.
GPT는 "사용자가 말한 문장을 분석해서 → 어떤 툴을 쓸지 판단하고 → 그에 필요한 인자를 추출해서 → tool_calls에 넣는 방식"을 전반적으로 사전 학습했습니다.
지금보면 느끼는 거지만, 7장까지 정말 촘촘한 코드로 작성되어있다.
코드마다 배울 것이 무조건 하나씩 늘어난다.
그것도 갑자기 지식을 점프하지 않고 지금 배우는 코드에 대한 내용은 이미 전에 다 배우도록 만들어놓았다.
스트림릿도 구조만 배운다면 messages가 담기는 코드를 조금만 변경해서 적용할 수 있다.
그 전에 st.session_state.messages와 ai_response.choices[0].message의 구조적 차이를 알아야하지만^^
하나씩 배우는 게 많은 코드로 성장하는 느낌은 좋지만, 건너뛰면 중요한 내용을 놓치는 구조라서 하나씩 살펴봐야 한다.
3-3 : 스트림릿
7-1 : 스트림릿 + tool
7-2 : 스트림릿 + tool + yifinance(pandas DF 구조 지원)
7-3 : 스트림릿 + tool + yifinance(pandas DF 구조 지원) + 스트림(yield)
7-3도 이미 청크에 대한 얘기를 audio할 때 인지했기 때문에 비교적 쉽게 정보를 받아들일 수 있다.
내가 서평단이기도 하지만, 읽으면 읽을수록 매력적인 책인 것 같다.
* 이 서평은 <이지스퍼블리싱《Do it! LLM을 활용한 AI 에이전트 개발 입문》 서평단>에 선정되어 제공받은 도서를 기반으로 작성된 글입니다.