Go에서 Ollama Web Search API 사용하기
Source: Dev.to

시작하기
Ollama에 웹 검색을 위한 공식 Go 라이브러리가 있나요?
Ollama는 모든 Go HTTP 클라이언트와 함께 사용할 수 있는 웹 검색용 REST API를 제공합니다. 아직 웹 검색을 위한 공식 Go SDK는 없지만, 표준 라이브러리를 사용해 API 호출을 쉽게 구현할 수 있습니다.
- Ollama 계정에서 API 키를 생성합니다.
- 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)
}