标签: 生成式Ai

  • RAG 中的混合搜索对决!OpenSearch Serverless VS Aurora Serverless

    RAG 中的混合搜索对决!OpenSearch Serverless VS Aurora Serverless

    前言

    今天我要对可作为 Amazon Bedrock Knowledge Bases 向量数据库(搜索引擎)的工具进行对比。

    目前,Bedrock Knowledge Base 中支持混合搜索的向量数据库如下:

    • OpenSearch Serverless
    • OpenSearch Managed Cluster(OpenSearch 托管集群)
    • Aurora Serverless V2(PostgreSQL)
    • MongoDB Atlas

    本次,我将针对其中使用率较高的OpenSearch ServerlessAurora Serverless V2(PostgreSQL) ,对比二者在混合搜索中的精度表现。

    概述

    混合搜索是一种结合向量(语义)搜索关键词(全文)搜索来查找相关文档的搜索方式。这种方式既能通过向量搜索实现基于语义的检索,又能通过关键词搜索,在检索过程中纳入指定关键词的考量。

    OpenSearch Serverless 与 Aurora Serverless V2(PostgreSQL)的对比

    下面我将对本次作为数据存储使用的 OpenSearch Serverless 和 Aurora Serverless V2(PostgreSQL)进行简单对比。

    对比维度OpenSearch ServerlessAurora Serverless V2(PostgreSQL)
    混合搜索(Bedrock Knowledge Bases)支持支持
    中文支持可使用 Kuromoji 等中文形态素分析PostgreSQL 标准全文搜索(目前不支持中文形态素分析)
    向量存储格式支持浮点数 / 二进制两种格式浮点数(基于 pgvector 插件)
    计费单位OCU / 小时(最小 1 个 OCU,含 0.5 计算 OCU+0.5 存储 OCU)ACU / 小时(最小 0.5 个 ACU)
    最小配置计费示例175.22 美元(1 个 OCU:175.2 美元,存储:0.02 美元)87.83 美元(1 个 ACU:87.60 美元,I/O:0.13 美元)

    (参考链接:aws.amazon.comaws.amazon.com

    OpenSearch Serverless 支持中文形态素分析,因此即便使用中文,也能高精度地进行关键词搜索。另一方面,Aurora Serverless V2(PostgreSQL)在最小配置下的费用更具优势,但由于其默认不支持中文形态素分析,因此在中文混合搜索的精度方面存在不确定性。

    精度对比实验

    为对比 OpenSearch Serverless 与 Aurora Serverless V2(PostgreSQL)的精度,本次将开展以下两类实验:

    1. 英文数据集的搜索精度对比
    2. 中文数据集的搜索精度对比

    尤其对于中文数据集,由于 Aurora Serverless V2(PostgreSQL)不支持中文形态素分析,预计 OpenSearch Serverless 在精度上会更具优势。

    1. 实验设置

    以下是本次实验使用的基本设置。首先,Bedrock Knowledge Base 的基础设置如下,仅向量存储工具为两者的差异点。

    嵌入模型(Embedding Model)嵌入类型(Embedding Type)分块策略(Chunking Strategy)
    Titan Text Embeddings V21024 维浮点数向量嵌入分层分块(父块:2000 字符,子块:500 字符,重叠:50 字符)

    精度对比将通过 Bedrock Evaluations 完成。

    (参考链接:docs.aws.amazon.com

    本次对比将采用以下两项指标,指标取值范围均为 0~1,数值越大表示对问题的回答质量越高:

    • Context relevance(上下文相关性):衡量获取的文本与问题在上下文层面的关联程度
    • Context coverage(上下文覆盖率):衡量获取的文本对正确数据中全部信息的覆盖程度

    2. 混合搜索对比(英文数据集)

    1. 数据集

    本次实验使用的数据集如下:Amazon Reviews 2023(2023 年亚马逊评论数据集)

    (参考链接:amazon-reviews-2023.github.io

    该数据集包含约 2.8 万组 “产品 ID – 评论” 数据,示例如下:

    product/productId: B000GKXY4S
    product/title: Crazy Shape Scissor Set
    product/price: unknown
    review/userId: A1QA985ULVCQOB
    review/profileName: Carleen M. Amadio "Lady Dragonfly"
    review/helpfulness: 2/2
    review/score: 5.0
    review/time: 1314057600
    review/summary: Fun for adults too!
    review/text: I really enjoy these scissors for my inspiration books that I am making (like collage, but in books) and using these different textures these give is just wonderful, makes a great statement with the pictures and sayings. Want more, perfect for any need you have even for gifts as well. Pretty cool!
    

    2. 结果(英文)

    对比结果如下,
    数值越高,评估结果越好。

    指标类型OpenSearch无服务器Aurora Serverless V2(PostgreSQL)
    上下文相关性0.060.07
    上下文覆盖0.190.18

    3. 混合搜索对比(中文数据集)

    那么,接下来将对核心中文数据集的(检索)精度展开比较分析。​

    1. OpenSearch(中文分词设置示例)

    由于 OpenSearch Serverless 可使用 Kuromoji 形态素分析(中文分词工具),因此需进行相关配置。

    通过该配置,中文文本能被正确分割,进而有望提升关键词搜索的精度。

    配置示例

    PUT bedrock-knowledge-base-hybrid-index
    {
      "mappings": {
        "properties": {
          "AMAZON_BEDROCK_METADATA": {
            "type": "text",
            "index": false
          },
          "AMAZON_BEDROCK_TEXT_CHUNK": {
            "type": "text",
            "analyzer": "custom_kuromoji_analyzer"
          },
          "bedrock-knowledge-base-default-vector": {
            "type": "knn_vector",
            "dimension": 1024,
            "method": {
              "name": "hnsw",
              "engine": "faiss",
              "space_type": "cosinesimil"
            }
          },
          "id": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          }
        }
      },
      "settings": {
        "index": {
          "knn.algo_param": {
            "ef_search": "512"
          },
          "knn": "true",
          "analysis": {
            "analyzer": {
              "custom_kuromoji_analyzer": {
                "tokenizer": "kuromoji_tokenizer",
                "filter": [
                  "kuromoji_baseform",
                  "ja_stop"
                ],
                "char_filter": [
                  "icu_normalizer"
                ]
              }
            }
          }
        }
      }
    }
    
    

    2. 插入的中文文档

    本次使用的数据集,是让 ChatGPT 输出的,具体如下。
    在混合检索时,我们期望能以 “张居正生平” 作为关键词,检索到相关信息。

    张居正像(现藏于中国国家博物馆)

    时代 明朝中后期(嘉靖、隆庆、万历年间)

    生诞 嘉靖四年五月初三日(1525 年 5 月 24 日)

    死没 万历十年六月二十日(1582 年 7 月 9 日)(58 岁卒)

    改名 无(一直以 “张居正” 为名,字叔大,号太岳)

    字:叔大

    号:太岳

    谥号:文忠(万历朝初赠,后被追夺,天启朝恢复)

    墓所:湖北省荆州市沙市区张居正墓

    官职:吏部左侍郎兼东阁大学士、礼部尚书兼武英殿大学士、少师兼太子太师、吏部尚书、中极殿大学士(内阁首辅)

    主要事迹 1. 推行 “一条鞭法”,将田赋、徭役和杂税合并,按田亩折算银两征收,简化税制,增加财政收入;2. 实施 “考成法”,考核各级官吏政绩,整顿吏治,提高行政效率;3. 重用戚继光、李成梁等将领,加强北方边防,抵御蒙古部落侵扰,稳定边疆局势;4. 主持治理黄河、淮河,任用潘季驯负责河工,疏通河道,减少水患,保障农业生产。

    评估用数据集示例

    • 问题:请告知张居正被任命为吏部尚书的年份
    • 答案:张居正于明万历元年(公元 1573 年) 正式被任命为吏部尚书。

    3. 结果(中文)

    以下是中文数据集的精度对比结果。数值越大,代表评价结果越好。

    Metric typeOpenSearch ServerlessAurora Serverless V2(PostgreSQL)
    Context relevance0.450.43
    Context coverage1.000.93

    如上表所示,尽管优势微弱,但 OpenSearch Serverless 在两项指标上均超过 Aurora Serverless V2(PostgreSQL)。尤其在衡量 “问题回答覆盖度” 的上下文覆盖率(Context coverage)指标上,OpenSearch Serverless 的优势更为明显。

    我们认为,这一差异源于 OpenSearch Serverless 通过 Kuromoji 实现了中文形态素分析支持,进而在混合搜索的关键词搜索精度上形成了优势。

    此外,我们也对比了两者的搜索速度,结果如下:我们连续执行 5 种不同查询,去除最大值与最小值后计算 “截尾平均值”(Trimmed Mean)进行对比。

    OpenSearch Serverless(秒)Aurora Serverless V2(PostgreSQL)(秒)
    0.48 秒0.55 秒

    从搜索速度来看,OpenSearch Serverless 同样具备更快的检索表现。

    总结

    本次实验对比了在 Bedrock 知识库中,分别使用 OpenSearch Serverless 与 Aurora Serverless V2(PostgreSQL)实现混合搜索的效果。结果显示,在中文搜索的精度与速度上,OpenSearch Serverless 均优于 Aurora Serverless V2(PostgreSQL)。

    需要说明的是,本次验证基于 “数据量较少” 的场景,因此两者的差距并不显著;若后续数据量增加,结果可能会发生变化。不过,从整体来看,两款工具在精度与速度上均具备较高性能,建议根据实际使用场景数据量选择合适的工具。

  • 借助 StrandsAgents+AgentCore Memory 实现符合个人偏好的智能体

    借助 StrandsAgents+AgentCore Memory 实现符合个人偏好的智能体

    近年来,随着对话式 AI 的应用不断深入,为每位用户提供个性化体验变得愈发重要。当前所需的智能体,已不再是简单的一问一答模式,而是能够理解 “用户是谁、拥有怎样的关注点与目标” 后再进行响应的智能体。

    在本文中,我们将结合 Strands Agents 与 Bedrock AgentCore,对可记忆并活用用户对话历史的个性化智能体进行实现与验证。

    1. 引言

    首先,我们将对各个构成要素进行简单介绍。

    1.1 什么是 Strands Agents

    Strands Agents 是一套能够灵活设计并构建对话式智能体行为及对话流程的机制。通过组合多个工具,可在对话过程中实现所需的处理(如 API 调用、数据检索、记忆查询等)。

    相关内容也可参考 GitHub 链接:github.com

    1.1.1 Strands Agents 工具

    在 Strands Agents 中,“工具” 指的是智能体所使用的外部功能。本文将重点介绍用于处理对话记忆的 “Agent Core Memory” 工具。

    相关参考链接:github.com

    1.2 什么是 Bedrock AgentCore

    Bedrock AgentCore 是一项托管服务,为智能体的开发与运行提供所需功能。它具备以下功能,可助力智能体的顺畅构建:

    • 提供运行环境
    • 与各类工具联动
    • 认证与授权功能
    • 按用户管理记忆等

    官方参考链接:aws.amazon.com

    1.2.1 AgentCore 记忆功能(AgentCore Memory)

    AgentCore 具备 “Memory(记忆)” 功能,可让智能体拥有短期记忆与长期记忆。

    其中,长期记忆尤为重要,它能够记录通过与用户对话获取的事实信息,并在后续对话中加以活用。例如,通过记忆用户 “擅长 Python”“喜欢旅行” 等偏好与特征,智能体在之后的对话中,就能给出更贴合用户需求的响应与建议。

    需要注意的是,并非所有已记忆的内容都会被调用,系统会动态检索并使用与当前对话相关的信息。

    ChatGPT 也具备记忆功能,能够记住用户的个人信息与偏好,而通过 Bedrock AgentCore,我们可以自行实现同等功能,从而达成自然的个性化体验。

    官方文档参考链接:docs.aws.amazon.com

    2. 验证

    我们将实际创建智能体,验证其能否在保存、检索记忆的同时进行对话。

    由于短期记忆可通过 StrandsAgents 的 ConversationManager 进行管理,因此本次验证将重点关注长期记忆。

    我们已通过 AgentCore 的控制台,创建了启用 “用户偏好” 策略的记忆模块。

    2.1 结构图

    2.2 实现过程

    以下为智能体的实现代码。为了获取与特定用户的对话记录,我们设置了可通过参数接收 “与谁对话” 这一信息的功能。

    class MemoryAgent:
        PROMPT = dedent("""\
            请你扮演一个能为用户提供个性化服务、贴合用户需求的助手。
            请利用与用户过往的交互信息,理解用户想要做的事情。
    
            以下内容仅需在你内部处理,不得告知用户。
            请自然地进行互动。
            - 对于用户的输入内容,不得修改,需全部通过agent_core_memory的record工具进行记录。
            - 在对话过程中,若话题发生变化或开启新话题,请通过agent_core_memory的retrieve工具,从过往交互记录中获取与用户相关的信息。
            以上内容仅需在你内部处理,不得告知用户。
        """)
    
        def __init__(self, actor_id: str, session_id: str):
            model = BedrockModel(
                model_id='us.anthropic.claude-sonnet-4-20250514-v1:0',
                streaming=True,
                additional_request_fields={
                    'thinking': {'type': 'enabled', 'budget_tokens': 4000},
                    'anthropic_beta': ['interleaved-thinking-2025-05-14'],
                },
                region_name='us-west-2',
            )
    
            # 此处准备AgentCore Memory
            # 可指定使用的记忆模块以及长期记忆的整理策略
            provider = AgentCoreMemoryToolProvider(
                memory_id=MEMORY_ID,
                actor_id=actor_id,
                session_id=session_id,
                namespace=f'/strategies/{STRATEGY_ID}/actors/{actor_id}',
                region='us-west-2',
            )
    
            self.agent = Agent(
                model=model,
                system_prompt=self.PROMPT,
                tools=provider.tools,
            )
    
        async def stream(self, prompt):
            async for event in self.agent.stream_async(prompt):
                if text := event.get('event', {}).get('contentBlockDelta', {}).get('delta', {}).get('text', ''):
                    yield text
                for content in event.get('message', {}).get('content', []):
                    if isinstance(content, dict) and (tool_use := content.get('toolUse', '')):
                        logger.info('## 工具使用:%s', tool_use)
    

    2.3 尝试对话

    我平时习惯使用 “Python+Angular” 的组合开发应用。如果智能体生成的应用也采用这种技术组合,我不仅更容易理解,还能直接将其投入实际应用。

    本次验证中,我首先明确告知智能体需用 Python+Angular 实现,随后在不额外说明的情况下让其开发应用,以此检验它是否会主动使用 Angular。若智能体在未明确告知的情况下仍能选择 Angular,就说明它理解了我的偏好,实现了个性化,称得上是贴心的智能体。

    2.3.1 未理解用户偏好的情况

    我们先确认未设置 Strands Agents Tools、不使用记忆功能时的智能体表现。

    首次对话:明确告知所用框架并让智能体实现

    “请用 Python+Angular 开发一个 LLM 聊天 GUI 应用。”

    智能体按照需求,使用 Python+Angular 实现了应用:

    “将为您开发 LLM 聊天应用。我们将以 Python(FastAPI)作为后端,Angular 作为前端进行构建。”(其余省略)

    另起线程:不告知框架,让智能体实现

    若让同一个智能体开发,它有可能从对话历史中推断出需使用 Angular。为避免这种情况,我先停止了智能体应用,重新初始化一个新的智能体,再发出以下请求:“开发一个 RAG 聊天 GUI 应用。”

    由于新智能体未保留之前的对话记忆,不记得上次使用 Angular 作为前端框架的情况。因此,它并未采用我习惯使用的 Angular,而是生成了基于 Streamlit 的代码:

    “将为您开发 RAG 聊天 GUI 应用。我们将使用 Streamlit,构建一个包含文档上传、向量检索、聊天功能的完整应用。”(其余省略)

    2.3.2 已理解用户偏好的情况

    接下来,我们启用 Strands Agents Tools 的 Memory(记忆)工具,通过使用 AgentCore Memory,验证智能体是否能记住过往对话,从而成为具备个性化能力的智能体。

    首次对话:明确告知所用框架并让智能体实现

    “请用 Python+Angular 开发一个 LLM 聊天 GUI 应用。”

    智能体同样按照需求完成了开发:

    “好的,我们来用 Python + Angular 开发 LLM 聊天 GUI 应用!将采用全栈架构,打造一个实用的聊天应用。”(其余省略)

    另起线程:不告知框架,让智能体实现

    此处我们同样先创建一个新的智能体,再发起请求:“开发一个 RAG 聊天 GUI 应用。”

    智能体回复:

    “参考过往的交互记录,发现您对用 Python 和 Angular 开发 LLM 聊天应用很感兴趣!本次我们来开发一个集成了 RAG(检索增强生成)功能的聊天 GUI 应用吧。

    以下为您建议的技术架构:

    技术栈

    • 后端:Python(FastAPI)
    • 前端:Angular
    • RAG:LangChain + 向量数据库(Chroma/FAISS)
    • LLM:OpenAI API 或 Hugging Face

    (其余省略)”

    可见,智能体记住了此前用户使用 Python+Angular 开发 GUI 应用的偏好,因此主动提议采用相同技术架构进行开发。

    这表明 AgentCore Memory 实现了预期功能,能够输出符合用户偏好的响应。

    2.4 查看 Memory的内容

    由于无法从 AWS 控制台直接查看 Memory 的内容,我们通过 AWS 命令行工具(AWSCLI)获取相关数据。

    从获取的结果中可以看出,智能体已将 “对开发 LLM 应用感兴趣”“使用 Python+Angular 开发应用” 识别为用户的偏好。

    $ aws bedrock-agentcore list-memory-records \
        --memory-id $memoryId \
        --namespace /strategies/memory_preference/actors/sy
    {
        "memoryRecordSummaries": [
            {
                "memoryRecordId": "mem-cacf3145-324f-4f30-8e83-dade742bc2e0",
                "content": {
                    "text": "{\"context\":\"对开发LLM(大型语言模型)聊天应用表现出兴趣\",\"preference\":\"对基于LLM的聊天应用感兴趣\",\"categories\":[\"人工智能\",\"技术\",\"应用开发\"]}"
                },
                "memoryStrategyId": "memory_preference",
                "namespaces": ["/strategies/memory_preference/actors/sy"]
            },
            {
                "memoryRecordId": "mem-77a9f50f-8589-4229-874b-2dcac251708f",
                "content": {
                    "text": "{\"context\":\"用户要求使用Python+Angular开发LLM聊天GUI应用\",\"preference\":\"对使用Python和Angular开发应用感兴趣\",\"categories\":[\"编程\",\"软件开发\",\"技术\"]}"
                },
                "memoryStrategyId": "memory_preference",
                "namespaces": ["/strategies/memory_preference/actors/sy"]
            }
        ]
    }
    

    当 Strands Agents 的智能体调用该 Memory 时,可通过向量检索获取匹配度高的内容作为相关记忆。

    以下是第二次运行智能体时,Strands Agents 实际执行的工具调用内容,从中可看出其利用了向量检索的分数来获取相关记忆:

    agent.agent.tool.agent_core_memory(
        action='retrieve',
        query='RAG 聊天 GUI 应用 开发 编程',
    )
    {
        "memoryRecordSummaries": [
            {
                "content": {
                    "text": "{\"context\":\"用户要求使用Python+Angular开发LLM聊天GUI应用\",\"preference\":\"对使用Python和Angular开发应用感兴趣\",\"categories\":[\"编程\",\"软件开发\",\"技术\"]}"
                },
                "namespaces": ["/strategies/memory_preference/actors/sy"],
                "score": 0.49530885
            }
        ]
    }
    

    3. 应用示例

    通过将 Strands Agents Tools 与 AgentCore Memory 相结合,智能体能够记住对话上下文,并根据用户的偏好和目标提供个性化服务。

    此处将介绍几个在实际业务或服务中的应用场景。

    客户支持

    将用户过往的咨询内容及问题处理记录存储在长期记忆中,用户无需每次都从基础情况开始说明。例如,在处理错误问题时,智能体可实现 “上次出现的是XX错误,这次看起来是△△错误呢” 这类理解上下文的支持服务。

    持续学习支持

    作为教育类应用或企业内部培训的辅助工具,智能体可记录学习者的进度及薄弱领域,并据此调整出题内容和讲解方式。用户能获得 “以前你对这个问题不太擅长,这次已经能解出来了呢” 这类反馈,从而得到更具持续性的学习支持。

    个性化推荐系统

    在提供产品推荐或内容建议的应用中,智能体可结合用户的偏好及过往选择进行推荐。例如,旅行方案推荐智能体可实现 “上次您更喜欢安静的温泉胜地,这次为您推荐氛围相似的〇〇地区” 这类响应。

    4. 总结

    通过将 Strands Agents 与 Bedrock AgentCore 的 Memory 功能相结合,能够实现传统对话式 AI 难以做到的 “保持上下文”“结合个人偏好提供服务” 等能力。

    本文通过一个简单的聊天应用,对 AgentCore Memory 的功能进行了验证。

    结果表明,利用 Memory 工具能够为用户提供更自然、更具连贯性的体验。

    未来,还需要应对更复杂的应用场景,例如提升记忆的准确性、实现记忆的删除与修改控制、支持多用户使用等。可以说,让智能体具备 “记忆” 能力,是未来 AI 应用发展中的关键功能之一。