在 Python 中使用 Ollama Web Search API

使用 Python 和 Ollama 构建 AI 搜索代理

目录

Ollama 的 Python 库现在包含原生的 OLlama 网络搜索 功能。只需几行代码,你就可以使用网络上的实时信息增强本地 LLM,从而减少幻觉并提高准确性。

数字空间

入门

如何安装 Ollama 的 Python 库进行网络搜索? 使用 pip install 'ollama>=0.6.0' 安装 0.6.0 或更高版本。此版本包含 web_searchweb_fetch 函数。

pip install 'ollama>=0.6.0'

在管理 Python 环境和包时,可以考虑使用 uv,一个快速的 Python 包管理器,或使用 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("Ollama 是什么?")
print(response)

输出:

results = [
    {
        "title": "Ollama",
        "url": "https://ollama.com/",
        "content": "Ollama 现在提供云模型。.."
    },
    {
        "title": "Ollama 是什么?功能、定价和使用案例",
        "url": "https://www.walturn.com/insights/what-is-ollama",
        "content": "我们的服务。.."
    },
    {
        "title": "Ollama 完整指南:安装、使用和代码示例",
        "url": "https://collabnix.com/complete-ollama-guide",
        "content": "加入我们的 Discord 服务器。.."
    }
]

控制结果数量

import ollama

# 获取更多结果
response = ollama.web_search("最新的 AI 新闻", 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 获取完整内容,返回页面标题、Markdown 内容和链接。web_fetch 返回的 Markdown 内容非常适合进一步处理——如果你需要在其他上下文中将 HTML 转换为 Markdown,请参阅我们的指南:使用 Python 将 HTML 转换为 Markdown

from ollama import web_fetch

result = web_fetch('https://ollama.com')
print(result)

输出:

WebFetchResponse(
    title='Ollama',
    content='[云模型](https://ollama.com/blog/cloud-models) 现在在 Ollama 中可用\n\n**使用开放模型进行聊天和构建**\n\n[下载](https://ollama.com/download) [探索模型](https://ollama.com/models)\n\n适用于 macOS、Windows 和 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 2025 新功能")

# 从第一个结果获取完整内容
if search_results.results:
    first_url = search_results.results[0].url
    full_content = web_fetch(first_url)
    
    print(f"标题: {full_content.title}")
    print(f"内容: {full_content.content[:500]}...")
    print(f"找到的链接: {len(full_content.links)}")

构建搜索代理

哪些 Python 模型最适合 Ollama 搜索代理? 具有强大工具使用能力的模型效果最佳,包括 qwen3gpt-oss 以及云模型如 qwen3:480b-clouddeepseek-v3.1-cloud。对于需要这些模型生成结构化输出的更高级用例,请查看我们的指南:使用 Ollama 和 Qwen3 的结构化输出 LLM

首先,拉取一个功能强大的模型:

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': "Ollama 的新引擎是什么"}]

while True:
    response = chat(
        model='qwen3:4b',
        messages=messages,
        tools=[web_search, web_fetch],
        think=True
    )
    
    if response.message.thinking:
        print('🧠 思考:', response.message.thinking[:200], '...')
    
    if response.message.content:
        print('💬 回应:', response.message.content)
    
    messages.append(response.message)
    
    if response.message.tool_calls:
        print('🔧 工具调用:', 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('📥 结果:', 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_call.function.name}', 
                    '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"聊天时发生错误: {e}"
            
            self.messages.append(response.message)
            
            # 如果没有工具调用,我们已经有了最终答案
            if not response.message.tool_calls:
                return response.message.content or "未生成响应"
            
            # 执行工具调用
            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 "达到最大迭代次数而没有最终答案"
    
    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"未知工具: {func_name}"
        
        try:
            result = self.tools[func_name](**args)
            # 截断以适应上下文限制
            result_str = str(result)
            if len(result_str) > 8000:
                result_str = result_str[:8000] + "... [已截断]"
            return result_str
        except Exception as e:
            return f"工具错误: {e}"

# 使用
agent = SearchAgent(model='qwen3:4b')
answer = agent.query("Ollama 的最新功能是什么?")
print(answer)

异步网络搜索

能否在 Python 中使用 Ollama 的异步网络搜索? 是的,Ollama 的 Python 库支持异步操作。在异步应用中使用 AsyncClient 进行非阻塞的网络搜索和获取操作。对于无服务器环境中 Python 与其他语言的性能比较,请参阅我们的分析:AWS Lambda 在 JavaScript、Python 和 Golang 中的性能

import asyncio
from ollama import AsyncClient

async def async_search():
    client = AsyncClient()
    
    # 并发执行多个搜索
    tasks = [
        client.web_search("Ollama 功能"),
        client.web_search("本地 LLM 工具"),
        client.web_search("AI 搜索代理"),
    ]
    
    results = await asyncio.gather(*tasks)
    
    for i, result in enumerate(results):
        print(f"搜索 {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("Python 3.13 有什么新功能?"))
print(answer)

上下文长度和性能

Python 搜索代理应设置什么上下文长度? 为了合理性能,将上下文长度设置为大约 32000 个标记。搜索代理在使用完整上下文长度时效果最佳,因为 web_searchweb_fetch 可以返回数千个标记。

from ollama import chat, web_search

# 为搜索密集型任务设置更高的上下文
response = chat(
    model='qwen3:4b',
    messages=[{'role': 'user', 'content': '研究最新的 AI 发展'}],
    tools=[web_search],
    options={
        'num_ctx': 32768,  # 32K 上下文
    }
)

MCP 服务器集成

Ollama 提供了一个 Python MCP 服务器,可以在任何 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
"""用于 Ollama 网络搜索的简单 MCP 服务器。"""

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:
    """搜索网络信息。"""
    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:
    """获取网页的完整内容。"""
    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} 最新新闻", 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"总结这些关于 {topic} 的新闻条目:\n\n{news_content}"
        }]
    )
    
    return response.message.content

summary = summarize_news("人工智能")
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"来源: {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"""基于以下来源,回答这个问题: {question}

来源:
{context}

请提供一个包含来源引用的综合答案。"""
        }]
    )
    
    return ResearchResult(
        question=question,
        sources=sources,
        answer=response.message.content
    )

# 使用
result = research("Ollama 的新模型调度是如何工作的?")
print(f"问题: {result.question}")
print(f"来源: {result.sources}")
print(f"答案: {result.answer}")

推荐模型

模型 参数 最适合
qwen3:4b 4B 快速本地搜索
qwen3 8B 通用代理
gpt-oss 各种 研究任务
qwen3:480b-cloud 480B 复杂推理(云)
gpt-oss:120b-cloud 120B 长文研究(云)
deepseek-v3.1-cloud - 高级分析(云)

最佳实践

  1. 截断结果:始终截断网络搜索结果以适应上下文限制(约 8000 个字符)
  2. 错误处理:使用 try/except 包裹工具调用以处理网络故障
  3. 速率限制:遵守 Ollama 的网络搜索 API 速率限制
  4. 上下文长度:使用约 32000 个标记的上下文长度进行搜索代理
  5. 异步扩展:使用 AsyncClient 进行并发操作
  6. 测试:为搜索代理编写 单元测试 以确保可靠性
  7. Python 基础:随身携带 Python 快速参考 以便快速查阅语法和常见模式

有用的链接