用 Ollama 搜索 API 搭建会调用工具的研究助手

用 Ollama 搜索 API 搭建会调用工具的研究助手

作者:Ollama Blog(原文未列个人作者) 原文日期:2025-09-24 来源:Ollama Blog:Web search

Ollama 的 Web Search API 可为模型补充网上资料;配合 Web Fetch 和工具调用,可以把“搜索—读取页面—继续推理”串成一个研究流程。这里整理原文的 REST、Python、JavaScript 和 MCP 示例,并补充数据边界和静态安全注意事项。原文发表时称个人账户有免费搜索额度,订阅可提高限额;这类服务计划与限额可能变化,请以 Ollama 当前页面为准。

流程图:用户问题进入模型,模型调用搜索或抓取工具,工具返回网页片段后写入消息历史继续推理
工具循环概念图(本稿自绘,不代表代码已执行或生产部署)。

先区分搜索与抓取

web_search 接收查询词,返回若干结果;每项通常包含标题、URL 和内容片段。web_fetch 接收单个页面 URL,返回标题、正文与页面链接。REST 接口分别是 https://ollama.com/api/web_search 和 https://ollama.com/api/web_fetch,都需要 Ollama 云端 API 密钥。

原文的搜索响应示意为 {"results":[{"title":"…","url":"…","content":"…"}]};抓取响应示意为 {"title":"…","content":"…","links":["…"]}。这些是字段结构示例,不是固定结果。搜索与抓取都从外部服务取数,返回内容不会因为进入模型上下文就自动变成已核实事实。

REST 调用

先通过 Ollama 账户创建密钥,并由终端或密钥管理器提供 OLLAMA_API_KEY。下面不包含真实密钥;请勿把密钥写进代码仓库、截图或共享配置。

原文建议设置 OLLAMA_API_KEY。为了不在稿件中写入凭据,下面只检查该变量是否已由安全的进程环境提供;真实值应由本地密钥管理器、CI secrets 或服务启动器注入,不要放进源码或命令历史。

: "${OLLAMA_API_KEY:?请先通过安全的密钥管理器注入 OLLAMA_API_KEY}"

这条检查不会创建密钥,也不会显示密钥;变量缺失时会停止。下面的 curl 命令只读取该环境变量。

curl https://ollama.com/api/web_search \
  --header "Authorization: Bearer $OLLAMA_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{"query":"what is ollama?"}'

按页面抓取时,将请求地址换成 /api/web_fetch,JSON 请求体提供目标 URL,例如 {"url":"https://ollama.com"}:

curl --request POST \
  --url https://ollama.com/api/web_fetch \
  --header "Authorization: Bearer $OLLAMA_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{"url":"https://ollama.com"}'

服务响应会给出标题、正文和链接。实际访问的 URL 仍须经过应用侧的白名单与数据政策检查。

Python 与 JavaScript SDK

原文在 2025 年发布时要求安装 ollama>=0.6.0 或 ollama@>=0.6.0。Python 示例使用 web_search()、web_fetch();JavaScript 示例通过 new Ollama() 后调用 webSearch({query}) 和 webFetch({url})。密钥通过环境变量读取:

# Python:先安装 Ollama Python SDK(版本边界见上)
from ollama import web_fetch, web_search

hits = web_search("What is Ollama?")
page = web_fetch("https://ollama.com")
print(hits)  # results: title / url / content
print(page)  # title / content / links
// JavaScript:OLLAMA_API_KEY 由运行环境提供
import { Ollama } from "ollama";

const client = new Ollama();
const hits = await client.webSearch({ query: "What is Ollama?" });
const page = await client.webFetch({ url: "https://ollama.com" });
console.log(hits); // results
console.log(page); // title / content / links

SDK 与 API 的实际参数、默认结果数和限额会随版本或服务调整。原文代码和输出只展示调用形态;本稿未运行上述命令,也未发起线上请求。

把工具调用接成受控循环

原文先用 ollama pull qwen3:4b 获取示例模型,再以 qwen3:4b 为例:先把 web_search 与 web_fetch 注册为可用工具,把用户问题放进消息历史,再请求模型。若响应含工具调用,程序根据函数名找到已登记实现、读取参数、调用 API,并以 role=tool 把结果放回历史;没有新工具调用时,循环结束并返回模型文本。原文还打印 thinking、content、工具参数和部分工具结果,并把回传结果截到约 8,000 个字符,以减轻上下文占用。

