LabelConcept#

LabelConcept is a classification concept type in ContextGem that categorizes documents or content using predefined labels, supporting both single-label and multi-label classification approaches.

🏷️ Overview#

LabelConcept is used when you need to classify content into predefined categories, including:

  • Document classification: contract types, document categories, legal classifications

  • Content categorization: topics, themes, subjects, areas of focus

  • Quality assessment: compliance levels, risk categories, priority levels

  • Multi-faceted tagging: multiple applicable labels for comprehensive classification

This concept type supports two classification modes:

  • Multi-class: Selects exactly one label from the predefined set (mutually exclusive labels) - used for classifying the content into a single type or category. The model is to select the closest label even if none fits perfectly: a decision model always does, while an LLM can still return no item, so check that extracted_items is not empty.

  • Multi-label: Selects zero, one, or multiple labels from the predefined set (non-exclusive labels) - used when multiple topics or attributes can apply simultaneously. Returns only applicable labels, or no labels if none apply (the extracted_items list is then empty).

Important

For multi-class classification: Since multi-class classification selects exactly one label, you should consider including a general “other” label (such as “N/A”, “misc”, “unspecified”, etc.) to handle cases where none of the specific labels apply, unless your labels are broad enough to cover all cases, or you know that the classified content always falls under one of the predefined labels without edge cases. This ensures appropriate classification even when the content doesn’t clearly fit into any of the predefined specific categories.

💻 Usage Example#

Here’s a basic example of how to use LabelConcept for document type classification:

# ContextGem: Contract Type Classification using LabelConcept

import os

from contextgem import Document, DocumentLLM, LabelConcept


# Create a Document object from legal document text
legal_doc_text = """
NON-DISCLOSURE AGREEMENT

This Non-Disclosure Agreement ("Agreement") is entered into as of January 15, 2025, by and between TechCorp Inc., a Delaware corporation ("Disclosing Party"), and DataSystems LLC, a California limited liability company ("Receiving Party").

WHEREAS, Disclosing Party possesses certain confidential information relating to its proprietary technology and business operations;

NOW, THEREFORE, in consideration of the mutual covenants contained herein, the parties agree as follows:

1. CONFIDENTIAL INFORMATION
The term "Confidential Information" shall mean any and all non-public information...

2. OBLIGATIONS OF RECEIVING PARTY
Receiving Party agrees to hold all Confidential Information in strict confidence...
"""

doc = Document(raw_text=legal_doc_text)

# Define a LabelConcept for contract type classification
contract_type_concept = LabelConcept(
    name="Contract Type",
    description="Classify the type of contract",
    labels=["NDA", "Consultancy Agreement", "Privacy Policy", "Other"],
    classification_type="multi_class",  # only one label can be selected (mutually exclusive labels)
    singular_occurrence=True,  # expect only one classification result
)

# Attach the concept to the document
doc.add_concepts([contract_type_concept])

# Configure DocumentLLM with your API parameters
llm = DocumentLLM(
    model="openai/gpt-6-luna",
    api_key=os.getenv("CONTEXTGEM_OPENAI_API_KEY"),
)

# Extract the concept from the document
contract_type_concept = llm.extract_concepts_from_document(doc)[0]

# Check if any labels were extracted
if contract_type_concept.extracted_items:
    # Get the classified document type
    classified_type = contract_type_concept.extracted_items[0].value
    print(f"Document classified as: {classified_type}")  # Output: ['NDA']
else:
    print("No applicable labels found for this document")

⚙️ Parameters#

When creating a LabelConcept, you can specify the following parameters:

Parameter

Type

Default Value

Description

name

str

(Required)

A unique name identifier for the concept

description

str

(Required)

A clear description of what the concept represents and how classification should be performed

labels

list[str]

(Required)

List of predefined labels for classification. Must contain at least 2 unique labels

classification_type

str

"multi_class"

Classification mode. Available values: "multi_class" (select exactly one label), "multi_label" (select zero, one, or several labels).

model_role

str | None

None

The role label of the model that extracts the concept when a model group is used: the concept is routed to the model in the group with the same role. With the default None, the concept is routed to the model without a role. Ignored when a single model is used, as it extracts every concept it is given. For more details, see 🏷️ Model Roles.

modality

str

"text"

The document content the concept is extracted from. Available values: "text", "image", "multimodal" (text and/or images, whichever the document has). "image" and "multimodal" are supported for document-level concepts only, and require an LLM that supports vision when the document has images. A concept with "image" cannot have add_references=True. A decision model extracts from text only, and rejects "image" and "multimodal" with ValueError before any request is sent (see ✅ Supported Aspects and Concepts). For more details, see 🖼️ Concept Modality.

add_justifications

bool

False

