跳转到正文

RETRIEVAL Worker API(可选) ​

English · Worker API

RETRIEVAL v0.1 只提供 RETRIEVAL.SEARCH。它是按需启用的通用相关性检索执行层,适用于搜索需要独立 CPU/GPU、连接资源、服务部署或水平扩容的场景。Core Worker 仍然只有 INFER、CONTEXT、MEMORY、INTERACTION。

RETRIEVAL 作为独立的可选 npm 包 @codesoul-co/ditto-retrieval 分发,并将 @codesoul-co/ditto 声明为 peer dependency。需要检索时安装两个包。Core 根入口和 @codesoul-co/ditto/worker 不导出/加载 RETRIEVAL;只有显式导入并注册后才执行。YAML 配置不会启动 Worker。默认 MEMORY/CONTEXT 的本地或外部 Provider 接入不变,普通部署无需增加一跳远程调用。

功能选择与参数影响 ​

RETRIEVAL.SEARCH 返回相关资料候选,用于文档、外部知识库、代码索引或记忆搜索。它不生成最终答案、不写入源库,也不自动选择知识库。完整问答由 Loop 组合检索、Context 选择、INFER 与引用校验 Graph。内部记忆通常从 MEMORY.SEARCH 进入;外部知识库可以直接调用 RETRIEVAL.SEARCH,两者可复用同一 Provider 算法。

请求参数决定检索范围与返回规模 ​

参数对 Node 的影响对 Worker / 后端的影响
query.content文本、向量或结构化查询,具体语义由 Provider 校验向量 Provider 可直接查询预计算向量,或先 embedding 文本;文本 Provider 不调用 embedding。更长文本可能增加模型成本,不保证检索更好
target.name从已注册的目标选择 Provider选择语料与后端绑定,不从名称推断 URL、表或连接;未知目标失败,不自动换库
target.namespace / metadata向 Provider 传递范围与应用元数据只有 Provider 实际实施的约束才有效;namespace 本身不是授权身份。适配器从可信身份检查访问范围
strategy选择目标已注册的 vector / keyword / bm25 / hybrid / 自定义策略省略时使用注册默认;设置 hybrid 不自动创建分支。不同算法分数不同,不能直接视为置信度或相加
filter传递版本、租户、时间或其他筛选条件Provider 必须实施或明确拒绝;更窄范围可能提高精度,也可能排除唯一证据,索引影响性能
limit控制最终最多返回的候选,默认 10,允许 1–10000增大可能提高召回,也增加传输、排序与 Context 输入;不是 embedding batchSize 或模型采样 topK
options传递 Provider 专用查询参数不存在统一自动生效的 minScore / threshold 协议;按具体适配器说明配置并测试

Node 包装器校验目标、策略、候选形状和数量,保留 Provider 顺序。它不自动归一化分数、去重或重排;以下算法行为来自显式组合的可选 Provider。

Provider 参数决定候选池与计算成本 ​

参数默认 / 作用调整后的取舍
embedding.batchSize默认 64,1–2048;embedContents 顺序执行有界批次较大批次减少请求次数,但增加单次 payload、内存和失败影响范围,并受服务批次/token 限制;不是并行度
embedding.dimensions可选,验证向量长度检查模型输出与索引是否匹配,不截断向量,也不改变 HTTP embedding 请求维度;修改模型/索引维度需重建兼容数据
vector nativeEmbedding / embedding选择数据库原生 embedding 或外部 EmbeddingProvider,二者互斥原生模式由数据库处理文本,外部模式增加模型请求;相同维度但不同模型的向量仍可能不兼容
hybrid candidateLimit默认 100,每个分支使用至少 max(request.limit,candidateLimit) 的候选池提高候选覆盖,也增加每个后端返回量与融合工作;是池容量下限,不是忽略 request.limit 的硬上限
hybrid branches / weight分支并发查询,默认权重 1,必须为正更多分支增加后端调用;较高权重偏向该分支,但原始 score 不相加。任何分支失败使整个操作失败,已接收分支会先结束
hybrid rrfK默认 60,正整数;融合分数为各分支 weight/(rrfK+rank) 之和,rank 从 1 起较小值强调前列排名差异;较大值缩小排名差异的影响,使跨分支出现的贡献相对更突出。不是候选数量
hybrid key默认用来源目标与 ID / ref 识别记录决定去重与融合对象;不同来源的同一记录需共享身份映射,无 ID/ref 时需显式 key
rerank candidateLimit默认 100,至少最终 limit;先扩大检索池再重排提高裁判可见覆盖,也增加 reranker 工作;重排无法找回检索池之外的证据
createCosineReranker(embedding)embedding 查询和候选内容,再按余弦相似度排序候选越多 embedding 工作越多;它不是 cross-encoder,其他判分模型需注入 RerankProvider

