iText2KG

repository·main·Indexed 21 days ago

https://github.com/auvalab/itext2kg

A Python framework for incrementally constructing consistent and Dynamic Temporal Knowledge Graphs (DTKGs) from unstructured text using LLMs. It features ATOM, a scalable approach using atomic fact decomposition, dual-time modeling (distinguishing observation time from validity periods), and a parallelized merging pipeline. The library integrates with LangChain-supported chat and embedding models and provides Neo4jStorage for graph visualization.

Tokens
5.9K
Snippets
13
Records
21
Agent score
76%

What's inside itext2kg

  1. Overview of iText2KG architecture

    main

    iText2KG is a Python package for incrementally constructing consistent knowledge graphs (KGs) from unstructured text using LLMs. It uses a zero-shot approach to extract entities and relations, resolves ambiguities, and integrates the results into Neo4j for visualization.

    The architecture consists of four core modules:

    1. Document Distiller: Reformulates raw documents into semantic blocks based on a user-defined schema to improve the signal-to-noise ratio.
    2. Incremental Entity Extractor: Extracts unique entities from semantic blocks and resolves ambiguities using cosine similarity to match local entities with global entities.
    3. Incremental Relation Extractor: Identifies relationships between entities. It supports two modes: using global entities to enrich the graph or using local entities for higher precision.
    4. Graph Integrator and Visualization: Integrates extracted data into a Neo4j database for interactive exploration.
  2. What is ATOM and how does it work?

    main

    ATOM (AdapTive and OptiMized Dynamic Temporal Knowledge Graph Construction Using LLMs) is a scalable approach for building and continuously updating Dynamic Temporal Knowledge Graphs (DTKGs) from unstructured text.

    Unlike static KG construction, ATOM uses a three-module parallel pipeline to handle the dynamic and time-sensitive nature of data:

    1. Module-1 (Atomic Fact Decomposition): Splits input documents into minimal, self-contained "atomic facts" (ideally <400 tokens) to ensure LLMs don't omit facts in long contexts.
    2. Module-2 (Atomic TKGs Construction): Extracts 5-tuples (subject, predicate, object, t_start, t_end) in parallel from atomic facts. It uses dual-time modeling to distinguish between when a fact was observed (t_obs) and its validity period (t_start/t_end).
    3. Module-3 (Parallel Atomic Merge): Uses a binary merge algorithm to iteratively merge atomic TKGs in parallel. It resolves entities (using cosine similarity with threshold $\theta_E = 0.8$), relations (threshold $\theta_R = 0.7$), and temporal validity periods.

    The final result is a DTKG that evolves as new information is observed.

  3. ATOM Architecture and Parallelism

    main

    ATOM is designed for high scalability and low latency by replacing serial bottlenecks with a parallel architecture. Key performance features include:

    • Parallel 5-Tuple Extraction: Extracts all components of a quintuple in one step, reducing LLM calls compared to methods that separate entity and relation extraction.
    • LLM-Independent Merging: Uses distance metrics (cosine similarity) for entity and relation resolution instead of slow LLM-based resolution.
    • Parallel Atomic Merge: Employs an iterative pairwise merge algorithm that can run across multiple threads (e.g., 8 threads with a batch size of 40).
    • Early Temporal Resolution: Handles temporal logic during the extraction phase (Module-2) rather than waiting for the merge phase.
  4. Configure LLM and Embedding models for ATOM

    main
    ATOM is compatible with any LangChain-supported chat model and embedding model. When initializing the Atom class, you must provide instances of both a chat model (for relationship extraction) and an embeddings model (for semantic similarity). Ensure you have installed the specific LangChain integration package for your chosen provider (e.g., langchain-openai).
  5. Define a custom Pydantic schema for extraction

    main

    You can define custom extraction targets by creating a class that inherits from pydantic.BaseModel. Use Field(description=...) to provide instructions to the LLM about what each field represents. This allows the DocumentDistiller to map text to your specific data requirements.

    from typing import List
    from pydantic import BaseModel, Field
    
    class Author(BaseModel):
        name: str = Field(description="The name of the author")
        affiliation: str = Field(description="The affiliation of the author")
    
    class Article(BaseModel):
        title: str = Field(description="The title of the scientific article")
        authors: List[Author] = Field(description="The list of the article's authors and their affiliation")
        abstract: str = Field(description="The article's abstract")
  6. How ATOM handles temporal modeling and dual-time logic

    main

    ATOM uses dual-time modeling to prevent temporal misattribution. It distinguishes between:

    • t_obs: The date/time the information was actually observed (e.g., the publication date of a news article).
    • t_start / t_end: The actual validity period of the fact being described.

    Example Workflow:

    1. Observation 1: "Steve Jobs was the CEO of Apple Inc. on January 9, 2007" $\rightarrow$ (Steve Jobs, is_ceo, Apple Inc., [09-01-2007], [.]).
    2. Observation 2: "Steve Jobs is no longer the CEO of Apple Inc. on 05-10-2011".
    3. Transformation: Module-2 transforms the "no longer" fact into an affirmative end-validity fact: (Steve Jobs, is_ceo, Apple Inc., [.], [05-10-2011]).
    4. Resolution: Module-3 merges these into a single 5-tuple: (Steve Jobs, is_ceo, Apple Inc., [09-01-2007], [05-10-2011]).

    This prevents the error of assuming an event happened exactly at the time the text was written, which is a common issue in other frameworks like Graphiti.

  7. How to build a Dynamic Knowledge Graph

    main

    To build a Knowledge Graph that evolves over time, process time-series data (like news or social media posts) incrementally.

    The Workflow:

    1. Initialize DocumentDistiller and iText2KG_Star.
    2. For the first document, extract facts and build the initial KnowledgeGraph using build_graph.
    3. For every subsequent document:
      • Extract facts using DocumentDistiller.
      • Call iText2KG_Star.build_graph again, but this time pass the existing_knowledge_graph (using kg.model_copy()) and the new observation_date.
    4. The resulting graph will contain relationships with observation_dates tracking when they were first seen.
    # Incremental update loop snippet
    for i in range(1, len(time_series_data)):
        facts = await document_distiller.distill(
            documents=[time_series_data[i]['content']], 
            IE_query=IE_query, 
            output_data_structure=Facts
        )
        
        # Update the existing KG with new information
        kg = await itext2kg_star.build_graph(
            sections=facts.facts,
            observation_date=time_series_data[i]['observation_date'],
            existing_knowledge_graph=kg.model_copy(),
            ent_threshold=0.8,
            rel_threshold=0.7
        )
  8. Initialize LLM and Embedding models

    main

    iText2KG is compatible with any language models supported by LangChain. To use the library, you must provide both a chat model (for reasoning/extraction) and an embeddings model (for vector representations).

    Ensure you have installed the specific LangChain integration package for your chosen provider (e.g., langchain-openai or langchain-mistralai) before initializing.

    # Example using OpenAI
    from langchain_openai import ChatOpenAI, OpenAIEmbeddings
    
    openai_llm_model = ChatOpenAI(
        api_key="YOUR_API_KEY",
        model="gpt-4o",
        temperature=0,
    )
    
    openai_embeddings_model = OpenAIEmbeddings(
        api_key="YOUR_API_KEY",
        model="text-embedding-3-large",
    )
  9. Example: Building a TKG from text facts

    main

    This example demonstrates the full workflow: initializing LangChain models, preparing a dictionary of facts mapped to timestamps, building the TKG using build_graph_from_different_obs_times, and visualizing the result in Neo4j.

    ⚠️ Performance Note: Avoid running ATOM in Jupyter notebooks. Use dedicated Python scripts to prevent significant slowdowns caused by event loop conflicts and thread contention in notebook environments.

    import pandas as pd
    import asyncio
    import ast
    from langchain_openai import ChatOpenAI, OpenAIEmbeddings
    from itext2kg.atom import Atom
    from itext2kg import Neo4jStorage
    
    # 1. Setup Models
    openai_api_key = "#"
    openai_llm_model = ChatOpenAI(
        api_key=openai_api_key,
        model="gpt-4.1-2025-04-14",
        temperature=0,
    )
    
    openai_embeddings_model = OpenAIEmbeddings(
        api_key=openai_api_key,
        model="text-embedding-3-large",
    )
    
    # 2. Prepare Data
    news_covid = pd.read_pickle("../datasets/atom/nyt_news/2020_nyt_COVID_last_version_ready.pkl")
    
    def to_dictionary(df:pd.DataFrame, max_elements: int | None = 20): 
        if isinstance(df['factoids_g_truth'][0], str):
            df["factoids_g_truth"] = df["factoids_g_truth"].apply(lambda x:ast.literal_eval(x))
        grouped_df = df.groupby("date")["factoids_g_truth"].sum().reset_index()[:max_elements]
        return {
            str(date): factoids for date, factoids in grouped_df.set_index("date")["factoids_g_truth"].to_dict().items()
            }
    
    news_covid_dict = to_dictionary(news_covid)
    
    # 3. Run ATOM
    atom = Atom(llm_model=openai_llm_model, embeddings_model=openai_embeddings_model)
    
    # Note: build_graph_from_different_obs_times is an async function
    kg = await atom.build_graph_from_different_obs_times(
        atomic_facts_with_obs_timestamps=news_covid_dict,
    )
    
    # 4. Visualize
    URI = "bolt://localhost:7687"
    USERNAME = "neo4j"
    PASSWORD = "##"
    Neo4jStorage(uri=URI, username=USERNAME, password=PASSWORD).visualize_graph(knowledge_graph=kg)
  10. Use build_graph_from_different_obs_times to create a Temporal Knowledge Graph

    main

    The build_graph_from_different_obs_times function is used to construct a dynamic Temporal Knowledge Graph (TKG) by processing facts across multiple observation points.

    Arguments:

    • atomic_facts_with_obs_timestamps (dict): A dictionary where keys are observation timestamps (str) and values are lists of atomic facts (List[str]) for that timestamp.
    • existing_knowledge_graph (KnowledgeGraph, optional): An existing graph to merge with.
    • ent_threshold (float, default=0.8): Similarity threshold for entity resolution.
    • rel_threshold (float, default=0.7): Similarity threshold for relationship resolution.
    • entity_name_weight (float, default=0.8): Weight for entity name in similarity calculations.
    • entity_label_weight (float, default=0.2): Weight for entity label in similarity calculations.
    • max_workers (int, default=8): Maximum number of parallel workers.