让知识库先拆题再检索:Amazon Bedrock Agentic Retrieval 实战解析

2026-07-24 37 预计阅读时间: 1 分钟
来源: aws.amazon.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:10 分钟

传统 RAG 检索通常把用户问题编码成一个向量,再用它搜索知识库。这种方式处理单一事实问题很直接,但遇到包含多个约束、比较项或时间范围的复合问题时,一个查询向量很难同时准确表达所有意图。Amazon Bedrock Managed Knowledge Base 的 Agentic Retrieval 针对这一缺口,引入查询规划和流式执行,让检索过程能够拆题、分步搜索,并通过 trace 暴露中间决策。

为什么一次 Retrieve 不够

假设用户提出下面的问题:

比较 2023 年和 2024 年退款政策的变化,并说明企业客户是否受到影响。

这个问题至少包含三个检索目标:

  • 找到 2023 年退款政策;
  • 找到 2024 年退款政策;
  • 识别企业客户条款,并比较前后变化。

标准 Retrieve API 通常把整段文本作为一个检索查询。它速度快、行为容易预测,但返回结果可能集中在语义最强的部分,例如只命中 2024 年政策,遗漏旧版本或企业客户条款。

Agentic Retrieval 的差异不只是“多查几次”。它会围绕原始问题制定检索步骤,再逐步返回结果和执行轨迹。应用因此可以观察系统拆出了哪些子问题、调用了哪些检索步骤,以及最终证据来自哪里。

这并不意味着 Agentic Retrieval 应该替代所有向量检索。简单的产品编号查询、文档定位和单一事实问答,通常仍适合标准 Retrieve;复合比较、跨文档归纳和多约束问题,才更能体现 agentic 模式的价值。

AgenticRetrieveStream 的调用形态

AgenticRetrieveStream 是流式 API。客户端提交知识库标识、用户输入以及相关检索配置,然后持续消费服务端事件。与等待一个完整 JSON 响应相比,流式接口有两个工程影响:

  1. 结果和 trace 可能分散在多个事件中,不能假设一次读取就得到完整答案;
  2. 客户端必须区分内容事件、轨迹事件、引用或检索结果事件,以及异常事件。

具体字段会随 AWS SDK 和服务模型版本变化。接入前应升级 boto3,并直接检查本地 Botocore 模型,避免依赖手写且可能过期的请求结构:

python -m pip install --upgrade boto3 botocore
python - <<'PY'
import boto3

client = boto3.client("bedrock-agent-runtime", region_name="us-east-1")
model = client.meta.service_model

operation_name = "AgenticRetrieveStream"
if operation_name not in model.operation_names:
    raise SystemExit(
        "当前 SDK 尚未包含 AgenticRetrieveStream,请升级 boto3/botocore,"
        "并确认该 API 已在目标区域开放。"
    )

operation = model.operation_model(operation_name)
print("Input members:", sorted(operation.input_shape.members))
print("Output members:", sorted(operation.output_shape.members))
PY

这段命令不猜测请求字段,而是读取当前安装版本中的正式服务模型。部署环境也应执行同样的版本检查,因为开发机支持新操作,并不代表 Lambda 层或容器镜像里的 SDK 同样支持。

可以这样实践:构造请求并解析流式 trace

下面是一个可改造的 Python 客户端骨架。由于来源摘要没有给出所有字段的精确名称,示例会从 Botocore 模型校验请求;你需要根据脚本打印出的 input members,把 request 调整为当前 SDK 接受的结构。

运行前设置 BEDROCK_KB_ID 和 AWS 区域,并确保调用身份拥有对应的 Bedrock Knowledge Base 权限。

import json
import os
import boto3
from botocore.exceptions import ClientError, ParamValidationError

REGION = os.getenv("AWS_REGION", "us-east-1")
KNOWLEDGE_BASE_ID = os.environ["BEDROCK_KB_ID"]
QUESTION = os.getenv(
    "QUESTION",
    "比较 2023 年和 2024 年退款政策,并说明企业客户是否受到影响。",
)

