跳到主要内容

构建连接器

连接器可以索引 Gety 默认不覆盖的内容。本指南会带你从示例项目开始,把连接器安装到 Gety 中,再介绍如何发布,让其他人也能安装。完整字段和 API 说明见连接器参考。

了解当前能力范围​

连接器是一个 Deno 和 TypeScript 程序。它轮询某个来源,并产出文档供 Gety 索引。

它可以:

  • 从稳定、可访问的来源拉取数据,例如网页 API、本地枚举或内部服务
  • 索引带有稳定 ID、标题和 metadata 的文本内容
  • 用持久化 state 跟踪增量进度,并新增、更新或删除文档
  • 声明它需要的主机、文件夹、环境变量和程序,让 Gety 在沙箱中运行它

它不能:

  • 在 Gety 中添加自己的 UI,manifest 声明的配置字段除外
  • 在用户打开结果时,按需抓取、提取或缓存远程文件
  • 为每个文档使用不同的动态链接规则;文档链接需要在 manifest 中统一声明

如果来源只提供文件,而这些文件还需要 Gety 之后再抓取和提取,请不要这样设计。应当把连接器已经拿到的文本写入 content,再把稳定的 URL 或文件路径放到 metadata 中。

例如,Notion 就适合作为连接器场景:使用 Notion API 作为稳定来源,借助 souvikinator/notion-to-md 这类库把 Notion blocks 转换为 Markdown,再把 Markdown 作为索引内容添加到 Gety。

媒体播放器通常不适合作为连接器场景。它主要是交互式 UI,而不是稳定的文本来源。没有可靠 API、稳定本地文件或持久 ID 的来源,也不适合用连接器做增量同步。

前置条件​

开始前,请先安装:

  • Git,用于克隆示例连接器。
  • Deno,用于构建、测试和运行连接器。
  • Gety 0.7.0 或更新版本,用于安装和测试连接器。

如果要发布到 npm,还需要 Node.js 和一个 npm 账号。

使用 AI Agent 创建 Gety 连接器​

如果你的 AI 编程工具支持 Skills,优先使用 Gety 的连接器 skill。它会把连接器约定、示例项目流程和验证步骤交给 Agent。

npx skills add gety-ai/gety-skills --skills create-gety-connector

然后告诉 Agent 你想索引什么:

请使用 create-gety-connector skill,为 [数据来源] 创建一个 Gety 连接器。开始写代码前,如果缺少必要信息,请先向我确认。

如果你的 AI 编程工具不支持 Skills,可以把下面这段复制到聊天窗口:

为 [数据来源] 创建一个 Gety 连接器。请使用 https://docs.gety.ai/build-a-connector.md 作为实现流程,并使用 https://docs.gety.ai/connector-reference.md 作为完整的连接器约定和字段参考。开始写代码前,如果缺少必要信息,请先向我确认。

不要把 API key 等密钥粘贴到聊天中。密钥应放在连接器配置字段或本地 .env 文件中。

如果你要手动构建,请继续阅读下面的步骤。

从示例开始​

克隆示例连接器。不要从零手写项目骨架;示例已经包含构建脚本、生成的配置类型、本地 runner、打包和验证任务。

git clone https://github.com/gety-ai/gety-sample-connector my-connector
cd my-connector

查看项目结构​

manifest.json # 连接器元数据、配置 schema 和权限
package.json # npm 包信息;其中的 gety 字段由 manifest.json 生成
CHANGELOG.md # 用户切换版本时 Gety 显示的更新说明
src/index.ts # 连接器实现
src/index.test.ts # 单元测试
src/gen/manifest.d.ts # 生成的配置类型;不要编辑
dist/main.js # Gety 加载的构建入口
deno.json # build、check、test、verify、runner、package、sync 等任务
dev/runner.ts # 按 Gety 的方式运行连接器的本地 runner
scripts/build.ts # esbuild 打包脚本
scripts/package.ts # 生成 GitHub Release 的发布文件
vendor/gety-deno/ # Gety 的 SDK 和连接器 runner 副本;不要编辑

