본문 바로가기
C.W.K.
Stream
Lesson 02 of 04 · published

Tool 정의와 호출

~22 min · tools, schema

Level 0Downloader
0 XP0/41 lessons0/11 achievements
0/120 XP to next level120 XP to go0% complete

Schema가 prompt야

Tool description이랑 parameter description은 모델이 보는 prompt의 일부야. 모델이 올바른 tool 고르고 정확한 인자 넘기는지 결정해. "정보 가져오기" 같은 모호한 description을 주면 엉망인 tool call이 돌아와. 반대로 정확한 걸 주면 ("미국 상장 ticker (예: 'AAPL')의 주가를 조회해서 현재 USD 가격을 반환한다") 좋은 게 돌아오고.

여러 tool — 모델이 고르게

Tool을 array로 보낼 수 있어. 그중에 뭘 부를지는 (아예 안 부를 수도 있고) 모델이 정해. 한 turn 안에서 여러 개를 순차로 부르기도 하고 한꺼번에 부르기도 하니까, 양쪽 다 처리해둬.

응답 모양

모델이 tool을 부르기로 하면, 응답 message는 content가 비고 tool_calls array가 채워져서 와. 각 tool call에는 function.name (어떤 tool이냐)이랑 function.arguments가 들어 있어. arguments는 이미 dict로 parsing된 상태야 — Ollama가 알아서 JSON을 풀어주거든. JSON 문자열을 그대로 던지는 OpenAI랑 여기서 갈려.

Code

한 정의에 여러 tool·python
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Current weather for a city. Returns temp (number) and condition (string).",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "City name like 'Tokyo' or 'Seoul'"},
                    "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
                },
                "required": ["city"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "search_files",
            "description": "Search for files matching a glob pattern under a directory.",
            "parameters": {
                "type": "object",
                "properties": {
                    "pattern": {"type": "string", "description": "Glob pattern, e.g. '*.py'"},
                    "directory": {"type": "string", "description": "Directory path; default '.'"},
                },
                "required": ["pattern"],
            },
        },
    },
]
tool_calls 검사하고 dispatch·python
import httpx, json, glob

def get_weather(city: str, unit: str = "celsius") -> str:
    return json.dumps({"city": city, "temp": 22, "unit": unit, "condition": "sunny"})

def search_files(pattern: str, directory: str = ".") -> str:
    matches = glob.glob(f"{directory}/{pattern}")
    return json.dumps({"files": matches[:10], "count": len(matches)})

REGISTRY = {
    "get_weather": get_weather,
    "search_files": search_files,
}

resp = httpx.post(
    "http://localhost:11434/api/chat",
    json={"model": "qwen2.5:7b", "tools": tools, "stream": False,
          "messages": [{"role": "user", "content": "What's the weather in Tokyo?"}]},
    timeout=120.0,
).json()

assistant_msg = resp["message"]
for call in assistant_msg.get("tool_calls", []):
    name = call["function"]["name"]
    args = call["function"]["arguments"]
    print(f"Model wants: {name}({args})")
    if name in REGISTRY:
        result = REGISTRY[name](**args)
        print(f"  -> {result}")

External links

Exercise

Tool 셋 정의: get_time(timezone), calculate(expression), look_up(term). 두 개 순차 필요한 user message 하나 보내. 모델이 만든 tool call 어떤 건지 출력하고 각각 수동 dispatch. 아직 loop 만들지 마 — 구조만 봐.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.