Parte 1 ¿Qué es LangChain? La biblioteca de complementos/funciones de LLM

Parte 1 ¿Qué es LangChain? La biblioteca de complementos/funciones de LLM 


1.1 La estructura general de langchain
En términos simples, la llamada langchain (dirección del sitio web oficial, dirección de GitHub) encapsula muchas funciones comúnmente utilizadas en IA en una biblioteca , y tiene interfaces para llamar a varias API de modelos comerciales y modelos de código abierto , y admite los siguientes componentes

Los amigos que están en contacto con él por primera vez pueden marearse al ver tantos componentes (hay tantas cosas empaquetadas y siento que quiere empaquetar todas las funciones/herramientas que necesita LLM). Entendiendo, podemos comenzar con el gran nivel. Toda la biblioteca langchain se divide en tres capas principales: capa básica, capa de capacidad y capa de aplicación.

1.1.1 Capa básica: modelos, LLM, índice
Modelos: Modelos
Varios tipos de modelos e integración de modelos, como las diversas API/GPT-4 de OpenAI, etc. , proporcionan una interfaz unificada para varios modelos básicos
, como completar una pregunta y respuesta a través de API
import os
os.environ["OPENAI_API_KEY"] = 'su clave api'
de langchain.llms import OpenAI
 
llm = OpenAI(model_name="text-davinci-003",max_tokens=1024)
llm("Cómo evaluar la inteligencia artificial ")
Capa LLMS
Esta capa enfatiza principalmente la encapsulación de las capacidades de la capa de modelos y las capacidades de salida orientadas al servicio. Incluye principalmente:
  varias plataformas de gestión de modelos LLM: enfatizando la riqueza de los tipos de modelos y la facilidad de uso.
  Capacidades de servicio integradas Productos : haciendo hincapié en el uso inmediato
  de capacidades diferenciadas: como centrarse en la gestión de solicitudes (incluida la administración de solicitudes, la optimización de solicitudes y la serialización de solicitudes), el modo de operación del modelo basado en recursos compartidos, etc.

Por ejemplo, las API de texto PaLM de Google o
        model_token_mapping = {             "gpt-4": 8192,             "gpt-4-0314": 8192,             "gpt-4-0613": 8192,             "gpt-4 en el archivo llms/openai. archivo py -32k": 32768,             "gpt-4-32k-0314": 32768,             "gpt-4-32k-0613": 32768,             "gpt-3.5-turbo": 4096,             "gpt-3.5-turbo-0301 ": 4096,             "gpt-3.5-turbo-0613": 4096,             "gpt-3.5-turbo-16k": 16385,             "gpt-3.5-turbo-16k-0613": 16385,             "texto-ada-001": 2049,             "ada": 2049,             "texto-babbage-001": 2040,             "babbage": 2049,















            "text-curie-001": 2049,
            "curie": 2049,
            "davinci": 2049,
            "text-davinci-003": 4097,
            "text-davinci-002": 4097,
            "code-davinci-002": 8001,
            "code-davinci-001": 8001,
            "code-cushman-002": 2048,
            "code-cushman-001": 2048,
        }
Índice: el índice
realiza varios documentos, como texto de dominio privado del usuario, imágenes, PDF , etc. Almacenamiento y recuperación (equivalente a documentos estructurados, de modo que los datos y modelos externos puedan interactuar), existen dos esquemas de implementación específicos: Esquema vectorial: es decir, el
  archivo primero se divide en trozos y luego se codifica, almacena y recupera según Chunks, consulte este archivo de código: https://github.com/hwchase17/langchain/blob/master/langchain/indexes/vectorstore.py
  Solución KG: esta parte usa LLM para extraer los triples en el archivo y almacenar como KG para su recuperación posterior, puede consultar este archivo de código: https://github.com/hwchase17/langchain/blob/master/langchain/indexes/graph.py

Para indexar, debe involucrar las siguientes capacidades
Cargadores de documentos, la interfaz estándar para cargar documentos
Integrar con documentos y fuentes de datos en varios formatos, como correo electrónico, Markdown, PDF (para que pueda hacer aplicaciones como ChatPDF), Youtube. ..
similar También hay
docstore, que contiene:
document_transformers

Las incrustaciones, que involucran varios algoritmos de incrustaciones, están incorporadas en varios archivos de código:
elasticsearch.py, google_palm.py, gpt4all.py, huggingface.py, huggingface_hub.py
llamacpp.py, minimax.py, modelscope_hub.py, mosaicml .py
openai. py
sentencia_transformer.py, spacy_embeddings.py, tensorflow_hub.py, vertexai.py
1.1.2 Capa de capacidad: Cadenas, Memoria, Herramientas
Si la capa básica proporciona las capacidades principales, la capa de capacidad instalará estas capacidades, Pies y cerebro, déjalo tiene la capacidad de recordar y activar todas las cosas, incluidas: Cadenas, Memoria, Herramienta de tres partes

Cadenas: enlaces
En resumen, es equivalente a incluir una serie de llamadas a varios componentes, que pueden ser una plantilla de solicitud, un modelo de lenguaje y un analizador de salida, trabajando juntos para procesar la entrada del usuario, generar respuestas y procesar la salida.

Específicamente, es equivalente a abstraer y personalizar diferentes lógicas de ejecución de acuerdo con diferentes requisitos. Las cadenas se pueden anidar y ejecutar en serie. A través de esta capa, las capacidades de LLM se pueden vincular a varias industrias, como las que interactúan con las bases de datos de Elasticsearch. :
elasticsearch_database
Para ejemplo, basado en la pregunta y respuesta del gráfico de conocimiento: graph_qa
El archivo de código: chains/graph_qa/base.py implementa un sistema de respuesta a preguntas basado en el
gráfico de conocimiento. La información "Esto se logra a través de self.graph.get_entity_knowledge(entity), que devuelve toda la información relacionada con la entidad en forma de triplete".
Luego, combine todos los tripletes para formar un contexto.
Finalmente, coloque la pregunta y el contexto en qa_chain juntos para obtener la respuesta final.

Por ejemplo, los que pueden generar y ejecutar código automáticamente: llm_math, etc.
Por ejemplo, para datos de dominio privado: qa_with_sources, el archivo de código chains/qa_with_sources/vector_db.py es para responder preguntas utilizando bases de datos vectoriales, por ejemplo,
para datos SQL. fuentes: sql_database, puede centrarse en este archivo de código: chains/sql_database/base.py

Por ejemplo, diálogo orientado a modelos: chat_models, incluidos estos archivos de código: __init__.py, anthropic.py, azure_openai.py, base.py, fake.py, google_palm.py, human.py, jinachat.py, openai.py , promptlayer_openai .py, vertexai.py

Además, hay más llamativos:
constitucional_ai: la lógica de sesgar el resultado final y manejar los problemas de cumplimiento para garantizar que el resultado final se ajuste a los valores
llm_checker: la lógica que permite que LLM detecte automáticamente si su salida tiene algún problemas
Memoria: Memoria
En resumen, se utiliza para guardar el estado del contexto al interactuar con el modelo y tratar con la memoria a largo plazo

Específicamente, esta capa tiene principalmente dos puntos centrales:
  la memoria y el almacenamiento estructurado de la entrada y la salida durante la ejecución de las cadenas, y proporciona contexto para la próxima interacción. Esta parte puede almacenarse simplemente en Redis y
  construirse de acuerdo con el historial de interacción. El mapa de conocimiento brinda resultados precisos de acuerdo con la información asociada. El archivo de código correspondiente es: memory/kg.py
Capa de herramientas.
De hecho, la capa de herramientas Cadenas puede ejecutar alguna lógica específica de acuerdo con LLM + Prompt, pero si desea usar La cadena para implementar toda la lógica no es En realidad, también se puede realizar a través de la capa Herramientas. La capa Herramientas se entiende como una habilidad más razonable, como búsqueda, Wikipedia, pronóstico del tiempo, servicio ChatGPT, etc. 1.1.3
Aplicación capa: Agentes
Agentes:
En resumen, hay una capa básica Y la capa de habilidad, podemos construir una variedad de servicios divertidos y valiosos, aquí está el Agente

Específicamente, Agent actúa como un agente para enviar una solicitud a LLM, luego toma medidas y verifica los resultados hasta que se completa el trabajo, incluidos los agentes para tareas que LLM no puede manejar (como búsqueda o cálculo, los complementos como ChatGPT plus tienen llamadas a bing y función de calculadoras))
Por ejemplo, un agente puede usar Wikipedia para buscar la fecha de nacimiento de Barack Obama y luego usar una calculadora para calcular su edad en 2023 # pip install
wikipedia
from langchain.agents import load_tools
from langchain.agents import initialize_agent
from langchain.agents import AgentType
 
tools = load_tools(["wikipedia", "llm-math"], llm=llm)
agent = initialize_agent(tools, 
                         llm, 
                         agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, 
                         verbose=True)
 
 
agent.run( "¿Cuándo es el cumpleaños de Obama? ¿Cuántos años tiene en 2023?")
Además, puede prestar atención a este archivo de código sobre Wikipedia: langchain/docstore/wikipedia.py ...
Al final, la arquitectura técnica general de langchain se puede mostrar en la figura a continuación (consulte la imagen grande de alta definición, además, hay otro diagrama de arquitectura aquí)

1.2 Algunos ejemplos de aplicación de langchain: búsqueda en línea + preguntas y respuestas sobre documentos
Pero al leer la introducción teórica, es posible que no pueda comprender cuál es el uso de langchain. Para su comodidad, aquí hay algunos ejemplos de aplicación de langchain

1.2.1 Busque a través de Google y devuelva la respuesta
Dado que se necesita Serpapi para la implementación, y Serpapi proporciona una interfaz API para la búsqueda de Google

Entonces, primero registre un usuario en el sitio web oficial de Serpapi (https://serpapi.com/), y cópielo para generar una clave API para nosotros, y luego configúrelo en la variable de entorno.

import os
os.environ["OPENAI_API_KEY"] = 'su clave api'
os.environ["SERPAPI_API_KEY"] = 'su clave api'
Luego, comience a escribir código

de langchain.agents importar load_tools
de langchain.agents importar initialize_agent
de langchain.llms importar OpenAI
de langchain.agents importar AgentType
 
# cargar modelo OpenAI
llm = OpenAI(temperature=0,max_tokens=2048) 
 
 # cargar serpapi tools
tools = load_tools([" serpapi"])
 
# Si desea recalcular después de buscar, puede escribir así
# tools = load_tools(['serpapi', 'llm-math'], llm=llm)
 
# Si desea utilizar la impresión de Python para hacerlo después de buscar Para un cálculo simple, puede escribir así
# tools=load_tools(["serpapi","python_repl"])
 
# Las herramientas deben inicializarse después de la carga, el parámetro detallado es True y todos los detalles de ejecución se imprimirán
. = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
 
# ejecutar agente
agent.run("¿Qué fecha es hoy? ¿Qué grandes eventos han ocurrido hoy en la historia?") 1.2.2 Implementar un robot de diálogo de documentos con menos de
50 líneas de código

Suponiendo que todo el contenido actualizado en 2022 existe en el documento 2022.txt, luego, a través del siguiente código, ChatGPT puede admitir la respuesta de preguntas en 2022

El principio también es muy simple:

La vectorización de la entrada/solicitud del usuario,
la segmentación de documentos, la
segmentación de documentos
, la vectorización de texto,
la vectorización se pueden usar para calcular la similitud entre vectores,
y el texto vectorizado se almacena en la base de datos de vectores
para encontrar la respuesta (respuesta) en los datos de vectores de acuerdo con la entrada/mensaje del usuario El juicio se basa en la similitud entre el mensaje/entrada y el vector de párrafo relevante en el texto)
Finalmente, la respuesta es devuelta por LLM
#!/usr/bin/python
# -*- codificación: UTF- 8 -*-
 
import os # Importa el módulo os, para operaciones relacionadas con el sistema operativo
import jieba as jb # Importa el diccionario de sinónimos de tartamudeo
de langchain.chains import ConversationalRetrievalChain # Importa la clase utilizada para crear cadenas de recuperación de diálogos
de langchain.chat_models import ChatOpenAI # Importe la clase utilizada para crear objetos ChatOpenAI
desde langchain .document_loaders import DirectoryLoader # Importe la clase para cargar archivos
desde langchain.embeddings import OpenAIEmbeddings # Importe la clase para crear incrustaciones de vectores de palabras
from langchain.text_splitter import TokenTextSplitter # Clase de importación para dividir documentos
de langchain.vectorstores import Chroma # Clase de importación para crear una base de datos vectorial
 
# Función de inicialización para procesar documentos de entrada
def init():  
    files = ['2022. txt'] # lista de archivos para ser procesado
    para el archivo en archivos: # Recorra cada archivo
        con open(f"./data/{file}", 'r', encoding='utf-8') como f: # con Abrir el archivo en modo de lectura de
            datos = f.read() # lee el contenido del archivo
 
        cut_data = " ".join([w for w in list(jb.cut(data))]) # realiza la segmentación de palabras en el contenido del archivo leído
        cut_file = f"./data /cut/cut_{file}" # Defina la ruta y el nombre del archivo procesado
        con open(cut_file, 'w') como f: # Abra el archivo
            f en modo de escritura.write(cut_data) # Escribir el contenido procesado en el archivo
 
# Crear una nueva función para cargar el documento
def load_documents(directory):  
    # Crear un objeto DirectoryLoader para cargar todos los archivos .txt en la carpeta especificada
    loader = DirectoryLoader(directory, glob='**/*.txt')  
    docs = loader.load() # cargar archivos
    devolver documentos # Devolver documentos cargados
 
# Crear una nueva función para dividir documentos
def split_documents(docs):  
    # Crear objetos TokenTextSplitter para dividir documentos
    text_splitter = TokenTextSplitter(chunk_size=1000, chunk_overlap=0)  
    docs_texts = text_splitter.split_documents(docs) # Segmentar el texto cargado
    return docs_texts # Devolver el texto segmentado
 
# Crear una nueva función para crear una incrustación de palabras
def create_embeddings(api_key):  
    # Crear un objeto OpenAIEmbeddings para obtener las incrustaciones de vectores de palabras de OpenAI
    incrustaciones = OpenAIEmbeddings(openai_api_key=api_key)  
    return incrustaciones # devolver la palabra incrustada creada
 
# Crear una nueva función para crear una base de datos vectorial
def create_chroma(docs_texts, incrustaciones, persist_directory):  
    # Crear un objeto Chroma usando documentos, incrustaciones y un directorio persistente
    vectordb = Chroma.from_documents(docs_texts, incrustaciones, persist_directory=persist_directory)  
    vectordb.persist () #Almacenar datos vectoriales de forma persistente
    return vectordb #Regresar a la base de datos vectorial creada
 
#función de carga, llamar a la función definida anteriormente con varias responsabilidades
def load():
    docs = load_documents('./data/cut') #Llamar a la función load_documents para cargar documentos
    docs_texts = split_documents(docs) # llamar a la función split_documents para dividir documentos
    api_key = os.environ.get('OPENAI_API_KEY') # obtener la clave API de OpenAI de
    incrustaciones de variables de entorno = create_embeddings(api_key) # llamar a la función create_embeddings para crear palabras incrustadas
 
    # llamada La función create_chroma crea una base de datos vectorial
    vectordb = create_chroma(docs_texts, incrustaciones, './data/cut/')  
 
    # Crear objeto ChatOpenAI para diálogo de chat
    openai_ojb = ChatOpenAI(temperature=0, model_name="gpt-3.5-turbo")  
 
    # A partir del modelo y el vector El retriever crea la
    cadena de objetos ConversationalRetrievalChain = ConversationalRetrievalChain.from_llm(openai_ojb, vectordb.as_retriever())  
    cadena de retorno # Devolver el objeto
 
# Llamar a la función de carga para obtener la
cadena de objetos ConversationalRetrievalChain = load()  
 
# Definir una función para obtener la respuesta de acuerdo con la entrada pregunta
def get_ans(pregunta):  
    chat_history = [] # Inicializar el historial de chat como una lista vacía
    result = chain({ # llamar al objeto de la cadena para obtener el resultado del chat
        'chat_history': chat_history, # pasar el historial de chat
        'pregunta' : pregunta, # pasar la pregunta
    } )
    return result['answer'] # devuelve la respuesta obtenida
 