最终 limit 优先级为请求 → Worker defaults → Runtime YAML → 10。Provider 数值优先级为构造 options → 对应 Worker defaults 字段 → YAML → 内置值。已在构造时写死 candidateLimit 的 Provider 不会因 YAML 修改该值;需要集中调参时省略相应构造值,并显式传入配置。

资源占用与参数取舍实例 ​

Worker concurrency 限制 SEARCH 入口调用;一个 hybrid 搜索内部仍会并发调用多个分支。一个入口槽位不等于一个数据库请求。根据分支数、连接池与 embedding / rerank 配额设置并发,取消由 SDK / Provider 合作落实,远端 HTTP 取消不保证服务器停止。

例如最终 limit=8、两个 hybrid 分支各 candidateLimit=100,最多各读取 100 个候选再融合为最多 8 个。若外层 rerank candidateLimit=50,它会把内层最终检索池扩大到至少 50,再选出 8 个;hybrid 分支自己的 100 下限仍生效。Context 之后还可能只选择其中 5 个;提高搜索池并不意味着所有资料都进入模型。评估时分别检查后端召回、候选排序、进入 Context 的证据、延迟与实际资源用量。

完整构造与数据库适配见检索 Provider 文档。SEARCH 不创建索引或自动同步记忆写入;参数变化涉及向量模型、数据范围或索引时,先核对已有数据兼容性。

按需启用 ​

ts
import { createDitto, loadRuntimeConfigFile } from "@codesoul-co/ditto";
import {
  createRetrievalWorker, RetrievalTargetRegistry,
  type RetrievalSearchProvider,
} from "@codesoul-co/ditto-retrieval";

function startRetrieval(kbProvider: RetrievalSearchProvider, codeProvider: RetrievalSearchProvider) {
  const providers = new RetrievalTargetRegistry({
    "company-kb": { defaultStrategy: "hybrid", providers: { hybrid: kbProvider } },
    "code-index": { defaultStrategy: "bm25", providers: { bm25: codeProvider } },
  });
  return createDitto({
    config: loadRuntimeConfigFile("ditto.yaml", process.env),
    workers: [createRetrievalWorker({ providers, concurrency: 8 })],
  });
}

Provider 是应用传入的已有实现。将 MEMORY/CONTEXT 中使用的底层检索函数包装成 RetrievalSearchProvider,沿用同一后端与算法;远端 Provider 不应反向调用已经转接到自己的 MEMORY.SEARCH。可以复用已有检索函数,或连接向量数据库、全文索引、图数据库、远程检索 API。可选模块已提供批量/HTTP embedding、向量检索接线、数据库原生全文检索适配、加权 RRF 融合与可替换重排。SQL/Milvus 通过应用已有客户端注入,Ditto 不安装数据库或驱动,也不管理索引。Graph/custom 策略继续由对应 SearchProvider 执行。完整 API 和接线方式见检索链路与数据库适配。不创建空的 EMBED/RANK 目录。

