LangExtract

repository·main·Indexed 12 days ago

https://github.com/google/langextract

A Python library (v1.6.0) for extracting structured data from unstructured text using LLMs. It features precise source grounding, parallel processing for long documents, interactive visualization of extracted entities, and a plugin system for custom provider integration via BaseLanguageModel and BaseSchema.

Tokens
38.2K
Snippets
97
Records
138
Agent score
96%

What's inside LangExtract

  1. How provider resolution works

    main

    LangExtract uses a router system to match model_id requests to specific providers.

    Resolution Methods

    1. Auto-detection: If a model_id is provided that matches a registered pattern (e.g., mymodel-3b matching r'^mymodel'), the router automatically selects that provider.
    2. Explicit Selection: Users can force a specific provider using its class name via lx.factory.ModelConfig:
      config = lx.factory.ModelConfig(provider="MyProviderLanguageModel")
      Partial matches on the class name (e.g., provider="myprovider") are also supported.
    3. Default Provider: If a provider is instantiated without a model_id, it uses the provider's internal default.

    Pattern Priority

    All registered patterns have an equal priority of 0 by default. You can increase priority using the priority argument in @router.register to ensure specific patterns are matched before more general ones.

  2. How sequential extraction passes improve recall

    main

    For large or complex documents, a single extraction pass might miss entities due to the stochastic nature of LLMs. LangExtract addresses this via extraction_passes.

    Mechanism:

    • The library performs multiple independent runs of the extraction task using the same prompt and parameters.
    • Each pass processes the text independently.
    • Results are merged using a "first-pass wins" strategy: if two passes identify overlapping text spans, the entity from the earlier pass is preserved. Unique, non-overlapping entities from subsequent passes are added to the final set.
    • This increases the probability of capturing all relevant entities without introducing duplicates or conflicting spans.
  3. How third-party plugin discovery works

    main

    Third-party providers are discovered automatically using Python entry points. This allows for zero configuration: once a provider package is installed, it is available to LangExtract immediately.

    Discovery Lifecycle:

    1. pip install langextract-yourprovider installs a package containing a provider class decorated with @router.register and a Python entry point.
    2. import langextract triggers lazy loading of plugins.
    3. Calling lx.extract(model_id="...") triggers the discovery. The @router.register decorator adds the provider's patterns to the router, allowing it to match the model_id.
  4. Extend LangExtract with custom model providers

    main

    LangExtract features a lightweight plugin system that allows you to add support for new LLM providers without modifying the core library. Custom providers can be distributed as separate Python packages and keep their dependencies isolated.

    To implement a provider, you can:

    • Register it using @router.register(...) from langextract.providers.
    • Publish an entry point for automatic discovery.
    • Provide a schema via get_schema_class() for structured output.
    • Integrate with the factory using create_model(...).

    For a complete implementation guide, refer to the Provider System Documentation or the Custom Provider Plugin Example.

  5. How the LangExtract Provider System works

    main

    LangExtract uses a router pattern with automatic discovery to support different LLM backends. The system consists of three main components:

    1. Router (router.py): Maps model_id patterns (using regex) to specific provider classes.
    2. Factory (../factory.py): Creates provider instances based on the provided model_id or explicit configuration.
    3. Providers: Classes that implement the BaseLanguageModel interface to handle actual API calls.

    Resolution Flow: When you call lx.extract(model_id="gemini-3.5-flash"), the factory asks the router to resolve the ID. The router performs a pattern match (e.g., ^gemini) to find the matching provider (e.g., GeminiLanguageModel), instantiates it, and executes the inference.

  6. Use strict mode for prompt validation

    main

    When prompt_validation_strict=True is used in conjunction with PromptValidationLevel.ERROR, the validator becomes more sensitive.

    • With strict mode: Non-exact matches (such as fuzzy alignment or matches allowed by accept_match_lesser) will trigger a validation failure.
    • Without strict mode: Only extractions that are completely unalignable will cause a failure in ERROR mode.

    Strict mode is recommended during the Development phase to force the creation of clean, verbatim examples.

  7. Implement custom schema support for structured output

    main

    Providers can implement a custom schema by inheriting from langextract.core.schema.BaseSchema. This allows the provider to translate extraction requirements into specific API parameters (like JSON schemas).

    The Schema Lifecycle:

    1. from_examples(cls, examples_data, attribute_suffix): Analyze provided examples to build a schema dictionary.
    2. to_provider_config(self): Convert the internal schema into a dictionary of keyword arguments (kwargs) for the provider.
    3. requires_raw_output (property): Return True if the provider emits raw JSON/YAML without needing markdown fences.

    Integrating the Schema into the Provider: In your BaseLanguageModel implementation, use get_schema_class() to link the schema, and ensure __init__ can receive schema configuration from kwargs when use_schema_constraints=True is used.

    from langextract.core import schema as core_schema
    
    class CustomProviderSchema(core_schema.BaseSchema):
        @classmethod
        def from_examples(cls, examples_data, attribute_suffix="_attributes"):
            # Analyze examples to find patterns
            # Build schema based on extraction classes and attributes seen
            return cls(schema_dict)
    
        def to_provider_config(self):
            # Convert schema to provider kwargs
            return {
                "response_schema": self._schema_dict,
                "enable_structured_output": True
            }
    
        @property
        def requires_raw_output(self):
            # True = provider emits raw JSON, no markdown fences needed
            return True
  8. Use OpenAI models with LangExtract

    main

    To use OpenAI models, install the optional dependency: pip install langextract[openai]. LangExtract automatically detects the provider based on the model_id (e.g., gpt-4o).

    Batch API for large workloads

    For non-latency-sensitive workloads, you can enable the OpenAI Batch API via language_model_params. This is opt-in and falls back to real-time calls if the prompt count is below the specified threshold.

    Custom/OpenAI-compatible endpoints

    If you are using an OpenAI-compatible endpoint or a non-GPT model ID that skips auto-routing, use ModelConfig to explicitly define the provider and its configuration.

    import langextract as lx
    
    # Standard OpenAI usage
    result = lx.extract(
        text_or_documents=input_text,
        prompt_description=prompt,
        examples=examples,
        model_id="gpt-4o",
    )
    
    # Using OpenAI Batch API
    result = lx.extract(
        text_or_documents=documents,
        prompt_description=prompt,
        examples=examples,
        model_id="gpt-4o-mini",
        language_model_params={
            "batch": {
                "enabled": True,
                "threshold": 50,
                "poll_interval": 10,
            }
        },
    )
    
    # Using custom OpenAI-compatible endpoints
    from langextract.factory import ModelConfig
    
    result = lx.extract(
        text_or_documents=input_text,
        prompt_description=prompt,
        examples=examples,
        config=ModelConfig(
            model_id="my-openai-compatible-model",
            provider="openai",
            provider_kwargs={"api_key": "sk-...", "base_url": "https://..."},
        ),
    )
  9. How to add a new provider plugin to the registry

    main

    To contribute a new plugin to the LangExtract registry, follow these steps:

    1. Prepare your PyPI package: Ensure the name starts with langextract- (e.g., langextract-provider-<name>) and is published.
    2. Create a tracking issue: Open a tracking issue in the main LangExtract repository for integration and feedback.
    3. Format the registry entry: Use the following template to add your row to COMMUNITY_PROVIDERS.md. Ensure entries are sorted alphabetically by Plugin Name and inserted above the marker line.

    PR Checklist:

    • PyPI package name starts with langextract- (recommended: langextract-provider-<name>)
    • PyPI package is published (or will be soon) and listed in backticks
    • Maintainer(s) listed as GitHub profile links (comma-separated if multiple)
    • Repository link points to public GitHub repo
    • Description clearly explains what your provider does
    • Issue Link points to a tracking issue in the LangExtract repository
    • Entries are sorted alphabetically by Plugin Name
    | Your Plugin | `langextract-provider-yourname` | [@yourhandle](https://github.com/yourhandle) | [yourorg/yourrepo](https://github.com/yourorg/yourrepo) | Brief description (min 10 chars) | [#456](https://github.com/google/langextract/issues/456) |
  10. Activate the langextract-usage Agent Skill

    main

    The langextract-usage directory is an Agent Skill designed to teach AI coding assistants how to use LangExtract correctly. To use this skill, you must copy or symlink the directory into a path recognized by your Agent-Skills-compatible tool.

    Installation Methods

    Static Install (Copy): Use this if you want a standalone copy that does not change when the repository is updated.

    cp -R skills/langextract-usage <tool-skill-path>

    Dynamic Install (Symlink): Use this to track updates made to this repository.

    ln -s "$(pwd)/skills/langextract-usage" <tool-skill-path>

    Tool-Specific Paths

    Depending on your tool, use the following canonical paths (examples provided for project-scope and user-scope):

    ToolProject-scope pathUser-scope path
    Google Antigravity.agents/skills/langextract-usage/~/.gemini/antigravity/skills/langextract-usage/
    Anthropic Claude Code.claude/skills/langextract-usage/~/.claude/skills/langextract-usage/
    OpenAI Codex.agents/skills/langextract-usage/~/.agents/skills/langextract-usage/
    GitHub Copilot.github/skills/langextract-usage/~/.copilot/skills/langextract-usage/

    Note for Copilot users: Copilot also accepts .claude/skills/ or .agents/skills/ at the project scope, and ~/.claude/skills/ or ~/.agents/skills/ at the user scope.

    Note for Codex users: Codex scans .agents/skills/ from the current directory up through the repo root.

    After activation, restart your agent session if the tool does not automatically detect the new skill.