Go에서 Ollama Web Search API 사용하기

발행: (2025년 12월 5일 오후 02:40 GMT+9)
5 min read
원문: Dev.to

Source: Dev.to

Using Ollama Web Search API in Go 커버 이미지

시작하기

Ollama에 웹 검색을 위한 공식 Go 라이브러리가 있나요?
Ollama는 모든 Go HTTP 클라이언트와 함께 사용할 수 있는 웹 검색용 REST API를 제공합니다. 아직 웹 검색을 위한 공식 Go SDK는 없지만, 표준 라이브러리를 사용해 API 호출을 쉽게 구현할 수 있습니다.

  1. Ollama 계정에서 API 키를 생성합니다.
  2. API 키를 환경 변수로 설정합니다.
export OLLAMA_API_KEY="your_api_key"

Windows PowerShell에서는:

$env:OLLAMA_API_KEY = "your_api_key"

Ollama 명령 및 사용법에 대한 포괄적인 참고 자료는 Ollama cheatsheet를 확인하세요.

프로젝트 설정

새 Go 모듈을 생성합니다:

mkdir ollama-search
cd ollama-search
go mod init ollama-search

기본 웹 검색

Go에서 Ollama의 웹 검색 API에 어떻게 인증하나요?
Authorization 헤더에 API 키를 Bearer 토큰으로 설정합니다.

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
)

// Request/Response types for web_search
type WebSearchRequest struct {
	Query      string `json:"query"`
	MaxResults int    `json:"max_results,omitempty"`
}

type WebSearchResult struct {
	Title   string `json:"title"`
	URL     string `json:"url"`
	Content string `json:"content"`
}

type WebSearchResponse struct {
	Results []WebSearchResult `json:"results"`
}

func webSearch(query string, maxResults int) (*WebSearchResponse, error) {
	apiKey := os.Getenv("OLLAMA_API_KEY")
	if apiKey == "" {
		return nil, fmt.Errorf("OLLAMA_API_KEY environment variable not set")
	}

	reqBody := WebSearchRequest{
		Query:      query,
		MaxResults: maxResults,
	}
	jsonData, err := json.Marshal(reqBody)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal request: %w", err)
	}

	req, err := http.NewRequest("POST", "https://ollama.com/api/web_search", bytes.NewBuffer(jsonData))
	if err != nil {
		return nil, fmt.Errorf("failed to create request: %w", err)
	}
	req.Header.Set("Authorization", "Bearer "+apiKey)
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("request failed: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(resp.Body)
		return nil, fmt.Errorf("API error (status %d): %s", resp.StatusCode, string(body))
	}

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("failed to read response: %w", err)
	}

	var searchResp WebSearchResponse
	if err := json.Unmarshal(body, &searchResp); err != nil {
		return nil, fmt.Errorf("failed to unmarshal response: %w", err)
	}
	return &searchResp, nil
}

func truncate(s string, maxLen int) string {
	if len(s) = 5 {
			fmt.Printf("  ... and %d more\n", len(result.Links)-5)
			break
		}
		fmt.Printf("  - %s\n", link)
	}
}

재사용 가능한 클라이언트 패키지

코드를 더 깔끔하게 만들기 위해 재사용 가능한 Ollama 클라이언트 패키지를 생성합니다.

// ollama/client.go
package ollama

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

type Client struct {
	apiKey     string
	httpClient *http.Client
	baseURL    string
}

func NewClient() (*Client, error) {
	apiKey := os.Getenv("OLLAMA_API_KEY")
	if apiKey == "" {
		return nil, fmt.Errorf("OLLAMA_API_KEY environment variable not set")
	}
	return &Client{
		apiKey: apiKey,
		httpClient: &http.Client{
			Timeout: 30 * time.Second,
		},
		baseURL: "https://ollama.com/api",
	}, nil
}

// Generic POST helper
func (c *Client) post(endpoint string, payload interface{}, out interface{}) error {
	jsonData, err := json.Marshal(payload)
	if err != nil {
		return fmt.Errorf("marshal error: %w", err)
	}
	req, err := http.NewRequest("POST", c.baseURL+endpoint, bytes.NewBuffer(jsonData))
	if err != nil {
		return fmt.Errorf("request creation error: %w", err)
	}
	req.Header.Set("Authorization", "Bearer "+c.apiKey)
	req.Header.Set("Content-Type", "application/json")

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return fmt.Errorf("request error: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(resp.Body)
		return fmt.Errorf("API error (status %d): %s", resp.StatusCode, string(body))
	}
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return fmt.Errorf("read error: %w", err)
	}
	if err := json.Unmarshal(body, out); err != nil {
		return fmt.Errorf("unmarshal error: %w", err)
	}
	return nil
}

// WebSearch calls the /web_search endpoint
func (c *Client) WebSearch(query string, maxResults int) (*WebSearchResponse, error) {
	req := WebSearchRequest{
		Query:      query,
		MaxResults: maxResults,
	}
	var resp WebSearchResponse
	if err := c.post("/web_search", req, &resp); err != nil {
		return nil, err
	}
	return &resp, nil
}

// WebFetch calls the /web_fetch endpoint
func (c *Client) WebFetch(url string) (*WebFetchResponse, error) {
	req := WebFetchRequest{URL: url}
	var resp WebFetchResponse
	if err := c.post("/web_fetch", req, &resp); err != nil {
		return nil, err
	}
	return &resp, nil
}

이제 애플리케이션에서 클라이언트를 사용할 수 있습니다:

package main

import (
	"fmt"
	"log"

	"yourmodule/ollama"
)

func main() {
	client, err := ollama.NewClient()
	if err != nil {
		log.Fatalf("Failed to create client: %v", err)
	}

	// Example: web search
	searchRes, err := client.WebSearch("Ollama Go SDK", 3)
	if err != nil {
		log.Fatalf("Search error: %v", err)
	}
	for _, r := range searchRes.Results {
		fmt.Printf("- %s (%s)\n", r.Title, r.URL)
	}

	// Example: fetch a page
	fetchRes, err := client.WebFetch("https://ollama.com")
	if err != nil {
		log.Fatalf("Fetch error: %v", err)
	}
	fmt.Printf("\nFetched title: %s\n", fetchRes.Title)
}
Back to Blog

관련 글

더 보기 »

3계층 Terraform 아키텍처

전제 조건: Terraform ≥ 1.0, S3 버킷, DynamoDB 테이블, KMS 키, VPC, 서브넷, IGW, 라우트 테이블을 생성할 수 있는 권한이 있는 AWS 자격 증명.