Gety 实际加载的是 dist/main.js。修改 src/index.ts 后,需要运行 deno task build;只改源码不会更新已构建的连接器。

先规划文档契约​

写代码前,先确定来源如何映射为 Gety 文档。请提前明确这些点:

  • 来源及其认证方式。
  • 在多次轮询之间保持稳定的文档 ID。
  • 每条记录如何映射到 title、content 和 metadata。
  • 如何检测并删除已删除或已归档的记录。
  • 用户选中搜索结果时打开的链接。
  • 连接器需要访问哪些主机、文件夹、环境变量或程序。

编写最小 manifest​

manifest.json 告诉 Gety 如何安装和运行连接器:

{
"id": "acme_my_connector",
"name": "My Connector",
"version": "0.1.0",
"min_gety_app_version": "0.7.0",
"capabilities": ["data-source"],
"entry": "dist/main.js",
"description": "Indexes documents from My Connector.",
"schedule": { "strategy": "interval", "interval_seconds": 3600 },
"doc_link": { "kind": "url", "field": "url" },
"permissions": { "net": ["api.example.com"] },
"config": {
"fields": [
{
"id": "api_key",
"title": "API Key",
"type": "password",
"required": true,
"description": "Create this token in the service settings."
}
]
}
}

Gety 用 id 识别已安装的连接器。请给它加上你自己的名字作为前缀,避免和其他作者的连接器冲突,并在发布前定下来。参阅保持连接器 ID 稳定。

所有 manifest 字段见连接器参考。

声明权限​

permissions 决定连接器可以做什么,每次安装前 Gety 都会把它展示给用户审查。设置了 permissions 的连接器在沙箱中运行:除了你声明的权限和少量基础授权(例如它自己的数据文件夹),其他一律拒绝。

"permissions": {
"net": ["api.example.com"],
"read": ["~/Documents/notes"]
}
  • net 列出连接器可以访问的主机。请求经过的每个主机都要声明,包括重定向目标和 CDN。
  • read 列出连接器可以读取的、位于用户主目录下的文件夹。
  • env 列出可以读取的环境变量,run 列出可以运行的程序。
  • 如果权限要跟随用户填写的配置(例如服务器地址或文件夹),用 { "config_field": "<字段 id>" } 代替固定值。
  • 只需要基础授权的连接器,声明 "permissions": {}。

只声明连接器需要的权限。任意主机("*")、整个主目录("~")或 run 中的任何程序这类宽泛授权,需要用户二次确认。没有 permissions 的 manifest 会以完全权限运行,可以访问用户能访问的一切,Gety 会以红色向用户警告。

沙箱需要 Gety 0.7.0 或更新版本,所以请把 min_gety_app_version 设为 0.7.0 或更高。所有条目的写法见权限。

实现 src/index.ts​

连接器是一个继承 Connector<Config, State> 的类。你需要把 poll() 实现为 async generator,产出成批的文档更新和 state 检查点。

import { Connector, type PollResult, del, upsert } from '@gety-ai/connector-sdk';
import type { ManifestConfig } from './gen/manifest.d.ts';

type State = {
cursor?: string;
};

export default class MyConnector extends Connector<ManifestConfig, State> {
async *poll(): AsyncGenerator<PollResult, void, unknown> {
let cursor = this.lastState?.cursor;

for await (const page of fetchPages(this.config.api_key, cursor, this.signal)) {
yield {
updates: [
...page.items.map((item) =>
upsert({
id: item.id,
title: item.title,
content: item.body,
content_format: 'markdown',
doc_type: 'my:item',
doc_updated_at: item.updatedAt,
metadata: { url: item.url },
}),
),
...page.removed.map((id) => del(id)),
],
state: { cursor: page.next_cursor },
};
cursor = page.next_cursor;
}
}
}

