为什么要用向量数据库

​ 传统数据库系统通常以结构化的形式存储数据,即由预定义的字段及其对应值构成。当我们面临的内容不再是数据,而是知识,提出的问题也不再局限于某个字段值,而是自然语言描述的问题,传统的关键字检索局限性就太大了。

​ 为实现非结构化数据的高效检索,关键在于将其转化为结构化的表示形式。向量化技术为此提供了可行的解决方案。通过对海量文档进行文本分块、向量化处理,并将其存储于专用数据库中,可将非结构化内容转换为数值化的向量表示。在进行检索时,查询内容经过相同的向量化处理,通过计算向量间的相似度,从数据库中找出与之最接近的k个向量。最终,所需的答案即蕴含于这k个向量所对应的文本块之中。

代码实现
  • 加载文档

    from langchain_community.document_loaders import Docx2txtLoader
    
    
    contract_file_path = "/Users/q/基金合同.docx"
    document = Docx2txtLoader(contract_file_path)
    doc = document.load()  # 返回的是一个包含 document 对象的列表
    
  • 构造切割器及文档切割

    from langchain.text_splitter import RecursiveCharacterTextSplitter
    
    
    text_splitter = RecursiveCharacterTextSplitter(separators=["\n\n", "\n", "。", "!", "?", ";", ",", " ", ""], chunk_size=200,chunk_overlap=50)
    documents = text_splitter.split_documents(doc)
    
  • 构造向量模型

    from langchain_community.embeddings import DashScopeEmbeddings
    
    embeddings = DashScopeEmbeddings(
        model="text-embedding-v1",
        dashscope_api_key=my_api_key
    )
    
  • 切割后文档存入向量数据库

    from langchain.vectorstores import FAISS
    
    
    store = FAISS.from_documents(documents, embeddings)
    
  • 执行检索

    from langchain_community.document_loaders import Docx2txtLoader
    from  langchain.text_splitter import RecursiveCharacterTextSplitter
    from langchain.vectorstores import FAISS
    import time
    
    query="基金名称"
    docs=store.similarity_search(query,k=2)
    doc_content = "\n".join([item.page_content for item in docs])
    
  • 构建 chat 模型client

    from langchain_community.llms import Tongyi
    from langchain.prompts import PromptTemplate
    
    # 使用阿里云专用LLM类
    llm = Tongyi(
        model_name='qwen-max',  # 这里可以使用 qwen-max
        api_key=my_api_key,
        temperature=0.3,
        max_tokens=300
    )
    
  • 创建提示词模板并调用大模型检索

    from langchain.prompts import PromptTemplate
    
    
    prompt_template = """你是一个专业的信息提取助手。你的任务是从给定的文本中精确提取指定字段的值。
    
    要求:
    1. 只提取文本中明确提到的信息,不要推测或生成不存在的信息
    2. 如果字段值不存在,返回 null
    3. 保持值的原始格式,不要修改
    4. 对于数字、日期等格式,保持原文中的形式
    5. 如果字段有多个可能的值,选择最符合语境的一个
    
    原文档内容为:
    {source_content}
    
    请根据文档内容提取字段{field_name}的值,并以数组嵌套json格式输出,json 的key是 field_name 和 value。
    """
    
    
    prompt_template = PromptTemplate(template=prompt_template, input_variables=['source_content','field_name'])
    
    prompt = prompt_template.format(source_content=doc_content, field_name="基金名称")
    
    print(llm.invoke(prompt))
    
    
总结
  1. 选择合适的切割器和embedding 模型是保证检索质量的关键,参考切割器选型
  2. 文档存储入向量数据库是一个比较耗时的过程,生产中可以使用预加载结合缓存的方式提升响应速率;
  3. 利用 RAG 先检索到文档块,再请求 LLM 可以节省 token
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