应用决定是否将该 Worker 注册到本地 Runtime,或在独立服务进程中启动。Core 没有自动根据负载启停服务的机制。

公共类型与 API ​

ts
interface RetrievalQuery { content: unknown; metadata?: Record<string, unknown>; }
interface RetrievalTarget {
  name: string;
  type?: string;
  namespace?: string;
  metadata?: Record<string, unknown>;
}
interface RetrievalCandidate {
  id?: string;
  content: unknown;
  score?: number;
  source?: { target?: string; ref?: string };
  metadata?: Record<string, unknown>;
}
interface RetrievalSearchInput {
  query: RetrievalQuery;
  target: RetrievalTarget;
  strategy?: string;
  filter?: Record<string, unknown>;
  limit?: number;
  options?: Record<string, unknown>;
}
interface RetrievalSearchOutput {
  candidates: readonly RetrievalCandidate[];
  strategy?: string;
  target: RetrievalTarget;
  metadata?: Record<string, unknown>;
}
interface RetrievalSearchProvider {
  search(input: RetrievalSearchInput, context?: RetrievalExecutionContext): Promise<RetrievalSearchOutput>;
}
interface RetrievalProviderRegistry {
  resolve(target: RetrievalTarget, strategy?: string): RetrievalSearchProvider;
}
interface RetrievalResources { readonly providers: RetrievalProviderRegistry; }
interface RetrievalOptions extends RetrievalResources {
  readonly defaults?: RetrievalDefaults;
  readonly concurrency?: number;
}
  • createRetrievalWorker(options): WorkerDefinition:注册唯一叶子 SEARCH,复用现有 Runtime 路由、并发和关闭语义。
  • createRetrieval(options).search(input, runtimeDefaults?, context?):直接 SDK;defaults 包含 searchLimit 及嵌套 embedding/hybrid/rerank 配置,context 可传进程内 AbortSignal。直接 SDK 不限制并发。见Provider 配置。
  • runtime.invoke("RETRIEVAL.SEARCH", input) / ctx.invoke(...):使用共享 NodeResult<RetrievalSearchOutput>,含 executionId、node、status、output/error。
  • retrievalSearchNode:语义身份 scaffold。SEARCH 的 TypeScript 契约通过可选入口增强 NodeContractMap,不加入 Core 的默认契约导出。

query.content 必须存在,可为字符串、向量或任意自定义对象;具体格式由 Provider 校验。target.name 必须由调用者指定,不自动选 corpus。其他名称字段非空;metadata/filter/options 为对象;limit 是 1–10000 整数。

HTTP 跨进程调用使用 JSON,内容应遵循应用约定的可序列化格式;本地 SDK 不强制把 content 转成字符串。Target 是逻辑标识,不是数据库连接描述,API 不接收专用 credential、collection 或连接 URL 字段。私有后端配置保留在 Provider 中。

ts
const result = await runtime.invoke("RETRIEVAL.SEARCH", {
  query: { content: "agent memory migration" },
  target: { name: "company-kb" },
  strategy: "hybrid",
  filter: { year: { gte: 2024 } },
  limit: 20,
});
if (result.status !== "success" || !result.output) throw new Error(result.error?.code ?? result.status);
const candidates = result.output.candidates;

Target 与 Strategy 绑定 ​

ts
const providers = new RetrievalTargetRegistry({
  "agent-memory": {
    defaultStrategy: "vector",
    providers: { vector: vectorProvider, hybrid: hybridProvider },
  },
});

RetrievalTargetRegistry 是内置的最小 Registry 实现;每个 target 绑定一个默认策略及策略到 Provider 的映射。可以将同一个 Provider 注册到多个策略。绑定在创建时形成快照,查找使用 Map;不做网络发现或动态建库。不提供热注册/自动回退。