要点:

  • upsert(doc) 新增或更新文档。只有 id 和 title 必填;id 必须在多次轮询之间保持稳定。
  • del(id) 在来源明确表明文档已消失时删除文档。
  • this.config 包含用户在 manifest 配置字段中填写的值。
  • this.lastState 是上一次成功轮询最后产出的 state;首次运行时为 null。
  • this.signal 会在 Gety 停止本次轮询时触发中止,例如用户禁用或重启连接器时。能传给 fetch 时,应传进去。
  • this.dataDir 是连接器自己的数据文件夹,在多次轮询之间保留。

管理 state 和批次​

每批更新都应带上一个 state 检查点,并且这个 state 应位于该批更新之后。只有整次轮询成功结束时,Gety 才会保存你最后产出的 state,并在下次轮询时作为 this.lastState 传入。如果轮询中途失败或被取消,Gety 保留上一次成功轮询的 state,下次轮询会从那里重做。

失败的轮询中可能已经有一部分更新被索引,而且 Gety 会把大批次分成几部分写入,而不是一次写完。因此你的更新必须可以安全重放:从同一个 state 重新运行轮询,最终得到的文档必须相同。使用稳定的文档 ID 和 upsert,自然就能满足这一点。

不要在产出对应文档之前推进 state。应按来源可以继续的边界产出,例如 API 分页或持久游标。

遵守运行规则​

每次轮询都在一个新进程中运行,Gety 会监控它:

  • 报告进度。 如果一次轮询 10 分钟内没有向 Gety 发送任何内容,Gety 会认为它卡住并停止它。产出一批更新或写一行日志都算有进度。在不产出任何内容的耗时步骤中(例如下载大文件),隔一段时间用 console.info() 写一行简短日志。
  • 按要求停止。 Gety 停止轮询时,this.signal 会中止。把它传给 fetch() 和其他耗时调用,并在各个工作单元之间检查 this.signal.aborted。如果 5 秒后连接器仍未退出,Gety 会结束进程。
  • 保持 state 精简。 下次轮询开始时,Gety 会把 state 和配置一起传回。两者合计超过 16 MiB 时,轮询会失败。大块数据请放在 this.dataDir 中。

SDK 会自动把大批次拆成较小的消息。单个文档更新必须小于 16 MiB,并且 Gety 只保留文档 content 的前 10 MB。

避免这些写法​

这些写法可能会造成内存压力、链接失效或轮询失败:

  • 一次性把所有远程数据读入内存。应尽量改为分页或流式处理来源。
  • 在 doc_link 中使用临时 URL。链接在轮询结束后必须保持稳定。
  • 让文档链接指向连接器自己写出的文件。Gety 不会打开连接器目录中的文件;请链接到来源服务或用户自己的文件。
  • 把大块数据放进 metadata。metadata 应保持精简,正文请通过 content 索引。
  • 在构造函数中读取 this.config。配置会在 Gety 注入之后,于 onLoad()、poll() 等生命周期方法中可用。
  • 在运行时从 URL 或 npm 导入模块。沙箱会阻止这种导入;请把所有依赖打包进 dist/main.js。

本地验证​

安装连接器前,先运行示例项目的验证任务:

deno task verify

verify 会运行格式化、lint 修复、配置类型生成、类型检查、测试和构建。然后用本地 runner 演练连接器生命周期:

cp .env.example .env
deno task runner -- --reset-state

Runner 按 Gety 的方式运行连接器:每次轮询都是一个新进程,在 Gety 的沙箱中以 manifest 声明的权限运行。manifest 没有授予的访问会让轮询失败,错误信息与 Gety 显示的相同,例如 permission denied: net access to "example.com:443" is not granted by the connector's manifest。

Runner 会把每次运行的输出写入 dev/runs/<timestamp>/,包括文档、更新、删除和 state 快照。重点检查 ID 是否稳定、内容是否符合预期、metadata 是否正确、时间戳是否符合 RFC 3339。和 Gety 一样,runner 只在轮询成功时保存 state。--reset-state 从空 state 开始,方便你测试一次干净的首次轮询。想在不修改 manifest 的情况下试用其他权限,可以传入 --permissions '<json>'。运行 deno task runner -- --help 查看所有选项。

