# OpenAI function calling: 60줄 Python으로 만드는 Google 검색 도구

> OpenAI 모델에 Google 검색 도구를 부여하세요: JSON schema, SerpCrypto SERP API에서의 Python 도구 호출 루프, 그리고 Claude용 동일한 schema. KYC 없이.

- URL: https://serpcrypto.com/ko/docs/openai/
- 마지막 업데이트: 2026-10-22
- 발행자: SerpCrypto (https://serpcrypto.com)

`google_search` 함수를 모델에 설명하고, 모델이 요청하는 검색을 실행한 뒤 결과를 되돌려 보냅니다. schema는 순수 JSON Schema이므로 Claude와 다른 도구 호출 모델에도 그대로 적용됩니다.

**빠른 답변 — OpenAI 모델에 웹 검색 도구를 부여하려면 어떻게 하나요?**

`tools` 안에 JSON Schema로 `google_search` 함수를 선언한 뒤 루프를 돌립니다. 모델이 `tool_calls`를 반환하면 `https://serpcrypto.com/api/v1/search`에서 각 검색을 실행하고 결과를 `tool` 메시지로 덧붙여, 모델이 답할 때까지 반복합니다. **SerpCrypto**은 성공한 검색 1건당 크레딧 1개를 청구하며, US$0.30/1K 검색부터 KYC 없이 암호화폐로 결제합니다.

## 도구 schema는 어떻게 생겼나요?

함수 도구에는 이름, 설명, JSON Schema의 parameters가 있습니다. 모델은 이 세 가지만 보므로, 설명에 도구가 무엇을 반환하고 언제 사용해야 하는지 명시해야 합니다. `query`만 필수이며, country와 language는 선택 사항이고 코드에서 기본값은 US English입니다.

*도구 정의 (Chat Completions 형식)*

```json
{
  "type": "function",
  "function": {
    "name": "google_search",
    "description": "Search Google for current information. Returns the top results with title, link and snippet. Use it for facts newer than your training data.",
    "parameters": {
      "type": "object",
      "properties": {
        "query": { "type": "string", "description": "The search query, as a person would type it." },
        "gl": { "type": "string", "description": "Two-letter country code of the results, e.g. us, gb, de." },
        "hl": { "type": "string", "description": "Language code, e.g. en, de, pt-BR." }
      },
      "required": ["query"]
    }
  }
}
```

## 도구 호출 루프는 어떻게 동작하나요?

`tools`로 질문을 보냅니다. 응답에 `tool_calls`이 포함되어 있으면 각각을 실행하고, 어시스턴트 메시지와 호출마다 일치하는 `tool_call_id`을 담은 `tool` 메시지를 하나씩 추가한 뒤 모델을 다시 호출합니다. 응답에 도구 호출이 없으면 그것이 최종 답변입니다.

아래 루프는 세 번의 검색 후에 멈춥니다. 모델이 계속 검색할 때 크레딧을 보호하는 상한이며, 대부분의 사실형 질문은 세 번의 검색으로 답할 수 있습니다.

*search_agent.py*

```python
"""Tool-calling loop: the model asks for searches, this code runs them on SerpCrypto."""
import json
import os

import requests
from openai import OpenAI

client = OpenAI()  # reads OPENAI_API_KEY
MODEL = os.environ["OPENAI_MODEL"]  # any OpenAI chat model with tool calling
API_URL = "https://serpcrypto.com/api/v1/search"

TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "google_search",
            "description": "Search Google for current information. Returns the top results with title, link and snippet.",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {"type": "string", "description": "The search query."},
                    "gl": {"type": "string", "description": "Two-letter country code, e.g. us."},
                    "hl": {"type": "string", "description": "Language code, e.g. en."},
                },
                "required": ["query"],
            },
        },
    }
]


def google_search(query, gl="us", hl="en"):
    r = requests.get(
        API_URL,
        params={"q": query, "gl": gl, "hl": hl},
        headers={"Authorization": "Bearer " + os.environ["SERPCRYPTO_API_KEY"]},
        timeout=90,
    )
    if r.status_code != 200:
        return f"Search failed with HTTP {r.status_code}."
    items = r.json().get("organic_results", [])[:5]
    return "\n\n".join(f"{x['title']}\n{x['link']}\n{x.get('snippet', '')}" for x in items) or "No results."


def ask(question, max_searches=3):
    messages = [{"role": "user", "content": question}]
    for _ in range(max_searches + 1):
        reply = client.chat.completions.create(model=MODEL, messages=messages, tools=TOOLS)
        msg = reply.choices[0].message
        if not msg.tool_calls:
            return msg.content
        messages.append(msg)
        for call in msg.tool_calls:
            args = json.loads(call.function.arguments)
            messages.append({"role": "tool", "tool_call_id": call.id, "content": google_search(**args)})
    return "Stopped: search limit reached."


print(ask("Which countries changed their data protection laws in 2026? Cite sources."))
```

## 같은 스키마가 Claude와 다른 모델에서도 동작하나요?

네, 래퍼만 다릅니다. Claude의 도구 사용은 `name`, `description` 옆에 있는 `input_schema` 아래에 동일한 JSON Schema를 받습니다. 대부분의 다른 도구 호출 API도 파라미터에 JSON Schema를 받으며, 바깥 필드 이름만 달라집니다. 검색 함수 자체는 SerpCrypto endpoint만 호출하므로 그대로 유지됩니다.

*Claude용 동일한 도구 (Messages API)*

```json
{
  "name": "google_search",
  "description": "Search Google for current information. Returns the top results with title, link and snippet.",
  "input_schema": {
    "type": "object",
    "properties": {
      "query": { "type": "string", "description": "The search query." },
      "gl": { "type": "string", "description": "Two-letter country code, e.g. us." },
      "hl": { "type": "string", "description": "Language code, e.g. en." }
    },
    "required": ["query"]
  }
}
```

## 도구는 모델에 무엇을 반환해야 하나요?

링크가 포함된 짧은 텍스트입니다. 제목, 링크, 스니펫이 있는 결과 다섯 개면 보통 모델이 답하고 인용하기에 충분합니다. 전체 JSON을 반환해도 되지만 토큰이 더 들고 모델이 읽어야 할 노이즈가 늘어납니다.

모델이 Google의 요약을 보길 원한다면 AI Overview 텍스트가 있을 때 추가하고, 답변이 개요가 아니라 페이지를 인용할 수 있도록 출처 링크를 유지하세요.

## 검색 비용을 예측 가능하게 유지하려면 어떻게 하나요?

도구 호출을 세세요: 성공한 호출 하나가 크레딧 하나입니다. 루프에서처럼 질문당 검색 횟수를 제한하고, 각 호출을 검색 쿼리와 함께 로그로 남겨 모델이 무엇을 요청하는지 확인하세요. 검색 100,000회 팩에서 요금은 US$0.56/1K 검색이고, 선불 검색 크레딧은 만료되지 않습니다: 사용하지 않은 검색은 사용할 때까지 계정에 남아 있습니다입니다.

오류는 비용이 들지 않습니다: 1 크레딧 = 성공한 검색 요청 1건이며, 지원되는 모든 엔진에서 결과 한 페이지를 반환합니다. 실패한 요청은 과금되지 않습니다.

## 함수 호출 관련 질문

### Chat Completions 대신 Responses API를 사용할 수 있나요?

네. Responses API는 동일한 JSON Schema로 함수 도구를 받으며, 각 도구의 최상위에 `name`, `description`, `parameters`가 있습니다. 검색 함수와 루프의 개념은 달라지지 않습니다.

### 모델 제공사의 내장 웹 검색을 사용하지 않는 이유는 무엇인가요?

내장 검색 도구는 자체적으로 출처와 설정을 선택합니다. SerpCrypto의 함수는 선택한 국가와 언어에 대한 구글 검색 결과를 로그로 남길 수 있는 JSON으로, 검색당 정해진 가격에 제공합니다.

### 모델이 국가를 선택할 수 있나요?

네. `gl`은 도구의 파라미터이므로 모델이 질문에서 설정할 수 있습니다. 예를 들어 영국에 관한 질문이라면 `gb`입니다. 국가를 명시하지 않은 질문을 위해 코드에 기본값을 두세요.

### 검색 API 키를 받으려면 신용카드가 필요한가요?

아니요. SerpCrypto 크레딧은 BTC, USDT, USDC, ETH, SOL, LTC로 결제하며, 신분증도, 셀피도, 서류도 필요 없습니다. 계정 번호로 로그인하며 이메일은 선택 사항입니다.

---

SerpCrypto: SerpCrypto는 개발자와 AI 에이전트를 위한 SERP API로, Google 및 Bing 검색 결과를 JSON으로 반환하며 신분증 업로드 없이 암호화폐로 결제합니다. 선불 검색 크레딧 US$0.30/1K 검색는 만료되지 않습니다. KYC 없이 — 신분증도, 셀피도, 서류도 없습니다. 암호화폐 결제.