调用未提供 strategy 时使用该 target 的 defaultStrategy,选中的策略会传入 Provider 并写入输出。未知 target 和未注册 strategy 明确失败;默认策略必须已注册。rag 不允许作为策略。Vector、BM25、hybrid、graph 等只作为 Provider/策略名,Worker 不固化 EMBED → RETRIEVE → RANK 流水线。

内置 Registry 按 target.name 查找,target.type/namespace/metadata 原样传递给 Provider。namespace 不是访问凭证;租户权限和命名空间合法性应由 Provider 或自定义 RetrievalProviderRegistry.resolve 校验。自定义 Registry 也负责解释缺省策略。

输出与归一化 ​

Provider 返回原始 RetrievalSearchOutput,不返回第二层 NodeResult。Worker 校验候选数组、必需 content、可选 id/source/metadata、有限 score 和结果数。输出 target 的 name/type/namespace 必须与请求一致;显式策略也必须一致。错误结果不会被静默截断或当成成功。

输出 target 使用请求的逻辑标识,缺省策略由内置 Registry 补齐。候选及输出 metadata、source ref、排序和 score 原样保留;不重新评分、排序、去重或补造 id。不同来源可以有同名 id,候选也可无 id。空结果为 { candidates: [], target, strategy? }。

MEMORY 可选转接 ​

普通部署继续传入自己的 MemorySearchProvider。需要独立检索服务时,才导入第二个可选入口:

ts
import { createMemoryWorker } from "@codesoul-co/ditto";
import { RemoteRetrievalSearchProvider } from "@codesoul-co/ditto-retrieval/adapters/memory";

const search = new RemoteRetrievalSearchProvider({
  runtime, // 本地或已配置 HTTP 远程 Worker 的 Runtime
  target: { name: "agent-memory" },
  mapOutput(output) {
    return output.candidates.map(candidate => {
      // 此应用约定 candidate.id 是 Memory ID,content 是完整的记忆内容。
      if (!candidate.id) throw new Error("Missing Memory ID");
      return {
        memory: { id: candidate.id, content: candidate.content,
          ...(candidate.metadata === undefined ? {} : { metadata: candidate.metadata }) },
        ...(candidate.score === undefined ? {} : { score: candidate.score }),
        metadata: { source: candidate.source },
      };
    });
  },
});
runtime.register(createMemoryWorker({ store: applicationMemoryStore, search }));

RemoteRetrievalSearchOptions 包含必填 target、可选 runtime?: Pick<RuntimeClient, "invoke"> 和 mapOutput。candidate.content 为完整 MemoryItem 时可省略 mapOutput,使用默认映射保留 key/content/metadata;其它候选结构需显式提供 mapOutput,可同步或异步返回完整 MemorySearchOutput;它一次接收所有候选,便于在需要时批量补全记录。转接器不会自行创建存储连接、推断 Memory ID 或执行 N 次 SQL GET。

转接关系:MemorySearchInput.query → query.content;strategy/filter/limit/options 原样传递;target 固定在应用配置中。SEARCH 失败时不调用 mapper。转接器通过 Runtime 调用公共节点,只依赖 MEMORY 的类型接口,不导入其执行实现。MEMORY 调用方仍使用原来的输入、输出和 NodeResult。

转接失败在 MEMORY Worker 中遵循其现有异常规则,返回 MEMORY_BACKEND_ERROR;直接 RETRIEVAL 调用可获得下面的详细错误码。内置转接器不把远端错误原文转发给 MEMORY 调用者。

独立部署与扩容 ​

服务进程创建只包含 RETRIEVAL Worker 的 Runtime,然后使用现有 HTTP handler:

ts
import { createServer } from "node:http";
import { createWorkerHttpHandler } from "@codesoul-co/ditto";

const token = process.env.DITTO_TRANSPORT_HTTP_WORKER_TOKEN;
if (!token) throw new Error("Missing transport token");
const server = createServer(createWorkerHttpHandler(retrievalRuntime, { token }));
server.listen(8080, "127.0.0.1");
// 将 retrievalRuntime.workers()[0].address 通过部署配置交给调用方。

