Back to catalog
Prompt Chain OpenAI Cookbook 5.0 (1) 0
Add to Favorites

1. Executive Summary

---

1. Executive Summary


1.1. Purpose and Audience

This notebook provides a hands-on guide for building temporally-aware knowledge graphs and performing multi-hop retrieval directly over those graphs.

It's designed for engineers, architects, and analysts working on temporally-aware knowledge graphs. Whether you’re prototyping, deploying at scale, or exploring new ways to use structured data, you’ll find practical workflows, best practices, and decision frameworks to accelerate your work.

This cookbook presents two hands-on workflows you can use, extend, and deploy right away:

  1. Temporally-aware knowledge graph (KG) construction

    A key challenge in developing knowledge-driven AI systems is maintaining a database that stays current and relevant. While much attention is given to boosting retrieval accuracy with techniques like semantic similarity and re-ranking, this guide focuses on a fundamental—yet frequently overlooked—aspect: systematically updating and validating your knowledge base as new data arrives.

    No matter how advanced your retrieval algorithms are, their effectiveness is limited by the quality and freshness of your database. This cookbook demonstrates how to routinely validate and update knowledge graph entries as new data arrives, helping ensure that your knowledge base remains accurate and up to date.

  2. Multi-hop retrieval using knowledge graphs

    Learn how to combine OpenAI models (such as o3, o4-mini, GPT-4.1, and GPT-4.1-mini) with structured graph queries via tool calls, enabling the model to traverse your graph in multiple steps across entities and relationships.

    This method lets your system answer complex, multi-faceted questions that require reasoning over several linked facts, going well beyond what single-hop retrieval can accomplish.

Inside, you'll discover:

  • Practical decision frameworks for choosing models and prompting techniques at each stage
  • Plug-and-play code examples for easy integration into your ML and data pipelines
  • Links to in-depth resources on OpenAI tool use, fine-tuning, graph backend selection, and more
  • A clear path from prototype to production, with actionable best practices for scaling and reliability

Note: All benchmarks and recommendations are based on the best available models and practices as of June 2025. As the ecosystem evolves, periodically revisit your approach to stay current with new capabilities and improvements.

1.2. Key takeaways

Creating a Temporally-Aware Knowledge Graph with a Temporal Agent

  1. Why make your knowledge graph temporal?

    Traditional knowledge graphs treat facts as static, but real-world information evolves constantly. What was true last quarter may be outdated today, risking errors or misinformed decisions if the graph does not capture change over time. Temporal knowledge graphs allow you to precisely answer questions like “What was true on a given date?” or analyse how facts and relationships have shifted, ensuring decisions are always based on the most relevant context.

  2. What is a Temporal Agent?

    A Temporal Agent is a pipeline component that ingests raw data and produces time-stamped triplets for your knowledge graph. This enables precise time-based querying, timeline construction, trend analysis, and more.

  3. How does the pipeline work?

    The pipeline starts by semantically chunking your raw documents. These chunks are decomposed into statements ready for our Temporal Agent, which then creates time-aware triplets. An Invalidation Agent can then perform temporal validity checks, spotting and handling any statements that are invalidated by new statements that are incident on the graph.

Multi-Step Retrieval Over a Knowledge Graph

  1. Why use multi-step retrieval?

    Direct, single-hop queries frequently miss salient facts distributed across a graph's topology. Multi-step (multi-hop) retrieval enables iterative traversal, following relationships and aggregating evidence across several hops. This methodology surfaces complex dependencies and latent connections that would remain hidden with one-shot lookups, providing more comprehensive and nuanced answers to sophisticated queries.

  2. Planners

    Planners orchestrate the retrieval process. Task-orientated planners decompose queries into concrete, sequential subtasks. Hypothesis-orientated planners, by contrast, propose claims to confirm, refute, or evolve. Choosing the optimal strategy depends on where the problem lies on the spectrum from deterministic reporting (well-defined paths) to exploratory research (open-ended inference).

  3. Tool Design Paradigms

    Tool design spans a continuum: Fixed tools provide consistent, predictable outputs for specific queries (e.g., a service that always returns today’s weather for San Francisco). At the other end, Free-form tools offer broad flexibility, such as code execution or open-ended data retrieval. Semi-structured tools fall between these extremes, restricting certain actions while allowing tailored flexibility—specialized sub-agents are a typical example. Selecting the appropriate paradigm is a trade-off between control, adaptability, and complexity.

  4. Evaluating Retrieval Systems

    High-fidelity evaluation hinges on expert-curated "golden" answers, though these are costly and labor-intensive to produce. Automated judgments, such as those from LLMs or tool traces, can be quickly generated to supplement or pre-screen, but may lack the precision of human evaluation. As your system matures, transition towards leveraging real user feedback to measure and optimize retrieval quality in production.

    A proven workflow: Start with synthetic tests, benchmark on your curated human-annotated "golden" dataset, and iteratively refine using live user feedback and ratings.