Whether to include justifications for extracted items. Justifications provide explanations of why specific labels were selected and the reasoning behind the classification decision. A decision model provides no justifications, and rejects True with ValueError before any request is sent (see ✅ Supported Aspects and Concepts).

justification_depth

str

"brief"

Justification detail level. Available values: "brief", "balanced", "comprehensive".

justification_max_sents

int

2

Maximum sentences in a justification.

add_references

bool

False

Whether to include source references for extracted items. References indicate the specific locations in the document that informed the classification decision. A decision model provides no references for concepts, and rejects True with ValueError before any request is sent (see ✅ Supported Aspects and Concepts).

reference_depth

str

"paragraphs"

Source reference granularity. Available values: "paragraphs", "sentences".

decision_threshold

float | None

None

Relevant when the concept is extracted by a decision model (DocumentDecisionModel): the lowest probability (above 0, up to 1) with which a label is selected. Can be set for classification_type="multi_label" only: with "multi_class", the most probable label is always selected, and setting the threshold raises a validation error. With the default None, the decision_threshold of the decision model applies. Ignored when the concept is extracted by an LLM. See 🎚️ Decision Threshold.

singular_occurrence

bool

False

Whether this concept has at most one extracted item. If True, at most one item is extracted, and none if there is nothing to extract: an LLM that returns more than one is asked again, as for any other invalid data. This is particularly useful for global document classifications where only one classification result is expected. With a decision model (DocumentDecisionModel), a concept gets at most one item with or without this parameter, unless the text is sent in parts, i.e. max_paragraphs_to_analyze_per_call is passed to the extraction method: a decision model then returns an item for each part, and rejects a concept with singular_occurrence=True with ValueError before any request is sent. See sending a long text in parts.

custom_data

dict

{}

Optional. Dictionary for storing any additional data that you want to associate with the concept. This data must be JSON-serializable. This data is not used for extraction but can be useful for custom processing or downstream tasks.

🚀 Advanced Usage#

🏷️ Multi-Class vs Multi-Label Classification#

Choose the classification type based on your use case:

  • Multi-class (classification_type="multi_class") is ideal for document types, priority levels, and status categories. Example: a document is classified as one of “NDA”, “Consultancy Agreement”, “Privacy Policy”, or “Other” if none of them applies.

  • Multi-label (classification_type="multi_label") is ideal for content topics, applicable regulations, and feature tags. Example: a document can cover several of the topics “Finance”, “Legal”, “Technology”, or none of them.

Here’s an example demonstrating multi-label classification for content topic identification:

# ContextGem: Multi-Label Classification with LabelConcept

import os

from contextgem import Document, DocumentLLM, LabelConcept


# Create a Document object with business document text covering multiple topics
business_doc_text = """
QUARTERLY BUSINESS REVIEW - Q4 2024

FINANCIAL PERFORMANCE
Revenue for Q4 2024 reached $2.8 million, exceeding our target by 12%. The finance team has prepared detailed budget projections for 2025, with anticipated growth of 18% across all divisions.

TECHNOLOGY INITIATIVES
Our development team has successfully implemented the new cloud infrastructure, reducing operational costs by 25%. The IT department is now focusing on cybersecurity enhancements and data analytics platform upgrades.

HUMAN RESOURCES UPDATE
We welcomed 15 new employees this quarter, bringing our total headcount to 145. The HR team has launched a comprehensive employee wellness program and updated our remote work policies.

LEGAL AND COMPLIANCE
All regulatory compliance requirements have been met for Q4. The legal department has reviewed and updated our data privacy policies in accordance with recent legislation changes.

MARKETING STRATEGY
The marketing team launched three successful campaigns this quarter, resulting in a 40% increase in lead generation. Our digital marketing efforts have expanded to include LinkedIn advertising and content marketing.
"""

doc = Document(raw_text=business_doc_text)

# Define a LabelConcept for topic classification allowing multiple topics
content_topics_concept = LabelConcept(
    name="Document Topics",
    description="Identify all relevant business topics covered in this document",
    labels=[
        "Finance",
        "Technology",
        "HR",
        "Legal",
        "Marketing",
        "Operations",
        "Sales",
        "Strategy",
    ],
    classification_type="multi_label",  # multiple labels can be selected (non-exclusive labels)
)


# Attach the concept to the document
doc.add_concepts([content_topics_concept])

# Configure DocumentLLM with your API parameters
llm = DocumentLLM(
    model="openai/gpt-6-luna",
    api_key=os.getenv("CONTEXTGEM_OPENAI_API_KEY"),
)

# Extract the concept from the document
content_topics_concept = llm.extract_concepts_from_document(doc)[0]

