sillydaddy
5.47D
4.88D
V2EX  ›  数据库

向量数据库的正确用法是什么?

  •  
  •   sillydaddy · May 26 · 5521 views
    想用它预处理文档,然后帮助提取与关键字匹配的内容。看起来很理想,但实际提取不尽人意。

    我做了个小工具,把切分后的每段,与关键字的匹配程度,可视化出来了,可以直观看到匹配度。

    从网页内容中,提取“中国人民银行的编制”,效果不错:


    从网页内容中,提取“中国人民银行的职责”,开头匹配的很好,但漏掉了接下来的那些:


    可以看到,在提取“中国人民银行的职责”匹配的句段时,会漏掉枚举的那几条。

    这可以说是段落拆分的问题,我是逐句拆分的,问题是,段落怎么才能合理拆分呢?如果必须知道哪些跟哪些是在一起的,那就相当于已经提前理解文章的内容了,就没有必要上向量数据库了。

    所以,向量数据库如何做是比较合适的呢?就比如我上面的这种应用场景。
    Supplement 1  ·  May 26
    最佳使用方法应该是向量数据库配合 LLM 的 ReACT 模式,感谢楼里的各位。

    数据搜集以及向量数据库的方案:
    核心框架是:多路召回(向量搜索+匹配搜索)+ReACT 的 Agent 机制。
    召回:
    其中向量搜索,使用关键句式去枚举,即借助已经搜集到的那些,作为示例向量,取匹配。
    其中匹配搜索,使用扩充的关键字、正则表达式。
    ReACT 机制:
    对于向量检索,取 topK 个匹配项,给到 Agent 合并 meta 信息。由 Agent 来 ReACT ,即是否继续扩展。
    对于匹配搜索,取关键字所在的词句,给到 Agent 合并 meta 信息。由 Agent 来 ReACT ,即是否继续扩展。
    ReACT 除了匹配项的内容,还需要 meta 信息,即匹配项的位置、周围字句的环境。由 Agent 决定是否扩展。
    36 replies    2026-05-27 09:45:59 +08:00
    IsaacYoung
        1
    IsaacYoung  
       May 26
    没太研究过,不过记得之前好像看到过几个方向,楼主可以参考下:
    1. 分段的时候不要完全分割开,上一段和下一段保留一部分重叠
    2. 用语义分割,印象中好像是根据文本的结构例如段落、标题等进行分割
    cryptovae
        2
    cryptovae  
       May 26
    400 个 token 一段的情况下,上一段的后 50 个 token 和下一段开头的 50 个 token ,一起算向量,连贯性有了
    每个段落都有自己的 metadata ,包含标题,章节,目录名称,都可以拿来计算向量
    通过 LLM 提取时间线和关键词计算向量,可以增强相对应的语义检索
    sillydaddy
        3
    sillydaddy  
    OP
       May 26
    @IsaacYoung
    @cryptovae
    这些方法应该能缓解,但是没有从根儿上解决。比如,如果恰好关键信息不在重叠的 token 里面呢?

    关键在于,向量搜索它会漏掉。

    如果是人来交互式的查看结果,可以把最匹配的 topK 个,优先展示出来,如果不满意,再动态增加 topK 。
    可如果是程序来处理呢?怎么保证不会漏掉呢?
    IsaacYoung
        4
    IsaacYoung  
       May 26
    fennu2333
        5
    fennu2333  
       May 26   ❤️ 2
    同语言搜索用向量 + BM25 混合搜索效果会更好些,根据你的目的调整权重。向量搜索也不是银弹,他只能解决 query 和 chuck 之间向量表征相似度的问题,还是要看你具体场景看怎么切 chunk ,如何加入更多的召回手段进行多路召回
    maolon
        6
    maolon  
       May 26   ❤️ 1
    实际我觉得是关键字匹配的问题,关键字匹配本身是 sparse 匹配任务,对应的应该是 tfidf 这种算法搞出来的向量,但是你用的这种 embedding 模型生成向量是 desnse 的,换言之就是关键字那边语义信息不足,

    正常做法应该是问题改写,也就是从你的关键词里改写出多个问题(比如加入上下文 context 然后改写),再来匹配,或者反向操作,直接用 bm25 来处理文本片段
    sillydaddy
        7
    sillydaddy  
    OP
       May 26
    @IsaacYoung 感谢分享,里面提到的「父子文档」,其实跟楼上提到的依赖预制的语义结构是一样的。这个依赖条件,其实本身也需要 LLM 的介入,否则只凭借解析文本的结构、网页的结构来确定,并不稳定。

    所以,感觉还是需要 LLM 的理解能力来介入,提取多层的抽象信息。但这里有个悖论,如果是整理出的知识,需要多次检索,那 LLM 介入一次,后续多次使用,效率比较高。但如果是我这种,只需要提取一次,那直接让 LLM 提取所需的信息就可以,就没必要再让向量数据库转一次手了。

    前者抽取多层抽象信息,感觉跟我之前提到的笔记的网状 tag 系统,不谋而合了: https://v2ex.com/t/825142
    cuimc
        8
    cuimc  
       May 26
    我最近在使用 llm wiki 的形式在做,感觉还不错
    Morriaty
        9
    Morriaty  
       May 26   ❤️ 2
    这个悖论,它的发展历程其实就是 cursor 类以 RAG 向量匹配为核心的 CodingIDE ,逐步过渡到 ClaudeCode 类以 ReACT 多工具( grep, ls, find, mcp 等)为核心的 CodingAgent 的过程

    所以,理论上你这个中国人民银行的查询要搞好,最快的方法是接个 CC ,和一些工具函数
    sillydaddy
        10
    sillydaddy  
    OP
       May 26
    @maolon #6 这个把关键词改写成长句的,还是第一次见到,应该是叫 HyDE 吧,还挺神奇的!我感觉挺适合我的需求的,感谢!
    sillydaddy
        11
    sillydaddy  
    OP
       May 26
    @Morriaty 你的意思是不是,让大模型自己根据搜索匹配的过程,来适应性的查找?比如搜索到某些关键字,然后再扩展它的范围?也很道理。因为我的目的就是节省 token ,如果不用读全文,那就满足我的需求了。
    nomagick
        12
    nomagick  
       May 26
    你的颗粒度太细了,你是想在一篇文章里找出和查询最相关的句是吗? 这就需要在句向量里包括之前的上下文信息,关键词 late chunking , 通俗来讲就是每个句子的向量不是它自己,而是整篇文章截止到句子结束。

    如果是想在海量文档里找出相关文档,那就按篇章段分片,不要拘泥于句向量。
    sillydaddy
        13
    sillydaddy  
    OP
       May 26
    @nomagick 对了,补充一下这件事的背景,其实我在做一个 govmap 项目,需要搜集国省市县乡的各机构的职责、构成、编制等等:
    https://v2ex.com/t/907899#r_12559610

    涉及到的文档处理比较多,需要不少的搜索工作量和整理工作量。还是希望能尽量减少一些 token 的消耗。所以,需要一个比较流程化的处理过程,比如搜索、下载、抽取关联片段、提取信息、整理为格式化数据。
    nomagick
        14
    nomagick  
       May 26
    @nomagick Late chunking 不是所有模型都能支持,需要 mean pooling 的模型才可以
    sillydaddy
        15
    sillydaddy  
    OP
       May 26
    @nomagick @sillydaddy #13 当然也不止这一个项目。而且我感觉所有需要从互联网收集、整理信息的,都会遇到类似的需求:不能漏掉关键信息,不能消耗太多 token 。
    nofishing
        16
    nofishing  
       May 26
    @sillydaddy #13 这个需求过去是由数据清洗、建模、检索多个数据团队互相配合做的工作,光靠通用 RAG 和 AI 效果肯定不能让人很满意
    PiersSoCool
        17
    PiersSoCool  
       May 26
    重叠一点,然后召回多一点,就好了,成本我建议你直接用 deepseek 就好了,便宜的很
    PiersSoCool
        18
    PiersSoCool  
       May 26
    如果有很多关系,估计要知识图谱了
    PiersSoCool
        19
    PiersSoCool  
       May 26
    暴力一点,检索的时候,召回全文给 llm ,也没有多少钱的
    Clannad0708
        20
    Clannad0708  
       May 26
    @IsaacYoung #4 重点在于你怎么把你以为的“不满意” 可以量化的表示出来。

    就好比模型训练的时候,输入给她的不是英文单词不是汉字,而是根据 embeding 后的向量表-才能被拿去计算,才能被算法计算相似性。

    你想要让他做的很好就一定要把握好所谓展示所谓满意的标准是什么,如果只是人为的无法用逻辑和算法表示的话,那确实没办法了。
    superkite
        21
    superkite  
       May 26
    检索从来都不是问题,问题在于召回率。。。
    Morriaty
        22
    Morriaty  
       May 26   ❤️ 3
    @sillydaddy 不要指望一次向量召回就“选中全部关键句子”,而是让模型自己在“看结果”的过程中,决定要不要扩大范围、补充召回、重新提问。

    一个典型的 ReAct 交互轨迹可以长这样(简化版,伪日志):

    Thought 1:
    任务是抽取“中国人民银行的职责”。先用检索工具看看跟该机构和“职责”相关的片段。

    Action 1:
    使用 tool_search_chunks
    参数:query = "中国人民银行 职责 主要职责"
    top_k = 20
    检索方式:向量 + 关键词 BM25 混合

    Observation 1:
    返回了若干句子:
    - [chunk_101] ……中国人民银行是国务院组成部门,负责……(开头介绍)
    - [chunk_102] ……主要职责是:(一)拟定和执行货币政策……
    - [chunk_103] ……(二)防范和化解金融风险……
    - [chunk_104] ……(三)维护金融稳定……
    - [chunk_205] ……编制情况为机关行政编制若干名……
    其中一些句子被分得很碎,看起来每条职责是一小句。

    Thought 2:
    目前召回里已经出现了一些典型“主要职责是:(一)(二)(三)……”结构。
    但这些 chunk 可能只覆盖了前几条,后面可能还有(四)(五)(六)。
    我应该基于这些 chunk 的位置,再向前向后扩展一小段上下文,以免漏掉枚举条款。

    Action 2:
    使用 tool_expand_window
    参数:chunk_ids = [101,102,103,104]
    window_size = 3 # 每个句子向前、向后各扩 3 句

    Observation 2:
    得到了一个更完整的段落:
    - 段落 P1:包含从“主要职责是:”到“(六)……”的全部条款;
    - 同时保留了段首“主要职责是:”这句,方便后续抽取。

    Thought 3:
    P1 里已经包含了完整的“职责”枚举条款。
    接下来可以不再扩展检索范围,而是专注于信息抽取。
    我将调用一个专门的抽取工具,把职责条款提成结构化列表。

    Action 3:
    使用 tool_extract_duties
    参数:text = 段落 P1 的完整文本

    Observation 3:
    抽取结果 duty_list:
    1. 拟定和执行货币政策,防止通货膨胀和通货紧缩,保持货币币值稳定。
    2. 防范和化解金融风险,维护国家金融安全。
    3. 维护金融稳定,推进金融改革和发展。
    4. 负责金融市场的监管和发展工作。
    5. ……
    (略)

    Thought 4:
    抽取结果看起来已经覆盖了所有枚举条目,且结构化良好。
    为保险起见,可以再做一次“职责相关性检查”,确认没有某条“职责”散落在别处被我漏掉。

    Action 4:
    使用 tool_search_chunks
    参数:query = "中国人民银行 职责 负责 主要职责"
    top_k = 50
    并过滤掉已经在 P1 中的语句,只看其它位置的命中。

    Observation 4:
    新检索命中的其它片段大多是对上述职责的解释、扩展说明或引用,
    而不是新的“主要职责”条目。

    Thought 5:
    没有观察到新的“职责枚举”,当前 duty_list 可以视为基本完整。
    接下来,将其写入 govmap 的结构化数据。

    Action 5:
    使用 tool_save_structured_result
    参数:
    entity = "中国人民银行"
    type = "职责"
    data = duty_list

    Observation 5:
    保存成功。

    Final Answer:
    已完成对“中国人民银行”的职责抽取,得到 N 条职责,写入 govmap 。
    sillydaddy
        23
    sillydaddy  
    OP
       May 26
    @Morriaty 太感谢了!看样子最优解就是这个了。我把它作为附言吧,标记为已解决。

    这样 token 数量应该是比较少的,配合 DeepSeek 的低缓存价格,完全足够了,token 数量基本取决于未缓存的输入 token ,而这些 token 基本就是那些包含有效信息的文字量,最多增加一个常数倍。

    而且这种方式,应该就是向量数据库的最优解了:因为向量数据库只是给出一种渐进的匹配度。不存在机械式的程序可以客观判定的分割线,所以,最终的截止需要由人类来决定,或者由类似于人类理解力的 LLM 来决定。你说的 ReACT 模式,渐进式,恰恰符合这个模式。
    dantangfan
        24
    dantangfan  
       May 26
    mark ,其实我也有这个问题。所以在做这种课题的时候,我的体感是还不如搞个简单搜索引擎。。
    sillydaddy
        25
    sillydaddy  
    OP
       May 26
    @PiersSoCool #17 我算了一下,DeepSeek V4 Flash ,百万输入 token 是 1 块钱,我单单 govmap 这个项目就要花费三千块左右。
    icew23
        26
    icew23  
       May 26
    (尴尬,好像回复错地方了)
    我刚好也在做类似事情(不过是知识库搭建),最近也在反复想这个问题。

    我现在的理解是,向量库本身可能不是最终答案,它更像是最后“找到原文证据”的一个环节。真正难的是前置处理:怎么把原始内容整理成后面能稳定召回、能解释、能复用的结构。

    我的思路大概是:

    1. 先用 AI 对原文做一轮标签化;
    2. 再提取一部分结构化信息;
    3. 对于一些“不是很像人话”的内容,或者表达很绕、噪声很多的内容,先做归纳和清洗;
    4. 但原文不丢,结构化信息只是为了帮助检索和过滤;
    5. 真正回答用户问题时,还是根据标签 + 结构化信息 + 向量/关键词召回,最终找到原文片段,再把原文喂给 AI 一起分析。

    也就是说,前面做标签、摘要、结构化,并不是为了替代原文,而是为了最后能更稳地找到原文。因为很多时候用户问的问题不是刚好命中某一句,而是命中一个场景、一组枚举、一个上下文范围。如果只靠 embedding topK ,确实很容易只捞到相似的一小段,然后漏掉后面连续的条目或者条件说明。


    目前我的想法是,AI 前处理更像是给原始资料建立“索引层”和“导航层”,而不是把原文压缩成一个最终答案库。原文仍然是最终证据来源。
    5261
        27
    5261  
       May 26
    搜推中用的比较多?
    laminux29
        28
    laminux29  
       May 26
    不仅是这些,还有全文搜索,具体的技术手段,我们称之为 [优化] 。

    [优化] 本质上是在软硬件条件不够的情况下,牺牲一部分,来换取另一部分,这就是你看到的 [效果不好] 的根源所在。
    sillydaddy
        29
    sillydaddy  
    OP
       May 26
    @icew23 #26 感觉有达成共识了,对于知识库这种,用向量数据库+结构化信息。结构化信息需要 AI 跑一遍来提取。我在那篇笔记标签网络的主题里面,就是在手动建标签网络,现在有了 AI ,跑一遍就可以把标签网络建立起来了。你觉得那篇的想法怎么样?对于这个主题里搜集信息这种一次性的,AI 驱动的 ReACT 模式,应该比较省成本,不用考虑无关的内容。
    sillydaddy
        30
    sillydaddy  
    OP
       May 26
    @icew23 #26 而且,即使是建立了结构化信息,仍然要使用 ReACT 模式。比如我提到的标签网络,搜索一个句子,可以转化成搜索多个标签,通过搜索多个标签,找到这些标签关联节点集合,然后对它们取交并差,问题在于,每个标签所关联到的节点集合,都是非常多的,就像向量搜索时匹配到的句段一样。这就让最后的筛选结果,仍然面临 topK 类似的困境。需要由 AI 来 ReACT ,决定是否继续筛选,是否要调整筛选条件。
    teaguexiao
        31
    teaguexiao  
       May 26
    9 楼说的这个演进路径总结得很准——cursor 系是 RAG 范式(人预设检索策略),CC 是 ReACT 范式(让模型自己决定去哪找),后者 ceiling 明显更高。楼主的悖论其实更根本:如果是一次性提取任务,直接给模型工具自己读比走 RAG 更合适。
    elbisiv
        32
    elbisiv  
       May 26
    不知道你的文档多大,我做了个人知识库(文档对话),核心就是向量搜索+匹配搜索,对于切割核心方式就是转为 md 格式,根据 MD 文件切割,目前效果够用,ReACT 的话可能比较耗费 token,速度也会变慢,但是效果肯定会好
    PiersSoCool
        33
    PiersSoCool  
       May 26
    @sillydaddy 切分的小一些,召回的时候策略多一些,这个自己定制召回的力度就好,你需要两个 agent ,一个 agent 负责解答,另一个 agent 负责查询,查询的 agent 你可以给他注册几个函数,检索,召回,召回的粒度都定义好,ai 自己决定就好,如果 ai 不决定,就在提示词协助他决定,怎么做都行的,完全可以把粒度控制在函数中,另外一个 agent 负责总结就行
    PiersSoCool
        34
    PiersSoCool  
       May 26
    思路应该是给 ai 提供召回方法和工具的粒度,让他自己决定怎么召回,召回多少,不应该想着 ai 怎么处理,他比人聪明
    PiersSoCool
        35
    PiersSoCool  
       May 26
    这其实就是一个信息检索 web_search 的问题,没必要非要用向量数据库做,es 做都行,怎么爽怎么来
    icew23
        36
    icew23  
       May 27   ❤️ 1
    @sillydaddy
    是的,我目前确实也是按这个方向在做。

    我把知识库大致分成了四层:原文层、提取层、描述层、知识层。

    其中原文层、提取层和知识层基本可以按字面意思理解。这里我觉得比较关键的是“描述层”,它主要用来承接后续的检索、筛选和预览。

    我目前理解的描述层大概包括三部分:

    1. 向量数据库
    主要解决大段文字之间的语义关联问题,适合用来做内容召回。

    2. 结构化信息
    主要提取业务强相关的属性,比如一些可以明确归类、过滤、组合查询的信息。

    3. 标签系统
    标签由 AI 生成,但需要做到人能看懂、能检索、能预览。因为向量数据库和结构化信息更偏机器使用,对人工查看和调试来说不够直观,或者说预览效率太低。

    所以我的理解是,向量、结构化信息和标签系统并不是互相替代的关系,而是在描述层里分别解决不同问题:向量负责语义关联,结构化信息负责业务属性,标签系统负责人能理解和快速预览。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   1160 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 61ms · UTC 23:48 · PVG 07:48 · LAX 16:48 · JFK 19:48
    ♥ Do have faith in what you're doing.