Prototype to Production

  1. Keep the graph lean

    Established archival policies and assign numeric relevance scores to each edge (e.g., recency x trust x query-frequency). Automate the archival or sparsification of low-value nodes and edges, ensuring only the most critical and frequently accessed facts remain for rapid retrieval.

  2. Parallelize the ingestion pipeline

    Transition from a linear document → chunk → extraction → resolution pipeline to a staged, asynchronous architecture. Assign each processing phase its own queue and dedicated worker pool. Apply clustering or network-based batching for invalidation jobs to maximize efficiency. Batch external API requests (e.g., OpenAI) and database writes wherever possible. This design increases throughput, introduces backpressure for reliability, and allows you to scale each pipeline stage independently.

  3. Integrate Robust Production Safeguards

    Enforce rigorous output validation: standardise temporal fields (e.g., ISO-8601 date formatting), constrain entity types to your controlled vocabulary, and apply lightweight model-based sanity checks for output consistency. Employ structured logging with traceable identifiers and monitor real-time quality and performance metrics in real lime to proactively detect data drift, regressions, or pipeline anomalised before they impact downstream applications.

2. How to Use This Cookbook


This cookbook is designed for flexible engagement:

  1. Use it as a comprehensive technical guide—read from start to finish for a deep understanding of temporally-aware knowledge graph systems.
  2. Skim for advanced concepts, methodologies, and implementation patterns if you prefer a high-level overview.
  3. Jump into any of the three modular sections; each is self-contained and directly applicable to real-world scenarios.

Inside, you'll find:

  1. Creating a Temporally-Aware Knowledge Graph with a Temporal Agent

    Build a pipeline that extracts entities and relations from unstructured text, resolves temporal conflicts, and keeps your graph up-to-date as new information arrives.

  2. Multi-Step Retrieval Over a Knowledge Graph

    Use structured queries and language model reasoning to chain multiple hops across your graph and answer complex questions.

  3. Prototype to Production

    Move from experimentation to deployment. This section covers architectural tips, integration patterns, and considerations for scaling reliably.

2.1. Pre-requisites

Before diving into building temporal agents and knowledge graphs, let's set up your environment. Install all required dependencies with pip, and set your OpenAI API key as an environment variable. Python 3.12 or later is required.

3. Creating a Temporally-Aware Knowledge Graph with a Temporal Agent


Accurate data is the foundation of any good business decision.
OpenAI’s latest models like o3, o4-mini, and the GPT-4.1 family are enabling businesses to build state-of-the-art retrieval systems for their most important workflows. However, information evolves rapidly: facts ingested confidently yesterday may already be outdated today.

Benefits of Temporal Knowledge Base

Without the ability to track when each fact was valid, retrieval systems risk returning answers that are outdated, non-compliant, or misleading. The consequences of missing temporal context can be severe in any industry, as illustrated by the following examples.

Industry Example question Risk if database is not temporal
Financial Services "How has Moody’s long‑term rating for Bank YY evolved since Feb 2023?" Mispricing credit risk by mixing historical & current ratings
"Who was the CFO of Retailer ZZ when the FY‑22 guidance was issued?" Governance/insider‑trading analysis may blame the wrong executive
"Was Fund AA sanctioned under Article BB at the time it bought Stock CC in Jan 2024?" Compliance report could miss an infraction if rules changed later
Manufacturing / Automotive "Which ECU firmware was deployed in model Q3 cars shipped between 2022‑05 and 2023‑03?" Misdiagnosing field failures due to firmware drift
"Which robot‑controller software revision ran on Assembly Line 7 during Lot 8421?" Root‑cause analysis may blame the wrong software revision
"What torque specification applied to steering‑column bolts in builds produced in May 2024?" Safety recall may miss affected vehicles

