Python에서 Ollama 웹 검색 API 사용
Python과 Ollama를 활용한 AI 검색 에이전트 구축
Ollama의 Python 라이브러리에 이제 네이티브 Ollama 웹 검색 기능이 추가되었습니다. 몇 줄의 코드만으로 웹의 실시간 정보를 활용하여 로컬 LLM을 강화할 수 있으며, 이는 환각(hallucination)을 줄이고 정확도를 높이는 데 도움이 됩니다.

시작하기
웹 검색을 위한 Ollama Python 라이브러리를 설치하는 방법은 무엇인가요? pip install 'ollama>=0.6.0' 명령을 사용하여 0.6.0 버전 이상을 설치하세요. 이 버전에는 web_search와 web_fetch 함수가 포함되어 있습니다.
pip install 'ollama>=0.6.0'
Python 환경과 패키지를 관리하려면 빠른 Python 패키지 매니저인 uv를 고려해 보거나, venv를 사용하여 가상 환경을 설정하여 종속성 관계를 격리시키는 것이 좋습니다.
Ollama 계정에서 API 키를 생성하여 환경 변수로 설정하세요:
export OLLAMA_API_KEY="your_api_key"
Windows PowerShell의 경우:
$env:OLLAMA_API_KEY = "your_api_key"
기본 웹 검색
Ollama로 웹을 검색하는 가장 간단한 방법입니다:
import ollama
# 간단한 웹 검색
response = ollama.web_search("What is Ollama?")
print(response)
출력 결과:
results = [
{
"title": "Ollama",
"url": "https://ollama.com/",
"content": "Cloud models are now available in Ollama..."
},
{
"title": "What is Ollama? Features, Pricing, and Use Cases",
"url": "https://www.walturn.com/insights/what-is-ollama",
"content": "Our services..."
},
{
"title": "Complete Ollama Guide: Installation, Usage & Code Examples",
"url": "https://collabnix.com/complete-ollama-guide",
"content": "Join our Discord Server..."
}
]
결과 개수 조절
import ollama
# 더 많은 결과 가져오기
response = ollama.web_search("latest AI news", max_results=10)
for result in response.results:
print(f"📌 {result.title}")
print(f" {result.url}")
print(f" {result.content[:100]}...")
print()
전체 페이지 내용 가져오기
Ollama Python에서 web_search와 web_fetch의 차이는 무엇인가요? web_search는 인터넷을 쿼리하여 제목, URL, 스니펫을 포함한 여러 검색 결과를 반환합니다. web_fetch는 특정 URL의 전체 콘텐츠를 가져와 페이지 제목, 마크다운 콘텐츠, 링크를 반환합니다. web_fetch가 반환하는 마크다운 콘텐츠는 추가 처리에 최적입니다. 다른 컨텍스트에서 HTML을 마크다운으로 변환해야 하는 경우, Python으로 HTML을 Markdown으로 변환하는 방법 가이드를 참조하세요.
from ollama import web_fetch
result = web_fetch('https://ollama.com')
print(result)
출력 결과:
WebFetchResponse(
title='Ollama',
content='[Cloud models](https://ollama.com/blog/cloud-models) are now available in Ollama\n\n**Chat & build with open models**\n\n[Download](https://ollama.com/download) [Explore models](https://ollama.com/models)\n\nAvailable for macOS, Windows, and Linux',
links=['https://ollama.com/', 'https://ollama.com/models', 'https://github.com/ollama/ollama']
)
검색과 가져오기 조합
검색을 먼저 수행한 다음, 관련 결과에서 전체 콘텐츠를 가져오는 것이 일반적인 패턴입니다:
from ollama import web_search, web_fetch
# 정보 검색
search_results = web_search("Ollama new features 2025")
# 첫 번째 결과에서 전체 내용 가져오기
if search_results.results:
first_url = search_results.results[0].url
full_content = web_fetch(first_url)
print(f"Title: {full_content.title}")
print(f"Content: {full_content.content[:500]}...")
print(f"Links found: {len(full_content.links)}")
검색 에이전트 구축
Ollama 검색 에이전트에 최적인 Python 모델은 무엇인가요? 강력한 도구 사용(tool-use) 능력을 갖춘 모델이 가장 적합하며, qwen3, gpt-oss, 그리고 qwen3:480b-cloud와 deepseek-v3.1-cloud 같은 클라우드 모델이 이에 해당합니다. 이러한 모델에서 구조화된 출력을 필요로 하는 더 고급적인 사용 사례의 경우, Ollama와 Qwen3를 사용한 구조화 출력 LLM 가이드를 확인해 보세요. 도구나 JSON 모드가 신뢰할 수 있는 페이로드를 반환한 이후에는, Python에서 견고한 LLM 구조화 출력 검증 가이드에서 애플리케이션 측의 파싱, Pydantic 체크, 재시도, 테스트에 대해 다루고 있습니다.
먼저 기능적인 모델을 가져오세요:
ollama pull qwen3:4b
간단한 검색 에이전트
여기에는 언제 검색할지 자율적으로 결정할 수 있는 기본 검색 에이전트가 있습니다:
from ollama import chat, web_fetch, web_search
available_tools = {'web_search': web_search, 'web_fetch': web_fetch}
messages = [{'role': 'user', 'content': "what is ollama's new engine"}]
while True:
response = chat(
model='qwen3:4b',
messages=messages,
tools=[web_search, web_fetch],
think=True
)
if response.message.thinking:
print('🧠 Thinking:', response.message.thinking[:200], '...')
if response.message.content:
print('💬 Response:', response.message.content)
messages.append(response.message)
if response.message.tool_calls:
print('🔧 Tool calls:', response.message.tool_calls)
for tool_call in response.message.tool_calls:
function_to_call = available_tools.get(tool_call.function.name)
if function_to_call:
args = tool_call.function.arguments
result = function_to_call(**args)
print('📥 Result:', str(result)[:200], '...')
# 제한된 컨텍스트 길이에 맞게 결과를 잘라내기
messages.append({
'role': 'tool',
'content': str(result)[:2000 * 4],
'tool_name': tool_call.function.name
})
else:
messages.append({
'role': 'tool',
'content': f'Tool {tool_call.function.name} not found',
'tool_name': tool_call.function.name
})
else:
break
Python에서 대규모 웹 검색 결과를 처리하는 방법은 무엇인가요? 컨텍스트 한계에 맞도록 결과를 잘라내세요. 권장하는 방법은 모델로 전달하기 전에 결과 문자열을 약 8000자(토큰 2000개 × 4자)로 슬라이스하는 것입니다.
에러 처리가 강화된 고급 검색 에이전트
더 나은 에러 처리를 가진 향상된 버전을 살펴보세요:
from ollama import chat, web_fetch, web_search
import json
class SearchAgent:
def __init__(self, model: str = 'qwen3:4b'):
self.model = model
self.tools = {'web_search': web_search, 'web_fetch': web_fetch}
self.messages = []
self.max_iterations = 10
def query(self, question: str) -> str:
self.messages = [{'role': 'user', 'content': question}]
for iteration in range(self.max_iterations):
try:
response = chat(
model=self.model,
messages=self.messages,
tools=[web_search, web_fetch],
think=True
)
except Exception as e:
return f"Error during chat: {e}"
self.messages.append(response.message)
# 도구 호출이 없으면 최종 답변
if not response.message.tool_calls:
return response.message.content or "No response generated"
# 도구 호출 실행
for tool_call in response.message.tool_calls:
result = self._execute_tool(tool_call)
self.messages.append({
'role': 'tool',
'content': result,
'tool_name': tool_call.function.name
})
return "Max iterations reached without final answer"
def _execute_tool(self, tool_call) -> str:
func_name = tool_call.function.name
args = tool_call.function.arguments
if func_name not in self.tools:
return f"Unknown tool: {func_name}"
try:
result = self.tools[func_name](**args)
# 컨텍스트 한계에 맞게 잘라내기
result_str = str(result)
if len(result_str) > 8000:
result_str = result_str[:8000] + "... [truncated]"
return result_str
except Exception as e:
return f"Tool error: {e}"
# 사용법
agent = SearchAgent(model='qwen3:4b')
answer = agent.query("What are the latest features in Ollama?")
print(answer)
비동기(Async) 웹 검색
Ollama Python 웹 검색을 비동기 코드와 함께 사용할 수 있나요? 네, Ollama Python 라이브러리는 비동기 작업을 지원합니다. 비동기 애플리케이션에서 블로킹되지 않는 웹 검색 및 가져오기 작업에 AsyncClient를 사용하세요.
import asyncio
from ollama import AsyncClient
async def async_search():
client = AsyncClient()
# 여러 검색을 병렬로 수행
tasks = [
client.web_search("Ollama features"),
client.web_search("local LLM tools"),
client.web_search("AI search agents"),
]
results = await asyncio.gather(*tasks)
for i, result in enumerate(results):
print(f"Search {i + 1}:")
for r in result.results[:2]:
print(f" - {r.title}")
print()
# 비동기 검색 실행
asyncio.run(async_search())
비동기 검색 에이전트
import asyncio
from ollama import AsyncClient
async def async_research_agent(question: str):
client = AsyncClient()
messages = [{'role': 'user', 'content': question}]
while True:
response = await client.chat(
model='qwen3:4b',
messages=messages,
tools=[client.web_search, client.web_fetch],
)
messages.append(response.message)
if not response.message.tool_calls:
return response.message.content
# 도구 호출을 병렬로 실행
tool_tasks = []
for tool_call in response.message.tool_calls:
if tool_call.function.name == 'web_search':
task = client.web_search(**tool_call.function.arguments)
elif tool_call.function.name == 'web_fetch':
task = client.web_fetch(**tool_call.function.arguments)
else:
continue
tool_tasks.append((tool_call.function.name, task))
# 결과 수집
for tool_name, task in tool_tasks:
result = await task
messages.append({
'role': 'tool',
'content': str(result)[:8000],
'tool_name': tool_name
})
# 실행
answer = asyncio.run(async_research_agent("What's new in Python 3.13?"))
print(answer)
컨텍스트 길이 및 성능
Python 검색 에이전트에 컨텍스트 길이를 어떻게 설정해야 하나요? 적절한 성능을 위해 컨텍스트 길이를 약 32000 토큰으로 설정하세요. web_search와 web_fetch가 수천 개의 토큰을 반환할 수 있으므로, 검색 에이전트는 전체 컨텍스트 길이와 함께 가장 잘 작동합니다.
from ollama import chat, web_search
# 검색 중심 작업에 더 높은 컨텍스트 설정
response = chat(
model='qwen3:4b',
messages=[{'role': 'user', 'content': 'Research the latest AI developments'}],
tools=[web_search],
options={
'num_ctx': 32768, # 32K 컨텍스트
}
)
MCP 서버 통합
Ollama는 모든 MCP 클라이언트에서 웹 검색을 가능하게 하는 Python MCP 서버를 제공합니다. 웹 검색 및 스크레이핑 기능이 포함된 Python으로 MCP 서버를 구축하는 포괄적인 가이드를 위해, Python으로 MCP 서버 구축하기에 대한 자세한 튜토리얼을 확인해 보세요.
Cline 통합
Cline 설정에서 MCP 서버를 구성하세요:
MCP 서버 관리 → MCP 서버 구성 → 추가:
{
"mcpServers": {
"web_search_and_fetch": {
"type": "stdio",
"command": "uv",
"args": ["run", "path/to/web-search-mcp.py"],
"env": { "OLLAMA_API_KEY": "your_api_key_here" }
}
}
}
Codex 통합
~/.codex/config.toml에 추가하세요:
[mcp_servers.web_search]
command = "uv"
args = ["run", "path/to/web-search-mcp.py"]
env = { "OLLAMA_API_KEY" = "your_api_key_here" }
자체 MCP 서버 만들기
#!/usr/bin/env python3
"""Simple MCP server for Ollama web search."""
import os
from mcp.server import Server
from mcp.types import Tool, TextContent
from ollama import web_search, web_fetch
app = Server("ollama-web-search")
@app.tool()
async def search_web(query: str, max_results: int = 5) -> str:
"""Search the web for information."""
results = web_search(query, max_results=max_results)
output = []
for r in results.results:
output.append(f"**{r.title}**\n{r.url}\n{r.content}\n")
return "\n---\n".join(output)
@app.tool()
async def fetch_page(url: str) -> str:
"""Fetch the full content of a web page."""
result = web_fetch(url)
return f"# {result.title}\n\n{result.content}"
if __name__ == "__main__":
app.run()
실용적 예제
이 예제들은 Ollama 웹 검색 API의 실제 응용을 보여줍니다. 이러한 패턴을 확장하여 더 복잡한 시스템을 구축할 수 있습니다. 예를 들어, 검색 결과를 Python으로 PDF 생성하기와 결합하여 연구 보고서를 만들 수 있습니다.
뉴스 요약기
from ollama import chat, web_search
def summarize_news(topic: str) -> str:
# 최신 뉴스 검색
results = web_search(f"{topic} latest news", max_results=5)
# 모델을 위해 검색 결과 포맷팅
news_content = "\n\n".join([
f"**{r.title}**\n{r.content}"
for r in results.results
])
# 모델에게 요약 요청
response = chat(
model='qwen3:4b',
messages=[{
'role': 'user',
'content': f"Summarize these news items about {topic}:\n\n{news_content}"
}]
)
return response.message.content
summary = summarize_news("artificial intelligence")
print(summary)
연구 어시스턴트
from ollama import chat, web_search, web_fetch
from dataclasses import dataclass
@dataclass
class ResearchResult:
question: str
sources: list
answer: str
def research(question: str) -> ResearchResult:
# 관련 정보 검색
search_results = web_search(question, max_results=3)
# 상위 소스에서 전체 내용 가져오기
sources = []
full_content = []
for result in search_results.results[:3]:
try:
page = web_fetch(result.url)
sources.append(result.url)
full_content.append(f"Source: {result.url}\n{page.content[:2000]}")
except:
continue
# 포괄적인 답변 생성
context = "\n\n---\n\n".join(full_content)
response = chat(
model='qwen3:4b',
messages=[{
'role': 'user',
'content': f"""Based on the following sources, answer this question: {question}
Sources:
{context}
Provide a comprehensive answer with citations to the sources."""
}]
)
return ResearchResult(
question=question,
sources=sources,
answer=response.message.content
)
# 사용법
result = research("How does Ollama's new model scheduling work?")
print(f"Question: {result.question}")
print(f"Sources: {result.sources}")
print(f"Answer: {result.answer}")
권장 모델
| 모델 | 파라미터 | 최적 용도 |
|---|---|---|
qwen3:4b |
4B | 빠른 로컬 검색 |
qwen3 |
8B | 범용 에이전트 |
gpt-oss |
다양 | 연구 과제 |
qwen3:480b-cloud |
480B | 복잡한 추론 (클라우드) |
gpt-oss:120b-cloud |
120B | 장문 연구 (클라우드) |
deepseek-v3.1-cloud |
- | 고급 분석 (클라우드) |
모범 사례
- 결과 잘라내기: 항상 웹 결과를 컨텍스트 한도에 맞도록 잘라내기 (~8000자)
- 에러 처리: 네트워크 실패에 대비하여 도구 호출을 try/except로 감싸기
- 율 제한(Rate Limiting): 웹 검색 시 Ollama의 API 율 제한을 준수하기
- 컨텍스트 길이: 검색 에이전트에 ~32000 토큰 사용
- 스케일링을 위한 비동기: 동시 작업을 위해 AsyncClient 사용
- 테스트: 신뢰성을 보장하기 위해 검색 에이전트에 대해 단위 테스트 작성
- Python 기초: 구문 및 일반 패턴에 대한 빠른 참조용으로 Python 치트시트를 비치해 두기