如果 .env 需要 API key 等密钥,请自己编辑文件。不要把密钥粘贴到和 Agent 的聊天中。

安装到 Gety​

  1. 运行 deno task build,刷新 dist/main.js。
  2. 打开 Gety → 设置 → 连接器,点击从本地文件夹安装。
  3. 选择你的连接器文件夹。
  4. 审查权限,点击允许。
  5. 如果连接器有配置项,填写后点击安装。
  6. 让 Gety 按连接器的同步计划运行。手动计划需要点击更多操作(⋯)→ 立即同步。

你也可以在终端中用 gety connector install ./my-connector 安装。参阅 CLI。

之后修改代码时,需要再次运行 deno task build,再在 Gety 中点击更多操作(⋯)→ 重启加载新的构建产物。Gety 只在安装时读取 manifest.json,因此修改 manifest(例如权限)后,需要点击更多操作(⋯)→ 删除,再重新安装连接器。想在不重新安装的情况下测试一次全新同步,点击更多操作(⋯)→ 完全重建索引。

发布连接器​

用户可以在 Gety 中通过从远程安装,或用 CLI 安装已发布的连接器。你可以发布到 npm、GitHub,或两者都发布:

渠道用户的安装方式更新
npm从远程安装 → npm、精选连接器,或 gety connector install --npm <package>Gety 会检查新版本,并允许用户切换版本。
GitHub Release从远程安装 → GitHub,或 gety connector install --github <owner>/<repo>用户需要删除连接器,再安装新的 Release。

只有 npm 连接器支持版本管理,也只有 npm 连接器可以进入精选列表,所以建议优先发布到 npm。

Gety 从不从源码构建。它只安装你发布的文件,记录它们的校验和,并保存一份自己的代码副本。Release 或 npm 包不能超过 100 MiB,解压后不能超过 20,000 个文件和 500 MiB,并且不能包含符号链接。

保持连接器 ID 稳定​

Gety 用 manifest 的 id 识别已安装的连接器。已发布连接器的 id 永远不要修改:Gety 会把新的 id 当作另一个连接器,用户会把它安装成第二个连接器,并重新索引所有内容。从 npm 安装了旧版本的用户也无法切换到新版本:Gety 会拒绝 id 已改变的版本。

在 npm 上发布​

npm 包的 package.json 用 gety 字段携带完整的 manifest:

{
"name": "@acme/gety-my-connector",
"version": "0.1.0",
"description": "Indexes documents from My Connector.",
"homepage": "https://github.com/acme/gety-my-connector#readme",
"files": ["dist/main.js", "dist/main.js.map", "CHANGELOG.md"],
"gety": {
"id": "acme_my_connector",
"name": "My Connector",
"version": "0.1.0",
"min_gety_app_version": "0.7.0",
"capabilities": ["data-source"],
"entry": "dist/main.js",
"permissions": { "net": ["api.example.com"] }
}
}
  • gety 是完整的 manifest,gety.version 必须等于包的 version。Gety 不读取包中的 manifest.json。
  • 把 manifest.json 作为唯一来源。在示例项目中,deno task sync 会根据 manifest.json 写入包的 version、description 和 gety,deno task verify 也会运行它,因此两者不会不一致。
  • files 必须包含入口文件,以及连接器运行时需要的其他所有文件,例如图标和 source map。还要列出 CHANGELOG.md:设置了 files 后,npm 不会自动打包它。
  • 把 homepage 设为介绍这个连接器的页面,例如它的 README。
  • 包必须是公开的。

发布:

deno task verify
npm publish

在示例项目中,npm publish 会先运行 deno task sync:check,package.json 没有同步时会失败。如果想改由 CI 发布,推送 v* tag 即可:示例项目的 .github/workflows/npm-publish.yml 会运行 deno task verify,再用 npm 可信发布(trusted publishing)运行 npm publish,因此仓库不需要 npm token。npm 只允许为已经存在的包配置可信发布者,所以请先手动发布第一个版本,再在 npmjs.com 上该包的设置中添加可信发布者。