While we've called out some specific examples here, this theme is true across many industries including pharmaceuticals, law, consumer goods, and more.

Looking beyond standard retrieval

A temporally-aware knowledge graph allows you to go beyond static fact lookup. It enables richer retrieval workflows such as factual Q&A grounded in time, timeline generation, change tracking, counterfactual analysis, and more. We dive into these in more detail in our retrieval section later in the cookbook.

Question types suitable for temporal knowledge bases

3.1. Introducing our Temporal Agent


A temporal agent is a specialized pipeline that converts raw, free-form statements into time-aware triplets ready for ingesting into a knowledge graph that can then be queried with the questions of the character “What was true at time T?”.

Triplets are the basic building blocks of knowledge graphs. It's a way to represent a single fact or piece of knowledge using three parts (hence, "triplet"):

  • Subject - the entity you are talking about
  • Predicate - the type of relationship or property
  • Object - the value or other entity that the subject is connected to

You can thinking of this like a sentence with a structure [Subject] - [Predicate] - [Object]. As a more clear example:

"London" - "isCapitalOf" - "United Kingdom"

The Temporal Agent implemented in this cookbook draws inspiration from Zep and Graphiti, while introducing tighter control over fact invalidation and a more nuanced approach to episodic typing.

3.1.1. Key enhancements introduced in this cookbook

  1. Temporal validity extraction

    Builds on Graphiti's prompt design to identify temporal spans and episodic context without requiring auxiliary reference statements.

  2. Fact invalidation logic

    Introduces bidirectionality checks and constrains comparisons by episodic type. This retains Zep's non-lossy approach while reducing unnecessary evaluations.

  3. Temporal & episodic typing

    Differentiates between Fact, Opinion, Prediction, as well as between temporal classes Static, Dynamic, Atemporal.

  4. Multi‑event extraction

    Handles compound sentences and nested date references in a single pass.

This process allows us to update our sources of truth efficiently and reliably:


Statement Invalidation in practice

Note: While the implementation in this cookbook is focused on a graph-based implementation, this approach is generalizable to other knowledge base structures e.g., pgvector-based systems.


3.1.2. The Temporal Agent Pipeline

The Temporal Agent processes incoming statements through a three-stage pipeline:

  1. Temporal Classification

    Labels each statement as Atemporal, Static, or Dynamic:

    • Atemporal statements never change (e.g., “The speed of light in a vaccuum is ≈3×10⁸ m s⁻¹”).
    • Static statements are valid from a point in time but do not change afterwards (e.g., "Person YY was CEO of Company XX on October 23rd 2014.").
    • Dynamic statements evolve (e.g., "Person YY is CEO of Company XX.").
  2. Temporal Event Extraction

    Identifies relative or partial dates (e.g., “Tuesday”, “three months ago”) and resolves them to an absolute date using the document timestamp or fallback heuristics (e.g., default to the 1st or last of the month if only the month is known).

  3. Temporal Validity Check

    Ensures every statement includes a t_created timestamp and, when applicable, a t_expired timestamp. The agent then compares the candidate triplet to existing knowledge graph entries to:

    • Detect contradictions and mark outdated entries with t_invalid
    • Link newer statements to those they invalidate with invalidated_by

Temporal Agent

3.1.3. Selecting the right model for a Temporal Agent

When building systems with LLMs, it is a good practice to start with larger models then later look to optimize and shrink.

The GPT-4.1 series is particularly well-suited for building Temporal Agents due to its strong instruction-following ability. On benchmarks like Scale’s MultiChallenge, GPT-4.1 outperforms GPT-4o by $10.5%_{abs}$, demonstrating superior ability to maintain context, reason in-conversation, and adhere to instructions - key traits for extracting time-stamped triplets. These capabilities make it an excellent choice for prototyping agents that rely on time-aware data extraction.

