LiteLLM에서 함수 호출(Function Calling) 사용하기
LiteLLM에서 함수 호출(Function Calling) 사용하기
모델에게 '그냥 대답'만 시키는 게 아니라, 외부 도구나 함수를 불러서 실제 일을 시키고 싶을 때가 있어요. 예를 들어 날씨 API를 호출한다거나 DB를 조회하는 작업 말이죠. 이때 모델이 함수를 '호출하겠다'고 결정하는 것, 그리고 그 결과를 다시 모델에 돌려주는 전체 흐름을 LiteLLM에서는 어떻게 다루는지 살펴볼게요. Tools를 쓰는 '도구 호출(Tool Calling)'의 핵심이 바로 이 함수 호출 패턴이에요.
출처: 공식문서
모델이 함수 호출을 지원하는지 확인하기
함수 호출 기능은 모든 모델이 지원하는 게 아니에요. 먼저 litellm.supports_function_calling(model="")로 해당 모델이 함수 호출을 지원하는지 확인할 수 있어요. True면 지원, False면 지원하지 않는 거예요.
assert litellm.supports_function_calling(model="gpt-5.6-luna") == True
assert litellm.supports_function_calling(model="azure/gpt-5.6-terra") == True
assert litellm.supports_function_calling(model="palm/chat-bison") == False
assert litellm.supports_function_calling(model="xai/grok-2-latest") == True
assert litellm.supports_function_calling(model="ollama/llama2") == False
병렬 함수 호출 지원 확인하기
'한 번에 여러 함수를 함께 호출하는 능력'도 모델별로 달라요. litellm.supports_parallel_function_calling(model="")로 확인할 수 있어요. 병렬 함수 호출은 여러 함수 호출을 한 번에 수행하고, 그 결과들을 병렬로 해결할 수 있게 하는 모델의 능력이에요.
assert litellm.supports_parallel_function_calling(model="gpt-5.6-terra") == True
assert litellm.supports_parallel_function_calling(model="gpt-4") == False
병렬 함수 호출 — 전체 흐름
gpt-3.5-turbo-1106를 예로 들어 병렬 함수 호출이 어떻게 돌아가는지 볼게요. 아래 코드는 get_current_weather 함수 하나를 정의하고, 모델이 필요할 때 이 함수를 호출하도록 하는 3단계 흐름이에요.
Step 1: 사용자 질문과 함께 사용 가능한 함수를 모델에 보낸다.
Step 2: 모델 응답을 파싱해서, 모델이 알려준 인자로 get_current_weather를 실행한다.
Step 3: 함수 실행 결과를 다시 모델에 보내, 모델이 최종 답을 내린다.
전체 코드 — gpt-3.5-turbo-1106로 병렬 함수 호출하기
import litellm
import json
# set openai api key
import os
os.environ['OPENAI_API_KEY'] = "" # litellm reads OPENAI_API_KEY from .env and sends the request
# Example dummy function hard coded to return the same weather
# In production, this could be your backend API or an external API
def get_current_weather(location, unit="fahrenheit"):
"""Get the current weather in a given location"""
if "tokyo" in location.lower():
return json.dumps({"location": "Tokyo", "temperature": "10", "unit": "celsius"})
elif "san francisco" in location.lower():
return json.dumps({"location": "San Francisco", "temperature": "72", "unit": "fahrenheit"})
elif "paris" in location.lower():
return json.dumps({"location": "Paris", "temperature": "22", "unit": "celsius"})
else:
return json.dumps({"location": location, "temperature": "unknown"})
def test_parallel_function_call():
try:
# Step 1: send the conversation and available functions to the model
messages = [{"role": "user", "content": "What's the weather like in San Francisco, Tokyo, and Paris?"}]
tools = [
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "Get the current weather in a given location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
},
"required": ["location"],
},
},
}
]
response = litellm.completion(
model="gpt-5.6-luna",
messages=messages,
tools=tools,
tool_choice="auto", # auto is default, but we'll be explicit
)
print("\nFirst LLM Response:\n", response)
response_message = response.choices[0].message
tool_calls = response_message.tool_calls
print("\nLength of tool calls", len(tool_calls))
# Step 2: check if the model wanted to call a function
if tool_calls:
# Step 3: call the function
# Note: the JSON response may not always be valid; be sure to handle errors
available_functions = {
"get_current_weather": get_current_weather,
} # only one function in this example, but you can have multiple
messages.append(response_message) # extend conversation with assistant's reply
# Step 4: send the info for each function call and function response to the model
for tool_call in tool_calls:
function_name = tool_call.function.name
function_to_call = available_functions[function_name]
function_args = json.loads(tool_call.function.arguments)
function_response = function_to_call(
location=function_args.get("location"),
unit=function_args.get("unit"),
)
messages.append(
{
"tool_call_id": tool_call.id,
"role": "tool",
"name": function_name,
"content": function_response,
}
) # extend conversation with function response
second_response = litellm.completion(
model="gpt-5.6-luna",
messages=messages,
) # get a new response from the model where it can see the function response
print("\nSecond LLM response:\n", second_response)
return second_response
except Exception as e:
print(f"Error occurred: {e}")
test_parallel_function_call()
흐름 뜯어보기
1단계 — litellm.completion()에 tools 넘기기
tools 리스트에 함수 스키마(이름·설명·파라미터)를 정의하고, tool_choice="auto"로 넘겨요. auto가 기본값이지만 명시적으로 적어두면 의도가 드러나요. 모델은 응답의 response_message.tool_calls에 호출할 함수와 인자를 담아 돌려줘요.
2단계 — 함수 실행
tool_calls가 비어 있지 않으면, 각 함수 호출의 이름(tool_call.function.name)과 인자(json.loads(tool_call.function.arguments))를 꺼내 실제 함수를 실행해요. 이때 JSON 응답이 항상 유효한 건 아니니 에러 처리를 반드시 고려해야 해요.
3단계 — 결과를 대화에 추가하고 두 번째 요청
함수 실행 결과는 role: "tool" 메시지로 대화에 추가하고, tool_call_id로 어떤 호출의 결과인지 연결해요. 그리고 그 대화를 다시 litellm.completion()에 넘기면, 모델은 함수 결과를 보고 최종 답을 내려요.
더 알아보기
get_supported_openai_params()로 도구 관련 파라미터(tools,tool_choice)가 어떤 공급자에서 지원되는지 확인할 수 있어요.- 도구 호출의 스키마 정의와 제어에 대해 더 알고 싶다면 관련 도구 스키마 문서를 참고해요.