# Check if any labels were extracted
if content_topics_concept.extracted_items:
    # Get all identified topics
    identified_topics = content_topics_concept.extracted_items[0].value
    print(f"Document covers the following topics: {', '.join(identified_topics)}")
    # Expected output might include: Finance, Technology, HR, Legal, Marketing
else:
    print("No applicable topic labels found for this document")

🔍 References and Justifications for Classification#

You can configure a LabelConcept to include justifications and references to understand classification decisions. This is particularly valuable when dealing with complex documents that might contain elements of multiple document types:

# ContextGem: LabelConcept with References and Justifications

import os

from contextgem import Document, DocumentLLM, LabelConcept


# Create a Document with content that might be challenging to classify
mixed_content_text = """
QUARTERLY BUSINESS REVIEW AND POLICY UPDATES
GlobalTech Solutions Inc. - February 2025

EMPLOYMENT AGREEMENT AND CONFIDENTIALITY PROVISIONS

This Employment Agreement ("Agreement") is entered into between GlobalTech Solutions Inc. ("Company") and Sarah Johnson ("Employee") as of February 1, 2025.

EMPLOYMENT TERMS
Employee shall serve as Senior Software Engineer with responsibilities including software development, code review, and technical leadership. The position is full-time with an annual salary of $125,000.

CONFIDENTIALITY OBLIGATIONS
Employee acknowledges that during employment, they may have access to confidential information including proprietary algorithms, customer data, and business strategies. Employee agrees to maintain strict confidentiality of such information both during and after employment.

NON-COMPETE PROVISIONS
For a period of 12 months following termination, Employee agrees not to engage in any business activities that directly compete with Company's core services within the same geographic market.

INTELLECTUAL PROPERTY
All work products, inventions, and discoveries made during employment shall be the exclusive property of the Company.

ADDITIONAL INFORMATION:

FINANCIAL PERFORMANCE SUMMARY
Q4 2024 revenue exceeded projections by 12%, reaching $3.2M. Cost optimization initiatives reduced operational expenses by 8%. The board approved a $500K investment in new data analytics infrastructure for 2025.

PRODUCT LAUNCH TIMELINE
The AI-powered customer analytics platform will launch Q2 2025. Marketing budget allocated: $200K for digital campaigns. Expected customer acquisition target: 150 new enterprise clients in the first quarter post-launch.
"""

doc = Document(raw_text=mixed_content_text)

# Define a LabelConcept with justifications and references enabled
document_classification_concept = LabelConcept(
    name="Document Classification with Evidence",
    description="Classify this document type and provide reasoning for the classification",
    labels=[
        "Employment Contract",
        "NDA",
        "Consulting Agreement",
        "Service Agreement",
        "Partnership Agreement",
        "Other",
    ],
    classification_type="multi_class",  # a single label is always returned
    add_justifications=True,  # enable justifications to understand classification reasoning
    justification_depth="comprehensive",  # provide detailed reasoning
    justification_max_sents=5,  # allow up to 5 sentences for justification
    add_references=True,  # include references to source text
    reference_depth="paragraphs",  # reference specific paragraphs that informed classification
    singular_occurrence=True,  # expect only one classification result
)

# Attach the concept to the document
doc.add_concepts([document_classification_concept])

# Configure DocumentLLM with your API parameters
llm = DocumentLLM(
    model="openai/gpt-6-luna",
    api_key=os.getenv("CONTEXTGEM_OPENAI_API_KEY"),
)

# Extract the concept from the document
document_classification_concept = llm.extract_concepts_from_document(doc)[0]

# Display the classification results with evidence
if document_classification_concept.extracted_items:
    item = document_classification_concept.extracted_items[0]

    print("=== DOCUMENT CLASSIFICATION RESULTS ===")
    print(f"Classification: {item.value[0]}")
    print("\nJustification:")
    print(f"{item.justification}")

    print("\nEvidence from document:")
    for i, paragraph in enumerate(item.reference_paragraphs, 1):
        print(f"{i}. {paragraph.raw_text}")

else:
    print("No classification could be determined - none of the predefined labels apply")

# This example demonstrates how justifications help explain why the LLM
# chose a specific classification and how references show which parts
# of the document informed that decision

🎯 Document Aspect Analysis#

LabelConcept can be used to classify extracted Aspect instances, providing a powerful way to analyze and categorize specific information that has been extracted from documents. This approach allows you to first extract relevant content using aspects, then apply classification logic to those extracted items.

Here’s an example that demonstrates using LabelConcept to classify the financial risk level of extracted financial obligations from legal contracts:

# ContextGem: Aspect Analysis with LabelConcept

import os

from contextgem import Aspect, Document, DocumentLLM, LabelConcept