Recommended development workflow

  1. Prototype with GPT-4.1

    Maximize correctness and reduce prompt-debug time while you build out the core pipeline logic.

  2. Swap to GPT-4.1-mini or GPT-4.1-nano

    Once prompts and logic are stable, switch to smaller variants for lower latency and cost-effective inference.

  3. Distill onto GPT-4.1-mini or GPT-4.1-nano

    Use OpenAI's Model Distillation to train smaller models with high-quality outputs from a larger 'teacher' model such as GPT-4.1, preserving (or even improving) performance relative to GPT-4.1.

Model Relative cost Relative latency Intelligence Ideal Role in Workflow
GPT-4.1 ★★★ ★★ ★★★ (highest) Ground-truth prototyping, generating data for distillation
GPT-4.1-mini ★★ ★★ Balanced cost-performance, mid to large scale production systems
GPT-4.1-nano (lowest) (fastest) Cost-sensitive and ultra-large scale bulk processing

In practice, this looks like: prototype with GPT-4.1 → measure quality → step down the ladder until the trade-offs no longer meet your needs.

3.2. Building our Temporal Agent Pipeline


Before diving into the implementation details, it's useful to understand the ingestion pipeline at a high level:

  1. Load transcripts
  2. Creating a Semantic Chunker
  3. Laying the Foundations for our Temporal Agent
  4. Statement Extraction
  5. Temporal Range Extraction
  6. Creating our Triplets
  7. Temporal Events
  8. Defining our Temporal Agent
  9. Entity Resolution
  10. Invalidation Agent
  11. Building our pipeline

Architecture diagram

Temporal Agent Architecture

3.2.1. Load transcripts

For the purposes of this cookbook, we have selected the "Earnings Calls Dataset" (jlh-ibm/earnings_call) which is made available under the Creative Commons Zero v1.0 license. This dataset contains a collection of 188 earnings call transcripts originating in the period 2016-2020 in relation to the NASDAQ stock market. We believe this dataset is a good choice for this cookbook as extracting information from - and subsequently querying information from - earnings call transcripts is a common problem in many financial institutions around the world.

Moreover, the often variable character of statements and topics from the same company across multiple earnings calls provides a useful vector through which to demonstrate the temporal knowledge graph concept.

Despite this dataset's focus on the financial world, we build up the Temporal Agent in a general structure, so it will be quick to adapt to similar problems in other industries such as pharmaceuticals, law, automotive, and more.

For the purposes of this cookbook we are limiting the processing to two companies - AMD and Nvidia - though in practice this pipeline can easily be scaled to any company.

Let’s start by loading the dataset from HuggingFace.

Database Set-up

Before we get to processing this data, let’s set up our database.

For convenience within a notebook format, we've chosen SQLite as our database for this implementation. In the "Prototype to Production" section, and in Appendix section A.1 "Storing and Retrieving High-Volume Graph Data" we go into more detail of considerations around different dataset choices in a production environment.

If you are running this cookbook locally, you may chose to set memory = False to save the database to storage, the default file path my_database.db will be used to store your database or you may pass your own db_path arg into make_connection.

We will set up several tables to store the following information:

  • Transcripts
  • Chunks
  • Temporal Events
  • Triplets
  • Entities (including canonical mappings)

This code is abstracted behind a make_connection method which creates the new SQLite database. The details of this method can be found in the db_interface.py script in the GitHub repository for this cookbook.

3.2.2. Creating a Semantic Chunker

Before diving into buidling the Chunker class itself, we begin by defining our first data models. As is generally considered good practice when working with Python, Pydantic is used to ensure type safety and clarity in our model definitions. Pydantic provides a clean, declarative way to define data structures whilst automatically validating and parsing input data, making our data models both robust and easy to work with.

Chunk model

This is a core data model that we'll use to store individual segments of text extracted from transcripts, along with any associated metadata. As we process the transcripts by breaking them into semantically meaningful chunks, each piece will be saved as a separate Chunk.

Each Chunk contains:

  • id: A unique identifier automatically generated for each chunk. This helps us identify and track chunks of text throughout
  • text: A string field that contains the text content of the chunk
  • metadata: A dictionary to allow for flexible metadata storage

Transcript model