调用方安装已有 transport 并注册该地址,不在 Node 请求中放网络位置:

ts
import { createHttpTransport } from "@codesoul-co/ditto";
const transport = createHttpTransport({ id: "retrieval-service", url, token });
const runtime = createDitto({ transports: [transport] });
runtime.registerRemote({ address, transportId: transport.id, capabilities: ["RETRIEVAL.SEARCH"] });

每个服务地址安装一个 transport,可注册多个副本。详见 Worker 通信。concurrency 是每副本的并发入口上限;Runtime 优先选择本地、同主机、远端,并在同优先级可用副本间轮转。全部本地副本满载时立即拒绝,不新建等待队列、不自动重试、不自动扩容机器;远端容量由接收方执行。

路由按 Node capability,不按 target。加入同一调用方候选池的副本必须支持该池所需的相同逻辑 target/strategy 集合。不同 target 可在每个 Registry 中连接不同后端集群;若必须使用彼此不兼容的专用服务池,应用需使用独立 Runtime/transport 绑定,而不能期待调度器推断目标亲和性。

同进程副本共享事件循环,不会增加 CPU 核心。CPU/GPU 隔离和多核计算需部署到独立进程/机器。Worker 的价值是执行资源隔离和扩容边界,不能保证启用后单次检索更快。

注入的 Provider/Registry 由应用持有;同一 Worker definition 注册多次会共享这些对象。需要独立连接/模型句柄时分别创建 definition。关闭 Runtime 会停止路由并等待已接受请求结束,应用随后关闭 Provider 连接及 HTTP server。Worker 不保存业务事实或拥有 corpus。

配置与错误 ​

yaml
workers:
  retrieval:
    searchLimit: 10
    embedding:
      batchSize: 64
    hybrid:
      candidateLimit: 100
      rrfK: 60
    rerank:
      candidateLimit: 100

根目录 YAML 经 loadRuntimeConfigFile 读取为 config.retrieval。优先级:请求 limit > options.defaults.searchLimit > Runtime YAML > 内置 10。直接 SDK 可传 defaults: config.retrieval。配置在启动时读取,热路径没有文件 I/O。数据库/检索服务地址与凭据由应用 Provider 读取 env;通信沿用现有 HTTP token;可选 HTTP embedding 由工厂显式读取 RETRIEVAL 分组的 env 地址、模型和凭据。详见配置与接线。

错误码语义
RETRIEVAL_INVALID_INPUT公共参数不合法
RETRIEVAL_TARGET_NOT_FOUNDtarget 未注册
RETRIEVAL_STRATEGY_UNSUPPORTED该 target 不支持策略,或使用 rag 策略
RETRIEVAL_PROVIDER_UNAVAILABLERegistry/Provider 未提供可调用的方法
RETRIEVAL_INVALID_BACKEND_OUTPUT输出形状、目标、策略或条数不符合契约
RETRIEVAL_BACKEND_ERROR未分类后端异常,隐藏原始信息
RETRIEVAL_INVALID_EMBEDDING向量数量、索引、数值或维度错误
RETRIEVAL_CANCELLED本地 SDK 信号取消,status 为 cancelled
RETRIEVAL_TIMEOUTProvider 显式报告超时,NodeResult.status 为 timeout
RETRIEVAL_PERMISSION_DENIEDProvider/自定义 Registry 显式拒绝权限

Provider 可抛出 new RetrievalError(code, safeMessage);message 是公开内容,不能包含凭据或私有连接信息。其他异常转换为通用错误。

直接 SDK 的取消信号经 context 协作式传给 Provider,HTTP embedding 自带请求 deadline;其他后端 deadline/cancellation 由 Provider 自己实现;没有 Promise.race 超时后仍占用资源却提前释放并发配额的逻辑。HTTP transport 的客户端 timeout 只停止客户端等待,不保证服务端计算被取消。Runtime 注册/路由/通信层的失败仍按已有规则拒绝 Promise;不伪装成成功的空候选。

