The LLM Graph Transformer operates in two distinct modes, every designed to generate graphs from paperwork utilizing an LLM in numerous situations.
- Software-Based mostly Mode (Default): When the LLM helps structured output or operate calling, this mode leverages the LLM’s built-in
with_structured_output
to make use of instruments. The software specification defines the output format, making certain that entities and relationships are extracted in a structured, predefined method. That is depicted on the left facet of the picture, the place code for the Node and Relationship lessons is proven. - Immediate-Based mostly Mode (Fallback): In conditions the place the LLM doesn’t assist instruments or operate calls, the LLM Graph Transformer falls again to a purely prompt-driven method. This mode makes use of few-shot prompting to outline the output format, guiding the LLM to extract entities and relationships in a text-based method. The outcomes are then parsed by way of a customized operate, which converts the LLM’s output right into a JSON format. This JSON is used to populate nodes and relationships, simply as within the tool-based mode, however right here the LLM is guided completely by prompting somewhat than structured instruments. That is proven on the proper facet of the picture, the place an instance immediate and ensuing JSON output are supplied.
These two modes make sure that the LLM Graph Transformer is adaptable to totally different LLMs, permitting it to construct graphs both straight utilizing instruments or by parsing output from a text-based immediate.
Be aware that you should use prompt-based extraction even with fashions that assist instruments/features by setting the attribute ignore_tools_usage=True
.
Software-based extraction
We initially selected a tool-based method for extraction because it minimized the necessity for intensive immediate engineering and customized parsing features. In LangChain, the with_structured_output
methodology means that you can extract info utilizing instruments or features, with output outlined both by way of a JSON construction or a Pydantic object. Personally, I discover Pydantic objects clearer, so we opted for that.
We begin by defining a Node
class.
class Node(BaseNode):
id: str = Area(..., description="Title or human-readable distinctive identifier")
label: str = Area(..., description=f"Out there choices are {enum_values}")
properties: Non-compulsory[List[Property]]
Every node has an id
, a label
, and non-compulsory properties
. For brevity, I haven’t included full descriptions right here. Describing ids as human-readable distinctive identifier is necessary since some LLMs have a tendency to know ID properties in additional conventional approach like random strings or incremental integers. As a substitute we wish the title of entities for use as id property. We additionally restrict the out there label varieties by merely itemizing them within the label
description. Moreover, LLMs like OpenAI’s, assist an enum
parameter, which we additionally use.
Subsequent, we check out the Relationship
class
class Relationship(BaseRelationship):
source_node_id: str
source_node_label: str = Area(..., description=f"Out there choices are {enum_values}")
target_node_id: str
target_node_label: str = Area(..., description=f"Out there choices are {enum_values}")
kind: str = Area(..., description=f"Out there choices are {enum_values}")
properties: Non-compulsory[List[Property]]
That is the second iteration of the Relationship
class. Initially, we used a nested Node
object for the supply and goal nodes, however we rapidly discovered that nested objects decreased the accuracy and high quality of the extraction course of. So, we determined to flatten the supply and goal nodes into separate fields—for instance, source_node_id
and source_node_label
, together with target_node_id
and target_node_label
. Moreover, we outline the allowed values within the descriptions for node labels and relationship varieties to make sure the LLMs adhere to the required graph schema.
The tool-based extraction method permits us to outline properties for each nodes and relationships. Beneath is the category we used to outline them.
class Property(BaseModel):
"""A single property consisting of key and worth"""
key: str = Area(..., description=f"Out there choices are {enum_values}")
worth: str
Every Property
is outlined as a key-value pair. Whereas this method is versatile, it has its limitations. As an illustration, we won’t present a novel description for every property, nor can we specify sure properties as obligatory whereas others non-compulsory, so all properties are outlined as non-compulsory. Moreover, properties aren’t outlined individually for every node or relationship kind however are as a substitute shared throughout all of them.
We’ve additionally applied a detailed system immediate to assist information the extraction. In my expertise, although, the operate and argument descriptions are likely to have a better affect than the system message.
Sadly, in the meanwhile, there is no such thing as a easy technique to customise operate or argument descriptions in LLM Graph Transformer.
Immediate-based extraction
Since just a few industrial LLMs and LLaMA 3 assist native instruments, we applied a fallback for fashions with out software assist. It’s also possible to set ignore_tool_usage=True
to modify to a prompt-based method even when utilizing a mannequin that helps instruments.
A lot of the immediate engineering and examples for the prompt-based method had been contributed by Geraldus Wilsen.
With the prompt-based method, we’ve to outline the output construction straight within the immediate. Yow will discover the entire immediate right here. On this weblog publish, we’ll simply do a high-level overview. We begin by defining the system immediate.
You're a top-tier algorithm designed for extracting info in structured codecs to construct a information graph. Your process is to establish the entities and relations specified within the consumer immediate from a given textual content and produce the output in JSON format. This output must be an inventory of JSON objects, with every object containing the next keys:- **"head"**: The textual content of the extracted entity, which should match one of many varieties specified within the consumer immediate.
- **"head_type"**: The kind of the extracted head entity, chosen from the required checklist of varieties.
- **"relation"**: The kind of relation between the "head" and the "tail," chosen from the checklist of allowed relations.
- **"tail"**: The textual content of the entity representing the tail of the relation.
- **"tail_type"**: The kind of the tail entity, additionally chosen from the supplied checklist of varieties.
Extract as many entities and relationships as doable.
**Entity Consistency**: Guarantee consistency in entity illustration. If an entity, like "John Doe," seems a number of instances within the textual content beneath totally different names or pronouns (e.g., "Joe," "he"), use probably the most full identifier constantly. This consistency is important for making a coherent and simply comprehensible information graph.
**Essential Notes**:
- Don't add any further explanations or textual content.
Within the prompt-based method, a key distinction is that we ask the LLM to extract solely relationships, not particular person nodes. This implies we gained’t have any remoted nodes, not like with the tool-based method. Moreover, as a result of fashions missing native software assist sometimes carry out worse, we don’t enable extraction any properties — whether or not for nodes or relationships, to maintain the extraction output less complicated.
Subsequent, we add a few few-shot examples to the mannequin.
examples = [
{
"text": (
"Adam is a software engineer in Microsoft since 2009, "
"and last year he got an award as the Best Talent"
),
"head": "Adam",
"head_type": "Person",
"relation": "WORKS_FOR",
"tail": "Microsoft",
"tail_type": "Company",
},
{
"text": (
"Adam is a software engineer in Microsoft since 2009, "
"and last year he got an award as the Best Talent"
),
"head": "Adam",
"head_type": "Person",
"relation": "HAS_AWARD",
"tail": "Best Talent",
"tail_type": "Award",
},
...
]
On this method, there’s at the moment no assist for including customized few-shot examples or further directions. The one technique to customise is by modifying the whole immediate by way of the immediate
attribute. Increasing customization choices is one thing we’re actively contemplating.
Subsequent, we’ll check out defining the graph schema.
When utilizing the LLM Graph Transformer for info extraction, defining a graph schema is important for guiding the mannequin to construct significant and structured information representations. A well-defined graph schema specifies the sorts of nodes and relationships to be extracted, together with any attributes related to every. This schema serves as a blueprint, making certain that the LLM constantly extracts related info in a approach that aligns with the specified information graph construction.
On this weblog publish, we’ll use the opening paragraph of Marie Curie’s Wikipedia web page for testing with an added sentence on the finish about Robin Williams.
from langchain_core.paperwork import Doctextual content = """
Marie Curie, 7 November 1867 – 4 July 1934, was a Polish and naturalised-French physicist and chemist who performed pioneering analysis on radioactivity.
She was the primary girl to win a Nobel Prize, the primary individual to win a Nobel Prize twice, and the one individual to win a Nobel Prize in two scientific fields.
Her husband, Pierre Curie, was a co-winner of her first Nobel Prize, making them the first-ever married couple to win the Nobel Prize and launching the Curie household legacy of 5 Nobel Prizes.
She was, in 1906, the primary girl to turn out to be a professor on the College of Paris.
Additionally, Robin Williams.
"""
paperwork = [Document(page_content=text)]
We’ll even be utilizing GPT-4o in all examples.
from langchain_openai import ChatOpenAI
import getpass
import osos.environ["OPENAI_API_KEY"] = getpass.getpass("OpenAI api key")
llm = ChatOpenAI(mannequin='gpt-4o')
To begin, let’s study how the extraction course of works with out defining any graph schema.
from langchain_experimental.graph_transformers import LLMGraphTransformerno_schema = LLMGraphTransformer(llm=llm)
Now we will course of the paperwork utilizing the aconvert_to_graph_documents
operate, which is asynchronous. Utilizing async with LLM extraction is really helpful, because it permits for parallel processing of a number of paperwork. This method can considerably scale back wait instances and enhance throughput, particularly when coping with a number of paperwork.
information = await no_schema.aconvert_to_graph_documents(paperwork)
The response from the LLM Graph Transformer will probably be a graph doc, which has the next construction:
[
GraphDocument(
nodes=[
Node(id="Marie Curie", type="Person", properties={}),
Node(id="Pierre Curie", type="Person", properties={}),
Node(id="Nobel Prize", type="Award", properties={}),
Node(id="University Of Paris", type="Organization", properties={}),
Node(id="Robin Williams", type="Person", properties={}),
],
relationships=[
Relationship(
source=Node(id="Marie Curie", type="Person", properties={}),
target=Node(id="Nobel Prize", type="Award", properties={}),
type="WON",
properties={},
),
Relationship(
source=Node(id="Marie Curie", type="Person", properties={}),
target=Node(id="Nobel Prize", type="Award", properties={}),
type="WON",
properties={},
),
Relationship(
source=Node(id="Marie Curie", type="Person", properties={}),
target=Node(
id="University Of Paris", type="Organization", properties={}
),
type="PROFESSOR",
properties={},
),
Relationship(
source=Node(id="Pierre Curie", type="Person", properties={}),
target=Node(id="Nobel Prize", type="Award", properties={}),
type="WON",
properties={},
),
],
supply=Doc(
metadata={"id": "de3c93515e135ac0e47ca82a4f9b82d8"},
page_content="nMarie Curie, 7 November 1867 – 4 July 1934, was a Polish and naturalised-French physicist and chemist who performed pioneering analysis on radioactivity.nShe was the primary girl to win a Nobel Prize, the primary individual to win a Nobel Prize twice, and the one individual to win a Nobel Prize in two scientific fields.nHer husband, Pierre Curie, was a co-winner of her first Nobel Prize, making them the first-ever married couple to win the Nobel Prize and launching the Curie household legacy of 5 Nobel Prizes.nShe was, in 1906, the primary girl to turn out to be a professor on the College of Paris.nAlso, Robin Williams!n",
),
)
]
The graph doc describes extracted nodes
and relationships
. Moreover, the supply doc of the extraction is added beneath the supply
key.
We will use the Neo4j Browser to visualise the outputs, offering a clearer and extra intuitive understanding of the information.