原文完整示例:Python 搜索代理循环

下面保留 Ollama Blog 2025-09-24 页面中的完整循环、工具名分派与消息历史回写。该示例展示机制;它本身没有最大轮数、超时、完整参数校验或 URL allowlist,不宜不经加固直接部署。

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)
  if response.message.content:
    print('Content: ', 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]+'...')
        # Result is truncated for limited context lengths
        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

循环的关键步骤是:把模型返回的 assistant 消息写回历史;仅在出现 tool_calls 时分派已登记的函数;再把抓取内容作为 tool 消息回传。原文打印结果摘要前截到 200 个字符,回传历史的结果截到约 8,000 个字符。截断只限制上下文体积,不会核实来源或消除提示注入。

原文示例输出(中文转译)

这是博客在 2025 年展示的一次模型运行与搜索响应,不是本稿实测,也不是当前功能说明。输出中包含模型的 thinking 文本,内容可能不完整或错误,正式结论应回到来源页面核实。

Thinking: 用户在问 Ollama 新引擎是什么,我需要弄清楚他具体指什么。Ollama 是一家开发大型语言模型的公司,因此可能发布了新模型,或者更新了现有引擎……

Tool calls: [ToolCall(function=Function(name='web_search', arguments={'max_results': 3, 'query': 'Ollama new engine'}))]

Result: 搜索结果包含一篇题为“New model scheduling”的页面,日期为 2025 年 9 月 23 日。页面摘录从“Ollama 现在加入了显著改进的模型调度系统……”开始;原文示例在此处也截断了摘录。

Thinking: 用户问的是 Ollama 的新引擎。让我查看搜索结果。第一条结果来自 2025 年 9 月 23 日,介绍新的模型调度系统:改进了内存管理、减少崩溃、提升 GPU 利用率和多 GPU 表现;文中还提及 gemma3、llama4、qwen3 等支持型号……

Content: Ollama 在 2025 年推出两项引擎更新:

1. 增强模型调度(2025 年 9 月 23 日)
   - 更精确地管理内存分配,减少内存不足崩溃并优化 GPU 利用率。
   - 性能示例包含 85.54 tokens/s 与 52.02 tokens/s 的比较,并提到更准确的显存使用报告。
   - 改进多 GPU 支持。
   - 支持型号包括 gemma3、llama4、qwen3、mistral-small3.2 等。

2. 多模态引擎(2025 年 5 月 15 日)
   - 支持 llama4:scout(109B 参数)、gemma3、qwen2.5vl、mistral-small3.1 等视觉模型。
   - 示例任务包括识别多张图像中的动物、根据视频回答位置问题以及扫描文档。

这些更新显示 Ollama 当时在效率、性能和文本/视觉能力上的工作。

以上输出保留了原文示例中的日期、型号和性能数字,但它们属于源文章展示的一次历史模型回答;未由作者逐条验证的回答内容不应被当作官方事实。搜索结果本身也需要逐条核验。

流程可概括为:①把用户问题加入消息;②请求模型,并只开放明确登记的工具;③校验工具名、参数和目标 URL 后再调用;④把有来源标记的结果以工具消息加入历史;⑤达到轮数上限、错误预算或没有工具调用时停止。截短文本只控制上下文大小,不验证内容真伪,也不替代调用次数上限。

原文展示了一次查询“what is ollama’s new engine”的搜索过程,输出由模型组织成关于 2025 年更新的摘要。这只是当时的一次示例输出:模型摘要可能遗漏、误读或拼接搜索结果,不应作为当前版本说明或性能证据;请打开引用的原始页面逐项核实。

原文建议长研究任务预留约 32,000 token 的上下文,并在当时列出 qwen3、gpt-oss,以及 qwen3:480b-cloud、gpt-oss:120b-cloud、deepseek-v3.1-cloud 等云端型号。这个数字和型号清单是 2025 年文章中的建议,不是当前模型排名、能力保证或最低配置要求。仓库现行示例已改用 qwen3,与原文的 qwen3:4b 不同,说明模型名和调用示例应按所用 SDK、运行环境与模型版本复核。

抓取页面与 MCP 客户端

Python、JavaScript 和 cURL 的 web_fetch 示例都以单个 URL 为输入,并返回页面标题、正文与链接。实际研究时可用搜索结果给出的 URL 再抓取详情;也可以处理用户主动提供的网址。两种情形都应保留来源 URL 与抓取时间,避免把摘录误当作完整页面。