si __name__ == '__main__': # si este script se ejecuta como el programa principal
    s = input('por favor ingrese:') # obtenga la entrada del usuario
    mientras s != 'exit ': # Si la entrada del usuario no es 'salir'
        ans = get_ans(s) # Llame a la función get_ans para obtener la respuesta
        print(ans) # Imprima la respuesta
        s = input('por favor ingrese:') # Obtenga la entrada del usuario

//Para actualizarse

La segunda parte se basa en LangChain + ChatGLM-6B respuesta a preguntas de la base de conocimiento local
2.1 Pasos básicos: Cómo realizar la respuesta a preguntas de la base de conocimiento local a través de LangChain+LLM
Hay una aplicación de respuesta a preguntas basada en la base de conocimiento local implementada utilizando la idea langchain en GitHub : langchain-ChatGLM (esta es su dirección de GitHub y, por supuesto, hay proyectos similares que admiten Vicuna-13b, como LangChain-ChatGLM-Webui), el objetivo es construir una base de conocimiento que sea amigable con las escenas chinas y de código abierto modelos, y puede ejecutar una solución de preguntas y respuestas fuera de línea

Inspirado en el proyecto document.ai de GanymedeNil y ChatGLM-6B Pull Request creado por Alex Zhangji, este proyecto establece una aplicación de respuesta a preguntas de base de conocimiento local que se puede implementar utilizando modelos de código abierto durante todo el proceso. Ahora admite el acceso a modelos de idiomas grandes como ChatGLM-6B, ClueAI/ChatYuan-large-v2.
En este proyecto, la selección predeterminada de Embedding es GanymedeNil/text2vec-large-chinese, y la selección predeterminada de LLM es ChatGLM-6B , basándose en los modelos anteriores , este proyecto puede realizar todas las implementaciones privadas fuera de línea utilizando un modelo de código abierto
. /6 Vectorización de texto -> 8/9 Vectorización de preguntas -> 10 Haga coincidir los k vectores de preguntas más similares en el vector de documento -> 11/ 12/13 El texto coincidente se agrega como contexto y preguntas al indicador -> 14/15 para enviar a LLM para generar una respuesta)

La primera etapa: cargar archivo - leer archivo - divisor de texto (divisor de texto)
cargar archivo: este es el paso de leer el archivo de la base de conocimiento almacenado localmente
leer archivo: leer el contenido del archivo cargado, generalmente convertirlo en formato de texto
Divisor de texto (texto splitter): divide el texto de acuerdo con ciertas reglas (como párrafos, oraciones, palabras, etc.), el siguiente es solo un código de muestra (no el código fuente del proyecto langchain-ChatGLM)

    def _load_file(self, filename):
        # Determine el tipo de archivo
        si filename.lower().endswith(".pdf"): # Si el archivo está en formato PDF
            loader = UnstructuredFileLoader(filename) # Use el cargador UnstructuredFileLoader para cargar el PDF file
            text_splitor = CharacterTextSplitter() # Use CharacterTextSplitter para dividir el texto en el archivo
            docs = loader.load_and_split(text_splitor) # Cargue el archivo y divida el texto
        más: # Si el archivo no está en formato PDF
            loader = UnstructuredFileLoader(filename, mode="elements") # Usar UnstructuredFileLoader El cargador carga el archivo en modo elemento
            text_splitor = CharacterTextSplitter() # Usar CharacterTextSplitter para dividir el texto en el archivo
            docs = loader.load_and_split(text_splitor) # Cargar el archivo y dividir el texto
        return docs # Devuelve los datos del archivo procesado
La segunda etapa: incrustación de texto (incrustación): almacenado en la
base de datos vectorial y otros métodos para convertir el texto segmentado en un vector numérico

    # Método de inicialización, acepta un parámetro de nombre de modelo opcional, el valor predeterminado es Ninguno
    def __init__(self, nombre_del_modelo=Ninguno) -> Ninguno:  
        si no nombre_del_modelo: # Si no se proporciona ningún nombre del modelo
            # Usar el modelo de incrustación predeterminado
            # Crear un HuggingFaceEmbeddings Objeto, el nombre del modelo es el atributo model_name de la clase
            self.embeddings = HuggingFaceEmbeddings(model_name=self.model_name)  
se almacena en la base de datos vectorial: el texto se vectoriza y almacena en la base de datos vectorstore (FAISS, la siguiente sección explicará FAISS en detalle)

def init_vector_store(self):
    persist_dir = os.path.join(VECTORE_PATH, ".vectordb") # La dirección de la base de datos de vectores persistentes
    print("Dirección persistente de la base de datos de vectores: ", persist_dir) # Imprimir la dirección persistente
 
    # Si la dirección es persistente existe
    si os.path.exists(persist_dir):  
        # Cargar desde archivo persistente local
        print("Cargar datos desde vector local...")
        # Usar Chroma para cargar datos vectoriales persistentes
        vector_store = Chroma(persist_directory=persist_dir, embedding_function=self. incrustaciones)  
 
    # Si la dirección persistente no existe
    más:      
        # Cargar
        documentos de la base de conocimientos = self.load_knownlege()  
        # Usar Chroma para crear almacenamiento vectorial a partir de documentos
        vector_store = Chroma.from_documents(documents=documents, 
                                             embedding=self.embeddings,
                                             persist_directory=persist_dir)  
        vector_store.persist() # almacenamiento de vectores persistente
    return vector_store # retorno de almacenamiento de vectores
donde está la implementación de load_knownlege

def load_knownlege(self):
    documentos = [] # Inicializa una lista vacía para almacenar documentos
 
    # Recorre todos los archivos en el directorio DATASETS_DIR
    para root, _, archivos en os.walk(DATASETS_DIR, topdown=False):
        for file in files:
            filename = os.path.join(root, file) # Obtener la ruta completa del archivo
            docs = self._load_file(filename) # Cargar documentos en el archivo
 
            # Actualizar datos de metadatos
            new_docs = [] # Inicializar una lista vacía para almacenar nuevos documentos
            para doc en docs:
                # Actualice los metadatos del documento y reemplace el valor del campo "fuente" con una ruta relativa que no incluya DATASETS_DIR
                doc.metadata = {"fuente": doc.metadata["fuente"]. replace(DATASETS_DIR, "")} 
                print("Inicialización del vector del documento 2, espere...", doc.metadatos) # imprime los metadatos del documento que se está inicializando
                new_docs.append(doc) #Agregar el documento a la nueva lista de documentos
 
            docments += new_docs #Agregar la nueva lista de documentos a la lista total de documentos
 
    return docments #Devolver la lista de todos los documentos
La tercera etapa: vectorización de preguntas
Esta es la consulta del usuario o problema en vectores, se debe usar el mismo enfoque que la vectorización de texto para la comparación en el mismo espacio

La cuarta etapa: haga coincidir los k superiores más similares al vector de pregunta en el vector de texto.
Este paso es el núcleo de la recuperación de información. Al calcular la similitud del coseno, la distancia euclidiana, etc., encuentre el texto más cercano al vector de pregunta vector.

    def consulta(self, q):
        """Buscar vectores de texto similares a los vectores de pregunta en la base de datos de vectores"""
        vector_store = self.init_vector_store()
        docs = vector_store.similarity_search_with_score(q, k=self.top_k)
        for doc in docs :
            dc, s = doc
            yield s, dc
La quinta etapa: el texto coincidente se agrega al indicador junto con la pregunta como contexto
Esto es para usar el texto coincidente para formar un contexto relacionado con la pregunta, que se usa como entrada para el modelo de lenguaje

La sexta etapa: Enviar a LLM para generar respuestas
Finalmente, envíe esta pregunta y contexto al modelo de lenguaje (como la serie GPT), deje que genere respuestas
como consulta de conocimiento (código fuente)