client = boto3.client("bedrock-agent-runtime", region_name=REGION)
operation_name = "AgenticRetrieveStream"

if operation_name not in client.meta.service_model.operation_names:
    raise RuntimeError("当前 boto3/botocore 版本不支持 AgenticRetrieveStream")

# 这是接入模板。请按照当前 SDK 的 input shape 调整字段名称和嵌套结构。
request = {
    "knowledgeBaseId": KNOWLEDGE_BASE_ID,
    "input": {"text": QUESTION},
}


def walk(value, path="event"):
    """递归打印流式事件,便于识别 trace、结果和异常的实际结构。"""
    if isinstance(value, dict):
        for key, child in value.items():
            walk(child, f"{path}.{key}")
    elif isinstance(value, list):
        for index, child in enumerate(value):
            walk(child, f"{path}[{index}]")
    else:
        print(f"{path}: {value}")


try:
    response = client.agentic_retrieve_stream(**request)
    event_stream = response.get("stream") or response.get("body")
    if event_stream is None:
        print(json.dumps(response, ensure_ascii=False, default=str, indent=2))
        raise RuntimeError("响应中未找到事件流,请检查当前 SDK 的 output shape")

    for event in event_stream:
        print("\n--- stream event ---")
        walk(event)
except ParamValidationError as exc:
    shape = client.meta.service_model.operation_model(operation_name).input_shape
    print("可用顶层字段:", sorted(shape.members))
    raise SystemExit(f"请求结构与当前 SDK 不匹配: {exc}")
except ClientError as exc:
    error = exc.response.get("Error", {})
    raise SystemExit(
        f"Bedrock 调用失败: {error.get('Code')} - {error.get('Message')}"
    )

首次联调时,建议保留完整事件并写入受控日志,再根据实际事件类型建立显式分发器。例如将 trace 发送到调试日志,将检索结果转换为统一的证据对象,将可展示文本推送到 WebSocket 或 Server-Sent Events 客户端。

不要在生产环境无条件记录 trace。轨迹里可能包含用户问题、拆分后的查询和文档片段,应执行脱敏、访问控制和日志保留期限管理。

Trace 应该回答哪些问题

Trace 的价值不只是调试请求失败。它可以帮助团队判断 agentic 检索是否真的改善了答案:

  • 查询规划是否覆盖了原问题中的每个约束;
  • 不同子查询是否只返回了同一批重复文档;
  • 最终结果是否引用了每个比较项的证据;
  • 某个子查询无结果时,系统是否仍生成了过度确定的结论;
  • 拆分查询带来的额外延迟和调用成本是否可以接受。

解析 trace 时,不要把事件顺序硬编码成“规划、检索、结束”三个固定位置。流式协议可能插入多个检索步骤或错误事件,更稳妥的做法是按事件键或 SDK 定义的事件类型分派,并忽略客户端暂时不认识的可选事件。这样服务端增加新事件后,旧客户端不会立即崩溃。

Retrieve 与 AgenticRetrieveStream 怎么选

可以从问题复杂度、延迟预算和可观测性三个维度做决定。

选择标准 Retrieve 的典型场景包括:

  • 用户输入通常是关键词、编号或单一事实问题;
  • 应用已经自行完成查询拆分;
  • 需要稳定的低延迟,并能接受一次召回的边界;
  • 只需要检索结果,不需要观察规划过程。

选择 AgenticRetrieveStream 的典型场景包括:

  • 问题经常包含比较、条件、时间范围或多个实体;
  • 证据分布在不同文档或文档版本中;
  • 应用希望边执行边展示状态或结果;
  • 团队需要通过 trace 审计查询规划和检索步骤。

上线前不要只比较最终答案的主观流畅度。准备一组带证据标注的复合问题,同时记录召回覆盖率、引用正确率、首事件延迟、总延迟、错误率和单次请求成本。Agentic Retrieval 增加了规划能力,也增加了调用链长度和运行时不确定性。最稳妥的落地方式通常是按问题复杂度路由:简单问题继续使用 Retrieve,只有检测到多意图或多约束时才进入 AgenticRetrieveStream


相关推荐