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}")
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.