As the name suggests, we will use the Transcript model to represent the full content of an earnings call transcript. It captures several key pieces of information:

  • id: Analogous to Chunk, this gives us a unique identifier
  • text: The full text of the transcript
  • company: The name of the company that the earnings call was about
  • date: The date of the earnings call
  • quarter: The fiscal quarter that the earnings call was in
  • chunks: A list of Chunk objects, each representing a meaningful segment of the full transcript

To ensure the date field is handled correctly, the to_datetime validator is used to convert the value to datetime format.

Chunker class

Now, we define the Chunker class to split each transcript into semantically meaningful chunks. Instead of relying on arbitrary rules like character count or line break, we apply semantic chunking to preserve more of the contextual integrity of the original transcript. This ensures that each chunk is a self-contained unit that keeps contextually linked ideas together. This is particularly helpful for downstream tasks like statement extraction, where context heavily influences accuracy.

The chunker class contains two methods:

  • find_quarter

    This method attempts to extract the fiscal quarter (e.g., "Q1 2023") directly from the transcript text using a simple regular expression. In this case, this is straightforward as the data format of quarters in the transcripts is consistent and well defined.

    However, in real world scenarios, detecting the quarter reliably may require more work. Across multiple sources or document types the detailing of the quarter is likely to be different. LLMs are great tools to help alleviate this issue. Try using GPT-4.1-mini with a prompt specifically to extract the quarter given wider context from the document.

  • generate_transcripts_and_chunks

    This is the core method that takes in a dataset (as an iterable of dictionaries) and returns a list of Transcript objects each populated with semantically derived Chunks. It performs the following steps:

    1. Transcript creation: Initializes Transcript objects using the provided text, company, and date fields
    2. Filtering: Uses the SemanticChunker from chonkie along with OpenAI's text-embedding-3-small model to split the transcript into logical segments
    3. Chunk assignment: Wraps each semantic segment into a Chunk model, attaching relevant metadata like start and end indices

The chunker falls in to this part of our pipeline:

Temporal Agent Pipeline - Chunker

Alternatively, we can load just the AMD and NVDA pre-chunked transcripts from pre-processed files in transcripts/

Now we can inspect a couple of chunks:

With this, we have successfully split our transcripts into semantically sectioned chunks. We can now move onto the next steps in our pipeline.

3.2.3. Laying the Foundations for our Temporal Agent

Before we move onto defining the TemporalAgent class, we will first define the prompts and data models that are needed for it to function.

Formalizing our label definitions

For our temporal agent to be able to accurately extract the statement and temporal types we need to provide it with sufficiently detailed and specific context. For convenience, we define these within a structured format below.

Each label contains three crucial pieces of information that we will later pass to our LLMs in prompts.

  • definition

    Provides a concise description of what the label represents. It establishes the conceptual boundaries of the statement or temporal type and ensures consistency in interpretation across examples.

  • date_handling_guidance

    Explains how to interpret the temporal validity of a statement associated with the label. It describes how the valid_at and invalid_at dates should be derived when processing instances of that label.

  • date_handling_examples

    Includes illustrative examples of how real-world statements would be labelled and temporally annotated under this label. These will be used as few-shot examples to the LLMs downstream.

3.2.4. Statement Extraction

"Statement Extraction" refers to the process of splitting our semantic chunks into the smallest possible "atomic" facts. Within our Temporal Agent, this is achieved by:

  1. Finding every standalone, declarative claim

    Extract statements that can stand on their own as complete subject-predicate-object expressions without relying on surrounding context.

  2. Ensuring atomicity

    Break down complex or compound sentences into minimal, indivisible factual units, each expressing a single relationship.

  3. Resolving references

    Replace pronouns or abstract references (e.g., "he" or "The Company") with specific entities (e.g., "John Smith", "AMD") using the main subject for disambiguation.

  4. Preserving temporal and quantitative precision

    Retain explicit dates, durations, and quantities to anchor each fact precisely in time and scale.

  5. Labelling each extracted statement

    Every statement is annotated with a StatementType and a TemporalType.

Temporal Types

The TemporalType enum provides a standardized set of temporal categories that make it easier to classify and work with statements extracted from earnings call transcripts.

