网页搜索 (Keenable)
直接在你的代码里搜索互联网、读取网页——用的还是调用模型的那把密钥。有两种方式:通过 /v1/chat/completions 当作普通模型调用,或者用返回纯 JSON 的专用接口。
价格
每次请求 0.005 美元,也就是每 1000 次请求 5 美元。
按调用计费:一次调用就是一次请求,无论返回多少条结果。找到 50 个来源与找到 1 个来源,价格完全一样。
请求失败不计费——无论是搜索本身出错,还是参数写错。
| 情况 | 计为 |
|---|---|
| 返回 1 条结果的搜索 | 1 次请求 |
| 返回 50 条结果的搜索 | 1 次请求 |
| 读取一个网页 | 1 次请求 |
| 任何类型的错误 | 0 |
方式一 —— 当作模型
在 Cursor、Claude Code、OpenCode 以及任何 OpenAI 客户端里都能直接用,不需要改动任何配置:选择模型即可。
模型:
| 模型 | 作用 |
|---|---|
keenable/search | 搜索互联网,返回带摘录的来源列表 |
keenable/read | 读取网页,以 markdown 返回正文 |
搜索
curl https://nordrouter.com/v1/chat/completions \
-H "Authorization: Bearer $NORDROUTER_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "keenable/search",
"messages": [{"role": "user", "content": "今天比特币价格"}]
}'返回的是一条普通的助手消息,里面是来源列表:标题、发布日期、完整网址,以及每条来源的摘录。
读取网页
消息的第一个词是网址。之后可以补充说明你在这个页面上具体关心什么。
curl https://nordrouter.com/v1/chat/completions \
-H "Authorization: Bearer $NORDROUTER_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "keenable/read",
"messages": [{"role": "user", "content": "https://zh.wikipedia.org/wiki/东京 人口数量"}]
}'不加说明时返回整页 markdown。加了说明就只返回你要的部分:当结果还要送进模型时,这样更快,你这边的 token 开销也明显更低。
说明有什么用
一篇维基百科条目有几万个字符。如果你只需要一个数字,这句说明既省时间,也省下一步的 token。
Python
from openai import OpenAI
client = OpenAI(
api_key="你的密钥",
base_url="https://nordrouter.com/v1",
)
found = client.chat.completions.create(
model="keenable/search",
messages=[{"role": "user", "content": "本周人工智能新闻"}],
)
print(found.choices[0].message.content)方式二 —— 专用接口
如果你需要带字段、日期和筛选条件的结果,而不是一段文字,就用 JSON。
POST /v1/search
curl https://nordrouter.com/v1/search \
-H "Authorization: Bearer $NORDROUTER_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "神经网络新闻",
"max_results": 5,
"published_after": "7d"
}'参数:
| 参数 | 类型 | 默认值 | 作用 |
|---|---|---|---|
query | 字符串 | 必填 | 搜索什么 |
site | 字符串 | — | 只在该域名内搜索,例如 zhihu.com |
max_results | 数字 | 10 | 返回多少条结果,1 到 50 |
snippet_max_chars | 数字 | — | 摘录长度,180 到 10000 个字符 |
published_after | 字符串 | — | 在此时刻之后发布的内容 |
published_before | 字符串 | — | 在此之前发布的 |
acquired_after | 字符串 | — | 在此之后进入索引的 |
acquired_before | 字符串 | — | 在此之前进入索引的 |
query_time | 字符串 | — | 按索引在该时刻的状态搜索 |
日期接受三种写法:2026-08-01、完整的 ISO 8601 时间戳,或相对写法——30min、12h、7d、3mo、1y。
发布时间和入库时间不是一回事
published_* 按内容本身的发布日期筛选,acquired_* 按页面进入索引的日期筛选。这个区别很重要:页面可能被改写过,而发布日期没有变。如果你想知道「一天之内网上新出现了什么」,请用 acquired_after。
响应:
{
"query": "神经网络新闻",
"count": 5,
"results": [
{
"title": "文章标题",
"url": "https://example.com/article",
"description": "简短描述",
"snippet": "页面正文的一段摘录…",
"published_at": "2026-08-25T10:30:00Z",
"acquired_at": "2026-08-25T11:02:00Z"
}
]
}GET /v1/fetch
curl -G https://nordrouter.com/v1/fetch \
-H "Authorization: Bearer $NORDROUTER_KEY" \
--data-urlencode "url=https://example.com/article" \
--data-urlencode "prompt=提取价格表"参数:
| 参数 | 类型 | 默认值 | 作用 |
|---|---|---|---|
url | 字符串 | 必填 | 页面网址 |
max_chars | 数字 | 50000 | 返回多少个字符 |
prompt | 字符串 | — | 具体要提取什么,最多 2000 个字符 |
live | true / false | false | 直接从网站抓取,而不是走索引 |
响应:
{
"url": "https://example.com/article",
"title": "标题",
"description": "描述",
"author": "作者",
"content": "# 页面正文,markdown 格式…",
"published_at": 1787777084
}什么时候需要 live
走索引更快,但索引里并非什么都有。如果页面很新,或者对爬虫关闭,就设置 live=true——这样会直接从网站读取。价格相同。
限制
| 频率 | 每把密钥每秒 2 次请求 |
| 摘录长度 | 180 到 10000 个字符 |
| 每次调用的结果数 | 最多 50 条 |
| 读取时说明的长度 | 最多 2000 个字符 |
超出频率会返回 429,并带上 Retry-After 响应头——请隔一秒后重试。
错误
| 状态码 | 含义 | 该怎么办 |
|---|---|---|
400 | 缺少 query 或 url,或网址没有 http:// | 修正请求 |
401 | 密钥未被接受 | 检查 Authorization |
402 | 余额用尽 | 在个人后台充值 |
429 | 请求过于频繁 | 隔一秒后重试 |
502 | 搜索没有响应 | 重试;未产生扣费 |
503 | 搜索暂时不可用 | 我们正在处理;未产生扣费 |
常见问题
搜不到结果也要收费吗? 是的,只要搜索实际运行过并如实回答「什么都没找到」——工作已经完成了。只有出错才免费。
能用流式返回吗? 不能,也没有必要:结果在几分之一秒内一次性返回。
会统计 token 吗? 价格按调用计算,token 不影响费用。模型响应里仍会给出 token 数,以免客户端库把这次响应当成空的。
这和 search/… 系列模型有什么区别? 那些模型先搜索,再用语言模型把找到的内容组织成回答——你要为两份工作付费。这里你拿到的是原始结果,怎么用由你自己决定。