Gety 安装 latest dist-tag 指向的版本,或用户指定的确切版本,例如 @acme/gety-my-connector@0.2.0-beta.1。不支持其他 dist-tag 和版本范围。发布预发布版本时请使用其他 dist-tag,例如 npm publish --tag next,让 latest 继续指向稳定版本。中国大陆的用户会优先从镜像下载,镜像通常在几分钟内同步新版本。

发布 GitHub Release​

每个版本发布一个 GitHub Release,tag 使用 manifest 的 version,可以加 v 前缀(0.1.0 对应 v0.1.0)。每个 Release 包含两个附件:

  • manifest.json,与 zip 中的 manifest.json 逐字节相同。用户确认前,Gety 只下载这个文件来展示权限。
  • <id>-<version>.zip,其中 id 和 version 来自 manifest。zip 的根目录就是连接器文件夹:manifest.json、入口文件和连接器需要的其他所有文件,外面不能再包一层文件夹。

示例项目可以生成并检查这两个附件:

deno task build
deno task package

deno task package 会把附件写入 release/。它会打包 manifest.json、入口文件及其 source map,以及图标;用 --include <path> 添加其他文件,传入 --tag <tag> 可以检查 tag 是否与 manifest 版本一致。示例项目的 .github/workflows/release.yml 会在你推送 v* tag 时发布 Release;示例的 README 说明了其他仓库如何复用它。

Gety 默认安装 GitHub 标记为 Latest 的 Release。预发布版本只能通过它的 Release 链接或 --version 安装。请在仓库设置中开启不可变 Release(immutable releases),让已发布的 tag 和附件无法再修改。

发布新版本​

  1. 提高 manifest.json 中的 version;如果新版本需要更新的 Gety,同时提高 min_gety_app_version。
  2. 在 CHANGELOG.md 中为新版本添加一个小节,例如 ## 0.2.0。用户切换 npm 连接器的版本时,Gety 会把这一节显示为该版本的更新说明。
  3. 按上文的方式发布。
  • 如果新版本无法接着旧版本已同步的内容继续(例如 state 的结构变了,或文档 ID 规则变了),请提高 manifest 中的 sync_version。用户更新时,Gety 会删除该连接器的全部文档并从头同步。
  • 如果新版本需要更多权限,用户切换前需要审查新增的权限。已发布的 npm 版本无法修改,所以修改权限总是意味着发布新版本。
  • 要撤回有问题的 npm 版本,用 npm deprecate <package>@<version> "<说明>" 弃用它。Gety 不会把已弃用的版本作为更新提供。

完整规则见版本与更新。

发布到精选列表​

要让你的连接器出现在 Gety 精选连接器的社区标签页中:

  1. 把连接器作为公开包发布到 npm,并在 Gety 中从 npm 安装它(<package>@<version>),确认可以正常工作。

  2. 向 gety-ai/gety-connectors 提交一个 pull request,添加 community/<id>.json,其中 <id> 是你的 manifest id:

    {
    "package": "@acme/gety-my-connector",
    "version": "0.1.0",
    "author": { "github": "acme" }
    }
  3. 等待检查和审核。pull request 合并后,精选列表会重新生成并发布,有时要等到官方连接器的下一次发布。之后 Gety 下次加载精选列表时,就会列出你的连接器。

列表显示的名称、描述和图标来自所登记版本的 manifest,同时显示你的 GitHub 头像和名称。Gety 安装的正是所登记的版本。要列出更新的版本,提交一个修改 version 的 pull request;已经安装的用户随时可以在 Gety 中更新。

图标要求、检查项以及如何下架,参阅贡献指南。

下一步​

完整约定,包括 manifest 字段、权限、配置字段类型、SDK 生命周期和 WireDoc 字段,见连接器参考。