如果你在使用 langchain_community 时遇到 text_splitterRecursiveCharacterTextSplitter 未找到的问题,可能是因为 langchain_community 的模块结构发生了变化。以下是正确的导入方式和解决方案:

正确的导入方式

  1. RecursiveCharacterTextSplitter
    • 在较新的 langchain_community 版本中,RecursiveCharacterTextSplitter 仍然存在,但可能需要从 langchain.text_splitter 导入,而不是 langchain_community.text_splitter
    • 如果你使用的是 langchain_community,请确保安装的是最新版本。

  2. Embeddings
    Embeddings 是一个基类,通常从 langchain.embeddings.base 导入,而不是 langchain_community.embeddings.base

更新后的代码

以下是更新后的代码,确保正确导入 RecursiveCharacterTextSplitterEmbeddings

import warnings
from langchain_community.document_loaders import TextLoader, PyPDFLoader, Docx2txtLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter  # 从 langchain 导入
from langchain_community.vectorstores import Milvus
from langchain.embeddings.base import Embeddings  # 从 langchain 导入
from langchain_community.chains import RetrievalQA
from langchain_community.llms import Ollama
import os
import requests
from email import policy
from email.parser import BytesParser
from email import message_from_bytes
from extract_msg import Message  # 用于解析 .msg 文件


# 完全禁用所有警告(生产环境慎用)
warnings.filterwarnings("ignore")


# 使用 Ollama 的 nomic-embed-text 生成嵌入
class NomicEmbedText(Embeddings):
    def __init__(self, base_url="http://10.80.0.230:11434"):
        self.base_url = base_url

    def embed_query(self, text):
        response = requests.post(
            f"{self.base_url}/api/embeddings",
            json={"model": "nomic-embed-text:v1.5", "prompt": text}
        )
        if response.status_code != 200:
            raise ValueError(f"嵌入生成失败: {response.text}")
        return response.json()["embedding"]

    def embed_documents(self, texts):
        embeddings = []
        for text in texts:
            embedding = self.embed_query(text)
            embeddings.append(embedding)
        return embeddings


# 自定义 EML 文件加载器
class EMLoader:
    def __init__(self, file_path):
        self.file_path = file_path

    def load(self):
        with open(self.file_path, "rb") as f:
            msg = message_from_bytes(f.read(), policy=policy.default)

        # 提取邮件正文内容
        text = self._extract_email_content(msg)
        return [{"page_content": text, "metadata": {"source": self.file_path}}]

    def _extract_email_content(self, msg):
        """递归提取邮件内容"""
        if msg.is_multipart():
            # 如果是多部分邮件,遍历每个部分
            text = ""
            for part in msg.walk():
                content_type = part.get_content_type()
                if content_type in ["text/plain", "text/html"]:
                    # 提取文本或 HTML 内容
                    text += part.get_payload(decode=True).decode(part.get_content_charset() or "utf-8", errors="ignore")
            return text
        else:
            # 如果是单部分邮件,直接提取内容
            return msg.get_payload(decode=True).decode(msg.get_content_charset() or "utf-8", errors="ignore")


# 自定义 MSG 文件加载器
class MSGLoader:
    def __init__(self, file_path):
        self.file_path = file_path

    def load(self):
        msg = Message(self.file_path)
        text = msg.body
        return [{"page_content": text, "metadata": {"source": self.file_path}}]


# 加载并分割文档
def load_and_split_documents(file_path):
    # 检查文件路径是否有效
    if not file_path:
        raise ValueError("文件路径不能为空")
    if not os.path.isfile(file_path):
        raise FileNotFoundError(f"文件不存在: {file_path}")

    print(f"加载文件: {file_path}")
    if file_path.endswith('.pdf'):
        print("使用 PyPDFLoader")
        loader = PyPDFLoader(file_path)
    elif file_path.endswith('.docx'):
        print("使用 Docx2txtLoader")
        loader = Docx2txtLoader(file_path)
    elif file_path.endswith('.txt'):
        print("使用 TextLoader")
        loader = TextLoader(file_path)
    elif file_path.endswith('.eml'):
        print("使用 EMLoader")
        loader = EMLoader(file_path)
    elif file_path.endswith('.msg'):
        print("使用 MSGLoader")
        loader = MSGLoader(file_path)
    else:
        raise ValueError("不支持的文件格式")

    # 加载文档
    documents = loader.load()
    print(f"加载了 {len(documents)} 个文档块")

    # 文档分块
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=500,  # 每块 500 字符
        chunk_overlap=50  # 块之间重叠 50 字符
    )
    chunks = text_splitter.split_documents(documents)
    print(f"分块后得到 {len(chunks)} 个块")
    return chunks


def create_milvus_vector_store(chunks, collection_name, file_doc_id, file_path):
    embeddings = NomicEmbedText()
    texts = [chunk.page_content for chunk in chunks]
    metadatas = [{"doc_id": file_doc_id, "file_path": file_path} for _ in range(len(texts))]

    # 连接 Milvus
    vector_store = Milvus.from_texts(
        texts=texts,
        embedding=embeddings,
        metadatas=metadatas,
        collection_name=collection_name,
        connection_args={"host": "10.80.0.230", "port": "19530"}
    )
    return vector_store


# 设置 RAG 管道
def setup_rag_pipeline(vector_store):
    llm = Ollama(model="deepseek-r1:1.5b", base_url="http://10.80.0.230:11434")
    qa_pipeline = RetrievalQA.from_chain_type(
        llm=llm,
        chain_type="stuff",
        retriever=vector_store.as_retriever(search_kwargs={"k": 3})
    )
    return qa_pipeline


def main():
    file_path = r"/root/leon/oceanx-ai/demo-5-ai-demonstration/word/ISO14001-2015标准的七个实质性变化.docx"

    chunks = load_and_split_documents(file_path)
    collection_name = "oceanx_ecm_04091556"
    file_doc_id = 666
    create_milvus_vector_store(chunks, collection_name, file_doc_id, file_path)
    print(f"milvus_nomic_embed_text_rag success.")


if __name__ == "__main__":
    main()

关键点说明

  1. RecursiveCharacterTextSplitter 的导入
    RecursiveCharacterTextSplitter 是从 langchain.text_splitter 导入的,而不是 langchain_community.text_splitter
    • 如果你仍然遇到问题,可以尝试更新 langchainlangchain_community 到最新版本:

    pip install -U langchain langchain_community
    
  2. Embeddings 的导入
    Embeddings 是从 langchain.embeddings.base 导入的,而不是 langchain_community.embeddings.base

  3. 版本兼容性
    • 确保 langchainlangchain_community 的版本兼容。如果问题仍然存在,可以尝试降级到较旧的版本:

    pip install langchain==0.1.0 langchain_community==0.1.0
    
  4. 检查安装的包
    • 运行以下命令检查已安装的包及其版本:

    pip show langchain langchain_community
    

如果问题仍然存在

如果你仍然遇到问题,可以尝试以下方法:

  1. 直接从 langchain 导入 RecursiveCharacterTextSplitter

    from langchain.text_splitter import RecursiveCharacterTextSplitter
    
  2. 检查 langchain_community 的文档
    • 访问 langchain_community 文档 确认模块路径是否正确。

  3. 手动安装特定版本
    • 如果你知道某个版本是稳定的,可以手动安装:

    pip install langchain==0.1.0 langchain_community==0.1.0
    

希望这些信息能帮助你解决问题!如果还有其他问题,请随时告诉我。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