9장. 도구를 쓰는 LLM 과 Agentic Workflow
도구란
공구함의 공구마다 이름표와 쓰는 법이 붙어 있으면, 처음 보는 사람도 알맞은 공구를 고릅니다. LLM 에게 내어 주는 도구도 이름, 하는 일의 설명, 인자의 생김새를 함께 적어 줍니다.
세 카드가 도구 하나를 설명하는 세 부분입니다. 이름(calculate)은 모델이 부를 때 쓰고, 설명은 언제 이 도구를 쓸지 판단하는 데 쓰며, 인자 스키마는 어떤 값을 어떤 꼴로 넘길지 정합니다. 여기서 공구의 이름표가 이름, 쓰는 법 쪽지가 설명입니다.
도구를 적는 꼴
OpenAI 호환 API 에서 도구 하나는 이런 사전입니다. 6장의 Ollama 도 같은 꼴을 받습니다.
| 칸 | 넣는 것 | 예 |
|---|---|---|
type | 늘 "function" | "function" |
function.name | 도구 이름(영문, 밑줄) | "calculate" |
function.description | 언제, 무엇에 쓰는지 | "사칙연산 식을 계산한다" |
function.parameters | 인자의 JSON 스키마 | {"type": "object", "properties": {...}, "required": [...]} |
calculator_tool = {
"type": "function",
"function": {
"name": "calculate",
"description": "사칙연산 식을 계산한다. 숫자 계산이 필요하면 반드시 이 도구를 쓴다.",
"parameters": {
"type": "object",
"properties": {"expression": {"type": "string", "description": "계산할 식. 예: 1234*5678"}},
"required": ["expression"],
},
},
}
print(calculator_tool["function"]["name"], list(calculator_tool["function"]["parameters"]["properties"]))calculate ['expression'] 가 나옵니다. 모델은 이 사전을 읽고 {"expression": "1234*5678"} 같은 인자를 만듭니다.
코드에 나오는 함수
| 코드 | 쉬운 뜻 |
|---|---|
"type": "function" | 이 도구가 함수 꼴이라는 표시다. 늘 이 값을 쓴다 |
"parameters": {"type": "object", ...} | parameters(인자들)는 사전(object, 객체) 한 덩어리로 넘긴다는 뜻이다 |
"properties": {"expression": {...}} | properties(속성들). 사전 안에 들어갈 키와 그 꼴을 적는다. 여기서는 키가 expression(식) 하나다 |
{"type": "string", ...} | 그 값이 string(글자)이라는 뜻이다. 그래서 식을 "1234*5678" 처럼 글자로 받는다 |
"required": ["expression"] | required(꼭 필요한). 빠뜨리면 안 되는 키의 목록이다 |
calculator_tool["function"]["name"] | 사전 안의 사전을 차례로 열어 도구 이름을 꺼낸다 |
list(...["properties"]) | 사전을 목록으로 바꾸면 키만 남는다. 인자 이름의 목록이다 |
이 코드가 뜻하는 것
택배 접수 양식을 떠올려 보세요. 양식 맨 위에 "택배 접수"라는 이름이 있고, 아래에 "무엇을 하는 양식인지" 안내가 있고, "받는 분(글자, 꼭 적기)" 같은 빈칸이 있습니다. 여기서 양식의 이름이 name, 안내문이 description, 빈칸 목록이 parameters 입니다.
| 줄 | 하는 일 | 쉽게 말하면 |
|---|---|---|
"name": "calculate" | 도구 이름을 정한다 | 양식 맨 위의 이름 |
"description": "사칙연산 식을 계산한다. ..." | 언제 쓰는지 적는다 | 양식의 안내문 |
"properties": {"expression": ...} | 빈칸 하나와 그 꼴을 적는다 | "계산할 식" 칸, 글자로 적기 |
"required": ["expression"] | 꼭 채울 칸을 정한다 | 칸 옆의 "필수" 표시 |
print(...) | 이름과 인자 이름을 찍어 본다 | 양식이 바르게 만들어졌는지 훑어본다 |
출력 calculate ['expression'] 은 "calculate 라는 도구에 expression 칸 하나를 채워 달라"는 양식이 만들어졌다는 뜻입니다. 비유와 다른 점은, 양식을 채우는 쪽이 사람이 아니라 모델이라 칸을 빠뜨리거나 이름을 틀리게 적을 수 있다는 것입니다.
빠진 칸 찾아보기
모델이 채운 인자에 꼭 필요한 칸이 다 있는지 required 로 확인해 봅니다. 모델이 보낸 인자는 설명을 위해 지어낸 값입니다.
import json
required = ["expression"] # 도구 설명의 "required" 와 같은 목록
# 모델이 보냈다고 치는 인자 세 가지(설명용으로 지어낸 값)
for raw in ['{"expression": "2+3"}', '{"expr": "2+3"}', '{}']:
args = json.loads(raw)
missing = [k for k in required if k not in args]
print(raw, "→ 빠진 인자:", missing){"expression": "2+3"} → 빠진 인자: []
{"expr": "2+3"} → 빠진 인자: ['expression']
{} → 빠진 인자: ['expression']| 결과 | 읽는 법 |
|---|---|
첫 줄의 [] | 빠진 칸이 없다. 도구를 실행해도 된다 |
둘째 줄의 ['expression'] | 값은 있지만 칸 이름을 expr 로 잘못 적었다. 이름이 다르면 없는 것과 같다 |
셋째 줄의 ['expression'] | 아무 칸도 채우지 않았다 |
빠진 칸이 있으면 도구를 실행하지 않고, "expression 칸이 필요합니다" 같은 오류를 tool 메시지로 돌려줍니다. json.loads 는 다음 절에서 풉니다.
주의할 점
- 도구가 모든 모델에서 되는 것은 아닙니다. 교안을 만든 PC 에서
qwen2.5:3b,qwen2.5:1.5b,llama3.2:1b는 도구를 받았고,gemma3:1b는 "does not support tools" 오류를 냈습니다. 도구를 못 받는 모델은 ReAct 처럼 글로 흉내 냅니다(실습 5). - 도구 이름은 영문과 밑줄로 짓고, 설명은 모델이 읽을 말(한국어도 된다)로 씁니다.