用户 Graph ​

RAG 由用户 Graph 组合 RETRIEVAL.SEARCH → 显式候选映射 → CONTEXT.UPDATE → INFER。SEARCH 不更新 Context、不写 Memory、不调用 INFER/Tool,也不改写 query。候选到 ContextItem 的映射由调用方决定,不将 content 强制解释成文档或 Message。

逐 API 使用示例 ​

完整代码:examples/retrieval.ts。下列函数共用该文件的 imports;函数不会在导入时自动执行。数据库、模型和 MCP 参数由应用注入,不是 Ditto 内置的模拟后端。选择需要的函数调用;写入、删除、模型调用等会产生对应的真实操作。

ts
import { createDitto, createMemoryWorker, loadRuntimeConfigFile } from "@codesoul-co/ditto";
import type { MemorySearchProvider, MemoryStore, MemoryItem } from "@codesoul-co/ditto/worker/memory";
import {
  createRetrieval, createRetrievalWorker, RetrievalTargetRegistry, RetrievalError, retrievalSearchNode,
  embedContents, validateVector, createVectorSearchProvider, createTextSearchProvider,
  createHybridSearchProvider, createCosineReranker, rerankCandidates, createRerankSearchProvider,
  createHttpEmbeddingProvider, embeddingConfigFromEnv, createSqlSearchProvider, createMilvusSearchProvider,
  type RetrievalSearchProvider, type RetrievalSearchInput, type RetrievalSearchOutput,
  type EmbeddingProvider, type RerankProvider, type SqlSearchOptions, type MilvusSearchOptions,
} from "@codesoul-co/ditto-retrieval";
import {
  createMemoryRetrievalProvider, createRetrievalMemorySearchProvider,
  RemoteRetrievalSearchProvider, mapMemoryCandidates,
} from "@codesoul-co/ditto-retrieval/adapters/memory";

export const request: RetrievalSearchInput = { query: { content: "agent memory" }, target: { name: "kb" }, limit: 5 };

本节共享 request 使用 query.content="agent memory"、target.name="kb"、limit=5。provider 参数必须支持该 target 的查询语义。

createRetrieval / createRetrievalWorker:显式启用 ​

providers 必填。createRetrieval 返回仅有 search 方法的直接 SDK;createRetrievalWorker 注册唯一 SEARCH 节点。concurrency 只约束 Worker,不影响直接 SDK。

ts
export function setupRetrieval(provider: RetrievalSearchProvider) {
  const config = loadRuntimeConfigFile("ditto.yaml", process.env);
  const providers = new RetrievalTargetRegistry({ kb: { defaultStrategy: "vector", providers: { vector: provider } } });
  const runtime = createDitto({ config, workers: [createRetrievalWorker({ providers, concurrency: 4 })] });
  const retrieval = createRetrieval({ providers, defaults: config.retrieval });
  return { runtime, retrieval };
}

retrieval.search / RETRIEVAL.SEARCH:返回候选 ​

示例比较本地 SDK 和 Runtime 调用。成功且无匹配时 output.candidates 为 [],仍然保留 target/strategy。Worker/SDK 不强制 candidate.id 存在。

ts
export async function retrievalSearch(provider: RetrievalSearchProvider) {
  const { runtime, retrieval } = setupRetrieval(provider);
  try {
    const local = await retrieval.search(request);
    const routed = await runtime.invoke("RETRIEVAL.SEARCH", request);
    if (routed.status !== "success" || !routed.output) throw new Error(routed.error?.code ?? routed.status);
    return { local, candidates: routed.output.candidates, target: routed.output.target };
  } finally { await runtime.close(); }
}

RetrievalTargetRegistry.resolve:选择 Provider ​

