知识库由向量存储、知识库本身、数据源和服务角色四部分组成,chunking 配置一旦创建无法修改是最大陷阱;多数教程遗漏的同步步骤是导致查询空结果的直接原因。
A Bedrock knowledge base 看起来是一个资源,实际上是四个,其中恰好有一个设置创建之后无法更改。在创建时把 chunking 配置搞对是大部分的工作;剩下的就是接线,再加上一个同步步骤——出乎意料的是,很多教程完全略过了这一步,这就是为什么最终有那么多人查询一个空索引。
在任何 API 调用之前,先搞清楚你要创建的是什么:
向量存储。Bedrock 不会在每种配置下都自动为你托管一个——你需要把 knowledge base 指向一个 OpenSearch Serverless 集合、S3 向量桶、带 pgvector 的 Aurora PostgreSQL 或其他支持的存储。这是大部分运行成本所在的地方。
Knowledge base 本身,它把向量存储和一个 embedding 模型绑定在一起。
数据源,指向你的 S3 bucket 和前缀,并携带 chunking 配置。
服务角色,Bedrock 假设该角色来读取 S3、调用 embedding 模型,以及写入向量存储。
这种分离很重要,因为 knowledge base 和数据源有不同的生命周期。你可以在一个 live 的 knowledge base 上添加和删除数据源;但无法更改现有数据源的 chunk 方式。
AWS 在 CreateDataSource API 参考中明确指出,创建数据源连接器后无法更改 chunkingConfiguration。改变主意意味着删除数据源并重新摄入——对于大型语料库来说,这是真实的 embedding 成本,不只是时间。所以要想清楚了再决定。
chunkingStrategy 字段在四种文档记录在案的行为之间选择:
fixedSizeChunkingConfiguration 接受 maxTokens 和 overlapPercentage。可预测、成本低,对于均匀散文是合理的默认选择。Overlap 的存在是为了让跨越边界的完整事实在至少一个 chunk 中完整出现;它按比例增加存储和 embedding 调用成本。
AWS 描述默认行为为将内容切分为大约 300 个 token 的块,同时尊重句子边界,从而保留完整的句子。作为首次尝试还不错,但对于任何特定场景很少是最优的。
hierarchicalChunkingConfiguration 接受两级 levelConfigurations——一个 parent maxTokens 和一个 child maxTokens——外加 overlapTokens 作为绝对 token 数量而非百分比。检索时先匹配小而精确的 child chunk,然后将更大的 parent 交给模型。这是有结构文档的策略——答案是一个句子,但上下文是一个段落。AWS 声明了两个注意事项:返回的结果数量可能低于请求数量,因为 child 会合并到共享的 parent 中;不建议与 S3 向量桶一起使用,因为较高的合并 token 计数可能触及元数据大小限制。
semanticChunkingConfiguration 接受 maxTokens、bufferSize 和 breakpointPercentileThreshold。Buffer size 是决定边界落在何处时一起嵌入的相邻句子数量——buffer 为 1 意味着前一个、当前和下一个句子。阈值是句子差异度的百分位数;越高意味着 chunk 越少、越大。AWS 指出 semantic chunking 会产生额外成本,因为它在摄入期间使用了一个基础模型。
你也可以选择不 chunking,将每个文档作为一个单独的 chunk。AWS 指出其权衡:没有 chunking,你会在引用中丢失页码,并且无法按 x-amz-bedrock-kb-document-page-number 元数据属性进行过滤。如果你的用户需要被告知答案来自哪一页,这一条就决定了。
S3 配置是三个字段:bucket ARN、可选的 inclusionPrefixes,以及当 bucket 位于另一个账户时需要填写的 bucketOwnerAccountId。
aws bedrock-agent create-data-source \
--knowledge-base-id ABCDEFGHIJ \
--name policy-documents \
--data-source-configuration '{
"type": "S3",
"s3Configuration": {
"bucketArn": "arn:aws:s3:::acme-policy-docs",
"inclusionPrefixes": ["published/"]
}
}' \
--vector-ingestion-configuration '{
"chunkingConfiguration": {
"chunkingStrategy": "HIERARCHICAL",
"hierarchicalChunkingConfiguration": {
"levelConfigurations": [{"maxTokens": 1500}, {"maxTokens": 300}],
"overlapTokens": 60
}
}
}' \
--data-deletion-policy RETAIN
inclusionPrefixes 值得使用,即使 bucket 只存放文档。它让你可以把草稿和已发布内容放在同一个 bucket 中而不摄入草稿,而且当有人问为什么内部备忘录出现在面向客户的回答中时,你伸手去调的就是这个旋钮。
dataDeletionPolicy 接受 RETAIN 或 DELETE,控制删除数据源或 knowledge base 时向量的处理方式。AWS 明确指出,在这两种情况下,向量存储本身都不会被删除——只会删除数据。删除一个 knowledge base 不会让 OpenSearch Serverless 集合停止计费。
创建数据源不会读取任何文档。没有任何东西被 embedding,没有任何东西可以被查询,针对新 knowledge base 的检索调用会返回空结果集而不会报错。你必须启动一个摄入任务,而且每次文档发生变化时都必须重新启动一个。
启动它:aws bedrock-agent start-ingestion-job --knowledge-base-id ABCDEFGHIJ --data-source-id KLMNOPQRST。
用返回的 ingestionJobId 轮询 get-ingestion-job。statistics 块报告已扫描、已索引、失败和已删除的文档——失败计数是需要警惕的那个数字,因为一个任务可能以它无法解析的文档完成。
在前缀每次更改后重新运行。后续任务是增量性的:未更改的文档不会被重新 embedding,所以常规同步的成本与变动的内容成正比,而非语料库大小。
让它自动化。S3 事件触发前缀,加上 debounce,是常见的形态——参见 S3 事件 embedding 流水线了解通用模式。如果一天内的 freshness 可以接受,每夜一次的 EventBridge 调度是更便宜的版本。
删除是人们忘记的情况。从 S3 中删除一个文档不会将它从索引中移除,直到下一次摄入任务运行,所以在删除和同步之间,你的 knowledge base 会很乐意引用一个已经不存在的文档。如果这在法律层面有意义而非仅仅是美观层面,同步就必须由删除事件触发,而不是由调度触发。
Retrieve 返回 chunk 及其评分,并把 prompt 留给你。RetrieveAndGenerate 检索、构建 prompt、调用模型并返回带引用的文本。
aws bedrock-agent-runtime retrieve \
--knowledge-base-id ABCDEFGHIJ \
--retrieval-query '{"text": "What is the refund window for annual plans?"}' \
--retrieval-configuration '{
"vectorSearchConfiguration": {
"numberOfResults": 5,
"overrideSearchType": "HYBRID"
}
}'
先用 Retrieve,即使你打算使用 RetrieveAndGenerate。它是唯一能判断坏答案是检索问题还是生成问题的方式,而且使用 hierarchical chunking 时,它也是你看到自己请求了五个结果却只得到三个的原因——因为两个 child 共享了同一个 parent。overrideSearchType 接受 HYBRID 或 SEMANTIC;hybrid 加入关键词匹配,这正是拯救了包含 embedding 处理不好的产品代码和标识符的查询的方式。