# Create a Document object from contract text
contract_text = """
SOFTWARE DEVELOPMENT AGREEMENT
...

SECTION 5. PAYMENT TERMS
Client shall pay Developer a total fee of $150,000 for the complete software development project, payable in three installments: $50,000 upon signing, $50,000 at milestone completion, and $50,000 upon final delivery.
...

SECTION 8. MAINTENANCE AND SUPPORT
Following project completion, Developer shall provide 12 months of maintenance and support services at a rate of $5,000 per month, totaling $60,000 annually.
...

SECTION 12. PENALTY CLAUSES
In the event of project delay beyond the agreed timeline, Developer shall pay liquidated damages of $2,000 per day of delay, with a maximum penalty cap of $50,000.
...

SECTION 15. INTELLECTUAL PROPERTY LICENSING
Client agrees to pay ongoing licensing fees of $10,000 annually for the use of Developer's proprietary frameworks and libraries integrated into the software solution.
...

SECTION 18. TERMINATION COSTS
Should Client terminate this agreement without cause, Client shall pay Developer 75% of all remaining unpaid fees, estimated at approximately $100,000 based on current project status.
...
"""

doc = Document(raw_text=contract_text)

# Define a LabelConcept to classify the financial risk level of the obligations
risk_classification_concept = LabelConcept(
    name="Client Financial Risk Level",
    description=(
        "Classify the financial risk level for the Client's financial obligations based on:\n"
        "- Amount size and impact on Client's cash flow\n"
        "- Payment timing and predictability for the Client\n"
        "- Penalty or liability exposure for the Client\n"
        "- Ongoing vs. one-time obligations for the Client"
    ),
    labels=["Low Risk", "Moderate Risk", "High Risk", "Critical Risk"],
    classification_type="multi_class",
    add_justifications=True,
    justification_depth="comprehensive",  # provide a comprehensive justification
    justification_max_sents=10,  # set an adequate justification length
    singular_occurrence=True,  # global risk level for the client's financial obligations
)

# Define Aspect containing the concept
financial_obligations_aspect = Aspect(
    name="Client Financial Obligations",
    description="Financial obligations that the Client must fulfill under the contract",
    concepts=[risk_classification_concept],
)

# Attach the aspect to the document
doc.add_aspects([financial_obligations_aspect])

# Configure DocumentLLM with your API parameters
llm = DocumentLLM(
    model="openai/gpt-6-luna",
    api_key=os.getenv("CONTEXTGEM_OPENAI_API_KEY"),
)

# Extract all data from the document
doc = llm.extract_all(doc)

# Get the extracted aspect and concept
financial_obligations_aspect = doc.get_aspect_by_name(
    "Client Financial Obligations"
)  # or `doc.aspects[0]`
risk_classification_concept = financial_obligations_aspect.get_concept_by_name(
    "Client Financial Risk Level"
)  # or `financial_obligations_aspect.concepts[0]`

# Display the extracted information

print("Extracted Client Financial Obligations:")
for extracted_item in financial_obligations_aspect.extracted_items:
    print(f"- {extracted_item.value}")

if risk_classification_concept.extracted_items:
    assert (
        len(risk_classification_concept.extracted_items) == 1
    )  # as we have set `singular_occurrence=True` on the concept
    risk_item = risk_classification_concept.extracted_items[0]
    print(f"\nClient Financial Risk Level: {risk_item.value[0]}")
    print(f"Justification: {risk_item.justification}")
else:
    print("\nRisk level could not be determined")

📊 Extracted Items#

When a LabelConcept is extracted, it is populated with a list of extracted items accessible through the .extracted_items property. Each item is an instance of the _LabelItem class with the following attributes:

Attribute

Type

Description

value

list[str]

List of selected labels (always a list for API consistency, even for multi-class with single selection)

justification

str

Explanation of why these labels were selected (only if add_justifications=True)

probabilities

dict[str, float]

Probability of each label of the concept, e.g. {"NDA": 0.95, "Other": 0.05} (only if the concept is extracted by a decision model, None otherwise; see 🎲 Probabilities of Extracted Items)

reference_paragraphs

list[Paragraph]

List of paragraph objects that informed the classification (only if add_references=True)

reference_sentences

list[Sentence]

List of sentence objects that informed the classification (only if add_references=True and reference_depth="sentences")

Note

To find the position of a reference paragraph or sentence in the document, e.g. to cite it or to retrieve its surrounding context, see 📍 Locating Paragraphs and Sentences.

💡 Best Practices#

Here are some best practices to optimize your use of LabelConcept:

  • Choose meaningful labels: Use clear, distinct labels that cover your classification needs without overlap.

  • Provide clear descriptions: Explain what each classification represents and when each label should be applied.

  • Consider label granularity: Balance between too few labels (insufficient precision) and too many labels (classification complexity).

  • Enable justifications: Use add_justifications=True to understand and validate classification decisions, especially for complex or ambiguous content.