Each category captures a different kind of temporal reference:

  • Atemporal: Statements that are universally true and invariant over time (e.g., “The speed of light in a vacuum is ≈3×10⁸ m s⁻¹.”).
  • Static: Statements that became true at a specific point in time and remain unchanged thereafter (e.g., “Person YY was CEO of Company XX on October 23rd, 2014.”).
  • Dynamic: Statements that may change over time and require temporal context to interpret accurately (e.g., “Person YY is CEO of Company XX.”).

Statement Types

Similarly, the StatementType enum classifies the nature of each extracted statement, capturing its epistemic characteristics.

  • Fact: A statement that asserts a verifiable claim considered true at the time it was made. However, it may later be superseded or contradicted by other facts (e.g., updated information or corrections).
  • Opinion: A subjective statement reflecting a speaker’s belief, sentiment, or judgment. By nature, opinions are considered temporally true at the moment they are expressed.
  • Prediction: A forward-looking or hypothetical statement about a potential future event or outcome. Temporally, a prediction is assumed to hold true from the time of utterance until the conclusion of the inferred prediction window.

Raw Statement

The RawStatement model represents an individual statement extracted by an LLM, annotated with both its semantic type (StatementType) and temporal classification (TemporalType). These raw statements serve as intermediate representations and are intended to be transformed into TemporalEvent objects in later processing stages.

Core fields:

  • statement: The textual content of the extracted statement
  • statement_type: The type of statement (Fact, Opinion, Prediction), based on the StatementType enum
  • temporal_type: The temporal classification of the statement (Static, Dynamic, Atemporal), drawn from the TemporalType enum

The model includes field-level validators to ensure that all type annotations conform to their respective enums, providing a layer of robustness against invalid input.

The companion model RawStatementList contains the output of the statement extraction step: a list of RawStatement instances.

Statement Extraction Prompt

This is the core prompt that powers our Temporal Agent's ability to extract and label atomic statements. It is written in Jinja allowing us to modularly compose dynamic inputs without rewriting the core logic.

Anatomy of the prompt
  1. Set up the extraction task

    We instruct the assistant to behave like a domain expert in finance and clearly define the two subtasks: (i) extracting atomic, declarative statements, and (ii) labelling each with a statement_type and a temporal_type.

  2. Enforces strict extraction guidelines

    The rules for extraction help to enforce consistency and clarity. Statements must:

    • Be structured as clean subject-predicate-object triplets
    • Be self-contained and context-independent
    • Resolve co-references (e.g., "he" → "John Smith")
    • Include temporal/quantitative qualifiers where present
    • Be split when multiple events or temporalities are described
  3. Supports plug-and-play definitions

    The {% if definitions %} block makes it easy to inject structured definitions such as statement categories, temporal types, and domain-specific terms.

  4. Includes few-shot examples

    We provide an annotated example chunk and the corresponding JSON output to demonstrate to the model how it should behave.

3.2.5. Temporal Range Extraction

Raw temporal range

The RawTemporalRange model holds the raw extraction of valid_at and invalid_at date strings for a statement. These both use the date-time supported string property.

  • valid_at represents the start of the validity period for a statement
  • invalid_at represents the end of the validity period for a statement

Temporal validity range

While the RawTemporalRange model preserves the originally extracted date strings, the TemporalValidityRange model transforms these into standardized datetime objects for downstream processing.

It parses the raw valid_at and invalid_at values, converting them from strings into timezone-aware datetime instances. This is handled through a field-level validator.

Date extraction prompt

Let's now create the prompt that guides our Temporal Agent in accurately determining the temporal validity of statements.

Anatomy of the prompt