原文把搜索和抓取包装成 MCP stdio 服务。下面保留 Cline JSON 与 Codex ~/.codex/config.toml 的完整配置结构。密钥值已替换为显式非密钥占位符;它不是可用凭据,也不是所有客户端都会自动解析的环境变量表达式。真实部署应使用客户端当前支持的 secret store 或受保护的进程环境,并确认其具体插值规则,不要把真实密钥提交到共享配置。

Cline 配置

{
  "mcpServers": {
    "web_search_and_fetch": {
      "type": "stdio",
      "command": "uv",
      "args": ["run", "path/to/web-search-mcp.py"],
      "env": { "OLLAMA_API_KEY": "REPLACE_WITH_LOCAL_SECRET_INJECTION" }
    }
  }
}

Codex 配置

[mcp_servers.web_search]
command = "uv"
args = ["run", "path/to/web-search-mcp.py"]
env = { "OLLAMA_API_KEY" = "REPLACE_WITH_LOCAL_SECRET_INJECTION" }

stdio 只描述客户端与本机子进程之间的连接方式;该 MCP 工具仍会向 Ollama 托管 API 发送查询或目标 URL。配置路径、字段和安全注入方式可能随客户端版本变化,使用前应核对当前客户端文档。Python 仓库快照中的 MCP server 还未加入调用端 URL allowlist;MCP 接入不会自动补上该边界。

安全边界与上线前检查

  • 数据会离开本机:搜索查询、抓取 URL、API 凭据和返回内容涉及云服务处理。不要在未获许可时发送客户数据、内部网址、访问令牌或其他机密;按组织要求确认地区、保留、配额和费用。
  • 核对模型许可:使用 qwen3:4b、qwen3 或替代模型前,查看所选模型对应的模型卡和许可条款,确认允许的用途与分发条件。SDK 仓库的 MIT 软件许可不等于模型权重或服务的使用许可。
  • 网页内容是不可信输入:页面可能含有诱导模型泄密或继续调用工具的文字。把页面当作资料而非指令,保留原始出处,并在关键结论处人工核对。
  • 限制工具能力:原文示例和当前仓库循环都没有明确的最大迭代次数;示例也未展示域名 allowlist、超时、重试预算或 URL/参数校验。生产实现应为轮数、时间、结果大小和错误重试设限;对 web_fetch 校验 scheme、域名及重定向目标,阻止访问本机或私有网络地址,并只允许调用白名单函数。
  • 审慎记录日志:示例会输出模型的 thinking、工具参数和内容片段。日志可能包含用户提问、敏感 URL 或模型内部分析;默认关闭或按最小必要原则脱敏、限权并设置保留期。
  • 保护本地 MCP 进程:仅从可信来源安装依赖和脚本,按最小权限运行,并确认子进程的环境变量、网络能力和文件访问范围。

以上建议是对公开示例的静态安全审阅,不代表完整威胁建模,也不证明代码在特定环境中安全。

版本范围、未执行事项与来源

版本范围:原文发表于 2025-09-24,未显示独立更新日期;示例写明 Python/JavaScript SDK 0.6.0 或更新版本,并使用 qwen3:4b。此次保存的最新可核验主分支代码快照来自 2026-09-29:Python commit 8785556 与 JavaScript commit 2b12fad;两者的 web-search 示例使用 qwen3。它们是有日期的仓库代码快照,不是 SDK release 号,也不保证仍是以后时点的最新提交。请按安装版本核对模型名、参数和服务计划。

本次仅阅读原文、示例源码和文档并做静态审阅;没有安装依赖、运行示例、启动模型或 MCP 服务、执行基准测试、调用数据库/云端 API,也没有使用账户密钥。所有响应、模型行为、SDK 兼容性、上下文表现、费用与限额均未在本稿中复现或验证。

作者与版权:Ollama Blog(原文未署个人作者);原文版权归 Ollama。本文为经授权的中文编译与安全性补充,不替代原文。原文页面没有声明适用于博客正文的开放许可证;关联 Python 与 JavaScript SDK 仓库的 MIT 许可仅覆盖其各自仓库材料,不自动许可博客正文。流程图为本稿自绘,未复用原站图片。原文及示例:Ollama Blog;Ollama Python Library;Ollama JavaScript Library。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容