# Exa

> 只需更换基础 URL 和密钥，即可通过 Search1API 使用 Exa 的 Python 和 JavaScript SDK，并控制何时读取结果页面。

Canonical URL: https://s1.dev/zh/docs/compatibility/exa

Search1API 兼容 Exa 的 `POST /search` 和 `POST /contents`。将 Exa 基础 URL 设置为：

```text
https://api.search1api.com/compat/exa
```

与 Exa SDK 的做法一样，通过 `x-api-key` 发送你的 Search1API 密钥，也可以使用 `Authorization: Bearer`。

## 配置客户端

<Tabs items={['Python', 'JavaScript']}>

<Tab value="Python">

```python
from exa_py import Exa

exa = Exa(api_key="YOUR_API_KEY", base_url="https://api.search1api.com/compat/exa")
results = exa.search("hono cloudflare workers", num_results=5, contents=False)
pages = exa.get_contents(["https://hono.dev/docs/"], text=True)
```

</Tab>

<Tab value="JavaScript">

```ts
import Exa from 'exa-js';

const exa = new Exa(process.env.SEARCH1API_KEY, 'https://api.search1api.com/compat/exa');
const results = await exa.search('hono cloudflare workers', { numResults: 5, contents: false });
const pages = await exa.getContents(['https://hono.dev/docs/'], { text: true });
```

</Tab>

</Tabs>

> **warn:** `exa-py` 和 `exa-js` 中的 `search()` 默认会请求页面正文，除非你传入 `contents=False`（JavaScript 中为 `contents: false`）。每读取一个页面消耗 1 积分，因此默认请求 10 条结果的搜索最多消耗 11 积分。如果标题、URL 和高亮片段已经足够，请传入 `contents=False`。

## 搜索

| 字段 | 行为 |
| --- | --- |
| `query` | 必填。 |
| `numResults` | 默认 `10`，最多 `50`。 |
| `category` | `news` 搜索新闻。其他分类搜索网页。 |
| `includeDomains`, `excludeDomains` | 限定或排除站点。 |
| `startPublishedDate`, `startCrawlDate` | 转换为能覆盖该时间段的最短区间：天、周、月或年。 |
| `contents.text` | 设为 `true` 或 `{ maxCharacters }` 时，读取每个结果页面，以 Markdown 形式放入 `text`，并截断到 `maxCharacters`。 |
| `contents.highlights` | 将搜索摘要作为唯一的高亮片段返回，高亮分数为 `1`。 |

`type`、`contents.summary`、`livecrawl`、`maxAgeHours`、`userLocation` 等选项会被接受但忽略。

响应包含 `requestId`、`results` 和 `searchTime`。每条结果包含 `id`（即 URL）、`url`、`title`，以及在可用或被请求时提供的 `publishedDate`、`text`、`highlights` 和 `highlightScores`。不返回 `score`、`author`、`image`、`summary` 和 `costDollars`。

## 内容获取

`urls`（或 `ids`，即结果 URL）最多接受 100 个 URL。每个读取到的页面在 `results` 中返回，包含 `id`、`url`、`title` 和 `text`；`text.maxCharacters` 用于截断文本。`statuses` 会报告每个 URL 的状态为 `success` 或 `error`，页面不存在时错误标签为 `CRAWL_NOT_FOUND`，其他情况为 `CRAWL_UNKNOWN_ERROR`。

## 积分

| 请求 | 积分 |
| --- | --- |
| 使用 `contents: false` 或仅请求高亮片段的搜索 | 1 |
| 使用 `contents.text` 的搜索（SDK 默认） | 1，每读取一个页面再加 1 |
| 内容获取 | 每读取一个页面 1 |

## 错误

错误返回 `{ "requestId": "…", "error": "message", "tag": "…" }` 及相应状态码。标签包括 `INVALID_API_KEY`（401）、`NO_MORE_CREDITS`（402）、`RATE_LIMIT_EXCEEDED`（429）和 `INVALID_REQUEST_BODY`（400）。