This prompt helps the Temporal Agent precisely understand and extract temporal validity ranges.

  1. Clearly Defines the Extraction Task

    The prompt instructs our model to determine when a statement became true (valid_at) and optionally when it stopped being true (invalid_at).

  2. Uses Contextual Guidance

    By dynamically incorporating {{ inputs.temporal_type }} and {{ inputs.statement_type }}, the prompt guides the model in interpreting temporal nuances based on the nature of each statement (like distinguishing facts from predictions or static from dynamic contexts).

  3. Ensures Consistency with Clear Formatting Rules

    To maintain clarity and consistency, the prompt requires all dates to be converted into standardized ISO 8601 date-time formats, normalized to UTC. It explicitly anchors relative expressions (like "last quarter") to known publication dates, making temporal information precise and reliable.

  4. Aligns with Business Reporting Cycles

    Recognizing the practical need for quarter-based reasoning common in business and financial contexts, the prompt can interpret and calculate temporal ranges based on business quarters, minimizing ambiguity.

  5. Adapts to Statement Types for Semantic Accuracy

    Specific rules ensure the semantic integrity of statements—for example, opinions might only have a start date (valid_at) reflecting the moment they were expressed, while predictions will clearly define their forecast window using an end date (invalid_at).

3.2.6. Creating our Triplets

We will now build up the definitions and prompts to create the our triplets. As discussed above, these are a combination of:

  • Subject - the entity you are talking about
  • Predicate - the type of relationship or property
  • Object - the value or other entity that the subject is connected to

Let's start with our predicate.

Predicate

The Predicate enum provides a standard set of predicates that clearly describe relationships extracted from text.

We've defined the set of predicates below to be appropriate for earnings call transcripts. Here are some examples for how each of these predicates could fit into a triplet in our knowledge graph:
Here are more anonymized, generalized examples following your template:

  • IS_A: [Company ABC]-[IS_A]-[Software Provider]
  • HAS_A: [Corporation XYZ]-[HAS_A]-[Innovation Division]
  • LOCATED_IN: [Factory 123]-[LOCATED_IN]-[Germany]
  • HOLDS_ROLE: [Jane Doe]-[HOLDS_ROLE]-[CEO at Company LMN]
  • PRODUCES: [Company DEF]-[PRODUCES]-[Smartphone Model X]
  • SELLS: [Retailer 789]-[SELLS]-[Furniture]
  • LAUNCHED: [Company UVW]-[LAUNCHED]-[New Subscription Service]
  • DEVELOPED: [Startup GHI]-[DEVELOPED]-[Cloud-Based Tool]
  • ADOPTED_BY: [New Technology]-[ADOPTED_BY]-[Industry ABC]
  • INVESTS_IN: [Investment Firm JKL]-[INVESTS_IN]-[Clean Energy Startups]
  • COLLABORATES_WITH: [Company PQR]-[COLLABORATES_WITH]-[University XYZ]
  • SUPPLIES: [Manufacturer STU]-[SUPPLIES]-[Auto Components to Company VWX]
  • HAS_REVENUE: [Corporation LMN]-[HAS_REVENUE]-[€500 Million]
  • INCREASED: [Company YZA]-[INCREASED]-[Market Share]
  • DECREASED: [Firm BCD]-[DECREASED]-[Operating Expenses]
  • RESULTED_IN: [Cost Reduction Initiative]-[RESULTED_IN]-[Improved Profit Margins]
  • TARGETS: [Product Launch Campaign]-[TARGETS]-[Millennial Consumers]
  • PART_OF: [Subsidiary EFG]-[PART_OF]-[Parent Corporation HIJ]
  • DISCONTINUED: [Company KLM]-[DISCONTINUED]-[Legacy Product Line]
  • SECURED: [Startup NOP]-[SECURED]-[Series B Funding]

We also assign a definition to each predicate, which we will then pass to the extraction prompt downstream.

Defining your own predicates

When working with different data sources, you'll want to define your own predicates that are specific to your use case.

To define your own predicates:

  1. First, run your pipeline with PREDICATE_DEFINITIONS = {} on a representative sample of your documents. This initial run will derive a noisy graph with many non-standardized and overlapping predicates
  2. Next, drop some of your intial results into ChatGPT or manually review them to merge similar predicate classes. This process helps to eliminate duplicates such as IS_CEO and IS_CEO_OF
  3. Finally, carefully review and refine this list of predicates to ensure clarity and precision. These finalized predicate definitions will then guide your extraction process and ensure a consistent extraction pipeline

Raw triplet

With predicates now well-defined, we can begin building up the data models for our triplets.

The RawTriplet model represents a basic subject-predicate-object relationship that is extracted directly from textual data. This serves as a precursor for the more detailed triplet representation in Triplet which we introduce later.