签名 resolve(target, strategy?),省略策略时使用该 target 的 defaultStrategy。返回的包装 Provider 会将所选 strategy 传入后端并补到输出;直接调用它返回原始 Output,异常抛出。

ts
export async function registryResolve(provider: RetrievalSearchProvider) {
  const providers = new RetrievalTargetRegistry({ kb: { defaultStrategy: "keyword", providers: { keyword: provider } } });
  const selected = providers.resolve({ name: "kb" });
  return selected.search({ ...request, limit: 5 }); // Raw output, strategy is filled with "keyword".
}

search 的 runtimeDefaults / context 参数 ​

完整签名 search(input, runtimeDefaults = {}, context = {});第三参数传 signal,第二参数是默认值后备层,不是调用选项。SDK 会用工厂与 runtimeDefaults 合并结果覆盖 context.defaults,故默认配置不要放第三参数。没有自动 timeoutMs 参数。

ts
export async function cancelRetrieval(provider: RetrievalSearchProvider) {
  const providers = new RetrievalTargetRegistry({ kb: { defaultStrategy: "custom", providers: { custom: provider } } });
  const retrieval = createRetrieval({ providers, defaults: { searchLimit: 5 } });
  const controller = new AbortController(); controller.abort();
  return retrieval.search(request, { searchLimit: 10 }, { signal: controller.signal });
}

节点描述符 type / define ​

retrievalSearchNode.type 为 RETRIEVAL.SEARCH;.define(workerType, handler) 固定节点身份与类型,不自动注册 Worker。下面让自定义 handler 复用 SDK 的校验和 NodeResult 包装。通常使用 createRetrievalWorker 更直接。

ts
export function retrievalDescriptor(provider: RetrievalSearchProvider) {
  const providers = new RetrievalTargetRegistry({ kb: { defaultStrategy: "custom", providers: { custom: provider } } });
  const retrieval = createRetrieval({ providers });
  return retrievalSearchNode.define("RETRIEVAL", input => retrieval.search(input));
}

与 CONTEXT 组合 ​

CONTEXT.SELECT 的 ragStrategy 可复用当前 SearchProvider,也可通过 Runtime 委托 RETRIEVAL.SEARCH。独立调用须先检查 NodeResult,再显式映射候选,返回 ContextItem[];SELECT 不自动写回工作集。 完整 CONTEXT API 与调用示例。

ts
export function remoteContextRetrieval(runtime: import("@codesoul-co/ditto").RuntimeClient, target: RetrievalTarget) {
  return contextRetrieval({ async search(input) {
    const result = await runtime.invoke("RETRIEVAL.SEARCH", input);
    if (result.status !== "success" || !result.output) throw new Error(result.error?.code ?? result.status);
    return result.output;
  } }, target);
}

完整 imports 和代码。

Worker 调用上下文 ​

内置 RETRIEVAL Worker 将 Runtime 当前 signal 传给 Provider 的 RetrievalExecutionContext,向量 embedding、数据库查询、融合与重排适配器继续传递它。直接调用示例:await runtime.invoke("RETRIEVAL.SEARCH", { query: { content: "question" }, target: { name: "docs" } }, { signal: AbortSignal.timeout(5000) })。MEMORY 和 CONTEXT 的委托适配器也会继承父调用上下文;CONTEXT 接入见 Provider API。HTTP/IPC 取消不等于服务端数据库执行已被取消。

在 MEMORY Worker 内构造 RemoteRetrievalSearchProvider 时,可省略 runtime,继承本次执行绑定的 Runtime;显式 runtime 始终优先,独立 SDK 委托则必须提供它。例如 Worker 内可用 new RemoteRetrievalSearchProvider({ target: { name: "memories" } })。

带持久化和来源定位的完整 Agent 任务见信息检索与搜索工作流。

Ditto · @codesoul-co/ditto · Node.js 24+