clase KnownLedgeBaseQA:
    # Inicializar
    def __init__(self) -> Ninguno:
        k2v = KnownLedge2Vector() # Crear un convertidor de conocimiento a vector
        self.vector_store = k2v.init_vector_store() # Inicializar el almacenamiento de vectores
        self.llm = VicunaLLM() # Crear Un objeto VicunaLLM
    
    # Obtener respuestas similares a la consulta
    def get_similar_answer(self, query):
        # Crear una plantilla de aviso prompt
        = PromptTemplate(
            template=conv_qa_prompt_template, 
            input_variables=["contexto", "pregunta"] # Las variables de entrada incluyen "contexto"( contexto) y "pregunta" (pregunta)
        #
 
        usar almacén de vectores para recuperar documentos
        retriever = self.vector_store.as_retriever(search_kwargs={"k": VECTOR_SEARCH_TOP_K}) 
        docs = retriever.get_relevant_documents(query=query) # Obtener el texto relacionado con la consulta
 
        context = [d.page_content for d in docs] # Extraer el contenido del texto
        result = prompt.format(context="\n".join (contexto), pregunta=consulta) # Formatea la plantilla y llénala con el contenido y las preguntas extraídas del texto
        return result # Devuelve el resultado

Como puede ver, este método de combinar langchain+LLM es especialmente adecuado para algunos campos verticales o empresas de grupos grandes para construir un sistema privado de preguntas y respuestas a través de las capacidades de diálogo inteligente de LLM , y también es adecuado para que las personas realicen preguntas y respuestas específicas para algunos artículos en inglés. Por ejemplo, un proyecto de código abierto relativamente popular: ChatPDF, desde la perspectiva del procesamiento de documentos, el proceso de implementación es el siguiente (fuente):

2.2 Búsqueda de similitud de IA de Facebook (FAISS): búsqueda eficiente de similitud de vectores


El nombre completo de Faiss es Facebook AI Similarity Search (página de introducción oficial, dirección de GitHub). Es una herramienta desarrollada por el equipo de IA de FaceBook para problemas de recuperación de similitudes a gran escala. Está escrito en C++ y tiene una interfaz de Python. Puede indexar Mil millones de órdenes de magnitud Logre un rendimiento de recuperación de nivel de milisegundos

En pocas palabras, el trabajo de Faiss es encapsular nuestro propio conjunto de vectores candidatos en una base de datos de índices, lo que puede acelerar nuestro proceso de recuperación de vectores TopK similares, y algunos de los índices también admiten la construcción de GPU.

2.2.1 El proceso básico de recuperación Faiss del vector similar TopK
El proyecto de recuperación Faiss del vector similar TopK se puede dividir básicamente en tres pasos:

Obtenga el
número de importación de la biblioteca de vectores como np
d = 64 # dimensión del vector
nb = 100000 # volumen de datos de la biblioteca de vectores de índice
nq = 10000 # número de consultas que se recuperarán
np.random.seed(1234)             
xb = np.random.random((
nb , d
) 'float32')
xq[:, 0] += np.arange(nq) / 1000. # El vector de consulta a ser recuperado
Use faiss para construir el índice, y agregue el vector al índice.
La construcción del índice usa el método de recuperación violenta FlatL2 , L2 significa que el método de medición de similitud adoptado por el índice construido es la norma L2, es decir, la distancia euclidiana
importación          
índice faiss = faiss.IndexFlatL2(d)             
print(index.is_trained) # La salida es True, lo que significa que este tipo de índice no necesita ser entrenado, simplemente agregue el vector
index.add(xb) # Agregue el vector en la biblioteca de vectores al índice
print (index.ntotal) # Muestra el número total de vectores contenidos en el índice, que es 100000.
Usa el índice faiss para recuperar y recuperar la consulta similar de TopK
k = 4 # Valor K de topK
D, I = index.search( xq, k)# xq es el vector a recuperar, devuelto I es la lista de índice que es más similar a TopK para cada consulta a recuperar, y D es la distancia correspondiente print(I[:5])
print
(D[ -5:])
La impresión es:
>>> 
[[ 0 393 363 78 ] 
 [ 1 555 277 364] 
 [ 2 304 101 13] 
 [ 3 173 18 182] 
 [ 4 288 370 531]]  
[[ 0. 7.17517328 7.2076292 7.25116253] [ 0.  
 6.32356453 6.6 845808 6.79994535]  
 [ 0. 5.79640865 6.39173603 7.28151226]  
 [ 0. 7.27790546 7.52798653 7.66284657]  
 [ 0. 6.76380348 7.29512024 7.36881447]]

2.2.2 Múltiples formas de construir índices en FAISS


El método de índice de construcción y el método de paso de parámetros pueden ser

dim, medida = 64, faiss.METRIC_L2
param = 'Flat'
index = faiss.index_factory(dim, param, medida)
dim es la dimensión del vector,
el parámetro más importante es param, que es el parámetro pasado a index, que representa lo que necesita ser construido tipo de índice,
la medida es un método de medición, actualmente admite dos tipos, la distancia euclidiana y el producto interior, es decir, el producto interior. Por lo tanto, para calcular la similitud del coseno, solo necesita normalizar los vecs y usar el producto interno para medir.En
este artículo, faiss ahora admite oficialmente ocho métodos de medición, que son:

METRIC_INNER_PRODUCT (producto interno)
METRIC_L1 (distancia Manhattan)
METRIC_L2 (distancia euclidiana)
METRIC_Linf (norma infinita) METRIC_Lp
(norma p)
METRIC_BrayCurtis (disimilitud BC)
METRIC_Canberra (distancia de rango/distancia Canberra)
METRIC_JensenShannon (divergencia JS)
2.2.2.1 Plano: fuerza bruta Recuperación
Ventajas: este método es el más preciso y el método con la tasa de recuperación más alta entre todos los índices de Faiss; Desventajas
: baja velocidad y gran uso de memoria.
Uso: Hay muy pocos conjuntos de candidatos vectoriales, menos de 500 000, y la memoria no es escasa.
Nota: Aunque todas son búsquedas violentas, la velocidad de búsqueda violenta de faiss es mucho más rápida que la búsqueda violenta escrita por los propios programadores ordinarios, por lo que no significa que sea inútil. Se recomienda que los estudiantes que necesitan búsqueda violenta aún usen faiss .
Método de construcción:
dim, medida = 64, faiss.METRIC_L2
parámetro = 'Flat'
índice = faiss.index_factory(dim, parámetro, medida)
index.is_trained # salida es True
index.add(xb) # agregar vector al índice
2.2.2.2 IVFx Flat: recuperación de fuerza bruta de inversión
Ventajas: IVF utiliza principalmente la idea de inversión. La tecnología de inversión en el escenario de recuperación de documentos significa que un kw es seguido por muchos documentos que contienen la palabra. Dado que el número de kw es mucho Es más pequeño que doc, por lo que reducirá en gran medida el tiempo de recuperación. ¿Cómo usar la inversión en vector? Puede sacar el ID de vector debajo de cada centro de clúster, colgar un montón de vectores no centrales detrás de cada ID de centro, encontrar los ID de centro más cercanos cada vez que consulta el vector y buscar los no centros debajo de estos centros respectivamente vector . Mejore la eficiencia de la búsqueda al reducir el rango de búsqueda.
Desventajas: La velocidad no es muy rápida.
Uso: en comparación con Flat, aumentará considerablemente la velocidad de recuperación. Se recomienda que se puedan usar millones de vectores.
Parámetro: x en IVFx es el número de centros de agrupación de k-medias
Método de construcción:
dim, medida = 64, correcto. METRIC_L2 
param = 'IVF100,Flat' # Representa que el centro de agrupación de k-medias es 100,   
index = correcto. index_factory(dim , param, medida)
print(index.is_trained) # La salida es False en este momento, porque el índice invertido necesita entrenar k-means,
index.train(xb) # Así que primero necesita entrenar el índice y luego agregar el vector
index.add (xb)                                     
2.2.2.3 PQx: Cuantificación del producto
Ventajas: al usar el método de cuantificación del producto, se mejora la recuperación general, la dimensión de un vector se corta en x segmentos, cada segmento se recupera por separado y los resultados de la recuperación de cada segmento del vector se cruzan para obtener el TopK final. Por lo tanto, es rápido, ocupa menos memoria y tiene una tasa de recuperación relativamente alta.
Desventajas: en comparación con la recuperación violenta, la tasa de recuperación cae más.
Uso: la memoria es extremadamente escasa y se requiere una velocidad de recuperación más rápida, y el
parámetro de tasa de recuperación no está tan preocupado: x en PQx es el número de segmentos para dividir el vector, por lo tanto, x debe ser divisible por la dimensión del vector, y cuanto mayor sea x, cuanto más fina sea la segmentación, mayor será la complejidad del tiempo
Método de construcción:
dim, medida = 64, faiss.METRIC_L2 
param = 'PQ16' 
índice = faiss.index_factory(dim, param, medida)
print(index.is_trained) # La salida en este momento es Falso, porque el índice invertido necesita entrenar k-means,
index.train(xb) # Por lo tanto, primero debe entrenar el índice y luego agregar el vector
index.add(xb)          
2.2.2.4 IVFxPQy Cuantificación de producto invertida
Ventajas: este método es ampliamente utilizado en la industria, todos los indicadores son aceptables, utilizando el método de cuantificación de producto, se mejora el k-medio de FIV, la dimensión de un vector se corta en x segmentos, y k- medios se realizan en cada segmento para su recuperación.
Desventajas: Combina las fortalezas de cien escuelas de pensamiento y, naturalmente, también reúne las deficiencias de cien escuelas de
pensamiento. Uso: En términos generales, si no hay requisitos extremos especiales en todos los aspectos, ¡este método es el más recomendado!
Parámetros: IVFx, PQy, donde x e y son los mismos que arriba
Método de construcción:
dim, medida = 64, faiss.METRIC_L2  
param = 'IVF100,PQ16'
índice = faiss.index_factory(dim, param, medida) 
print(index. is_trained) # En este momento, la salida es False, porque el índice invertido necesita entrenar k-means, 
index.train(xb) # Por lo tanto, primero debe entrenar el índice y luego agregar el vector index.add(xb)       
2.2.2.5 LSH Local Sensitive Hash
Principio: Hash Es familiar para todos, pero el vector también puede usar hash para acelerar la búsqueda. El hash del que estamos hablando aquí se refiere a Locality Sensitive Hashing (LSH), que es diferente del tradicional. hashing, que trata de evitar colisiones y es localmente sensible. Se basa en las colisiones para encontrar vecinos. Si dos puntos en un espacio de alta dimensión están muy cerca, diseñe una función hash para realizar un cálculo hash en estos dos puntos y luego divídalos en cubos, de modo que sus valores de cubo hash tengan una alta probabilidad de ser iguales. la distancia entre ellos es grande, la probabilidad de que tengan el mismo valor de cubo de hash será muy pequeña.
Ventajas: entrenamiento muy rápido, soporte para importación por lotes, el índice ocupa una pequeña cantidad de memoria y la recuperación es relativamente rápida
Desventajas: la tasa de recuperación es muy baja.
Uso: la biblioteca de vectores candidatos es muy grande, la recuperación fuera de línea y los recursos de memoria son relativamente escasos
Método de construcción:
dim, medida = 64, faiss.METRIC_L2  
param = 'LSH'
index = faiss.index_factory(dim, param, measure) 
print(index.is_trained) # La salida es verdadera en este momento
index.add(xb)    

  
2.2.2.6 HNSWx


Ventajas: Este método es un método mejorado basado en la recuperación de gráficos. La velocidad de recuperación es extremadamente rápida, y los resultados de la recuperación se pueden recuperar en segundos al nivel de mil millones, y la tasa de recuperación es casi comparable a la de Flat, que puede alcanzar un asombroso 97%. La complejidad temporal de la recuperación es loglogn, que casi puede ignorar la magnitud de los vectores candidatos. Y admite la importación por lotes, que es muy adecuada para tareas en línea y experiencia de nivel de milisegundos.
Desventajas: construir un índice es extremadamente lento y ocupa mucha memoria (la más grande en Faiss, más grande que el tamaño de memoria ocupado por el vector original) Parámetros:
x en HNSWx es el número máximo de nodos conectados a cada punto al construir un gráfico, cuanto mayor sea x, la composición Cuanto más compleja sea la consulta, más precisa será la consulta. Por supuesto, el tiempo para construir el índice será más lento. x puede ser cualquier número entero de 4 a 64.
Uso: no se preocupe por la memoria y tenga mucho tiempo para crear el índice
Método de construcción:
dim, medida = 64, faiss.METRIC_L2   
param = 'HNSW64' 
índice = faiss.index_factory(dim, param, medida)  
print(index.is_trained ) # En este momento, el resultado es True 
index.add(xb)
2.3 Implementación del proyecto: langchain + ChatGLM-6B para construir una base de conocimiento local Preguntas y respuestas
2.3.1 Proceso de implementación 1: admitir múltiples modos de uso
Entre ellos, el modelo LLM puede seleccionarse de acuerdo con las necesidades comerciales reales, el ChatGLM-6B utilizado en este proyecto, su dirección de GitHub es: https://github.com/THUDM/ChatGLM-6B
ChatGLM-6B es un modelo de lenguaje de diálogo bilingüe chino-inglés de código abierto basado en la arquitectura General LanguageModel (GLM) con 6200 millones de parámetros. En combinación con la tecnología de cuantificación de modelos, los usuarios pueden implementar localmente en tarjetas gráficas de consumo (solo se requieren 6 GB de memoria de video en el nivel de cuantificación INT4)

ChatGLM-6B utiliza una tecnología similar a ChatGPT, optimizada para preguntas y respuestas y diálogos en chino. Después de aproximadamente 1T de identificadores de capacitación bilingüe chino-inglés, complementada con supervisión y ajuste, autoayuda de retroalimentación, aprendizaje de refuerzo de retroalimentación humana y otras tecnologías, ChatGLM-6B con 6.200 millones de parámetros ha podido generar respuestas que están bastante en línea. con preferencias humanas

Cree un entorno python3.8.13 (el archivo del modelo aún está disponible)
conda create -n langchain python==3.8.13
Tire del proyecto
git clone https://github.com/imClumsyPanda/langchain-ChatGLM.git
Ingrese al directorio
cd langchain -ChatGLM
requisitos de instalación.txt
conda active langchain
pip install -r requisitos.txt
La versión más alta de langchain compatible con el entorno actual es 0.0.166, y 0.0.174 no se puede instalar, así que intente instalar 0.0.166 primero. Modifique la
configuración ruta del archivo:
vi configs/model_config.py
establezca la ruta de chatglm-6b en su propio
"chatglm-6b": { "name": "chatglm-6b", "pretrained_model_name": "/data/sim_chatgpt/chatglm-6b" , "local_model_path": Ninguno, "proporciona": "ChatGLM" Modifique el archivo de código que se ejecutará: webui.py vi webui.py Establezca el recurso compartido en la función de inicio final en True y configure el navegador en True







Ejecutar el archivo webui.py
python webui.py
puede ser un problema de red, incapaz de crear un enlace público. Se puede realizar el mapeo entre el servidor en la nube y el puerto local, consulte: https://www.cnblogs.com/monologuesmw/p/14465117.html
Salida correspondiente:

Ocupación de la memoria de vídeo: unos 15 G

2.3.2 Proceso de implementación 2: Apoyar la experiencia en línea en varias comunidades
Dirección del proyecto: https://github.com/thomas-yanxin/LangChain-ChatGLM-Webui
Experiencia en línea de la comunidad HUggingFace: https://huggingface.co/spaces/ thomas- yanxin/LangChain-ChatLLM

Además, también admite experiencias en línea como la comunidad ModelScope y la comunidad Flying Paddle AIStudio.

Descargue el proyecto
git clone https://github.com/thomas-yanxin/LangChain-ChatGLM-Webui.git
Ingrese al directorio
cd LangChain-ChatGLM-Webui
para instalar los paquetes requeridos
pip install -r requirements.txt
pip install gradio== 3.10
modificación config.py
init_llm = "ChatGLM-6B"
 
llm_model_dict = {     "chatglm": {         "ChatGLM-6B": "/data/sim_chatgpt/chatglm-6b", modifique el archivo app.py, configure el recurso compartido en el lanzamiento función en True , inbrowser se establece en True para ejecutar el archivo webui.py python webui.py





 La memoria de video ocupa alrededor de 13G

La tercera parte es un análisis en profundidad línea por línea: Interpretación del código fuente del proyecto langchain-ChatGLM
y luego revisión del diagrama de arquitectura del proyecto langchain-ChatGLM (fuente)

Encontrará que el proyecto se compone principalmente de los siguientes módulos principales

cadenas: implementación de enlaces de trabajo, como cadenas/local_doc_qa implementa preguntas y respuestas basadas en archivosconocimiento_bas/contenido: se usa para almacenar los
configuraciones: almacenamiento de archivosdocumentos locales textsplitter : Vectorstores de clase de implementación de segmentación de texto : se utiliza para almacenar archivos de biblioteca de vectores, es decir, la ontología de la base de conocimiento local A continuación, para comodidad de los lectores, comprender más rápido






Básicamente, agregué comentarios en chino a "cada línea de código en el siguiente proyecto"
y, para comprender mejor, interpreto el orden de cada carpeta de código una por una de acuerdo con el proceso del proyecto (en lugar de cada archivo de código en GitHub en el orden de presentación de la carpeta de la imagen de arriba)
Si tiene alguna pregunta, puede dejar un comentario en cualquier momento

3.1 agente: agente_personalizado/bing_search
3.1.1 agente/agente_personalizado.py
de langchain.agents import Tool # Importar módulo de herramienta
de langchain.tools import BaseTool # Importar clase de herramienta básica
de langchain import PromptTemplate, LLMChain # Importar plantilla de solicitud y cadena de modelo de lenguaje
de agent.custom_search import DeepSearch # Importar módulo de búsqueda personalizado
 
# Importar agente básico de acción única, analizador de salida, modelo de lenguaje agente de acción única y ejecutor de agente
de langchain.agents import BaseSingleActionAgent, AgentOutputParser, LLMSingleActionAgent, AgentExecutor    
de escribir import List, Tuple, Any, Union , Opcional, Tipo # Importar módulo de anotación de tipo
de langchain.schema import AgentAction, AgentFinish # Importar acción de agente y modo de finalización de agente
de langchain.prompts import StringPromptTemplate # Importar plantilla de solicitud de cadena
from langchain.callbacks.manager import CallbackManagerForToolRun # Herramienta de importación para ejecutar el administrador de devolución de llamada
from langchain.base_language import BaseLanguageModel # Importar modelo de lenguaje básico
import re # Importar módulo de expresión regular
 
# Definir una cadena de plantilla de agente
agent_template = """
Ahora eres un {role }. Aquí hay información conocida:
{related_content}
{background_infomation}
{question_guide}: {input}
{answer_format}
"""
 
# Definir una clase de plantilla de solicitud personalizada, heredada de la clase de plantilla de solicitud de cadena
CustomPromptTemplate(StringPromptTemplate) :
    template: str # Herramientas de cadena de plantilla de solicitud
    : List[Tool] # Lista de herramientas
 
    # Defina una función de formato para generar la plantilla de solicitud final de acuerdo con los parámetros proporcionados
    def format(self, **kwargs) -> str:
        pasos_intermedios = kwargs.pop("pasos_intermedios")
        # Determine si hay información de consulta de Internet
        si len(pasos_intermedios) == 0:
            # Si no, proporcione la información de antecedentes predeterminada, el rol, la guía de preguntas y el formato de respuesta
            background_infomation = "\n "
            role = "Stupid Robot"
            question_guide = "Tengo una pregunta ahora"
            answer_format = "Si sabe la respuesta, dé su respuesta directamente. Si no sabe la respuesta, simplemente responda\"DeepSearch('término de búsqueda' )\", y reemplace 'término de búsqueda' con la palabra clave que cree que necesita buscar, y no responda nada más.\n\n¡Por favor responda la pregunta que hice anteriormente!" else: # De lo contrario, de acuerdo con el ensamblaje de
 
        AgentAction
            en intermedia_pasos background_infomation
            background_infomation = "\n\nTodavía tienes esta información conocida como referencia:\n\n"
            acción,observación = pasos_intermedios[0]
            información_antecedentes += f"{observación}\n"
            role = "Asistente inteligente de inteligencia artificial"
            question_guide = "Por favor, responda mi pregunta en función de esta información conocida"
            answer_format = ""
 
        kwargs["background_infomation"] = background_infomation
        kwargs["role"] = role
        kwargs["question_guide"] = question_guide
        kwargs[ "answer_format"] = answer_format
        return self.template.format(**kwargs) # formatea la plantilla y devuelve
 
# Define una clase de herramienta de búsqueda personalizada, heredada de la clase de herramienta base
CustomSearchTool(BaseTool):
    nombre: str = " DeepSearch" # Descripción del nombre de la herramienta
    : str = "" # Descripción de la herramienta
 
    # Defina una función de ejecución que acepte una cadena de consulta y un administrador de devolución de llamada opcional como parámetros, y devuelva los resultados de búsqueda de DeepSearch
    def _run(self, query: str, run_manager:Opcional[CallbackManagerForToolRun] = Ninguno):
        return DeepSearch.search(consulta = consulta)
 
    # Defina una función de operación asíncrona, pero debido a que DeepSearch no admite asíncrono, arroja directamente un error no implementado
    async def _arun(self, query: str):
        raise NotImplementedError("DeepSearch no admite asíncrono ")
 
# Definir una clase de agente personalizada, heredada de la
clase base de agente de acción única CustomAgent(BaseSingleActionAgent):
    # Definir un atributo de una clave de entrada
    @property
    def input_keys(self):
        return ["input"]
 
    # Definir una función de planificación, Acepta un conjunto de pasos intermedios y otros parámetros, devuelve una acción de agente o el agente completa el
    plan definido (self, pasos_intermedios: List[Tuple[AgentAction, str]],
            **kwargs: Any) -> Union[AgentAction, AgentFinish]:
        return AgentAction (herramienta="DeepSearch", tool_input=kwargs["input"],log="")
 
# Definir un analizador de salida personalizado, heredado del analizador de salida del proxy
class CustomOutputParser(AgentOutputParser):
    # Defina una función de análisis que acepte una cadena de salida de un modelo de lenguaje y devuelva una acción de agente o una finalización de agente
    def parse(self, llm_output: str) -> Union[AgentAction, AgentFinish]:
        # Use expresiones regulares El patrón coincide con la cadena de salida, group1 es el nombre de la función de llamada, group2 es el parámetro de entrada
        match = re.match(r'^[\s\w]*(DeepSearch)\(([^\)]+)\) ', llm_output, re.DOTALL)
        print(match)
 
        # Si el modelo de lenguaje no devuelve DeepSearch(), se considera que finaliza la instrucción directamente
        si no coincide:
            return AgentFinish(
                return_values={"output": llm_output.strip( )},
                log=llm_output,
            )
        # De lo contrario, se considera que la herramienta debe llamarse
        de otra manera:
            action = match.group(1).strip()
            action_input = match.group(2).strip()
            return AgentAction(tool=action, tool_input=action_input.strip(" ").strip('"'), log=llm_output)
 
 
# Definir una clase de agente profundo
class DeepAgent:
    tool_name : str = "DeepSearch" # Nombre de la herramienta
    agent_executor: any # Herramientas del ejecutor del agente
    : List[Tool] # Lista de herramientas
    llm_chain: any # Cadena del modelo de lenguaje
 
    # Defina una función de consulta que acepte una cadena de contenido relevante y una cadena de consulta, devuelva la ejecución resultado de la
    consulta def del actuador (self, related_content: str = "", query: str = ""):
        tool_name = El objetivo principal de este código es construir un agente de IA de búsqueda profunda. El agente de IA primero recibe una pregunta Ingrese, y luego genere una plantilla de solicitud basada en la entrada, y luego guíe a la IA para generar una respuesta o realizar una búsqueda más profunda a través de la plantilla.Ahora, continuaré agregando comentarios en chino para el código
 
restante```python
        self.nombre_herramienta
        result = self.agent_executor.run(related_content=related_content, input=query ,tool_name=self.tool_name)
        return result # Devuelve el resultado de ejecución del ejecutor
 
    # En la función de inicialización, primero cree una instancia de herramienta desde la herramienta DeepSearch y agréguela a la herramienta En la lista
    def __init__(self, llm: BaseLanguageModel, **kwargs):
        herramientas = [
                    Tool.from_function(
                        func=DeepSearch.search,
                        name="DeepSearch",
                        description=""
                    )
                ]
        self.tools = herramientas # guardar la lista de herramientas
        tool_names = [tool.name for tool in tools] # Extraer el nombre de la herramienta en la lista de herramientas
        output_parser = CustomOutputParser() # Crear una instancia de analizador de salida personalizada
        # Crear una solicitud de instancia de plantilla de solicitud personalizada
        = CustomPromptTemplate(template=agent_template,
                                      tools=tools,
                                      input_variables=["related_content","tool_name", "input", "intermediate_steps"])
        # Crear una instancia de cadena de modelo de lenguaje
        llm_chain = LLMChain ( llm=llm, prompt=prompt)
        self.llm_chain = llm_chain # Guardar instancia de cadena de modelo de idioma
 
        # Crear una instancia de agente de acción única de modelo de idioma
        agent = LLMSingleActionAgent(
            llm_chain=llm_chain,
            output_parser=output_parser,
            stop=["\nObservation:"] ,
            allow_tools=tool_names
        )
 
        # Crear una instancia de ejecutor de proxy
        agent_executor = AgentExecutor.from_agent_and_tools(agent=agent, tools=tools, verbose=True)
        self.agent_executor = agent_executor # guardar la instancia del ejecutor del agente

3.1.2 agent/bing_search.py
​​​​#codificación=utf8
# Declarar que el formato de codificación del archivo es utf8
 
de langchain.utilities import BingSearchAPIWrapper
# Importar la clase BingSearchAPIWrapper, que se utiliza para interactuar con la API de búsqueda de Bing
 
desde las configuraciones. model_config import BING_SEARCH_URL, BING_SUBSCRIPTION_KEY
# importa la URL de búsqueda de Bing y la clave de suscripción de Bing en el archivo de configuración
 
def bing_search(text, result_len=3):
    # Define una función llamada bing_search, que acepta un parámetro de texto y longitud de resultado, la longitud de resultado predeterminada es 3
 
    si no (BING_SEARCH_URL y BING_SUBSCRIPTION_KEY):
        # Si la URL de búsqueda de Bing o la clave de suscripción de Bing no están configuradas, devuelva un documento con un mensaje de error
        [{"fragmento": "establezca BING_SUBSCRIPTION_KEY y BING_SEARCH_URL en os ENV",
                 "título ": "env inof no encontrado",
                 "enlace": "https://python.langchain.com/en/latest/modules/agents/tools/examples/bing_search.html"}]
 
    búsqueda = BingSearchAPIWrapper(bing_subscription_key=BING_SUBSCRIPTION_KEY,
                                  bing_search_url=BING_SEARCH_URL)
    # crear instancia de clase BingSearchAPIWrapper , esta instancia se usa para interactuar con la API de búsqueda de Bing
 
    return search.results(text, result_len)
    # Devolver resultados de búsqueda, el número de resultados está determinado por el parámetro result_len
 
if __name__ == "__main__":
    # Si este archivo se ejecuta directamente , y si no se importa como módulo, ejecute el siguiente código
 
    r = bing_search('python')
    # utilice la API de búsqueda de Bing para buscar la palabra "python" y guarde el resultado en la variable r
 
    print(r)
    # imprimir los resultados de la búsqueda

3.2 modelos: incluidos modelos y cargador de documentos
modelos de cargador: clase de interfaz y clase de implementación de llm, que proporciona soporte de salida de transmisión para modelos de código abierto
cargador: clase de implementación del cargador de documentos


3.2.1 models/chatglm_llm.py
from abc import ABC # Importa la clase base abstracta
de langchain.llms.base import LLM # Importa la clase base del modelo de aprendizaje de idiomas
de la importación de escritura Opcional, List # Importa el módulo de anotación
de tipo de models.loader import LoaderCheckPoint # Importe el punto de carga del modelo
desde models.base import (BaseAnswer, # Importe el modelo de respuesta básico
                         AnswerResult) # Importe la clase de modelo de resultado de respuesta
 
 
ChatGLM (BaseAnswer, LLM, ABC): # Defina la clase ChatGLM, herede la respuesta básica, el modelo de aprendizaje de idiomas y la clase base abstracta
    max_token: int = 10000 # El número máximo de tokens
    temperatura: float = 0.01 # Parámetro de temperatura, utilizado para controlar la aleatoriedad del texto generado
    top_p = 0.9 # Se retendrán 0.9 tokens antes de ordenar
    checkPoint: LoaderCheckPoint = Ninguno # Modelo de punto de control
    # historial = [] # Registro histórico
    history_len: int = 10 # Longitud del registro histórico
 
    def __init__(self, checkPoint: LoaderCheckPoint = Ninguno): # Método de inicialización
        super().__init__() # Llamar al método de inicialización de la clase principal
        self.checkPoint = checkPoint # Modelo de punto de control de asignación
 
    @property
    def _llm_type(self) -> str: # Definir la propiedad de solo lectura _llm_type, devuelve el tipo de modelo de aprendizaje de idiomas
        return "ChatGLM"
 
    @property
    def _check_point(self) -> LoaderCheckPoint: # Define la propiedad de solo lectura _check_point, devuelve el modelo de punto de control
        return self.checkPoint
 
    @property
    def _history_len (self) -> int: # Define el atributo de solo lectura _history_len, devuelve la longitud del historial
        return self.history_len
 
    def set_history_len(self, history_len: int = 10) -> Ninguno: # Establece la longitud del historial
        self. historia_len = historia_len
 
    def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str: # Defina el método _call para implementar la llamada específica del modelo print(f"__call:{prompt}") # Imprima la respuesta
        de información de la solicitud de llamada
        , _ = self.checkPoint.model.chat( # Llame al método de chat del modelo para obtener respuestas y otra información
            self.checkPoint.tokenizer, # La
            solicitud del tokenizador utilizada, #
            Historial de información de la solicitud=[] , # Registro histórico
            max_length=self.max_token, # longitud máxima
            temperatura=self.temperature # parámetro de temperatura
        )
        print(f"response:{response}") # imprimir información de respuesta
        print(f"++++++++++ +++ ++++++++++++++++++++++++++") # Imprime la
        respuesta de retorno del separador # Devuelve la respuesta
 
    def generatorAnswer(self, prompt: str,
                         history: List[List[str]] = [],
                         streaming: bool = False): # Definir el método de generación de respuestas, que puede manejar la entrada de transmisión
 
        si se transmite: # Si se trata de transmisión de
            historial de entrada += [[]] # in Agregue una nueva lista vacía al historial
            para inum, (stream_resp, _) in enumerate(self.checkPoint.model.stream_chat( # Enumerar los resultados devueltos por el método stream_chat del modelo self.checkPoint.tokenizer
                    , # El
                    indicador utilizado por el tokenizador, # solicitar información
                    history=history[-self.history_len:-1] if self.history_len > 1 else [], # used history
                    max_length=self.max_token, # longitud máxima
                    temperatura=self.temperature # parámetro de temperatura
            ) ):
                # self.checkPoint.clear_torch_cache() # Borrar el
                historial de caché[-1] = [prompt, stream_resp] # Actualizar el último registro histórico
                answer_result = AnswerResult() # Crear un objeto de resultado de respuesta
                answer_result.history = history # Actualizar el registro histórico del resultado de la respuesta
                answer_result.llm_output = {"respuesta": stream_resp} # Actualizar la salida del resultado de la respuesta
                yield answer_result # Generar el resultado de la respuesta
        de lo contrario: # Si no es una
            respuesta de entrada de transmisión, _ = self.checkPoint.model. chat( # Llamar al método de chat del modelo, Obtener respuestas y otra información
                self.checkPoint.tokenizer, # indicador del tokenizador usado
                , # información del indicador
                history=history[-self.history_len:] if self.history_len > 0 else [], # historial usado
                max_length=self.max_token, # longitud máxima
                temperatura=self.temperature # parámetro de temperatura
            )
            self.checkPoint.clear_torch_cache() # borrar
            historial de caché += [[solicitud, respuesta]] # actualizar historial answer_result
            = AnswerResult() # crear resultado de respuesta object
            answer_result.history = history # Actualizar el historial de resultados de respuestas
            answer_result.llm_output = {"answer": response} # Actualizar la salida de resultados de respuestas
            yield answer_result # Generar resultados de respuestas

3.2.2
La función del archivo models/shared.py es llamar a LLM de forma remota

import sys # Importa el módulo sys, generalmente se usa para interactuar con el intérprete de Python
al escribir import Any # Import Any del módulo de escritura, se usa para representar cualquier tipo
 
# Importa el analizador del módulo models.loader.args, que se puede usar para analizar los parámetros de la línea de comandos
de models.loader.args import parser       
# Importar LoaderCheckPoint del módulo models.loader, puede ser un punto de carga del modelo
de models.loader import LoaderCheckPoint  
 
# Importar llm_model_dict y LLM_MODEL del módulo configs.model_config
de configs.model_config import ( llm_model_dict, LLM_MODEL)  
# From El módulo models.base importa BaseAnswer, que es la clase básica del modelo
from models.base import BaseAnswer  
 
# Defina una variable llamada loaderCheckPoint, cuyo tipo es LoaderCheckPoint, e inicializada en None
loaderCheckPoint: LoaderCheckPoint = None  
 
 
def loaderLLM(llm_model: str = Ninguno, no_remote_model : bool = False, use_ptuning_v2: bool = False) -> Cualquiera:
    """
    Inicialice llm_model_ins LLM
    : param llm_model: nombre del modelo
    : param no_remote_model: si usar el modelo remoto, si necesita cargar el modelo local, agregue `--no-remote-model
    : param use_ptuning_v2: si usar p-tuning- v2 PrefixEncoder
    : return:
    """
    pre_model_name = loaderCheckPoint.model_name # Obtener el nombre del modelo de loaderCheckPoint
    llm_model_info = llm_model_dict[pre_model_name] # Obtener información del modelo del diccionario de modelos
 
    si no_remote_model: # Si no usa el modelo remoto
        loaderCheckPoint.no_remote_model = no_remote_model # Configuración de LoaderCheckPoint no_remote_model True
    si use_ptuning_v2: # Si usa p-tuning-v2
        loaderCheckPoint.use_ptuning_v2 = use_ptuning_v2 # Establezca use_ptuning_v2 de loaderCheckPoint en True
 
    if llm_model: # Si se especifica el nombre del modelo
        llm_model_info = llm_model_dict[llm_model] # Obtenga la información del modelo especificado del diccionario de modelos
 
    if loaderCheckPoint.no_remote_model: # Si no se usa el modelo remoto
        loaderCheckPoint.model_name = llm_model_info['name'] # LoaderCheckPoint's El nombre del modelo se establece en el nombre en la información del modelo
    más: # Si usa un modelo remoto
        loaderCheckPoint.model_name = llm_model_info['pretrained_model_name'] # Establezca el nombre del modelo del loaderCheckPoint en el nombre del modelo preentrenado en la información del modelo
 
    loaderCheckPoint.model_path = llm_model_info["local_model_path"] # Establecer la ruta local del modelo
 
    si 'FastChatOpenAILLM' en llm_model_info["provides"]: # Si la información proporcionada en el modelo contiene 'FastChatOpenAILLM'
        loaderCheckPoint.unload_model() # Descargar el modelo
    de lo contrario: # Si no está incluido
        loaderCheckPoint.reload_model() # Recargar el modelo
 
    provide_class = getattr(sys.modules['models'], llm_model_info['provides']) # Obtener la clase de modelo modelInsLLM
    = provide_class(checkPoint=loaderCheckPoint) # Crear una instancia de modelo
    si 'FastChatOpenAILLM ' en llm_model_info["provides"]: # Si lo que se proporciona en la información del modelo contiene 'FastChatOpenAILLM'
        modelInsLLM.set_api_base_url(llm_model_info['api_base_url']) #Establece la URL base de la API
        modelInsLLM.call_model_name(llm_model_info['name']) # Establece el nombre del modelo
    return modelInsLLM # devuelve la instancia del modelo

 3.3 configuraciones: archivo de configuración almacenamiento model_config.py
import torch.cuda
import torch.backends
import os
import logging
import uuid
 
LOG_FORMAT = "%(levelname) -5s %(asctime)s" "-1d: %(message)s"
logger = logging.getLogger()
logger.setLevel(logging.INFO)
logging.basicConfig(format=LOG_FORMAT)
 
# Modifique el valor del atributo en el siguiente diccionario para especificar la ubicación de almacenamiento del modelo de incrustación local
# Por ejemplo, "text2vec": "GanymedeNil/text2vec -large -chinese" se cambia a "text2vec": "User/Downloads/text2vec-large-chinese"
# Aquí, escriba la ruta absoluta
embedding_model_dict = {     "ernie-tiny": "nghuyong/ernie-3.0-nano-zh" ,     "ernie-base": "nghuyong/ernie-3.0-base-zh",     "text2vec-base": "shibing624/text2vec-base-chino",



    "text2vec": "GanymedeNil/text2vec-large-chinese",
    "m3e-small": "moka-ai/m3e-small",
    "m3e-base": "moka-ai/m3e-base",
}
 
# Modelo incrustado nombre
EMBEDDING_MODEL = "text2vec"
 
# Incrustación del dispositivo en ejecución
EMBEDDING_DEVICE = "cuda" si torch.cuda.is_available() else "mps" si torch.backends.mps.está_disponible() else "cpu"
 
 
# modelos LLM admitidos
# llm_model_dict maneja algunos comportamientos preestablecidos del cargador, como la ubicación de carga, el nombre del modelo, la instancia del procesador del modelo
# Modifique el valor del atributo en el siguiente diccionario para especificar la ubicación de almacenamiento del modelo LLM local
# Por ejemplo, cambie "local_model_path" de "chatglm-6b" de Ninguno a "Usuario/Descargas/chatglm-6b"
# Escriba la ruta absoluta aquí
llm_model_dict = {     "chatglm-6b-int4-qe": {         "name" : " chatglm-6b-int4-qe",


        "pretrained_model_name": "THUDM/chatglm-6b-int4-qe",
        "local_model_path": Ninguno,
        "provides": "ChatGLM"
    },
    "chatglm-6b-int4": {         "name": "chatglm-6b-int4 ",         "pretrained_model_name": "THUDM/chatglm-6b-int4",         "local_model_path": Ninguno,         "provides": "ChatGLM"     },     "chatglm-6b-int8": {         "name": "chatglm-6b-int8 ",         "pretrained_model_name": "THUDM/chatglm-6b-int8",         "local_model_path": Ninguno,         "proporciona": "ChatGLM"     },     "chatglm-6b": {         "nombre": "chatglm-6b",













        "pretrained_model_name": "THUDM/chatglm-6b",
        "local_model_path": Ninguno,
        "provides": "ChatGLM"
    },
    "chatglm2-6b": {         "name": "chatglm2-6b",         "pretrained_model_name": "THUDM /chatglm2-6b",         "ruta_modelo_local": Ninguno,         "proporciona": "ChatGLM"     },     "chatglm2-6b-int4": {         "nombre": "chatglm2-6b-int4",         "nombre_modelo_preentrenado": "THUDM/chatglm2 -6b-int4",         "local_model_path": Ninguno,         "proporciona":"ChatGLM"     },     "chatglm2-6b-int8": {         "nombre": "chatglm2-6b-int8",













        "pretrained_model_name": "THUDM/chatglm2-6b-int8",
        "local_model_path": Ninguno,
        "proporciona": "ChatGLM"
    },
    "chatyuan": {         "name": "chatyuan",         "pretrained_model_name": "ClueAI/ChatYuan -large-v2",         "local_model_path": Ninguno,         "provides": Ninguno     },     "moss": {         "name": "moss",         "pretrained_model_name": "fnlp/moss-moon-003-sft",         "local_model_path ": Ninguno,         "proporciona": "MOSSLLM"     },     "vicuña-13b-hf": {         "nombre": "vicuña-13b-hf",         "pretrained_model_name": "vicuña-13b-hf",














        "local_model_path": Ninguno,
        "proporciona": "LLamaLLM"
    },
 
    # Consulte el siguiente formato para el modelo llamado por fastchat
    "fastchat-chatglm-6b": {         "name": "chatglm-6b", # "name " se cambia a "model_name" en el servicio fastchat         "pretrained_model_name": "chatglm-6b",         "local_model_path": Ninguno,         "provides": "FastChatOpenAILLM", # Al usar la API de fastchat, debe asegurarse de que "provides" sea " FastChatOpenAILLM"         "api_base_url": "http://localhost:8000/v1" # "nombre" se cambia a "api_base_url" en el servicio fastchat }     ,     "fastchat-chatglm2-6b": {         "name": "chatglm2-6b", # "name" se cambia a "model_name" en el servicio fastchat         "pretrained_model_name": "chatglm2-6b",









        "local_model_path": Ninguno,
        "provides": "FastChatOpenAILLM", # Al usar fastchat api, debe asegurarse de que "provides" sea "FastChatOpenAILLM" "
        api_base_url": "http://localhost:8000/v1" # Change " nombre" a "api_base_url" en el servicio fastchat
    },
 
    # Consulte el siguiente formato para el modelo llamado por fastchat
    "fastchat-vicuna-13b-hf": {         "name": "vicuna-13b-hf", # "name " se cambia al servicio de fastchat "model_name" en         "pretrained_model_name": "vicuna-13b-hf",         "local_model_path": Ninguno,         "proporciona": "FastChatOpenAILLM",# Al usar la api de fastchat, asegúrese de que "provides" sea "FastChatOpenAILLM         " "api_base_url": "http://localhost:8000/v1" # Cambie "name" a "api_base_url" en el servicio de fastchat     }, } # LLM nombre







 

LLM_MODEL = "chatglm-6b"
#Cuantifica y carga el modelo de 8 bits
LOAD_IN_8BIT = Falso
# Carga el modelo con precisión bfloat16. Requiere NVIDIA Ampere GPU.
BF16 = Falso
#Ubicación donde se almacena el lora local
LORA_DIR = "loras/"
 
# LLM lora ruta, el valor predeterminado es Vacío, si lo hay, especifique la ruta de la carpeta directamente
LLM_LORA_PATH = ""
USE_LORA = Verdadero si LLM_LORA_PATH de lo contrario Falso
 
# LLM respuesta de transmisión
STREAMING = Verdadero
 
# Use p-tuning-v2 PrefixEncoder
USE_PTUNING_V2 = Falso
 
# LLM en ejecución del dispositivo
LLM_DEVICE = "cuda" if torch .cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
 
# Ruta de almacenamiento predeterminada de la base de conocimientos
KB_ROOT_PATH = os.path.join(os.path.dirname (os.ruta.dirname( __archivo__)),"base de conocimientos")
 
# Plantilla de solicitud basada en el contexto, asegúrese de mantener "{question}" y "{context}"
PROMPT_TEMPLATE = """Información conocida:
{context} 
responderá la pregunta del usuario de manera concisa y profesional en función de la información conocida anterior. Si Si no puede obtener una respuesta, diga "esta pregunta no se puede responder según la información conocida" o "no se proporciona suficiente información relevante", no se permite agregar componentes fabricados a la respuesta, use chino para la respuesta. es: {pregunta}"""
 
# La cantidad de bases de conocimiento almacenadas en caché, si se trata de modelos ChatGLM2, ChatGLM2-int4, ChatGLM2-int8, si el efecto de recuperación no es bueno, puede ajustarlo a '10'
CACHED_VS_NUM = 1
 
# Longitud de la oración de texto
SENTENCE_SIZE = 100
 
# Longitud del contexto de segmento único después de la coincidencia
CHUNK_SIZE = 250
 
#Longitud del registro de historial de LLM entrante
LLM_HISTORY_LEN = 3
 
#Número de elementos de contenido coincidentes devueltos durante la recuperación de la base de conocimiento
VECTOR_SEARCH_TOP_K = 5
 
#Relevancia del contenido de recuperación de conocimiento Puntaje, el rango de valores es aproximadamente 0-1100, si es 0, no tendrá efecto, después Cuando la configuración de la prueba es inferior a 500, el resultado coincidente es más preciso
VECTOR_SEARCH_SCORE_THRESHOLD = 0
 
NLTK_DATA_PATH = os.path.join(os.path.dirname( os.ruta.dirname(__archivo__)), "nltk_data")
 
FLAG_USER_NAME = uuid.uuid4().hex
 
logger.info(f"""
configuración del modelo de carga
llm dispositivo: {LLM_DEVICE}
dispositivo de incrustación: {EMBEDDING_DEVICE}
dir: {os.path.dirname(os.path.dirname(__file__)) }
marcando nombre de usuario: {FLAG_USER_NAME}
""")
 
# Ya sea para habilitar el dominio cruzado, el valor predeterminado es Falso, si necesita habilitarlo, configúrelo en Verdadero
# está abierto el dominio cruzado
OPEN_CROSS_DOMAIN = Falso
 
# Bing busca la variable requerida
# La búsqueda de Bing requiere la clave de suscripción de Bing, debe solicitar una búsqueda de bing de prueba en el puerto azul
# Consulte
# https://learn.microsoft.com/en-us/bing/search-apis/bing-web-search /create-bing-search para métodos de aplicación específicos -service-resource
# Use python para crear una instancia de búsqueda de bing api para obtener detalles:
# https://learn.microsoft.com/en-us/bing/search-apis/bing- búsqueda web/inicios rápidos/descanso/python
BING_SEARCH_URL = "https://api.bing.microsoft.com/v7.0/search"
# Tenga en cuenta que no es la clave api de Bing Webmaster Tools,
 
# Además, si está en el servidor, informe Error al establecer una nueva conexión: [Errno 110] Conexión agotada
# Debido a que el servidor tiene un firewall, debe comunicarse con el administrador para agregar una lista blanca, si el servidor de la empresa, ni lo piense GG
BING_SUBSCRIPTION_KEY = ""
 
# Si habilite la mejora del título en chino y la configuración relacionada de la mejora del título
# Al agregar el juicio del título, determine qué textos son títulos y márquelos en los metadatos;
# Luego combine el texto con el título del nivel superior para realizar la mejora de la información del texto.
ZH_TITLE_ENHANCE = Falso

3.4 loader: carga de documentos y conversión de texto
3.4.1 loader/pdf_loader.py
# módulo de sugerencia de tipo de importación para mejorar la legibilidad y la robustez del código
al escribir import List
 
# import UnstructuredFileLoader, que es un archivo no estructurado La clase para cargar documentos
de langchain .document_loaders.unstructured import UnstructuredFileLoader
 
# Import PaddleOCR, que es una herramienta OCR de código abierto para reconocer y leer texto de imágenes
de paddleocr import PaddleOCR
 
# Importar módulo os para procesar archivos y directorios
import os
 
# importar módulo fitz para procesar archivos PDF
import fitz
 
# importar módulo nltk para procesar datos de texto
importar nltk
 
# importar NLTK_DATA_PATH en el archivo de configuración del modelo, esta es la ruta de los datos nltk
de configs.model_config importar NLTK_DATA_PATH
 
# establecer la ruta de datos nltk, agregar la ruta en la configuración del modelo a la ruta de datos de nltk
nltk.datos.ruta = [NLTK_DATA_PATH] + nltk.datos.ruta
 
#Definir una clase, UnstructuredPaddlePDFLoader, que hereda de
la clase UnstructuredFileLoader UnstructuredPaddlePDFLoader(UnstructuredFileLoader):
 
    #Definir un método interno _get_elements, devolver una lista
    def _get_elements(self) -> List:
 
        #Definir una función interna pdf_ocr_txt, utilizada para extraer de pdf Realizar OCR y salida de archivos de texto
        def pdf_ocr_txt(filepath, dir_path="tmp_files"):
            # Combinar dir_path y la parte del directorio de filepath en una nueva ruta
            full_dir_path = os.path.join(os.path.dirname(filepath), dir_path )
 
            # If el directorio correspondiente a full_dir_path no existe, cree este directorio
            si no os.path.exists(full_dir_path):
                os.makedirs(full_dir_path)
            
            # Cree una instancia de PaddleOCR y configure algunos parámetros
            ocr = PaddleOCR(use_angle_cls=True, lang="ch", use_gpu=False, show_log=False) #
 
            Abrir archivo pdf
            doc = fitz.open(filepath)
 
            # Crear una ruta de archivo
            txt txt_file_path = os.path.join(full_dir_path , f"{os.path.split(filepath)[-1]}.txt")
 
            # Crear una ruta de archivo de imagen temporal
            img_name = os.path.join(full_dir_path, 'tmp.png')
 
            # Abrir txt_file_path archivo correspondiente y ábralo en modo escritura
            con open(txt_file_path, 'w', encoding='utf-8') como fout:
                # recorrer todas las páginas de pdf
                para i in range(doc.page_count):
                    # obtener la
                    página actual page = doc [ i]
 
                    # Obtenga el contenido de texto de la página actual y escríbalo en un archivo txt
                    text = page.get_text("")
                    fout.write(text)
                    fout.write("\n")
 
                    # Obtiene todas las imágenes en la página actual
                    img_list = page.get_images()
 
                    # Recorre todas las imágenes
                    para img en img_list:
                        # Poner las imágenes Convert to Pixmap object
                        pix = fitz.Pixmap(doc, img[0])
 
                        # Si la imagen tiene información de color, convertirla a formato RGB
                        si pix.n - pix.alpha >= 4:
                            pix = fitz. Pixmap(fitz .csRGB, pix)
                        
                        # guarda la imagen
                        pix.save(img_name)
 
                        # realiza el reconocimiento OCR en la imagen
                        result = ocr.ocr(img_name)
 
                        # Extrae el texto del resultado de OCR y escribe en el archivo txt
                        ocr_result = [i[1][0] for line in result for i in line]
                        fout.write("\n".join (ocr_result ))
            
            # Si el archivo de imagen existe, elimínelo
            si os.path.exists(img_name):
                os.remove(img_name)
            
            # Devuelve la ruta del archivo txt
            return txt_file_path
 
        # Llama a la función definida anteriormente para obtener la ruta del txt file
        txt_file_path = pdf_ocr_txt(self.file_path)
 
        # Importar la función de texto_partición, que se usa para dividir el archivo de texto en bloques
        desde unstructured.partition.text import texto_partición
 
        # Dividir el archivo txt en bloques y devolver los resultados del bloque
        return partición_texto(filename=txt_file_path, **self.unstructured_kwargs)
 
# Ejecute la entrada
si __name__ == "__main__":
    # Importe el módulo sys para operar el entorno operativo de Python
    import sys
 
    # Agregue el directorio de nivel superior del archivo actual a Python En la ruta de búsqueda
    sys.path.append(os.path.dirname(os.path.dirname(__file__)))
 
    # Definir la ruta de un archivo pdf
    filepath = os.path.join(os.path.dirname(os .path .dirname(__file__)), "knowledge_base", "samples", "content", "test.pdf")
 
    # Crear una instancia de UnstructuredPaddlePDFLoader
    loader = UnstructuredPaddlePDFLoader(filepath, mode="elements")
 
    # Cargar documentos
    docs = loader.load()
 
    # recorre e imprime todos los documentos
    para doc en docs:
        print(doc)

// Para actualizarse..

3.5 textsplitter: segmentación de documentos
3.5.1 textsplitter/ali_text_splitter.py
el código de ali_text_splitter.py es el siguiente

# Importar el módulo CharacterTextSplitter para la segmentación de texto
desde langchain.text_splitter import CharacterTextSplitter  
import re # Importar el módulo de expresión regular para la coincidencia y el reemplazo de texto
desde la importación de la lista de escritura # Importar el tipo List para especificar el tipo de datos devuelto
 
# Definir una nueva clase AliTextSplitter, heredado de
la clase CharacterTextSplitter AliTextSplitter(CharacterTextSplitter):  
    # La función de inicialización de la clase, si el parámetro pdf es True, entonces use la regla de segmentación de texto pdf, de lo contrario use la regla predeterminada
    def __init__(self, pdf: bool = False, * * kwargs):  
        # Llamar a la función de inicialización de la clase padre y recibir otros parámetros pasados ​​en
        super().__init__(**kwargs)  
        self.pdf = pdf # Guardar el parámetro pdf como una variable miembro de la clase
 
    # Definir la segmentación del texto método, el parámetro de entrada es una cadena y el valor de retorno es una lista de cadenas
    def split_text(self, text: str) -> List[str]:  
        if self.pdf: # Si el parámetro pdf es True, entonces preprocesar el texto
 
            # Reemplazar 3 o más caracteres de nueva línea consecutivos con un carácter de nueva línea
            text = re.sub(r"\n{3,}", r"\n", text)  
            # Reemplazar todos los caracteres en blanco (incluidos espacios, tabuladores, fuentes de formulario, etc.) se reemplazan con un
            texto de espacio = re.sub('\s', " ", texto)  
            # Reemplazar dos nuevas líneas consecutivas con un carácter vacío
            texto = re.sub("\ n\n", "", texto )  
        
        # Importar el módulo de canalización para crear un flujo de procesamiento
        desde modelscope.pipelines import pipeline  
 
        # Crear un flujo de procesamiento para tareas de segmentación de documentos
        # El modelo utilizado es damo/nlp_bert_document-segmentation_chinese-base, El dispositivo informático es cpu
        p = pipeline(
            task ="document-segmentation",
            model='damo/nlp_bert_document-segmentation_chinese-base',
            dispositivo="cpu")
        result = p(documents=text) # Procesar el texto de entrada y devolver el resultado del procesamiento
        sent_list = [i for i in result["text"].split("\n\t") if i] # Procesar el resultado de acuerdo con Los saltos de línea y las tabulaciones se dividen para obtener una lista de oraciones
        return sent_list # return lista de oraciones

Entre ellos, hay tres puntos dignos de mención.

El parámetro use_document_segmentation especifica si usar la segmentación semántica para documentar.
El modelo de segmentación semántica de documentos adoptado aquí es de código abierto de DAMO Academy: nlp_bert_document-segmentation_chinese-base (este es su documento).
Además, si usa el modelo para la segmentación semántica de documentos , necesita instalar:
modelscope[nlp]: pip install "modelscope[nlp]" -f https://modelscope.oss-cn-beijing.aliyuncs.com/releases/repo.html
y considerando el uso de tres modelos, puede ser para gpu de configuración baja No es muy amigable, así que aquí el modelo se carga en la cpu para el cálculo.Si es necesario, puede reemplazar el dispositivo con su propia tarjeta gráfica id 3.6 conocimiento_bas: index.faiss/
index.pkl
Hay dos archivos en Knowledge_bas, un contenido es el archivo original cargado por el usuario, vector_store se usa para almacenar el archivo de la biblioteca de vectores, es decir, la ontología de la base de conocimiento local, porque el contenido varía de persona a persona, que carga lo que es qué, entonces no hay nada que analizar, y hay dos archivos en vector_store, uno index.faiss y otro index.pkl

3.7 cadenas: búsqueda/coincidencia de vectores
Como se mencionó anteriormente, "FAISS" en "Índice FAISS, búsqueda FAISS" en la figura al comienzo de esta sección es un método lanzado por Facebook AI para buscar efectivamente similitudes en gran escala de alta dimensión. espacios vectoriales Encontrar rápidamente el vector más similar a un vector determinado en un conjunto de datos a gran escala es una parte importante de muchas aplicaciones de IA, como en los sistemas de recomendación, el procesamiento del lenguaje natural, la recuperación de imágenes, etc.

3.7.1 archivo chains/modules/vectorstores.py: de acuerdo con la consulta de vector de consulta, encuentre vectores de texto similares a la consulta en la base de datos de vectores. Se trata
principalmente del uso de FAISS (Facebook AI Similarity Search) y un almacenamiento de vectores de FAISS. class (FAISSVS, FAISSVS La clase hereda de la definición de la clase FAISS) y contiene los siguientes métodos principales:

max_marginal_relevance_search
Dada una declaración de consulta, primero convierta la declaración de consulta en un vector incrustado "embedding = self.embedding_function(query)", y luego llame a la función max_marginal_relevance_search_by_vector para realizar la búsqueda MMR #Utilice la relevancia marginal máxima para devolver el texto seleccionado def
max_marginal_relevance_search
(
    self,
    query: str, # query
    k: int = 4, # el número de documentos devueltos, el valor predeterminado es 4
    fetch_k: int = 20, # el número de documentos capturados utilizados para pasar al algoritmo MMR
    **kwargs: Any,
) -> List[Tuple[ Document, float]]:    
 
    # consulta vectorización
    incrustación = self.embedding_function(consulta)
    # llamada: max_marginal_relevance_search_by_vector
    docs = self.max_marginal_relevance_search_by_vector(incrustación, k, fetch_k)
    return docs
  max_marginal_relevance_search_by_vector
Con un vector de incrustación dado, use el método de Relevancia Marginal Máxima (MMR) para devolver texto relevante. MMR
es un algoritmo para resolver la diversidad y relevancia de los resultados de la consulta. Específicamente, no solo requiere que el texto devuelto sea lo más similar posible al consulta, y espero que los conjuntos de texto devueltos sean lo más diversos
posible
max_marginal_relevance_search_by_vector(
    self, incrustado: List[float], k: int = 4, fetch_k: int = 20, **kwargs: Any
) -> List[Tuple[Document , float]]:
 
    # Use el índice para buscar e incrustar en el texto Contenido similar al vector, devuelva la puntuación y
    las puntuaciones   , indices = self.index.search(np.array([incrustación], dtype=np .float32), fetch_k)
    
    # Recuperar del texto por índice Construir el vector de incrustación, -1 significa que no hay suficiente texto para devolver
    incrustaciones = [self.index.reconstruct(int(i)) for i in indices[0] if i != -1] 
 
    # Usar el algoritmo de máxima correlación marginal para seleccionar el k texto más relevante
    mmr_selected = maximal_marginal_relevance(
        np.array([embedding], dtype=np.float32), embeddings, k=k
    )  
 
    selected_indices = [indices[0][i] for i in mmr_selected] # Obtiene el índice del texto seleccionado
    selected_scores = [scores[0 ][i] for i in mmr_selected] # Obtener la puntuación del texto seleccionado
    docs = []
    for i, score in zip(selected_indices, selected_scores): # Para cada índice de texto seleccionado y puntuación
        if i == -1 : # If el índice es -1, no hay suficiente texto para regresar
            continue
 
        _id = self.index_to_docstore_id[i] # Obtener el id del texto a través del índice
        doc = self.docstore.search(_id) # Buscar el texto en la biblioteca de documentos by id
        if not isinstance(doc, Document): # Si el texto buscado no es del tipo Documento, genere ValueError
            (f"No se pudo encontrar el documento para id {_id}, obtuve {doc}")
        docs.append((doc, score)) # agregar el texto y la puntuación a la lista de resultados
    return docs # devolver la lista de resultados

__from
se usa para crear una instancia de FAISSVS a partir de un conjunto de texto y los vectores de incrustación correspondientes.     Este método primero crea un índice FAISS y agrega vectores de incrustación, luego crea un almacén de texto para almacenar el texto asociado con cada vector de incrustación #Cree un objeto de índice FAISS a partir del texto dado, vectores de incrustación, metadatos     ,
etc. :     Lista [cadena], # lista de texto, cada texto se convertirá en un objeto de texto     . metadatos vectoriales incrustados     : Opcional[Lista[dict]] = Ninguno,     **kwargs: Cualquiera, ) -> FAISS:     faiss = dependable_faiss_import() # Importar     índice de biblioteca FAISS = faiss.IndexFlatIP(len(embeddings[ 0])) # Crear un nuevo índice usando la biblioteca FAISS, la dimensión del índice es igual a la longitud del vector de texto incrustado     index.add(np.array(embeddings, dtype=np.float32)) #Agregue el vector incrustado al índice FAISS








 



 
    # cuantificador = faiss.IndexFlatL2(len(incrustaciones[0]))
    # índice = faiss.IndexIVFFlat(cuantificador, len(incrustaciones[0]), 100)
    # index.train(np.array(incrustaciones, dtype=np.float32 ))
    # index.add(np.array(embeddings, dtype=np.float32))
 
    documentos = []
    for i, text in enumerate(texts): # Para cada fragmento de texto
        # Obtener los metadatos correspondientes, si no hay metadatos siempre Los datos usan un diccionario vacío
        metadata = metadatas[i] if metadatas else {}  
 
        # Crea un objeto de texto y agrégalo a la lista de texto
        documents.append(Document(page_content=text, metadata=metadata))  
 
    # Genera un texto único para cada ID de texto
    index_to_id = {i: str(uuid.uuid4()) for i in range(len(documents))} #  
 
    Crear una biblioteca de texto para almacenar objetos de texto y el ID correspondiente
    docstore = InMemoryDocstore(
        {index_to_id[i]: doc for i, doc in enumerate(documents)}  
    )
 
    # 返回FAISS对象
    return cls(embedding.embed_query, index, docstore, index_to_id)  

Lo anterior es el contenido principal de este código, al usar FAISS y MMR, puede ayudarnos a encontrar el texto más relevante para una consulta dada en una gran cantidad de texto

3.7.2 archivo de código chains/local_doc_qa.py: búsqueda vectorial
Importación de paquetes y módulos
El comienzo del código es una serie de declaraciones de importación que importan los paquetes y módulos de Python necesarios, incluidos cargadores de archivos, divisores de texto, configuraciones de modelos y algunos Python módulos integrados y otras bibliotecas de terceros
Anular el método hash de la clase HuggingFaceEmbeddings
El código define una función llamada _embeddings_hash y la asigna al método __hash__ de la clase HuggingFaceEmbeddings. El propósito de esto es hacer que el objeto HuggingFaceEmbeddings pueda ser hash, es decir, puede usarse como la clave del diccionario o agregarse a la colección.Cargar
almacenamiento de vectores
define una función llamada load_vector_store, que se usa para cargar un almacenamiento de vectores localmente y devolver Objeto de clase FAISS. El decorador lru_cache se utiliza para almacenar en caché los resultados CACHED_VS_NUM utilizados más recientemente para mejorar la eficiencia del código. La función de árbol
transversal del árbol de archivos
es una función recursiva que se utiliza para recorrer todos los archivos en el directorio especificado y devolver una ruta completa y un nombre de archivo que contiene la lista de todos los archivos de . Puede ignorar el archivo o directorio especificado.
Cargar archivo:
la función cargar_archivo selecciona el cargador y el divisor de texto adecuados según la extensión del archivo, carga y divide el archivo.
Generar recordatorio:
la función generar_prompt se utiliza para generar un recordatorio basado en documentos y consultas relacionados. . La plantilla del recordatorio la proporciona el parámetro prompt_template
Crear una lista de documentos
search_result2docs
# Crear una lista vacía para almacenar documentos
def search_result2docs(search_results):
    docs = []
 
    # Para cada elemento en los resultados de búsqueda
    para result in search_results:
        # Crear un objeto de documento
        # Si el resultado contiene la palabra clave "fragmento", su valor se usa como el contenido de la página; de lo contrario, el el contenido de la página es una cadena vacía
        # Si el resultado contiene la palabra clave "enlace", su valor se utiliza como enlace de origen en los metadatos; de lo contrario, el enlace de origen es una cadena vacía #
        Si el resultado contiene la palabra clave "título", su valor se utiliza como nombre de archivo de metadatos, de lo contrario, el nombre de archivo es una cadena vacía
        doc = Document(page_content=result["snippet"] if "snippet" in result.keys() else "",
                       metadata={"source": result[ "enlace" ] si "enlace" en resultado.keys() else "",
                                 "nombre de archivo": resultado["título"] si "título" en resultado.keys() else ""})
 
        # Agregar el objeto de documento creado a la lista
        docs.append(doc)
    
    # Devolver la lista de documentos
    return docs

Posteriormente, se define una clase llamada LocalDocQA, que se utiliza principalmente para tareas de respuesta a preguntas basadas en documentos. La función principal de la tarea de respuesta a preguntas basadas en documentos es devolver una respuesta basada en un conjunto dado de documentos (aquí llamado base de conocimientos) y preguntas ingresadas por el usuario. Los principales métodos de la clase LocalDocQA incluyen:

init_cfg(): este método inicializa algunas variables, incluida la asignación de llm_model (un modelo de lenguaje utilizado para generar respuestas) a self.llm, la asignación de un modelo de incrustación basado en HuggingFace a self.embeddings y la asignación del parámetro de entrada top_k a self.top_k
init_knowledge_vector_store (): Este método es responsable de inicializar el almacén de vectores de conocimiento. Primero verifica la ruta del archivo de entrada y, para cada archivo en la ruta, carga el contenido del archivo en un objeto Documento, luego convierte estos documentos en vectores incrustados y los almacena en la biblioteca de vectores one_knowledge_add(): Este método se usa Agrega
un nuevo documento de conocimientos a la base de conocimientos. Crea el título y el contenido de entrada como un objeto de documento, luego lo convierte en un vector incrustado y lo agrega a la biblioteca de vectores
get_knowledge_based_answer(): este método genera una respuesta basada en la base de conocimiento dada y la pregunta ingresada por el usuario. Primero encuentra el documento más relevante en la base de conocimientos en función de la pregunta ingresada por el usuario, luego genera un mensaje que contiene el documento relevante y la pregunta del usuario, y pasa el mensaje a llm_model para generar la respuesta. Tenga en cuenta que esta función llama al uno que se implementó anteriormente
: similarity_search_with_score
get_knowledge_based_conent_test(): este método es para probar, devolverá los documentos más relevantes y las sugerencias de consulta a     la     consulta
    de     entrada umbral de puntuación de coincidencia de búsqueda



    # vector_search_top_k El número de elementos de contenido de la base de conocimiento de búsqueda, la búsqueda predeterminada es 5 resultados
    # chunk_sizes Coincide con la longitud del contexto de conexión de una sola pieza de contenido
    def get_knowledge_based_conent_test(self, query, vs_path, chunk_conent,
                                        score_threshold=VECTOR_SEARCH_SCORE_THRESHOLD,
                                        vector_search_top_k=VECTOR_SE ARCH_TOP_K, chunk_size=CHUNK_SIZE):
get_search_result_based_answer( ): este método es similar a get_knowledge_based_answer(), pero el resultado de bing_search se usa aquí como base de conocimiento
def get_search_result_based_answer(self, query, chat_history=[], streaming: bool = STREAMING):
    # Realice una búsqueda de Bing en la
    consulta y obtenga el resultado de
 
    la     búsqueda
    .
 

    prompt = generar_prompt(result_docs, query)
 
    # Generar una respuesta a través de LLM (Long Language Model)
    para answer_result en self.llm.generatorAnswer(prompt=prompt, history=chat_history,
                                                  streaming=streaming):
        # Obtener el texto de la respuesta
        resp = answer_result.llm_output ["respuesta"]
 
        # Obtener el historial de chat
        = answer_result.history
 
        # Reemplazar la pregunta del último elemento en el historial de chat con el
        historial de consultas actual[-1][0] = consulta
 
        # Reunir el resultado del respuesta de respuesta
        = {"consulta": consulta,
                    "resultado": resp,
                    "documentos_fuente": resultado_docs}
 
        # Devuelve los resultados de la respuesta y el historial de chat
        produce respuesta, historial

Como puede ver, la principal diferencia entre esta función y la anterior es que esta función usa los resultados de búsqueda del motor de búsqueda directamente para generar una respuesta, mientras que la función anterior usa la búsqueda de similitud de consulta para encontrar el texto más relevante y luego, basándose en Estos textos generan respuestas
, y esta bing_search se definió en la Sección 3.1.2. A continuación ,
hay tres métodos para eliminar archivos, actualizar archivos y enumerar archivos del almacenamiento     de     vectores
. ,                                       ruta del archivo: str o List[str], # ruta del archivo, que puede ser un solo archivo o una lista de varios archivos                                       vs_path): # vector ruta de almacenamiento         vector_store = load_vector_store(vs_path, self.embeddings) # cargar desde una ruta dada Vector estado de almacenamiento         = vector_store.delete_doc(filepath) # eliminar el         estado de devolución del archivo especificado # devolver el estado de eliminación     # actualizar el archivo en el almacenamiento de vectores









 

    def update_file_from_vector_store(self,
                                      filepath: str o List[str], # La ruta del archivo que debe actualizarse, que puede ser un único archivo o una lista de varios archivos
                                      vs_path, # Vector storage path
                                      docs: List[Document],) : # El archivo que necesita ser actualizado Contenido, los archivos se dan en forma de documento
        vector_store = load_vector_store(vs_path, self.embeddings) # cargar vector store desde la ruta dada
        status = vector_store.update_doc(filepath, docs) # actualizar
        el estado de devolución del archivo especificado # devolver estado de actualización
 
    # enumerar vectores Archivos en almacenamiento
    def list_file_from_vector_store(self,
                                    vs_path, # vector storage path
                                    fullpath=False): # Si devolver la ruta completa, si es False, solo se devuelve el nombre del archivo
        vector_store = load_vector_store(vs_path, self.embeddings) # cargar el almacén de vectores desde la ruta dada
        docs = vector_store.list_docs() # enumerar todos los archivos
        si la ruta completa: # si se requiere la ruta completa
            devolver documentos # devolver la lista de rutas completas
        else: # si solo The se requiere el nombre del archivo
            devuelva [os.path.split(doc)[-1] for doc in docs] # Use os.path.split para separar la ruta y el nombre del archivo, y solo devuelva la lista de nombres de archivo

El código en la sección __main__ es un ejemplo de instanciación y uso de la clase LocalDocQA

Primero inicializa un objeto llm_model_ins
y luego crea una instancia de LocalDocQA y llama a su método init_cfg() para inicializar.
Después de eso, especifica una consulta y la ruta de la base de conocimiento
y luego llama al método get_knowledge_based_answer() o get_search_result_based_answer() para obtener la consulta basada en la respuesta e imprimir la información de la respuesta y el documento fuente
3.7.3 cadenas/text_load.py
También está el último archivo del proyecto en la carpeta de la cadena (langchain-ChatGLM/text_load.py en master imClumsyPanda /langchain-ChatGLM GitHub), de la siguiente manera

importar os
importar piña 
de tqdm importar tqdm
de langchain.llms importar OpenAI
de langchain.text_splitter importar SpacyTextSplitter
de langchain.document_loaders importar TextLoader
de langchain.document_loaders importar DirectoryLoader
de langchain.indexes importar VectorstoreInde xCreator
de langchain.embeddings.openai importar OpenAIEmbeddings
de langchain . Las tiendas de vectores importan Pinecone
 
#algunos archivos de configuración
openai_key="tu clave" # registra openai.com y obtén
pinecone_key="tu clave" # registra app.pinecone.io y obtén
pinecone_index="tu biblioteca" #app.pinecone.io get
pinecone_environment="su entorno" # Después de iniciar sesión en pinecone, compruebe el entorno en la página de índices
pinecone_namespace="su espacio de nombres" #Si no existe, se creará automáticamente
 
#Ciencia en línea que conoces
os.environ['HTTP_PROXY'] = 'http://127.0.0.1:7890'
os.environ['HTTPS_PROXY'] = 'http://127.0.0.1:7890'
 
#Inicializar piña
piña. init(
    api_key=pinecone_key,
    environment=pinecone_environment
)
index = pinecone.Index(pinecone_index)
 
#Inicialice las incrustaciones de OpenAI
incrustaciones = OpenAIEmbeddings(openai_api_key=openai_key)
 
#Inicialice text_splitter
text_splitter = SpacyTextSplitter(pipeline='zh _core_web_sm',chunk_size =1000,trozo_superpuesto= 200)
 
# Leer todos los archivos en el directorio con el sufijo txt
loader = DirectoryLoader('../docs', glob="**/*.txt", loader_cls=TextLoader)
 
#Leer archivos de texto
documents = loader.load( )
 
# Usar text_splitter para dividir el documento
split_text = text_splitter.split_documents(documents)
try:
    for document in tqdm(split_text):
        # Obtener el vector y almacenarlo en pinecone
        Pinecone.from_documents([document], incrustaciones, index_name=pinecone_index)
excepto Excepción como e:
    print(f" Error: {e}")
    salir()

3.8 almacenes de vectores: MyFAISS.py
dos archivos, uno __init__.py (solo una línea de código: from .MyFAISS import MyFAISS), el otro MyFAISS.py, como se muestra en el siguiente código

# Importar FAISS desde la biblioteca langchain.vectorstores
desde langchain.vectorstores import FAISS
# Importar VectorStore            
desde la biblioteca langchain.vectorstores.base desde langchain.vectorstores.base import VectorStore
# Importar dependable_faiss_import
desde langchain.vectorstores.faiss importar dep enable_faiss_import  
 
desde escribir import Any, Callable , List, Dict # Importar biblioteca de comprobación de tipo
de langchain.docstore.base import Docstore # Importar Docstore de langchain.docstore.base library
 
# Importar documento de langchain.docstore.document Library
de langchain.docstore.document Importar documento  
 
importar numpy como np # Importar biblioteca numpy para computación científica
importar copia # Importar biblioteca de copia para replicación de datos
import os # Importar biblioteca os para operaciones relacionadas con el sistema operativo
from configs.model_config import * # Importar todo el contenido de la biblioteca configs.model_config
 
 
# Definir la clase MyFAISS, que hereda de las dos clases principales de FAISS y VectorStore
class MyFAISS(FAISS, VectorStore):

A continuación, implemente las siguientes funciones una por una

3.8.1 Definir la función de inicialización de la clase: __init__
    # Definir la función de inicialización de la clase
    def __init__(
            self,
            embedding_function: Callable,
            index: Any,
            docstore: Docstore,
            index_to_docstore_id: Dict[int, str],
            normalize_L2: bool = Falso,
    ):
        # Llamar a la función de inicialización de la clase padre FAISS
        super().__init__(embedding_function=embedding_function,
                         index=index,
                         docstore=docstore,
                         index_to_docstore_id=index_to_docstore_id,
                         normalize_L2=normalize_L2)
        # Inicializar el umbral de puntuación
        self.score_threshold=VECTOR_SEARCH_SCORE_THRESHOLD
        # inicializar el tamaño del fragmento
        self.chunk_size = CHUNK_SIZE
        # inicializar el contenido del fragmento
        self.chunk_conent = False

3.8.2 lista_separada: descompone una lista en varias sublistas
    # Defina la función lista_separada para descomponer una lista en varias sublistas, los elementos en cada sublista son continuos en la lista original
    def lista_separada(self, ls: List[ int] ) -> List[List[int]]:
        # TODO: Agregar el juicio de si pertenecen al mismo documento
        list = []
        ls1 = [ls[0]]
        for i in range(1, len(ls) ):
            if ls[i - 1] + 1 == ls[i]:
                ls1.append(ls[i])
            else:
                listas.append(ls1)
                ls1 = [ls[i]]
        listas.append(ls1)
        return enumera
3.8.3 búsqueda_de_similitud_con_puntuación_por_vector, de acuerdo con el vector de entrada, encuentre el texto k más cercano.
La función de búsqueda_de_similitud_con_puntuación_por_vector se utiliza para realizar una búsqueda de similitud por vector y devuelve el texto más similar y la puntuación correspondiente al vector de incrustación dado.

    # Defina la función similarity_search_with_score_by_vector para encontrar los k textos más cercanos de acuerdo con el vector de entrada
    def similarity_search_with_score_by_vector(
            self, incrustando: List[float], k: int = 4
    ) -> List[Document]:
        # Llame a la función confiable_faiss_import para importar el faiss biblioteca
        faiss = dependable_faiss_import()
 
        # Convierta la lista de entrada en una matriz numpy y establezca el tipo de datos en float32
        vector = np.array([embedding], dtype=np.float32)
 
        # Si se requiere la normalización L2, llame a faiss. la función normalize_L2 está normalizada
        si self._normalize_L2:
            faiss.normalize_L2(vector)
 
        # Llame a la función de búsqueda de la biblioteca faiss para encontrar los k vectores más cercanos al vector de entrada y devolver sus puntajes y
        puntajes de índice, índices = self.index .search (vector, k)
 
        # Inicializar una lista vacía para almacenar el texto encontrado
        docs = []
        # Inicializar una colección vacía para almacenar el id del texto
        id_set = set()
 
        # Obtener el número de textos en la biblioteca de texto
        store_len = len(self.index_to_docstore_id)
 
        # Inicializar una variable booleana para indicar si es necesario reorganizar la lista de id.
        rearrange_id_list = False
 
        # Recorra los índices y puntajes encontrados
        para j, i en enumerate(indices[0]):
            # Si el índice es -1, o el puntaje es menor que el umbral, omita este índice
            si i == -1 o 0 < self.score_threshold < puntuaciones [0][j]:
                # Esto sucede cuando no se devuelven suficientes documentos
                continue
 
            # Si el índice existe en el diccionario index_to_docstore_id, obtenga el id de texto correspondiente
            si i en self.index_to_docstore_id:
                _id = self .index_to_docstore_id[i]
 
            # Si el índice no existe en el diccionario index_to_docstore_id, omita este índice
            ; de ​​lo contrario:
                continúe
            # Busque el texto correspondiente a la identificación de la biblioteca de texto
            doc = self.docstore.search(_id)
 
            # Si no hay necesidad de dividir el bloque contenido, o el documento Si no hay un campo context_expand en los metadatos, o el valor del campo context_expand es falso, ejecute el siguiente código
            si (no self.chunk_conent) o ("context_expand" en doc.metadata y no doc.metadata ["context_expand"]):
                # emparejar Si el texto no necesita expandir el contexto, ejecute el siguiente código
                # Si el texto buscado no es del tipo Documento, se lanza una excepción
                si no es instancia (doc, Documento):
                    aumentar ValueError(f"No se pudo encontrar el documento para id {_id}, obtuve {doc}")
                # Agregar un campo de puntaje a los metadatos del texto, cuyo valor es el puntaje encontrado
                doc.metadata["puntuación"] = int(puntuaciones[0][j])
 
                # Agregar el texto a la lista de documentos
                docs.append(doc)
                continuar
 
            # Agregar la identificación del texto a la colección id_set
            id_set.add(i)
 
            # Obtener la longitud del texto
            docs_len = len(doc.page_content)
 
            # recorrer el número k entre 1 a i y store_len - i
            for k in range(1, max(i, store_len - i)):
                # inicializar una variable booleana, indicando si salir del bucle
                break_flag = False
 
                # Si hay un campo context_expand_method en los metadatos del texto, y su valor es "forward", entonces el rango de expansión se establece en [i + k]
                si "context_expand_method" en doc.metadata y doc.metadata ["context_expand_method"] == "adelante":
                    expand_range = [i + k]
 
                # Si hay un campo context_expand_method en los metadatos del texto, y su valor es "hacia atrás", el rango de expansión se establece en [i - k] elif "
                context_expand_method" en doc.metadata y doc .metadata[" context_expand_method"] == "hacia atrás":
                    expand_range = [i - k]
 
                # Si no hay un campo context_expand_method en los metadatos del texto, o el valor del campo context_expand_method no es ni "hacia adelante" ni "hacia atrás" , el rango de expansión se establece en [i + k, i - k]
                más:
                    expand_range = [i + k, i - k]
 
                # Recorre el rango extendido
                para l en expand_range:
                    # Si l no está en la colección id_set, y l está entre 0 y len (self.index_to_docstore_id), luego ejecute el siguiente código
                    if l not in id_set and 0 <= l < len(self.index_to_docstore_id):
                        # Obtenga el texto id correspondiente a l
                        _id0 = self.index_to_docstore_id[l]
 
                        # Busque el texto correspondiente a id de la biblioteca de texto
                        doc0 = self.docstore .search (_id0)
 
                        # Si la longitud del texto más la longitud del nuevo documento es mayor que el tamaño del fragmento, o la fuente del nuevo texto no es igual a la fuente del texto actual, establezca break_flag en verdadero y rompa fuera del bucle
                        si docs_len + len(doc0.page_content) > self.chunk_size o doc0.metadata["fuente"] != \
                                doc.metadata["fuente"]:
                            break_flag = True
                            break
 
                        # Si la fuente del nuevo texto es igual a la fuente del texto actual, agregue la longitud del nuevo texto a la longitud del texto, agregue l a la colección id_set y establezca rerange_id_list en verdadero
                        elif doc0.metadata["fuente"] == doc.metadata["fuente"]:
                            docs_len += len(doc0.page_content)
                            id_set.add(l)
                            rearrange_id_list = True
 
                # Si break_flag es verdadero, saltar fuera del ciclo
                si break_flag:
                    break
 
        # Si no necesita dividir el contenido del fragmento, o si no necesita reorganizar la lista de ID, devuelva la lista de documentos
        si (no self.chunk_conent) o (no reorganizar_id_list):
            return docs
 
        # If la longitud de la colección id_set es 0 y el umbral de puntuación es mayor que 0, devuelve una lista vacía
        si len(id_set) == 0 y self.score_threshold > 0:
            return []
 
        # Ordena los elementos en la colección id_set y convierte a una lista
        id_list = sorted(list(id_set))
 
        # Llame a la función seperate_list para descomponer id_list en múltiples sublistas
        id_lists = self.seperate_list(id_list)
 
        # Recorra cada secuencia de id en id_lists
        para id_seq en id_lists:
            # Recorra cada secuencia de id en id_lists Un id
            para id en id_seq:
                # Si el id es igual al primer elemento de la secuencia de id, busque el texto correspondiente al id de la biblioteca de documentos y copie profundamente el texto
                if id == id_seq[0]:
                    _id = self.index_to_docstore_id[ id]
 
                    # doc = self.docstore.search(_id)
                    doc = copy.deepcopy(self.docstore.search(_id))
 
                # Si el id no es igual al primer elemento de la secuencia de id, busque para la identificación correspondiente del documento de la biblioteca de texto, agregue el contenido del nuevo texto al contenido del texto actual,
                de lo contrario:
                    _id0 = self.index_to_docstore_id[id]
                    doc0 = self.docstore.search(_id0)
                    doc.page_content += " " + doc0.page_content
 
            # Si el texto buscado no es del tipo Documento, se lanzará una excepción
            si no es instancia(doc , Documento):
                aumentar ValueError(f"No se pudo encontrar el documento para id {_id}, obtuve {doc}")
            # Calcular la puntuación del texto, la puntuación es igual al valor mínimo de la puntuación correspondiente a cada id en el lista de puntuaciones en la secuencia id
            doc_score = min([puntuaciones[0][id] for id in [indices[0].tolist().index(i) for i in id_seq if i in indices[0]]]) # Add score to text
 
            metadata Campo cuyo valor es el puntaje del documento
            doc.metadata["score"] = int(doc_score)
 
            # Agrega el texto a la lista de documentos docs
            .append(doc)
        # devuelve la lista de documentos
        devolver documentos

3.8.4 método delete_doc: elimina el texto de la fuente especificada en la biblioteca de texto
    #Define un método llamado delete_doc, que se usa para eliminar el texto de la fuente especificada en la biblioteca de texto
    def delete_doc(self, source: str o List[ str]) :
        # Use la estructura try-except para capturar posibles excepciones
        pruebe:
            # Si la fuente es un tipo de cadena
            if isinstance(source, str):
                # Averigüe las identificaciones de todos los textos cuya fuente es igual a la fuente en la biblioteca de texto ids
                = [k for k, v in self.docstore._dict.items() if v.metadata["source"] == source]
 
                # Obtenga la ruta de almacenamiento de vectores
                vs_path = os.path.join(os.path. split(os.path.split(fuente)[0])[0], "vector_store")
 
            # Si la fuente es una lista, escriba
            otra cosa:
                # Averigüe los ID de todos los textos en la lista de fuentes en la biblioteca de texto
                ids = [k for k, v in self.docstore._dict.items() if v.metadata["source"] in source]
 
                # Obtener la ruta de almacenamiento de vectores
                vs_path = os.path.join(os.path.split ( os.path.split(source[0])[0])[0], "vector_store")
 
            # Si no se encuentra el texto a eliminar, devuelve un mensaje de error
            si len(ids) == 0:
                devuelve f "docs delete fail"
 
            # Si el texto que se va a borrar se encuentra
            de otra manera:
                # Recorra todos los textos que se van a borrar id
                for id in ids:
                    # Obtener la posición del id en el índice
                    index = list(self.index_to_docstore_id.keys( ))[list(self. index_to_docstore_id.values()).index(id)]
 
                    # eliminar el id del índice
                    self.index_to_docstore_id.pop(index)
 
                    # Eliminar el texto correspondiente a la id de la biblioteca de texto
                    self.docstore._dict.pop(id)
 
                # TODO: Eliminar la id correspondiente de self.index, esta es una tarea inconclusa
                # self . index.reset()
                # Guarda el estado actual en el local
                self.save_local(vs_path)
 
                # Devuelve el mensaje de eliminación exitosa
                return f"docs delete success"
 
        # Captura la excepción
        excepto Exception as e:
            # Imprime la información de la excepción
            print(e )
            # Volver a borrar Información fallida
            return f"docs delete fail"

3.8.5 actualizar_doc y listas_doc
   # Defina un método llamado actualizar_doc, que se utiliza para actualizar documentos en la biblioteca de documentos
    def actualizar_doc(self, source, new_docs):
        # Use la estructura try-except para capturar posibles excepciones
        try:
            # Eliminar documentos antiguos
            delete_len = self.delete_doc(fuente)
 
            #Agregar nuevos documentos
            ls = self.add_documents(new_docs)
 
            #Regresar información de actualización exitosa
            return f"actualización exitosa de documentos"
        #Capturar excepción
        excepto Excepción como e:
            #Imprimir información de excepción
            print(e)
 
            # Regresar actualización de información de error
            return f"docs update fail"
 
    # Defina un método llamado list_docs, que se utiliza para enumerar las fuentes de todos los documentos en la biblioteca de documentos
    def list_docs(self):
        # Recorra todos los documentos en la biblioteca de documentos, extraiga la fuente de cada documento, conviértala en una colección, luego conviértala en una lista y finalmente devuelva esta lista return
        list(set(v.metadata["source"] for v en self.docstore._dict .values()))

La cuarta parte es la combinación de LLM y Knowledge Graph
4.1 ¿Por qué se debe combinar LLM con Knowledge Graph?
Del contenido anterior de este artículo o de este blog, podemos ver que la mayor parte del LLM se basa en el antiguo corpus de pre-entrenamiento de Internet. entrenamiento y razonamiento en el pasado Esto lleva a dos problemas

Al no poder obtener el conocimiento más reciente, para resolver este problema, la versión ChatGPT plus inicialmente obtuvo el conocimiento más reciente mediante la introducción del complemento de búsqueda de bing (pero se eliminó temporalmente debido a problemas comerciales), mientras que el producto de la competencia de ChatGPT, Claude, actualizó su configuración preestablecida Los datos de entrenamiento, como los datos en 2013
, no pueden responder algunas preguntas altamente especializadas y, a veces, cometen algunos errores de conocimiento fáctico al razonar
Frente a la segunda pregunta, hemos demostrado anteriormente que se puede resolver al combinar con langchain para construir una base de conocimiento local. Además, también puede considerar combinar LLM con gráficos de conocimiento

Los gráficos de conocimiento pueden almacenar conocimiento estructurado en forma de triples (es decir, entidad de cabeza, relación, entidad de cola), por lo que los gráficos de conocimiento son una forma estructurada y decisiva de representación de conocimiento, los ejemplos incluyen Wikidata, YAGO y NELL. Los gráficos de conocimiento son fundamentales para una variedad de aplicaciones, ya que proporcionan un conocimiento preciso e inequívoco. También se sabe que tienen una gran capacidad de razonamiento simbólico, lo que puede generar resultados interpretables. El gráfico de conocimiento también puede evolucionar activamente con la entrada continua de nuevos conocimientos. Por supuesto, el mapa de conocimiento en sí también tiene sus deficiencias, como una capacidad de generalización insuficiente.

De acuerdo con la diferente información almacenada, los gráficos de conocimiento existentes se pueden dividir en cuatro categorías: gráficos de conocimiento enciclopédico, gráficos de conocimiento de sentido común, gráficos de conocimiento de dominio específico y gráficos de conocimiento multimodal.

 La siguiente figura resume las ventajas y desventajas de LLM y el gráfico de conocimiento.

 De hecho, LLM y el gráfico de conocimiento pueden promoverse y mejorarse mutuamente.

Si el LLM se mejora con un gráfico de conocimiento, el gráfico de conocimiento no solo se puede integrar en las etapas previas al entrenamiento y al razonamiento del LLM para proporcionar conocimiento externo, sino que también se puede usar para analizar el LLM para brindar interpretabilidad mientras se usa el LLM para mejorar el
gráfico de conocimiento Por un lado, LLM se ha utilizado en una variedad de aplicaciones relacionadas con los gráficos de conocimiento, como la incrustación de gráficos de conocimiento, la finalización de gráficos de conocimiento, la construcción de gráficos de conocimiento, la generación de gráficos de conocimiento a texto y la respuesta a preguntas de gráficos de conocimiento. LLM puede mejorar el rendimiento del gráfico de conocimiento y ayudar a su aplicación.
En resumen, en la investigación relacionada de LLM y la colaboración del gráfico de conocimiento, los investigadores combinan las ventajas del LLM y el gráfico de conocimiento, de modo que sus habilidades en la representación del conocimiento y el razonamiento puedan promoverse entre sí. .

4.2 Uso de gráficos de conocimiento para mejorar la capacitación previa, el razonamiento y la interpretabilidad de LLM
En junio de este año, un documento "Unificación de modelos de lenguaje grande y gráficos de conocimiento: una hoja de ruta" señaló que hay varias formas específicas de mejorar LLM con gráficos de conocimiento 

Una es usar el gráfico de conocimiento para mejorar la capacitación previa de LLM, que tiene como objetivo inyectar conocimiento en LLM
durante la etapa de capacitación previa. generación de oraciones
Interpretabilidad de LLM, para que podamos comprender mejor el comportamiento de LLM
La siguiente tabla resume los métodos típicos para mejorar LLM con gráficos de conocimiento

4.2.1 Mejorar la formación previa de LLM con el gráfico de conocimiento


Los LLM existentes se basan principalmente en la realización de capacitación autosupervisada en corpus a gran escala. Aunque estos modelos sobresalen en tareas posteriores, carecen de conocimientos prácticos relevantes para el mundo real. En términos de integrar el gráfico de conocimiento en LLM, la investigación previa se puede dividir en tres categorías:

Integre el mapa de conocimiento en el objetivo de entrenamiento
Como se muestra en la figura a continuación, la información del mapa de conocimiento se inyecta en el objetivo de entrenamiento de LLM a través de la pérdida de alineación de conocimiento de texto, donde h representa la representación oculta generada por LLM


Integre el mapa de conocimiento en la entrada de LLM
Como se muestra en la figura a continuación, use la estructura del gráfico para inyectar información del mapa de conocimiento en la entrada de LLM


Integre el mapa de conocimiento en el módulo de fusión adicional
Como se muestra en la figura a continuación, el mapa de conocimiento se integra en el LLM a través del módulo de fusión adicional


4.2.2 Mejorar el razonamiento LLM con Knowledge Graph


El método anterior puede fusionar efectivamente el conocimiento con la representación textual en LLM. Sin embargo, el conocimiento del mundo real cambia, y una limitación de estos métodos es que no permiten actualizar el conocimiento integrado a menos que se vuelva a entrenar el modelo. Por lo tanto, durante el razonamiento, es posible que no puedan generalizar bien para el conocimiento no visto (por ejemplo, los datos previos al entrenamiento de ChatGPT finalizarán en septiembre de 2021. Para resolver este problema de actualización del conocimiento, ha utilizado un complemento externo búsqueda de bing para resolver)

Por lo tanto, se dedica una investigación considerable a mantener separados el espacio de conocimiento y el espacio de texto e inyectar conocimiento en el momento del razonamiento. Estos métodos se centran principalmente en tareas de control de calidad de respuesta a preguntas, porque la respuesta a preguntas requiere modelos para capturar tanto la semántica textual como el conocimiento del mundo real de última generación, como

Fusión de gráficos de conocimiento dinámicos para el razonamiento LLM
Específicamente, un enfoque directo es aprovechar una arquitectura de torres gemelas, donde un módulo separado maneja la entrada de texto y el otro maneja la entrada del gráfico de conocimiento relacionado. Sin embargo, este método carece de la interacción entre el texto y el conocimiento,
por lo que KagNet propone codificar primero el KG de entrada y luego mejorar la representación del texto de entrada. Por el contrario, MHGRN usa la salida LLM final del texto de entrada para guiar la inferencia

Como otro ejemplo, JointLK luego propone un marco para la interacción detallada entre cualquier token en la entrada de texto y cualquier entidad KG a través de mecanismos de atención bidireccional de LM a KG y de KG a lm (JointLK luego propone un marco con interacción detallada entre cualquier token en las entradas de texto y cualquier entidad de KG a través del mecanismo de atención bidireccional de LM a KG y de KG a LM) Como se muestra en la siguiente figura
, las integrales de puntos por pares se calculan en todas las entradas de texto y entidades de KG, respectivamente Calcule las puntuaciones de atención bidireccional (las puntuaciones de producto de puntos por pares se calculan sobre todos los tokens textuales y KGentities, las puntuaciones de atención bidireccional se calculan por separado)


Mejore la generación de LLM recuperando conocimiento externo


 Ver más detalles en el curso práctico de langchain de nuestra empresa

4.2.3 Mejora de la interpretabilidad de LLM con Knowledge Graph
// Se actualizará..

4.3 Mejorar el mapa de conocimiento con LLM
// Pendiente de actualización..

4.4 Colaboración entre LLM y Knowledge Graph
// pendiente de actualización..

4.5 Proyecto de combate de LLM combinado con KG: extracción de conocimiento KnowLM
KnowLM es un proyecto de extracción de conocimiento combinado con capacidades LLM Basado en llama 13b, usa sus propios datos + datos públicos para preentrenar el modelo, y luego usa el corpus de instrucciones en el preentrenamiento modelo Lora ajuste fino, el efecto final que se puede lograr se muestra en la figura a continuación (fuente de la imagen) Cuando se enfrenta a la misma entrada de entrada, cuando se dan cuatro tareas de instrucción diferentes, KnowLM puede obtener la salida de salida correspondiente respectivamente.

La siguiente figura muestra todo el proceso de entrenamiento y construcción del conjunto de datos. Todo el proceso de formación se divide en dos etapas:

En la etapa de pre-entrenamiento completo, el propósito de esta etapa es mejorar la capacidad y la reserva de conocimiento chino del modelo.Utilizando la
etapa de ajuste fino de instrucciones de LoRA, esta etapa permite que el modelo comprenda las instrucciones humanas y genere el contenido apropiado.


4.5.1 Construcción del conjunto de datos previo al entrenamiento y proceso de entrenamiento


Con el fin de mejorar la capacidad del modelo para comprender el chino y al mismo tiempo conservar la capacidad de codificación original y la capacidad en inglés, no ampliaron el vocabulario, sino que recopilaron el corpus chino, el corpus inglés y el corpus de código. El corpus chino proviene de los conjuntos de datos en inglés de la Enciclopedia Baidu
  . , Wudao y Wikipedia en chino
  son muestras del corpus original en inglés de LLaMA. La diferencia es Wikidata. El último punto de tiempo de Wikidata en inglés en el documento original es agosto de 2022. Además rastrearon desde septiembre de 2022 hasta febrero de 2023, un total de seis Meses de datos
  y conjunto de datos de código, debido a que la calidad del código en el conjunto de datos de Pile no es alta, rastrearon los datos de código de Github y Leetcode, parte del cual se usó para entrenamiento previo, la otra parte se usó para instrucción fina- sintonización
. Para el conjunto de datos rastreado anteriormente, utilizaron un método heurístico para eliminar el contenido dañino en el conjunto de datos. Además, también eliminamos los datos repetidos. Código de procesamiento de datos detallado
y código de entrenamiento, completo El script de entrenamiento y las condiciones de entrenamiento detalladas pueden ser encontrado en ./preentrenamiento

Antes del entrenamiento, los datos deben segmentarse primero. La longitud máxima de una sola muestra que establecen es 1024, y la longitud de la mayoría de los documentos es mucho mayor que esta longitud, por lo que estos documentos deben dividirse. Un algoritmo voraz está diseñado para segmentar documentos. El objetivo de la voracidad es garantizar que cada muestra sea lo más larga posible al tiempo que garantiza que cada muestra sea una oración completa y que el número de segmentos segmentados sea el menor posible. Además, debido
a la diversidad de fuentes de datos, se diseña un conjunto completo de herramientas de preprocesamiento de datos, que pueden procesar cada fuente de datos y luego fusionarlos.Finalmente,
debido a la gran cantidad de datos, si los datos se cargan directamente en la memoria, causará presión excesiva sobre el hardware, por lo que recurrieron a DeepSpeed-Megatron y utilizaron el método mmap para procesar y cargar los datos, es decir, leer el índice en la memoria y buscar en el disco duro según el índice cuando fuera necesario.

Finalmente, el entrenamiento previo se realiza en 5500 000 muestras en chino, 1500 000 muestras en inglés y 900 000 muestras en código. Utilizaron el entrenador de transformadores con Deepspeed ZeRO3 (la velocidad medida de usar ZeRO2 en escenarios de varias máquinas y varias tarjetas es más lenta) y realizaron un entrenamiento de varias máquinas y varias tarjetas en 3 nodos (ocho tarjetas V100 de 32 GB en cada nodo). ). La siguiente tabla muestra la velocidad de entrenamiento:
valor del parámetro
tamaño de lote micro (tamaño de lote de una sola tarjeta) 20
acumulación de gradiente (acumulación de gradiente) 3
tamaño de lote global (un paso, tamaño de lote global) 20*3*24=1440
un paso Tiempo -consumiendo 260s
4.5.2 Ajuste fino de instrucciones construcción de conjuntos de datos y proceso de entrenamiento de ajuste fino de instrucciones
En el modelo estereotipado actual, además de agregar capacidades generales (como capacidad de razonamiento, capacidad de código, etc.), capacidades adicionales de extracción de información (incluyendo NER, RE, EE). Cabe señalar que, dado que muchos conjuntos de datos de fuente abierta, como el conjunto de datos de código de conjunto de datos CoT de alpaca, están en inglés, para obtener el conjunto de datos chino correspondiente, estos conjuntos de datos en inglés se traducen mediante GPT4.

Hay dos situaciones:
1. Traducir directamente las preguntas y respuestas al chino
2. Introducir preguntas en inglés en el modelo y dejar que el modelo genere respuestas en chino

Utilice el segundo caso para conjuntos de datos genéricos y el primero para otros conjuntos de datos, como el conjunto de datos de código del conjunto de datos CoT

Para el conjunto de datos de extracción de información (IE), la parte en inglés utiliza conjuntos de datos de IE de código abierto como CoNLL ACE CASIS para construir el conjunto de datos de instrucción en inglés correspondiente. La parte china no solo usa conjuntos de datos de código abierto como DuEE, PEOPLE DAILY, DuIE, etc., sino que también usa su propia KG2Instruction para construir el correspondiente conjunto de datos de instrucciones en chino. Específicamente, KG2Instruction (InstructIE) es una Wikipedia en chino y
un conjunto de datos de extracción de información obtenidos a través de la supervisión remota en Wikidata, que cubre una amplia gama de campos para satisfacer las necesidades reales de extracción

Además, construyeron manualmente un conjunto de datos general en chino y lo tradujeron al inglés utilizando la segunda estrategia. Finalmente, la distribución de nuestros conjuntos de datos es la siguiente:
tipo de conjunto de datos
COT (chino e inglés) 202 333
conjuntos de datos generales (chino e inglés) 105 216
conjuntos de datos de código (chino e inglés) 44 688 conjuntos de
datos de extracción de instrucciones en inglés 537 429
datos de extracción de instrucciones en chino establece 486.768
KG2Instruction y otros conjuntos de datos de ajuste fino de instrucciones


En la actualidad, la mayoría de los scripts de ajuste fino se basan en alpaca-lora, por lo que no entraré en detalles aquí, y las instrucciones detalladas para ajustar los parámetros de entrenamiento y los scripts de entrenamiento se pueden encontrar en ./finetune/lora
Apéndice

 https://github.com/zjunlp/KnowLM
https://github.com/kaixindelele/ChatSensitiveWords
utiliza la biblioteca de palabras confidenciales LLM+ para identificar automáticamente si hay palabras confidenciales involucradas
https://github.com/XLabCU/gpt3-relationship-extraction -to-kg
https://github.com/niris/KGExtract/blob/main/get_kg.py
https://github.com/semantic-systems/coypu-LlamaKGQA/blob/main/knowledge_graph_coypu.py
https:// github.com/xixi019/coypu-LlamaKGQA
https://github.com/jamesdouglaspearce/kg-llama-7b
https://github.com/zhuojianc/financial_chatglm_KG
Además, esto es: una lista de artículos sobre LLM y gráficos de conocimiento

La quinta parte es la combinación de LLM y base de datos: DB-GPT


https://github.com/csunny/DB-GPT

5.1 Arquitectura de DB-GPT: uso de tecnología LLM privatizada para definir la próxima generación de interacción con bases de datos


DB-GPT crea un entorno operativo de modelo grande basado en FastChat y proporciona vicuña como un modelo de lenguaje grande basado en él. Además, LangChain proporciona capacidades de preguntas y respuestas de la base de conocimiento de dominio privado , y tiene almacenamiento e indexación de vectorización de datos unificados: proporciona una forma unificada de almacenar e indexar varios tipos de datos, admite el modo de complemento y admite de forma nativa el complemento Auto-GPT , con las siguientes funciones o capacidades

Genere gráficos de análisis basados ​​en diálogos en lenguaje natural, genere SQL para
comunicarse con la información de metadatos de la base de datos, genere declaraciones SQL precisas
para comunicarse con los datos y vea directamente los resultados de la ejecución
Gestión de la base de conocimientos (actualmente admite txt, pdf, md, html, doc, y url)
De acuerdo con el diálogo de la base de conocimientos, como pdf, csv, txt, word, etc.
admite una variedad de modelos de lenguaje grandes, actualmente admite Vicuna (7b, 13b), ChatGLM-6b (int4, int8), guanaco (7b , 13b, 33b), Gorilla(7b,13b), llama-2(7b,13b,70b), baichuan(7b,13b)
toda la arquitectura DB-GPT, como se muestra en la siguiente figura (fuente)

5.2 Aplicación de DB-GPT 


A través del método de QLoRA (cuantificación de nivel de 4 bits + LoRA), use 3090 para construir una base de conocimiento personal basada en 33B LLM en DB-GPT

// Para actualizarse

Ver más en clase: Combate real entre LLM y langchain/mapa de conocimiento/base de datos en julio [resolución de problemas, la practicidad es el rey]

Referencias y lecturas recomendadas
Sitio web oficial de langchain: LangChain, https://python.langchain.com/, Lista de API: https://api.python.langchain.com/en/latest/api_reference.html
Sitio web chino de langchain (traducción no disponible todavía) Bueno)
Panorama de LangChain
Un artículo para comprender LangChain (ignore este título, porque leer este artículo por sí solo no es suficiente)
Cómo construir un Smart Chatbot en 10 minutos con LangChain
Varios tutoriales sobre FAISS: introducción de Faiss y registros de experiencia de la aplicación,
QLoRA: Cuantificación a nivel de 4 bits + método LoRA, utilice 3090 para crear una base de conocimiento personal basada en 33B LLM en DB-GPT, cree un
control de calidad mejorado basado en LangChain+LLM, use LangChain para crear una aplicación de modelo de lenguaje grande, ¿qué es LangChain? LangChain
chino Tutorial introductorio
Modelo de lenguaje grande Una revisión de la investigación colaborativa con gráficos de conocimiento: dos ventajas técnicas principales complementan
csunny/DB-GPT, https://db-gpt.readthedocs.io/en/latest/July
LLM y langchain/knowledge graphs/database combate real [resolución de problemas, la práctica es el rey]
Posdata
Este artículo ha pasado por tres etapas

Hay muchos componentes en langchain
. Si desea comprender a fondo, debe hacerlo paso a paso, incluyéndome
a mí. Cuando comencé a mirar esta biblioteca, estaba realmente mareado y no podía comenzar. Después de 10 días, puedo abrir directamente un archivo a la vez Mira... En
resumen, todo es un proceso Interpretación
del código fuente del proyecto langchain-ChatGLM
Para ser honesto, estaba bastante mareado al principio porque había muchos archivos de proyectos diferentes. Afortunadamente, tomó una semana ordenar
LLM y gráficos de conocimiento Combinación de base de datos
Crear, modificar, optimizar registros
7.5-7.9 días, escribir una parte todos los días
7.10, mejorar la introducción de la primera parte sobre qué es langchain
7.11, según la última actualización del proyecto langchain-ChatGLM, resolvió el contenido escrito
7.12 Finalizó la primera sección 3.8 y ajustó el orden de interpretación de cada carpeta de acuerdo con el proceso del proyecto
. Tomó casi una semana
y finalmente resolvió el "código general estructura de langchain-ChatGLM". Dividido en tres capas principales: capa básica, capa de capacidad, capa de aplicación
7.17, comience a escribir la cuarta parte, concéntrese en la sección 4.2: use el gráfico de conocimiento para mejorar la capacitación previa de LLM, el razonamiento, la interpretabilidad
7.26, continúe escribiendo la cuarta parte, comience a actualizar la quinta parte: la combinación de LLM y base de datos
 

Supongo que te gusta

Origin blog.csdn.net/sinat_37574187/article/details/132269760
Recomendado
Clasificación