Core fields:

  • subject_name: The textual representation of the subject entity
  • subject_id: Numeric identifier for the subject entity
  • predicate: The relationship type, specified by the Predicate enum
  • object_name: The textual representation of the object entity
  • object_id: Numeric identifier for the object entity
  • value: Numeric value associated to relationship, may be None e.g. Company -> HAS_A -> Revenue with value='$100 mill'

Triplet

The Triplet model extends the RawTriplet by incorporating unique identifiers and optionally linking each triplet to a specific event. These identifiers help with integration into structured knowledge bases like our temporal knowledge graph.

RawEntity

The RawEntity model represents an Entity as extracted from the Statement. This serves as a precursor for the more detailed triplet representation in Entity which we introduce next.

Core fields:

  • entity_idx: An integer to differentiate extracted entites from the statement (links to RawTriplet)
  • name: The name of the entity extracted e.g. AMD
  • type: The type of entity extracted e.g. Company
  • description: The textual description of the entity e.g. Technology company know for manufacturing semiconductors

Entity

The Entity model extends the RawEntity by incorporating unique identifiers and optionally linking each entity to a specific event.
Additionally, it contains resolved_id which will be populated during entity resolution with the canonical entity's id to remove duplicate naming of entities in the database.
These updated identifiers help with integration and linking of entities to events and triplets .

Raw extraction

Both RawTriplet and RawEntity are extracted at the same time per Statement to reduce LLM calls and to allow easy referencing of Entities through Triplets.

Triplet Extraction Prompt

The prompt below guides our Temporal Agent to effectively extract triplets and entities from provided statements.

Anatomy of the prompt
  • Avoids temporal details

    The agent is specifically instructed to ignore temporal relationships, as these are captured separately within the TemporalValidityRange. Defined Predicates are deliberately designed to be time-neutral—for instance, HAS_A covers both present (HAS_A) and past (HAD_A) contexts.

  • Maintains structured outputs

    The prompt yields structured RawExtraction outputs, supported by detailed examples that clearly illustrate:

    • How to extract information from a given Statement
    • How to link Entities with corresponding Triplets
    • How to handle extracted values
    • How to manage multiple Triplets involving the same Entity

3.2.7. Temporal Event

The TemporalEvent model brings together the Statement and all related information into one handy class. It's a primary output of the TemporalAgent and plays an important role within the InvalidationAgent.

Main fields include:

  • id: A unique identifier for the event
  • chunk_id: Points to the specific Chunk associated with the event
  • statement: The specific RawStatement extracted from the Chunk detailing a relationship or event
  • embedding: A representation of the statement used by the InvalidationAgent to gauge event similarity
  • triplets: Unique identifiers for the individual Triplets extracted from the Statement
  • valid_at: Timestamp indicating when the event becomes valid
  • invalid_at: Timestamp indicating when the event becomes invalid
  • temporal_type: Describes temporal characteristics from the RawStatement
  • statement_type: Categorizes the statement according to the original RawStatement
  • created_at: Date the event was first created.
  • expired_at: Date the event was marked invalid (set to created_at if invalid_at is already set when building the TemporalEvent)
  • invalidated_by: ID of the TemporalEvent responsible for invalidating this event, if applicable

3.2.8. Defining our Temporal Agent

Now we arrive at a central point in our pipeline: The TemporalAgent class. This brings together the steps we've built up above - chunking, data models, and prompts. Let's take a closer look at how this works.

The core function, extract_transcript_events, handles all key processes:

  1. It extracts a RawStatement from each Chunk.
  2. From each RawStatement, it identifies the TemporalValidityRange along with lists of related Triplet and Entity objects.
  3. Finally, it bundles all this information neatly into a TemporalEvent for each RawStatement.

Here's what you'll get:

  • transcript: The transcript currently being analyzed.
  • all_events: A comprehensive list of all generated TemporalEvent objects.
  • all_triplets: A complete collection of Triplet objects extracted across all events.
  • all_entities: A detailed list of all Entity objects pulled from the events, which will be further refined in subsequent steps.

The diagram below visualizes this portion of our pipeline:

[Content truncated due to size limits]

Comments (0)

Sign In Sign in to leave a comment.