{"owner":"google","repo":"langextract","hasSkills":true,"totalSkillsCount":5,"totalTokensCount":4674,"categories":["anthropic-skill"],"hasMcp":false,"mcpConfig":null,"found":["skills/langextract-usage/references/resolver-params.md","skills/langextract-usage/references/prompt-validation.md","skills/langextract-usage/README.md","skills/langextract-usage/references/providers.md","skills/langextract-usage/SKILL.md"],"skills":{"skills/langextract-usage/references/resolver-params.md":"# resolver_params Reference\n\n`resolver_params` is a dict passed to `lx.extract()` to fine-tune how the\nmodel's output is parsed and aligned to source text. Keys may change across\nversions — check the current `extract()` docstring if in doubt.\n\n## Full example\n\n```python\nresult = lx.extract(\n    text_or_documents=text,\n    examples=examples,\n    prompt_description=prompt,\n    model_id=\"gemini-2.5-flash\",\n    resolver_params={\n        \"suppress_parse_errors\": True,\n        \"extraction_index_suffix\": \"_index\",\n        \"enable_fuzzy_alignment\": True,\n        \"fuzzy_alignment_threshold\": 0.75,\n        \"fuzzy_alignment_algorithm\": \"lcs\",\n        \"fuzzy_alignment_min_density\": 1 / 3,\n        \"accept_match_lesser\": True,\n    },\n)\n```\n\n## Key descriptions\n\n- **`suppress_parse_errors`** (default True in `extract()`): on parse or\n  schema errors for a chunk, log a warning and return `[]` for that chunk\n  rather than raising. The chunk is effectively dropped; no partial output\n  is recovered from the malformed response.\n- **`extraction_index_suffix`**: attribute name suffix used to preserve\n  extraction ordering (e.g. `\"_index\"` looks for attributes like\n  `medication_index` and sorts extractions by that value).\n- **`enable_fuzzy_alignment`** (default True): attempt fuzzy alignment when\n  exact substring match fails.\n- **`fuzzy_alignment_threshold`** (default 0.75): minimum fraction of\n  extraction tokens that must be matched in the source span.\n- **`fuzzy_alignment_algorithm`** (default `\"lcs\"`): algorithm for fuzzy\n  alignment. `\"lcs\"` uses longest-common-subsequence DP (O(n*m²)); `\"legacy\"`\n  uses the older difflib-based approach and is deprecated.\n- **`fuzzy_alignment_min_density`** (default 1/3): minimum ratio of matched\n  tokens to the span length. Filters out sparse matches where only a few\n  tokens align across a very long source span.\n- **`accept_match_lesser`**: accept `MATCH_LESSER` alignments — partial\n  exact matches where the model's `extraction_text` is longer than the span\n  that exactly matched in the source (e.g. the model returned a few extra\n  tokens at the edges). This is distinct from fuzzy alignment: the matched\n  portion is still an exact substring. Use it for truncation or\n  extra-token cases, not as a substitute for lowering\n  `fuzzy_alignment_threshold`.\n\n## When to tune these\n\n- **Too many `char_interval=None` extractions**: lower\n  `fuzzy_alignment_threshold` (e.g. 0.6). Enable `accept_match_lesser`\n  only if the model is returning extraction_text that contains an exact\n  source substring plus extra tokens.\n- **Fuzzy alignment matching the wrong span**: raise\n  `fuzzy_alignment_min_density` (e.g. 0.5) so matches must be denser.\n- **Performance-sensitive pipelines on long documents**: stick with `\"lcs\"`\n  and consider lowering `max_char_buffer` rather than disabling fuzzy\n  alignment entirely.\n","skills/langextract-usage/references/prompt-validation.md":"# Prompt Validation Reference\n\nPrompt validation catches example problems (non-verbatim text, alignment\nmismatches) early, before expensive extraction runs.\n\n## Levels\n\n```python\nfrom langextract.prompt_validation import PromptValidationLevel\n\nresult = lx.extract(\n    text_or_documents=text,\n    examples=examples,\n    prompt_description=prompt,\n    model_id=\"gemini-2.5-flash\",\n    prompt_validation_level=PromptValidationLevel.ERROR,\n    prompt_validation_strict=True,\n)\n```\n\n- **`OFF`** — skip validation entirely.\n- **`WARNING`** (default) — log issues, continue running.\n- **`ERROR`** — raise on validation failure.\n\n## Strict mode\n\nWhen `prompt_validation_strict=True`, non-exact matches (fuzzy alignment,\n`accept_match_lesser`) also trigger failures in `ERROR` mode. Without strict\nmode, only completely unalignable extractions fail.\n\n## How it aligns with resolver_params\n\nPrompt validation uses the same alignment settings from `resolver_params`.\nSo if you've tuned `fuzzy_alignment_threshold` or\n`fuzzy_alignment_algorithm`, validation honors those same values when\ndeciding whether an example extraction is aligned.\n\n## When to use each level\n\n- **Development**: `ERROR` + `strict=True` forces you to write clean,\n  verbatim examples.\n- **Staging/CI**: `ERROR` (non-strict) catches truly broken examples\n  without failing on minor fuzzy matches.\n- **Production**: `WARNING` or `OFF` — you've already validated offline and\n  don't want runtime failures over example drift.\n\n## Common fixes\n\n- **\"Extraction text not found in example text\"**: your `extraction_text`\n  doesn't appear verbatim in the example `text`. Copy-paste the exact\n  substring rather than paraphrasing.\n- **\"Extraction text aligned fuzzily\"** (strict only): same issue but with\n  minor whitespace/punctuation differences. Fix the example to match\n  exactly.\n","skills/langextract-usage/README.md":"# langextract-usage — Agent Skill\n\nThis directory is an [Agent Skill](https://agentskills.io) source that teaches\nAI coding assistants how to use LangExtract correctly. It follows the open\nAgent Skills format (`SKILL.md` with YAML frontmatter, optional\n`references/`, `examples/`).\n\nThis directory is **not** auto-discovered by any tool from the `skills/`\npath it lives in here. To use it, copy or symlink the directory into\nwhichever path your Agent-Skills-compatible tool reads from.\n\n## Activate\n\nPick your tool, then install at either project scope (this repo only) or\nuser scope (all your projects). Paths below are **canonical examples** per\neach tool's 2026 docs — some tools (Copilot, Codex) scan several paths,\nso any of the documented locations works. Check the linked docs for the\nfull list if your tool has moved.\n\nProject-scope paths are relative to your workspace/repo root. Run the copy\nor symlink command from there.\n\n| Tool | Project-scope path (example) | User-scope path (example) |\n|---|---|---|\n| [Google Antigravity](https://antigravity.google/docs/skills) | `.agents/skills/langextract-usage/` | `~/.gemini/antigravity/skills/langextract-usage/` |\n| [Anthropic Claude Code](https://code.claude.com/docs/en/skills) | `.claude/skills/langextract-usage/` | `~/.claude/skills/langextract-usage/` |\n| [OpenAI Codex](https://developers.openai.com/codex/skills) | `.agents/skills/langextract-usage/` | `~/.agents/skills/langextract-usage/` |\n| [GitHub Copilot](https://docs.github.com/en/copilot) | `.github/skills/langextract-usage/` | `~/.copilot/skills/langextract-usage/` |\n\nNotes:\n- **Antigravity** also recognizes legacy `.agent/skills/` (singular) for\n  backward compatibility; new installs should use `.agents/skills/`\n  (plural).\n- **Copilot** also accepts `.claude/skills/` or `.agents/skills/` at project\n  scope, and `~/.claude/skills/` or `~/.agents/skills/` at user scope.\n- **Codex** scans `.agents/skills/` from the current directory up through\n  the repo root, so a project-scope install works from any subdirectory.\n- A project-scope `.agents/skills/langextract-usage/` therefore activates\n  the skill in Antigravity, Codex, and Copilot simultaneously.\n\n### Copy (static install)\n\n```bash\ncp -R skills/langextract-usage <tool-skill-path>\n```\n\n### Symlink (tracks this repo's updates)\n\n```bash\nln -s \"$(pwd)/skills/langextract-usage\" <tool-skill-path>\n```\n\n### Other tools\n\n- **Agent-Skills-compatible tools not listed above** — point the tool at\n  this directory as a skill source, following its own docs.\n- **Tools that read their own instruction format** (e.g. Cursor\n  `.cursor/rules/`, Windsurf `.windsurf/rules/`, Aider `CONVENTIONS.md`) —\n  copy the relevant sections of `SKILL.md` / `references/*.md` into that\n  tool's convention. The content is portable; only the activation\n  mechanism differs.\n\nAfter activating, restart your agent session if the tool does not\nauto-detect changes.\n\n## Contents\n\n- `SKILL.md` — entry point; install, basic usage, key parameters, working with\n  results, common issues\n- `references/providers.md` — Gemini, OpenAI, Ollama, `ModelConfig`, custom\n  provider plugins\n- `references/resolver-params.md` — fuzzy alignment tuning\n- `references/prompt-validation.md` — `PromptValidationLevel` details\n- `examples/` — runnable scripts (`basic_extraction.py`,\n  `relationship_extraction.py`, `multiple_documents.py`)\n\n## Maintenance\n\nWhen changing user-facing LangExtract APIs (imports, `lx.extract()` kwargs,\nresolver or validation behavior), please update the affected files in this\nsubtree in the same PR. If you spot drift, open an issue or PR.\n","skills/langextract-usage/references/providers.md":"# Provider Reference\n\nLangExtract ships with three built-in providers (Gemini, OpenAI, Ollama) and\nsupports custom providers via a plugin system.\n\n## Gemini (default, recommended)\n\n```python\nresult = lx.extract(\n    text_or_documents=text,\n    prompt_description=prompt,\n    examples=examples,\n    model_id=\"gemini-2.5-flash\",  # or \"gemini-2.5-pro\" for complex reasoning\n)\n```\n\nEnv: `GEMINI_API_KEY` (falls back to `LANGEXTRACT_API_KEY`).\n\n## OpenAI\n\n```python\nresult = lx.extract(\n    text_or_documents=text,\n    examples=examples,\n    prompt_description=prompt,\n    model_id=\"gpt-4o\",\n)\n```\n\nEnv: `OPENAI_API_KEY` (falls back to `LANGEXTRACT_API_KEY`).\n\nThe OpenAI provider uses JSON Schema constraints by default. For models\nwithout JSON Schema support, such as `gpt-3.5-turbo`, set\n`use_schema_constraints=False` to use JSON mode\n(`response_format={\"type\":\"json_object\"}`). Leave `fence_output` unset —\n`extract()` and the factory/provider layer auto-determine fence behavior\nfrom the provider's schema. The OpenAI provider parallelizes batched\nprompts with a `ThreadPoolExecutor` when `max_workers > 1`.\n\n**Auto-routing scope:** the built-in OpenAI provider matches GPT-3.5,\nGPT-4, GPT-5, and o-series model IDs (`^gpt-3\\.5`, `^gpt-4`, `^gpt4\\.`,\n`^gpt-5`, `^gpt5\\.`, `^o[1-9]`). Both GPT and o-series IDs use the\nenvironment API keys above. Routing does not guarantee that a model\nsupports every request option: o-series models currently require omitting\n`max_output_tokens`, which this provider maps to the unsupported\n`max_tokens` parameter.\n\nFor **OpenAI-compatible endpoints** (LiteLLM, local servers, custom base\nURLs) or model IDs outside these families, use `ModelConfig` with an\nexplicit provider and kwargs:\n\n```python\nfrom langextract.factory import ModelConfig\n\nresult = lx.extract(\n    text_or_documents=text,\n    examples=examples,\n    prompt_description=prompt,\n    config=ModelConfig(\n        model_id=\"my-openai-compatible-model\",\n        provider=\"openai\",\n        provider_kwargs={\"api_key\": \"sk-...\", \"base_url\": \"https://...\"},\n    ),\n)\n```\n\n## Ollama (local)\n\nNo API key needed. Requires a running Ollama server.\n\n```python\nresult = lx.extract(\n    text_or_documents=text,\n    examples=examples,\n    prompt_description=prompt,\n    model_id=\"gemma2:2b\",\n    model_url=\"http://localhost:11434\",\n)\n```\n\nThe Ollama provider exposes `FormatModeSchema` for JSON mode. Leave\n`fence_output` and `use_schema_constraints` unset so `extract()` and the\nfactory/provider layer auto-configure from the provider's schema. The\nOllama provider processes batched prompts sequentially — `max_workers > 1`\nwill not parallelize it.\n\n## ModelConfig (advanced)\n\nFor provider-specific kwargs (custom base_url, explicit api_key, etc.):\n\n```python\nfrom langextract.factory import ModelConfig\n\nresult = lx.extract(\n    text_or_documents=text,\n    examples=examples,\n    config=ModelConfig(\n        model_id=\"gpt-4o\",\n        provider_kwargs={\"api_key\": \"your_key\", \"base_url\": \"https://...\"},\n    ),\n)\n```\n\nModelConfig fields: `model_id`, `provider` (for disambiguation when multiple\nproviders match a model_id pattern), `provider_kwargs`.\n\n## Custom provider plugins\n\nSubclass `BaseLanguageModel` and register a regex pattern for the model_ids\nyour provider should handle:\n\n```python\nfrom langextract.core.base_model import BaseLanguageModel\nfrom langextract.providers import router\n\n@router.register(r\"^my-model\")\nclass MyProvider(BaseLanguageModel):\n    ...\n```\n\nFor external packages, declare an entry point in your `pyproject.toml` so\nLangExtract discovers the provider at model-creation time:\n\n```toml\n[project.entry-points.\"langextract.providers\"]\nmy-model = \"my_package.provider:MyProvider\"\n```\n\nPlugin loading is **lazy**: `load_plugins_once()` runs the first time a\nmodel is created via the factory, not at package import. Once loaded, any\nregistered provider whose pattern matches the requested `model_id` is\nselected automatically.\n\n`langextract.inference` and `langextract.providers.registry` still exist\nas backward-compatibility aliases, but new code should import from\n`langextract.core.base_model` and `langextract.providers.router` as shown\nabove. A complete working example lives at\n`examples/custom_provider_plugin/` in the repo.\n","skills/langextract-usage/SKILL.md":"---\nname: langextract-usage\ndescription: How to use LangExtract to extract structured information from text. Use when writing code that calls lx.extract(), building extraction pipelines, defining examples, or troubleshooting alignment issues.\n---\n\n# LangExtract Usage\n\nLangExtract extracts structured information from unstructured text using LLMs.\nThe main entry point is `lx.extract()`. Every extraction needs at least one\nexample and input text. `prompt_description` is optional but recommended.\n\n## Install\n\n```bash\npip install langextract\n\n# For OpenAI model support:\npip install langextract[openai]\n```\n\n## API keys\n\n```bash\n# Gemini (checks GEMINI_API_KEY then LANGEXTRACT_API_KEY)\nexport GEMINI_API_KEY=\"your_key\"\n\n# OpenAI (checks OPENAI_API_KEY then LANGEXTRACT_API_KEY)\nexport OPENAI_API_KEY=\"your_key\"\n\n# Ollama: no API key needed, just a running Ollama server\n```\n\nAuto-routing + env-default resolution is tuned for GPT-style model IDs\n(`gpt-4*`, `gpt-5*`). For OpenAI-compatible endpoints or non-GPT IDs,\npass an explicit `ModelConfig` — see `references/providers.md`.\n\n## Basic extraction\n\n```python\nimport langextract as lx\n\nexamples = [\n    lx.data.ExampleData(\n        text=\"Patient takes lisinopril 10mg daily for hypertension.\",\n        extractions=[\n            lx.data.Extraction(\n                extraction_class=\"medication\",\n                extraction_text=\"lisinopril\",\n                attributes={\"dose\": \"10mg\", \"frequency\": \"daily\"},\n            ),\n            lx.data.Extraction(\n                extraction_class=\"condition\",\n                extraction_text=\"hypertension\",\n                attributes={\"status\": \"active\"},\n            ),\n        ],\n    )\n]\n\nresult = lx.extract(\n    text_or_documents=\"Patient is prescribed metformin 500mg twice daily.\",\n    prompt_description=\"Extract medications and conditions with attributes.\",\n    examples=examples,\n    model_id=\"gemini-2.5-flash\",\n)\n\nfor e in result.extractions:\n    print(e.extraction_class, e.extraction_text)\n    print(f\"  char_interval: {e.char_interval}\")\n    print(f\"  attributes: {e.attributes}\")\n```\n\nSee `examples/basic_extraction.py` for a runnable version and\n`examples/relationship_extraction.py` for using `extraction_class` +\n`attributes` to encode relationships between entities.\n\n## Writing good examples\n\nExamples drive model behavior. Follow these rules:\n\n1. `extraction_text` must be verbatim from the example text, not paraphrased\n2. List extractions in order of appearance in the text\n3. Each `extraction_class` should be consistent across examples\n4. Include attributes that match what you want extracted at runtime\n\nLangExtract can raise prompt-alignment warnings when an example's\n`extraction_text` values don't align cleanly to the example's `text`\n(failed alignment, or fuzzy/lesser rather than exact). The validator does\nnot enforce rules 2–4 above — those are guidance to steer the model's\noutput, not checked invariants.\n\nTo fail fast on alignment issues during development, pass these kwargs\ndirectly to `lx.extract()` (both default to permissive):\n\n```python\nfrom langextract.prompt_validation import PromptValidationLevel\n\nresult = lx.extract(\n    ...,\n    prompt_validation_level=PromptValidationLevel.ERROR,  # default: WARNING\n    prompt_validation_strict=True,                          # default: False\n)\n```\n\nSee `references/prompt-validation.md` for level semantics and strict-mode\nbehavior.\n\n## Key parameters\n\n```python\nresult = lx.extract(\n    text_or_documents=text,          # str, URL, or list of Documents\n    fetch_urls=False,                 # True to fetch a URL input\n    prompt_description=prompt,        # what to extract (optional)\n    examples=examples,                # few-shot examples (required)\n    model_id=\"gemini-2.5-flash\",     # model to use\n    extraction_passes=1,              # >1 for higher recall (costs more)\n    max_char_buffer=1000,             # chunk size\n    batch_length=10,                  # chunks per batch\n    max_workers=10,                   # parallel workers (provider-dependent)\n    context_window_chars=None,        # cross-chunk context for coreference\n)\n```\n\n- `text_or_documents` accepts a URL string, which is fetched only when\n  `fetch_urls=True`; otherwise it is treated as text. Only enable fetching\n  for URLs from a trusted source, in a sandboxed process.\n- For full parallelism, keep `batch_length >= max_workers`. Parallel\n  processing via `max_workers` is provider-dependent; some providers\n  parallelize batched prompts, while others (such as the current Ollama\n  provider) process them sequentially.\n- `context_window_chars` includes characters from the previous chunk as\n  context for the current one, which helps with coreference and entity\n  continuity across chunk boundaries.\n- For multiple documents, pass a list of `lx.data.Document` — see\n  `examples/multiple_documents.py`.\n\n## Working with results\n\n```python\n# Filter to grounded extractions only (have source positions)\ngrounded = [e for e in result.extractions if e.char_interval]\n\n# Access source position\nfor e in grounded:\n    start = e.char_interval.start_pos\n    end = e.char_interval.end_pos\n    matched_text = result.text[start:end]\n\n# Save to JSONL\nlx.io.save_annotated_documents(\n    [result], output_name=\"results.jsonl\", output_dir=\".\"\n)\n\n# Visualize from JSONL (shows first document)\nhtml = lx.visualize(\"results.jsonl\")\nwith open(\"visualization.html\", \"w\", encoding=\"utf-8\") as f:\n    if hasattr(html, \"data\"):\n        f.write(html.data)  # Jupyter/Colab\n    else:\n        f.write(html)\n\n# Or visualize an AnnotatedDocument directly\nhtml = lx.visualize(result)\n```\n\n## Provider selection\n\nThe default is Gemini. For other providers, see `references/providers.md`,\nwhich covers:\n\n- OpenAI (JSON mode; fence behavior auto-configured)\n- Ollama (local models, `model_url`)\n- `ModelConfig` for advanced provider_kwargs (custom `base_url`, etc.)\n- Custom provider plugins via `router.register()`\n\n## Common issues\n\n**Extractions with `char_interval=None`**: the extraction could not be\nlocated in the source text. Common causes include paraphrased output,\nalignment misses, or hallucinated entities. Filter with\n`[e for e in result.extractions if e.char_interval]`. To tune alignment,\nsee `references/resolver-params.md`.\n\n**Prompt alignment warnings**: your examples have `extraction_text` that\ndoesn't match the example text verbatim. Fix the examples, or see\n`references/prompt-validation.md` to fail fast during development.\n\n**Slow on long documents**: `extraction_passes > 1` multiplies processing\ntime. Start with 1 and increase only if recall is insufficient.\n\n**Model selection**: `gemini-2.5-flash` is recommended for most tasks;\n`gemini-2.5-pro` for complex reasoning.\n\n## Further reading\n\n- `references/providers.md` — OpenAI, Ollama, ModelConfig, custom plugins\n- `references/resolver-params.md` — fuzzy alignment tuning\n- `references/prompt-validation.md` — catching example issues early\n- `examples/` — runnable scripts for each scenario above\n"},"files":{"skills/langextract-usage/references/resolver-params.md":"# resolver_params Reference\n\n`resolver_params` is a dict passed to `lx.extract()` to fine-tune how the\nmodel's output is parsed and aligned to source text. Keys may change across\nversions — check the current `extract()` docstring if in doubt.\n\n## Full example\n\n```python\nresult = lx.extract(\n    text_or_documents=text,\n    examples=examples,\n    prompt_description=prompt,\n    model_id=\"gemini-2.5-flash\",\n    resolver_params={\n        \"suppress_parse_errors\": True,\n        \"extraction_index_suffix\": \"_index\",\n        \"enable_fuzzy_alignment\": True,\n        \"fuzzy_alignment_threshold\": 0.75,\n        \"fuzzy_alignment_algorithm\": \"lcs\",\n        \"fuzzy_alignment_min_density\": 1 / 3,\n        \"accept_match_lesser\": True,\n    },\n)\n```\n\n## Key descriptions\n\n- **`suppress_parse_errors`** (default True in `extract()`): on parse or\n  schema errors for a chunk, log a warning and return `[]` for that chunk\n  rather than raising. The chunk is effectively dropped; no partial output\n  is recovered from the malformed response.\n- **`extraction_index_suffix`**: attribute name suffix used to preserve\n  extraction ordering (e.g. `\"_index\"` looks for attributes like\n  `medication_index` and sorts extractions by that value).\n- **`enable_fuzzy_alignment`** (default True): attempt fuzzy alignment when\n  exact substring match fails.\n- **`fuzzy_alignment_threshold`** (default 0.75): minimum fraction of\n  extraction tokens that must be matched in the source span.\n- **`fuzzy_alignment_algorithm`** (default `\"lcs\"`): algorithm for fuzzy\n  alignment. `\"lcs\"` uses longest-common-subsequence DP (O(n*m²)); `\"legacy\"`\n  uses the older difflib-based approach and is deprecated.\n- **`fuzzy_alignment_min_density`** (default 1/3): minimum ratio of matched\n  tokens to the span length. Filters out sparse matches where only a few\n  tokens align across a very long source span.\n- **`accept_match_lesser`**: accept `MATCH_LESSER` alignments — partial\n  exact matches where the model's `extraction_text` is longer than the span\n  that exactly matched in the source (e.g. the model returned a few extra\n  tokens at the edges). This is distinct from fuzzy alignment: the matched\n  portion is still an exact substring. Use it for truncation or\n  extra-token cases, not as a substitute for lowering\n  `fuzzy_alignment_threshold`.\n\n## When to tune these\n\n- **Too many `char_interval=None` extractions**: lower\n  `fuzzy_alignment_threshold` (e.g. 0.6). Enable `accept_match_lesser`\n  only if the model is returning extraction_text that contains an exact\n  source substring plus extra tokens.\n- **Fuzzy alignment matching the wrong span**: raise\n  `fuzzy_alignment_min_density` (e.g. 0.5) so matches must be denser.\n- **Performance-sensitive pipelines on long documents**: stick with `\"lcs\"`\n  and consider lowering `max_char_buffer` rather than disabling fuzzy\n  alignment entirely.\n","skills/langextract-usage/references/prompt-validation.md":"# Prompt Validation Reference\n\nPrompt validation catches example problems (non-verbatim text, alignment\nmismatches) early, before expensive extraction runs.\n\n## Levels\n\n```python\nfrom langextract.prompt_validation import PromptValidationLevel\n\nresult = lx.extract(\n    text_or_documents=text,\n    examples=examples,\n    prompt_description=prompt,\n    model_id=\"gemini-2.5-flash\",\n    prompt_validation_level=PromptValidationLevel.ERROR,\n    prompt_validation_strict=True,\n)\n```\n\n- **`OFF`** — skip validation entirely.\n- **`WARNING`** (default) — log issues, continue running.\n- **`ERROR`** — raise on validation failure.\n\n## Strict mode\n\nWhen `prompt_validation_strict=True`, non-exact matches (fuzzy alignment,\n`accept_match_lesser`) also trigger failures in `ERROR` mode. Without strict\nmode, only completely unalignable extractions fail.\n\n## How it aligns with resolver_params\n\nPrompt validation uses the same alignment settings from `resolver_params`.\nSo if you've tuned `fuzzy_alignment_threshold` or\n`fuzzy_alignment_algorithm`, validation honors those same values when\ndeciding whether an example extraction is aligned.\n\n## When to use each level\n\n- **Development**: `ERROR` + `strict=True` forces you to write clean,\n  verbatim examples.\n- **Staging/CI**: `ERROR` (non-strict) catches truly broken examples\n  without failing on minor fuzzy matches.\n- **Production**: `WARNING` or `OFF` — you've already validated offline and\n  don't want runtime failures over example drift.\n\n## Common fixes\n\n- **\"Extraction text not found in example text\"**: your `extraction_text`\n  doesn't appear verbatim in the example `text`. Copy-paste the exact\n  substring rather than paraphrasing.\n- **\"Extraction text aligned fuzzily\"** (strict only): same issue but with\n  minor whitespace/punctuation differences. Fix the example to match\n  exactly.\n","skills/langextract-usage/README.md":"# langextract-usage — Agent Skill\n\nThis directory is an [Agent Skill](https://agentskills.io) source that teaches\nAI coding assistants how to use LangExtract correctly. It follows the open\nAgent Skills format (`SKILL.md` with YAML frontmatter, optional\n`references/`, `examples/`).\n\nThis directory is **not** auto-discovered by any tool from the `skills/`\npath it lives in here. To use it, copy or symlink the directory into\nwhichever path your Agent-Skills-compatible tool reads from.\n\n## Activate\n\nPick your tool, then install at either project scope (this repo only) or\nuser scope (all your projects). Paths below are **canonical examples** per\neach tool's 2026 docs — some tools (Copilot, Codex) scan several paths,\nso any of the documented locations works. Check the linked docs for the\nfull list if your tool has moved.\n\nProject-scope paths are relative to your workspace/repo root. Run the copy\nor symlink command from there.\n\n| Tool | Project-scope path (example) | User-scope path (example) |\n|---|---|---|\n| [Google Antigravity](https://antigravity.google/docs/skills) | `.agents/skills/langextract-usage/` | `~/.gemini/antigravity/skills/langextract-usage/` |\n| [Anthropic Claude Code](https://code.claude.com/docs/en/skills) | `.claude/skills/langextract-usage/` | `~/.claude/skills/langextract-usage/` |\n| [OpenAI Codex](https://developers.openai.com/codex/skills) | `.agents/skills/langextract-usage/` | `~/.agents/skills/langextract-usage/` |\n| [GitHub Copilot](https://docs.github.com/en/copilot) | `.github/skills/langextract-usage/` | `~/.copilot/skills/langextract-usage/` |\n\nNotes:\n- **Antigravity** also recognizes legacy `.agent/skills/` (singular) for\n  backward compatibility; new installs should use `.agents/skills/`\n  (plural).\n- **Copilot** also accepts `.claude/skills/` or `.agents/skills/` at project\n  scope, and `~/.claude/skills/` or `~/.agents/skills/` at user scope.\n- **Codex** scans `.agents/skills/` from the current directory up through\n  the repo root, so a project-scope install works from any subdirectory.\n- A project-scope `.agents/skills/langextract-usage/` therefore activates\n  the skill in Antigravity, Codex, and Copilot simultaneously.\n\n### Copy (static install)\n\n```bash\ncp -R skills/langextract-usage <tool-skill-path>\n```\n\n### Symlink (tracks this repo's updates)\n\n```bash\nln -s \"$(pwd)/skills/langextract-usage\" <tool-skill-path>\n```\n\n### Other tools\n\n- **Agent-Skills-compatible tools not listed above** — point the tool at\n  this directory as a skill source, following its own docs.\n- **Tools that read their own instruction format** (e.g. Cursor\n  `.cursor/rules/`, Windsurf `.windsurf/rules/`, Aider `CONVENTIONS.md`) —\n  copy the relevant sections of `SKILL.md` / `references/*.md` into that\n  tool's convention. The content is portable; only the activation\n  mechanism differs.\n\nAfter activating, restart your agent session if the tool does not\nauto-detect changes.\n\n## Contents\n\n- `SKILL.md` — entry point; install, basic usage, key parameters, working with\n  results, common issues\n- `references/providers.md` — Gemini, OpenAI, Ollama, `ModelConfig`, custom\n  provider plugins\n- `references/resolver-params.md` — fuzzy alignment tuning\n- `references/prompt-validation.md` — `PromptValidationLevel` details\n- `examples/` — runnable scripts (`basic_extraction.py`,\n  `relationship_extraction.py`, `multiple_documents.py`)\n\n## Maintenance\n\nWhen changing user-facing LangExtract APIs (imports, `lx.extract()` kwargs,\nresolver or validation behavior), please update the affected files in this\nsubtree in the same PR. If you spot drift, open an issue or PR.\n","skills/langextract-usage/references/providers.md":"# Provider Reference\n\nLangExtract ships with three built-in providers (Gemini, OpenAI, Ollama) and\nsupports custom providers via a plugin system.\n\n## Gemini (default, recommended)\n\n```python\nresult = lx.extract(\n    text_or_documents=text,\n    prompt_description=prompt,\n    examples=examples,\n    model_id=\"gemini-2.5-flash\",  # or \"gemini-2.5-pro\" for complex reasoning\n)\n```\n\nEnv: `GEMINI_API_KEY` (falls back to `LANGEXTRACT_API_KEY`).\n\n## OpenAI\n\n```python\nresult = lx.extract(\n    text_or_documents=text,\n    examples=examples,\n    prompt_description=prompt,\n    model_id=\"gpt-4o\",\n)\n```\n\nEnv: `OPENAI_API_KEY` (falls back to `LANGEXTRACT_API_KEY`).\n\nThe OpenAI provider uses JSON Schema constraints by default. For models\nwithout JSON Schema support, such as `gpt-3.5-turbo`, set\n`use_schema_constraints=False` to use JSON mode\n(`response_format={\"type\":\"json_object\"}`). Leave `fence_output` unset —\n`extract()` and the factory/provider layer auto-determine fence behavior\nfrom the provider's schema. The OpenAI provider parallelizes batched\nprompts with a `ThreadPoolExecutor` when `max_workers > 1`.\n\n**Auto-routing scope:** the built-in OpenAI provider matches GPT-3.5,\nGPT-4, GPT-5, and o-series model IDs (`^gpt-3\\.5`, `^gpt-4`, `^gpt4\\.`,\n`^gpt-5`, `^gpt5\\.`, `^o[1-9]`). Both GPT and o-series IDs use the\nenvironment API keys above. Routing does not guarantee that a model\nsupports every request option: o-series models currently require omitting\n`max_output_tokens`, which this provider maps to the unsupported\n`max_tokens` parameter.\n\nFor **OpenAI-compatible endpoints** (LiteLLM, local servers, custom base\nURLs) or model IDs outside these families, use `ModelConfig` with an\nexplicit provider and kwargs:\n\n```python\nfrom langextract.factory import ModelConfig\n\nresult = lx.extract(\n    text_or_documents=text,\n    examples=examples,\n    prompt_description=prompt,\n    config=ModelConfig(\n        model_id=\"my-openai-compatible-model\",\n        provider=\"openai\",\n        provider_kwargs={\"api_key\": \"sk-...\", \"base_url\": \"https://...\"},\n    ),\n)\n```\n\n## Ollama (local)\n\nNo API key needed. Requires a running Ollama server.\n\n```python\nresult = lx.extract(\n    text_or_documents=text,\n    examples=examples,\n    prompt_description=prompt,\n    model_id=\"gemma2:2b\",\n    model_url=\"http://localhost:11434\",\n)\n```\n\nThe Ollama provider exposes `FormatModeSchema` for JSON mode. Leave\n`fence_output` and `use_schema_constraints` unset so `extract()` and the\nfactory/provider layer auto-configure from the provider's schema. The\nOllama provider processes batched prompts sequentially — `max_workers > 1`\nwill not parallelize it.\n\n## ModelConfig (advanced)\n\nFor provider-specific kwargs (custom base_url, explicit api_key, etc.):\n\n```python\nfrom langextract.factory import ModelConfig\n\nresult = lx.extract(\n    text_or_documents=text,\n    examples=examples,\n    config=ModelConfig(\n        model_id=\"gpt-4o\",\n        provider_kwargs={\"api_key\": \"your_key\", \"base_url\": \"https://...\"},\n    ),\n)\n```\n\nModelConfig fields: `model_id`, `provider` (for disambiguation when multiple\nproviders match a model_id pattern), `provider_kwargs`.\n\n## Custom provider plugins\n\nSubclass `BaseLanguageModel` and register a regex pattern for the model_ids\nyour provider should handle:\n\n```python\nfrom langextract.core.base_model import BaseLanguageModel\nfrom langextract.providers import router\n\n@router.register(r\"^my-model\")\nclass MyProvider(BaseLanguageModel):\n    ...\n```\n\nFor external packages, declare an entry point in your `pyproject.toml` so\nLangExtract discovers the provider at model-creation time:\n\n```toml\n[project.entry-points.\"langextract.providers\"]\nmy-model = \"my_package.provider:MyProvider\"\n```\n\nPlugin loading is **lazy**: `load_plugins_once()` runs the first time a\nmodel is created via the factory, not at package import. Once loaded, any\nregistered provider whose pattern matches the requested `model_id` is\nselected automatically.\n\n`langextract.inference` and `langextract.providers.registry` still exist\nas backward-compatibility aliases, but new code should import from\n`langextract.core.base_model` and `langextract.providers.router` as shown\nabove. A complete working example lives at\n`examples/custom_provider_plugin/` in the repo.\n","skills/langextract-usage/SKILL.md":"---\nname: langextract-usage\ndescription: How to use LangExtract to extract structured information from text. Use when writing code that calls lx.extract(), building extraction pipelines, defining examples, or troubleshooting alignment issues.\n---\n\n# LangExtract Usage\n\nLangExtract extracts structured information from unstructured text using LLMs.\nThe main entry point is `lx.extract()`. Every extraction needs at least one\nexample and input text. `prompt_description` is optional but recommended.\n\n## Install\n\n```bash\npip install langextract\n\n# For OpenAI model support:\npip install langextract[openai]\n```\n\n## API keys\n\n```bash\n# Gemini (checks GEMINI_API_KEY then LANGEXTRACT_API_KEY)\nexport GEMINI_API_KEY=\"your_key\"\n\n# OpenAI (checks OPENAI_API_KEY then LANGEXTRACT_API_KEY)\nexport OPENAI_API_KEY=\"your_key\"\n\n# Ollama: no API key needed, just a running Ollama server\n```\n\nAuto-routing + env-default resolution is tuned for GPT-style model IDs\n(`gpt-4*`, `gpt-5*`). For OpenAI-compatible endpoints or non-GPT IDs,\npass an explicit `ModelConfig` — see `references/providers.md`.\n\n## Basic extraction\n\n```python\nimport langextract as lx\n\nexamples = [\n    lx.data.ExampleData(\n        text=\"Patient takes lisinopril 10mg daily for hypertension.\",\n        extractions=[\n            lx.data.Extraction(\n                extraction_class=\"medication\",\n                extraction_text=\"lisinopril\",\n                attributes={\"dose\": \"10mg\", \"frequency\": \"daily\"},\n            ),\n            lx.data.Extraction(\n                extraction_class=\"condition\",\n                extraction_text=\"hypertension\",\n                attributes={\"status\": \"active\"},\n            ),\n        ],\n    )\n]\n\nresult = lx.extract(\n    text_or_documents=\"Patient is prescribed metformin 500mg twice daily.\",\n    prompt_description=\"Extract medications and conditions with attributes.\",\n    examples=examples,\n    model_id=\"gemini-2.5-flash\",\n)\n\nfor e in result.extractions:\n    print(e.extraction_class, e.extraction_text)\n    print(f\"  char_interval: {e.char_interval}\")\n    print(f\"  attributes: {e.attributes}\")\n```\n\nSee `examples/basic_extraction.py` for a runnable version and\n`examples/relationship_extraction.py` for using `extraction_class` +\n`attributes` to encode relationships between entities.\n\n## Writing good examples\n\nExamples drive model behavior. Follow these rules:\n\n1. `extraction_text` must be verbatim from the example text, not paraphrased\n2. List extractions in order of appearance in the text\n3. Each `extraction_class` should be consistent across examples\n4. Include attributes that match what you want extracted at runtime\n\nLangExtract can raise prompt-alignment warnings when an example's\n`extraction_text` values don't align cleanly to the example's `text`\n(failed alignment, or fuzzy/lesser rather than exact). The validator does\nnot enforce rules 2–4 above — those are guidance to steer the model's\noutput, not checked invariants.\n\nTo fail fast on alignment issues during development, pass these kwargs\ndirectly to `lx.extract()` (both default to permissive):\n\n```python\nfrom langextract.prompt_validation import PromptValidationLevel\n\nresult = lx.extract(\n    ...,\n    prompt_validation_level=PromptValidationLevel.ERROR,  # default: WARNING\n    prompt_validation_strict=True,                          # default: False\n)\n```\n\nSee `references/prompt-validation.md` for level semantics and strict-mode\nbehavior.\n\n## Key parameters\n\n```python\nresult = lx.extract(\n    text_or_documents=text,          # str, URL, or list of Documents\n    fetch_urls=False,                 # True to fetch a URL input\n    prompt_description=prompt,        # what to extract (optional)\n    examples=examples,                # few-shot examples (required)\n    model_id=\"gemini-2.5-flash\",     # model to use\n    extraction_passes=1,              # >1 for higher recall (costs more)\n    max_char_buffer=1000,             # chunk size\n    batch_length=10,                  # chunks per batch\n    max_workers=10,                   # parallel workers (provider-dependent)\n    context_window_chars=None,        # cross-chunk context for coreference\n)\n```\n\n- `text_or_documents` accepts a URL string, which is fetched only when\n  `fetch_urls=True`; otherwise it is treated as text. Only enable fetching\n  for URLs from a trusted source, in a sandboxed process.\n- For full parallelism, keep `batch_length >= max_workers`. Parallel\n  processing via `max_workers` is provider-dependent; some providers\n  parallelize batched prompts, while others (such as the current Ollama\n  provider) process them sequentially.\n- `context_window_chars` includes characters from the previous chunk as\n  context for the current one, which helps with coreference and entity\n  continuity across chunk boundaries.\n- For multiple documents, pass a list of `lx.data.Document` — see\n  `examples/multiple_documents.py`.\n\n## Working with results\n\n```python\n# Filter to grounded extractions only (have source positions)\ngrounded = [e for e in result.extractions if e.char_interval]\n\n# Access source position\nfor e in grounded:\n    start = e.char_interval.start_pos\n    end = e.char_interval.end_pos\n    matched_text = result.text[start:end]\n\n# Save to JSONL\nlx.io.save_annotated_documents(\n    [result], output_name=\"results.jsonl\", output_dir=\".\"\n)\n\n# Visualize from JSONL (shows first document)\nhtml = lx.visualize(\"results.jsonl\")\nwith open(\"visualization.html\", \"w\", encoding=\"utf-8\") as f:\n    if hasattr(html, \"data\"):\n        f.write(html.data)  # Jupyter/Colab\n    else:\n        f.write(html)\n\n# Or visualize an AnnotatedDocument directly\nhtml = lx.visualize(result)\n```\n\n## Provider selection\n\nThe default is Gemini. For other providers, see `references/providers.md`,\nwhich covers:\n\n- OpenAI (JSON mode; fence behavior auto-configured)\n- Ollama (local models, `model_url`)\n- `ModelConfig` for advanced provider_kwargs (custom `base_url`, etc.)\n- Custom provider plugins via `router.register()`\n\n## Common issues\n\n**Extractions with `char_interval=None`**: the extraction could not be\nlocated in the source text. Common causes include paraphrased output,\nalignment misses, or hallucinated entities. Filter with\n`[e for e in result.extractions if e.char_interval]`. To tune alignment,\nsee `references/resolver-params.md`.\n\n**Prompt alignment warnings**: your examples have `extraction_text` that\ndoesn't match the example text verbatim. Fix the examples, or see\n`references/prompt-validation.md` to fail fast during development.\n\n**Slow on long documents**: `extraction_passes > 1` multiplies processing\ntime. Start with 1 and increase only if recall is insufficient.\n\n**Model selection**: `gemini-2.5-flash` is recommended for most tasks;\n`gemini-2.5-pro` for complex reasoning.\n\n## Further reading\n\n- `references/providers.md` — OpenAI, Ollama, ModelConfig, custom plugins\n- `references/resolver-params.md` — fuzzy alignment tuning\n- `references/prompt-validation.md` — catching example issues early\n- `examples/` — runnable scripts for each scenario above\n"},"items":[{"name":"README.md","path":"skills/langextract-usage/README.md","rawUrl":"https://raw.githubusercontent.com/google/langextract/HEAD/skills/langextract-usage/README.md","title":"Langextract-usage Skill","category":"anthropic-skill","format":"markdown","content":"# langextract-usage — Agent Skill\n\nThis directory is an [Agent Skill](https://agentskills.io) source that teaches\nAI coding assistants how to use LangExtract correctly. It follows the open\nAgent Skills format (`SKILL.md` with YAML frontmatter, optional\n`references/`, `examples/`).\n\nThis directory is **not** auto-discovered by any tool from the `skills/`\npath it lives in here. To use it, copy or symlink the directory into\nwhichever path your Agent-Skills-compatible tool reads from.\n\n## Activate\n\nPick your tool, then install at either project scope (this repo only) or\nuser scope (all your projects). Paths below are **canonical examples** per\neach tool's 2026 docs — some tools (Copilot, Codex) scan several paths,\nso any of the documented locations works. Check the linked docs for the\nfull list if your tool has moved.\n\nProject-scope paths are relative to your workspace/repo root. Run the copy\nor symlink command from there.\n\n| Tool | Project-scope path (example) | User-scope path (example) |\n|---|---|---|\n| [Google Antigravity](https://antigravity.google/docs/skills) | `.agents/skills/langextract-usage/` | `~/.gemini/antigravity/skills/langextract-usage/` |\n| [Anthropic Claude Code](https://code.claude.com/docs/en/skills) | `.claude/skills/langextract-usage/` | `~/.claude/skills/langextract-usage/` |\n| [OpenAI Codex](https://developers.openai.com/codex/skills) | `.agents/skills/langextract-usage/` | `~/.agents/skills/langextract-usage/` |\n| [GitHub Copilot](https://docs.github.com/en/copilot) | `.github/skills/langextract-usage/` | `~/.copilot/skills/langextract-usage/` |\n\nNotes:\n- **Antigravity** also recognizes legacy `.agent/skills/` (singular) for\n  backward compatibility; new installs should use `.agents/skills/`\n  (plural).\n- **Copilot** also accepts `.claude/skills/` or `.agents/skills/` at project\n  scope, and `~/.claude/skills/` or `~/.agents/skills/` at user scope.\n- **Codex** scans `.agents/skills/` from the current directory up through\n  the repo root, so a project-scope install works from any subdirectory.\n- A project-scope `.agents/skills/langextract-usage/` therefore activates\n  the skill in Antigravity, Codex, and Copilot simultaneously.\n\n### Copy (static install)\n\n```bash\ncp -R skills/langextract-usage <tool-skill-path>\n```\n\n### Symlink (tracks this repo's updates)\n\n```bash\nln -s \"$(pwd)/skills/langextract-usage\" <tool-skill-path>\n```\n\n### Other tools\n\n- **Agent-Skills-compatible tools not listed above** — point the tool at\n  this directory as a skill source, following its own docs.\n- **Tools that read their own instruction format** (e.g. Cursor\n  `.cursor/rules/`, Windsurf `.windsurf/rules/`, Aider `CONVENTIONS.md`) —\n  copy the relevant sections of `SKILL.md` / `references/*.md` into that\n  tool's convention. The content is portable; only the activation\n  mechanism differs.\n\nAfter activating, restart your agent session if the tool does not\nauto-detect changes.\n\n## Contents\n\n- `SKILL.md` — entry point; install, basic usage, key parameters, working with\n  results, common issues\n- `references/providers.md` — Gemini, OpenAI, Ollama, `ModelConfig`, custom\n  provider plugins\n- `references/resolver-params.md` — fuzzy alignment tuning\n- `references/prompt-validation.md` — `PromptValidationLevel` details\n- `examples/` — runnable scripts (`basic_extraction.py`,\n  `relationship_extraction.py`, `multiple_documents.py`)\n\n## Maintenance\n\nWhen changing user-facing LangExtract APIs (imports, `lx.extract()` kwargs,\nresolver or validation behavior), please update the affected files in this\nsubtree in the same PR. If you spot drift, open an issue or PR.\n","isInternal":false,"tokens":930,"sizeBytes":3633},{"name":"prompt-validation.md","path":"skills/langextract-usage/references/prompt-validation.md","rawUrl":"https://raw.githubusercontent.com/google/langextract/HEAD/skills/langextract-usage/references/prompt-validation.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Prompt Validation Reference\n\nPrompt validation catches example problems (non-verbatim text, alignment\nmismatches) early, before expensive extraction runs.\n\n## Levels\n\n```python\nfrom langextract.prompt_validation import PromptValidationLevel\n\nresult = lx.extract(\n    text_or_documents=text,\n    examples=examples,\n    prompt_description=prompt,\n    model_id=\"gemini-2.5-flash\",\n    prompt_validation_level=PromptValidationLevel.ERROR,\n    prompt_validation_strict=True,\n)\n```\n\n- **`OFF`** — skip validation entirely.\n- **`WARNING`** (default) — log issues, continue running.\n- **`ERROR`** — raise on validation failure.\n\n## Strict mode\n\nWhen `prompt_validation_strict=True`, non-exact matches (fuzzy alignment,\n`accept_match_lesser`) also trigger failures in `ERROR` mode. Without strict\nmode, only completely unalignable extractions fail.\n\n## How it aligns with resolver_params\n\nPrompt validation uses the same alignment settings from `resolver_params`.\nSo if you've tuned `fuzzy_alignment_threshold` or\n`fuzzy_alignment_algorithm`, validation honors those same values when\ndeciding whether an example extraction is aligned.\n\n## When to use each level\n\n- **Development**: `ERROR` + `strict=True` forces you to write clean,\n  verbatim examples.\n- **Staging/CI**: `ERROR` (non-strict) catches truly broken examples\n  without failing on minor fuzzy matches.\n- **Production**: `WARNING` or `OFF` — you've already validated offline and\n  don't want runtime failures over example drift.\n\n## Common fixes\n\n- **\"Extraction text not found in example text\"**: your `extraction_text`\n  doesn't appear verbatim in the example `text`. Copy-paste the exact\n  substring rather than paraphrasing.\n- **\"Extraction text aligned fuzzily\"** (strict only): same issue but with\n  minor whitespace/punctuation differences. Fix the example to match\n  exactly.\n","isInternal":false,"tokens":416,"sizeBytes":1847},{"name":"providers.md","path":"skills/langextract-usage/references/providers.md","rawUrl":"https://raw.githubusercontent.com/google/langextract/HEAD/skills/langextract-usage/references/providers.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Provider Reference\n\nLangExtract ships with three built-in providers (Gemini, OpenAI, Ollama) and\nsupports custom providers via a plugin system.\n\n## Gemini (default, recommended)\n\n```python\nresult = lx.extract(\n    text_or_documents=text,\n    prompt_description=prompt,\n    examples=examples,\n    model_id=\"gemini-2.5-flash\",  # or \"gemini-2.5-pro\" for complex reasoning\n)\n```\n\nEnv: `GEMINI_API_KEY` (falls back to `LANGEXTRACT_API_KEY`).\n\n## OpenAI\n\n```python\nresult = lx.extract(\n    text_or_documents=text,\n    examples=examples,\n    prompt_description=prompt,\n    model_id=\"gpt-4o\",\n)\n```\n\nEnv: `OPENAI_API_KEY` (falls back to `LANGEXTRACT_API_KEY`).\n\nThe OpenAI provider uses JSON Schema constraints by default. For models\nwithout JSON Schema support, such as `gpt-3.5-turbo`, set\n`use_schema_constraints=False` to use JSON mode\n(`response_format={\"type\":\"json_object\"}`). Leave `fence_output` unset —\n`extract()` and the factory/provider layer auto-determine fence behavior\nfrom the provider's schema. The OpenAI provider parallelizes batched\nprompts with a `ThreadPoolExecutor` when `max_workers > 1`.\n\n**Auto-routing scope:** the built-in OpenAI provider matches GPT-3.5,\nGPT-4, GPT-5, and o-series model IDs (`^gpt-3\\.5`, `^gpt-4`, `^gpt4\\.`,\n`^gpt-5`, `^gpt5\\.`, `^o[1-9]`). Both GPT and o-series IDs use the\nenvironment API keys above. Routing does not guarantee that a model\nsupports every request option: o-series models currently require omitting\n`max_output_tokens`, which this provider maps to the unsupported\n`max_tokens` parameter.\n\nFor **OpenAI-compatible endpoints** (LiteLLM, local servers, custom base\nURLs) or model IDs outside these families, use `ModelConfig` with an\nexplicit provider and kwargs:\n\n```python\nfrom langextract.factory import ModelConfig\n\nresult = lx.extract(\n    text_or_documents=text,\n    examples=examples,\n    prompt_description=prompt,\n    config=ModelConfig(\n        model_id=\"my-openai-compatible-model\",\n        provider=\"openai\",\n        provider_kwargs={\"api_key\": \"sk-...\", \"base_url\": \"https://...\"},\n    ),\n)\n```\n\n## Ollama (local)\n\nNo API key needed. Requires a running Ollama server.\n\n```python\nresult = lx.extract(\n    text_or_documents=text,\n    examples=examples,\n    prompt_description=prompt,\n    model_id=\"gemma2:2b\",\n    model_url=\"http://localhost:11434\",\n)\n```\n\nThe Ollama provider exposes `FormatModeSchema` for JSON mode. Leave\n`fence_output` and `use_schema_constraints` unset so `extract()` and the\nfactory/provider layer auto-configure from the provider's schema. The\nOllama provider processes batched prompts sequentially — `max_workers > 1`\nwill not parallelize it.\n\n## ModelConfig (advanced)\n\nFor provider-specific kwargs (custom base_url, explicit api_key, etc.):\n\n```python\nfrom langextract.factory import ModelConfig\n\nresult = lx.extract(\n    text_or_documents=text,\n    examples=examples,\n    config=ModelConfig(\n        model_id=\"gpt-4o\",\n        provider_kwargs={\"api_key\": \"your_key\", \"base_url\": \"https://...\"},\n    ),\n)\n```\n\nModelConfig fields: `model_id`, `provider` (for disambiguation when multiple\nproviders match a model_id pattern), `provider_kwargs`.\n\n## Custom provider plugins\n\nSubclass `BaseLanguageModel` and register a regex pattern for the model_ids\nyour provider should handle:\n\n```python\nfrom langextract.core.base_model import BaseLanguageModel\nfrom langextract.providers import router\n\n@router.register(r\"^my-model\")\nclass MyProvider(BaseLanguageModel):\n    ...\n```\n\nFor external packages, declare an entry point in your `pyproject.toml` so\nLangExtract discovers the provider at model-creation time:\n\n```toml\n[project.entry-points.\"langextract.providers\"]\nmy-model = \"my_package.provider:MyProvider\"\n```\n\nPlugin loading is **lazy**: `load_plugins_once()` runs the first time a\nmodel is created via the factory, not at package import. Once loaded, any\nregistered provider whose pattern matches the requested `model_id` is\nselected automatically.\n\n`langextract.inference` and `langextract.providers.registry` still exist\nas backward-compatibility aliases, but new code should import from\n`langextract.core.base_model` and `langextract.providers.router` as shown\nabove. A complete working example lives at\n`examples/custom_provider_plugin/` in the repo.\n","isInternal":false,"tokens":1046,"sizeBytes":4255},{"name":"resolver-params.md","path":"skills/langextract-usage/references/resolver-params.md","rawUrl":"https://raw.githubusercontent.com/google/langextract/HEAD/skills/langextract-usage/references/resolver-params.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# resolver_params Reference\n\n`resolver_params` is a dict passed to `lx.extract()` to fine-tune how the\nmodel's output is parsed and aligned to source text. Keys may change across\nversions — check the current `extract()` docstring if in doubt.\n\n## Full example\n\n```python\nresult = lx.extract(\n    text_or_documents=text,\n    examples=examples,\n    prompt_description=prompt,\n    model_id=\"gemini-2.5-flash\",\n    resolver_params={\n        \"suppress_parse_errors\": True,\n        \"extraction_index_suffix\": \"_index\",\n        \"enable_fuzzy_alignment\": True,\n        \"fuzzy_alignment_threshold\": 0.75,\n        \"fuzzy_alignment_algorithm\": \"lcs\",\n        \"fuzzy_alignment_min_density\": 1 / 3,\n        \"accept_match_lesser\": True,\n    },\n)\n```\n\n## Key descriptions\n\n- **`suppress_parse_errors`** (default True in `extract()`): on parse or\n  schema errors for a chunk, log a warning and return `[]` for that chunk\n  rather than raising. The chunk is effectively dropped; no partial output\n  is recovered from the malformed response.\n- **`extraction_index_suffix`**: attribute name suffix used to preserve\n  extraction ordering (e.g. `\"_index\"` looks for attributes like\n  `medication_index` and sorts extractions by that value).\n- **`enable_fuzzy_alignment`** (default True): attempt fuzzy alignment when\n  exact substring match fails.\n- **`fuzzy_alignment_threshold`** (default 0.75): minimum fraction of\n  extraction tokens that must be matched in the source span.\n- **`fuzzy_alignment_algorithm`** (default `\"lcs\"`): algorithm for fuzzy\n  alignment. `\"lcs\"` uses longest-common-subsequence DP (O(n*m²)); `\"legacy\"`\n  uses the older difflib-based approach and is deprecated.\n- **`fuzzy_alignment_min_density`** (default 1/3): minimum ratio of matched\n  tokens to the span length. Filters out sparse matches where only a few\n  tokens align across a very long source span.\n- **`accept_match_lesser`**: accept `MATCH_LESSER` alignments — partial\n  exact matches where the model's `extraction_text` is longer than the span\n  that exactly matched in the source (e.g. the model returned a few extra\n  tokens at the edges). This is distinct from fuzzy alignment: the matched\n  portion is still an exact substring. Use it for truncation or\n  extra-token cases, not as a substitute for lowering\n  `fuzzy_alignment_threshold`.\n\n## When to tune these\n\n- **Too many `char_interval=None` extractions**: lower\n  `fuzzy_alignment_threshold` (e.g. 0.6). Enable `accept_match_lesser`\n  only if the model is returning extraction_text that contains an exact\n  source substring plus extra tokens.\n- **Fuzzy alignment matching the wrong span**: raise\n  `fuzzy_alignment_min_density` (e.g. 0.5) so matches must be denser.\n- **Performance-sensitive pipelines on long documents**: stick with `\"lcs\"`\n  and consider lowering `max_char_buffer` rather than disabling fuzzy\n  alignment entirely.\n","isInternal":false,"tokens":690,"sizeBytes":2866},{"name":"SKILL.md","path":"skills/langextract-usage/SKILL.md","rawUrl":"https://raw.githubusercontent.com/google/langextract/HEAD/skills/langextract-usage/SKILL.md","title":"langextract-usage","category":"anthropic-skill","format":"markdown","content":"---\nname: langextract-usage\ndescription: How to use LangExtract to extract structured information from text. Use when writing code that calls lx.extract(), building extraction pipelines, defining examples, or troubleshooting alignment issues.\n---\n\n# LangExtract Usage\n\nLangExtract extracts structured information from unstructured text using LLMs.\nThe main entry point is `lx.extract()`. Every extraction needs at least one\nexample and input text. `prompt_description` is optional but recommended.\n\n## Install\n\n```bash\npip install langextract\n\n# For OpenAI model support:\npip install langextract[openai]\n```\n\n## API keys\n\n```bash\n# Gemini (checks GEMINI_API_KEY then LANGEXTRACT_API_KEY)\nexport GEMINI_API_KEY=\"your_key\"\n\n# OpenAI (checks OPENAI_API_KEY then LANGEXTRACT_API_KEY)\nexport OPENAI_API_KEY=\"your_key\"\n\n# Ollama: no API key needed, just a running Ollama server\n```\n\nAuto-routing + env-default resolution is tuned for GPT-style model IDs\n(`gpt-4*`, `gpt-5*`). For OpenAI-compatible endpoints or non-GPT IDs,\npass an explicit `ModelConfig` — see `references/providers.md`.\n\n## Basic extraction\n\n```python\nimport langextract as lx\n\nexamples = [\n    lx.data.ExampleData(\n        text=\"Patient takes lisinopril 10mg daily for hypertension.\",\n        extractions=[\n            lx.data.Extraction(\n                extraction_class=\"medication\",\n                extraction_text=\"lisinopril\",\n                attributes={\"dose\": \"10mg\", \"frequency\": \"daily\"},\n            ),\n            lx.data.Extraction(\n                extraction_class=\"condition\",\n                extraction_text=\"hypertension\",\n                attributes={\"status\": \"active\"},\n            ),\n        ],\n    )\n]\n\nresult = lx.extract(\n    text_or_documents=\"Patient is prescribed metformin 500mg twice daily.\",\n    prompt_description=\"Extract medications and conditions with attributes.\",\n    examples=examples,\n    model_id=\"gemini-2.5-flash\",\n)\n\nfor e in result.extractions:\n    print(e.extraction_class, e.extraction_text)\n    print(f\"  char_interval: {e.char_interval}\")\n    print(f\"  attributes: {e.attributes}\")\n```\n\nSee `examples/basic_extraction.py` for a runnable version and\n`examples/relationship_extraction.py` for using `extraction_class` +\n`attributes` to encode relationships between entities.\n\n## Writing good examples\n\nExamples drive model behavior. Follow these rules:\n\n1. `extraction_text` must be verbatim from the example text, not paraphrased\n2. List extractions in order of appearance in the text\n3. Each `extraction_class` should be consistent across examples\n4. Include attributes that match what you want extracted at runtime\n\nLangExtract can raise prompt-alignment warnings when an example's\n`extraction_text` values don't align cleanly to the example's `text`\n(failed alignment, or fuzzy/lesser rather than exact). The validator does\nnot enforce rules 2–4 above — those are guidance to steer the model's\noutput, not checked invariants.\n\nTo fail fast on alignment issues during development, pass these kwargs\ndirectly to `lx.extract()` (both default to permissive):\n\n```python\nfrom langextract.prompt_validation import PromptValidationLevel\n\nresult = lx.extract(\n    ...,\n    prompt_validation_level=PromptValidationLevel.ERROR,  # default: WARNING\n    prompt_validation_strict=True,                          # default: False\n)\n```\n\nSee `references/prompt-validation.md` for level semantics and strict-mode\nbehavior.\n\n## Key parameters\n\n```python\nresult = lx.extract(\n    text_or_documents=text,          # str, URL, or list of Documents\n    fetch_urls=False,                 # True to fetch a URL input\n    prompt_description=prompt,        # what to extract (optional)\n    examples=examples,                # few-shot examples (required)\n    model_id=\"gemini-2.5-flash\",     # model to use\n    extraction_passes=1,              # >1 for higher recall (costs more)\n    max_char_buffer=1000,             # chunk size\n    batch_length=10,                  # chunks per batch\n    max_workers=10,                   # parallel workers (provider-dependent)\n    context_window_chars=None,        # cross-chunk context for coreference\n)\n```\n\n- `text_or_documents` accepts a URL string, which is fetched only when\n  `fetch_urls=True`; otherwise it is treated as text. Only enable fetching\n  for URLs from a trusted source, in a sandboxed process.\n- For full parallelism, keep `batch_length >= max_workers`. Parallel\n  processing via `max_workers` is provider-dependent; some providers\n  parallelize batched prompts, while others (such as the current Ollama\n  provider) process them sequentially.\n- `context_window_chars` includes characters from the previous chunk as\n  context for the current one, which helps with coreference and entity\n  continuity across chunk boundaries.\n- For multiple documents, pass a list of `lx.data.Document` — see\n  `examples/multiple_documents.py`.\n\n## Working with results\n\n```python\n# Filter to grounded extractions only (have source positions)\ngrounded = [e for e in result.extractions if e.char_interval]\n\n# Access source position\nfor e in grounded:\n    start = e.char_interval.start_pos\n    end = e.char_interval.end_pos\n    matched_text = result.text[start:end]\n\n# Save to JSONL\nlx.io.save_annotated_documents(\n    [result], output_name=\"results.jsonl\", output_dir=\".\"\n)\n\n# Visualize from JSONL (shows first document)\nhtml = lx.visualize(\"results.jsonl\")\nwith open(\"visualization.html\", \"w\", encoding=\"utf-8\") as f:\n    if hasattr(html, \"data\"):\n        f.write(html.data)  # Jupyter/Colab\n    else:\n        f.write(html)\n\n# Or visualize an AnnotatedDocument directly\nhtml = lx.visualize(result)\n```\n\n## Provider selection\n\nThe default is Gemini. For other providers, see `references/providers.md`,\nwhich covers:\n\n- OpenAI (JSON mode; fence behavior auto-configured)\n- Ollama (local models, `model_url`)\n- `ModelConfig` for advanced provider_kwargs (custom `base_url`, etc.)\n- Custom provider plugins via `router.register()`\n\n## Common issues\n\n**Extractions with `char_interval=None`**: the extraction could not be\nlocated in the source text. Common causes include paraphrased output,\nalignment misses, or hallucinated entities. Filter with\n`[e for e in result.extractions if e.char_interval]`. To tune alignment,\nsee `references/resolver-params.md`.\n\n**Prompt alignment warnings**: your examples have `extraction_text` that\ndoesn't match the example text verbatim. Fix the examples, or see\n`references/prompt-validation.md` to fail fast during development.\n\n**Slow on long documents**: `extraction_passes > 1` multiplies processing\ntime. Start with 1 and increase only if recall is insufficient.\n\n**Model selection**: `gemini-2.5-flash` is recommended for most tasks;\n`gemini-2.5-pro` for complex reasoning.\n\n## Further reading\n\n- `references/providers.md` — OpenAI, Ollama, ModelConfig, custom plugins\n- `references/resolver-params.md` — fuzzy alignment tuning\n- `references/prompt-validation.md` — catching example issues early\n- `examples/` — runnable scripts for each scenario above\n","frontmatter":{"name":"langextract-usage","description":"How to use LangExtract to extract structured information from text. Use when writing code that calls lx.extract(), building extraction pipelines, defining examples, or troubleshooting alignment issues."},"isInternal":false,"tokens":1592,"sizeBytes":7032}],"systemPromptSnippet":"<yakaai_skills repo=\"google/langextract\">\n<!-- File: skills/langextract-usage/README.md (Tokens: ~930 | Category: anthropic-skill) -->\n# langextract-usage — Agent Skill\n\nThis directory is an [Agent Skill](https://agentskills.io) source that teaches\nAI coding assistants how to use LangExtract correctly. It follows the open\nAgent Skills format (`SKILL.md` with YAML frontmatter, optional\n`references/`, `examples/`).\n\nThis directory is **not** auto-discovered by any tool from the `skills/`\npath it lives in here. To use it, copy or symlink the directory into\nwhichever path your Agent-Skills-compatible tool reads from.\n\n## Activate\n\nPick your tool, then install at either project scope (this repo only) or\nuser scope (all your projects). Paths below are **canonical examples** per\neach tool's 2026 docs — some tools (Copilot, Codex) scan several paths,\nso any of the documented locations works. Check the linked docs for the\nfull list if your tool has moved.\n\nProject-scope paths are relative to your workspace/repo root. Run the copy\nor symlink command from there.\n\n| Tool | Project-scope path (example) | User-scope path (example) |\n|---|---|---|\n| [Google Antigravity](https://antigravity.google/docs/skills) | `.agents/skills/langextract-usage/` | `~/.gemini/antigravity/skills/langextract-usage/` |\n| [Anthropic Claude Code](https://code.claude.com/docs/en/skills) | `.claude/skills/langextract-usage/` | `~/.claude/skills/langextract-usage/` |\n| [OpenAI Codex](https://developers.openai.com/codex/skills) | `.agents/skills/langextract-usage/` | `~/.agents/skills/langextract-usage/` |\n| [GitHub Copilot](https://docs.github.com/en/copilot) | `.github/skills/langextract-usage/` | `~/.copilot/skills/langextract-usage/` |\n\nNotes:\n- **Antigravity** also recognizes legacy `.agent/skills/` (singular) for\n  backward compatibility; new installs should use `.agents/skills/`\n  (plural).\n- **Copilot** also accepts `.claude/skills/` or `.agents/skills/` at project\n  scope, and `~/.claude/skills/` or `~/.agents/skills/` at user scope.\n- **Codex** scans `.agents/skills/` from the current directory up through\n  the repo root, so a project-scope install works from any subdirectory.\n- A project-scope `.agents/skills/langextract-usage/` therefore activates\n  the skill in Antigravity, Codex, and Copilot simultaneously.\n\n### Copy (static install)\n\n```bash\ncp -R skills/langextract-usage <tool-skill-path>\n```\n\n### Symlink (tracks this repo's updates)\n\n```bash\nln -s \"$(pwd)/skills/langextract-usage\" <tool-skill-path>\n```\n\n### Other tools\n\n- **Agent-Skills-compatible tools not listed above** — point the tool at\n  this directory as a skill source, following its own docs.\n- **Tools that read their own instruction format** (e.g. Cursor\n  `.cursor/rules/`, Windsurf `.windsurf/rules/`, Aider `CONVENTIONS.md`) —\n  copy the relevant sections of `SKILL.md` / `references/*.md` into that\n  tool's convention. The content is portable; only the activation\n  mechanism differs.\n\nAfter activating, restart your agent session if the tool does not\nauto-detect changes.\n\n## Contents\n\n- `SKILL.md` — entry point; install, basic usage, key parameters, working with\n  results, common issues\n- `references/providers.md` — Gemini, OpenAI, Ollama, `ModelConfig`, custom\n  provider plugins\n- `references/resolver-params.md` — fuzzy alignment tuning\n- `references/prompt-validation.md` — `PromptValidationLevel` details\n- `examples/` — runnable scripts (`basic_extraction.py`,\n  `relationship_extraction.py`, `multiple_documents.py`)\n\n## Maintenance\n\nWhen changing user-facing LangExtract APIs (imports, `lx.extract()` kwargs,\nresolver or validation behavior), please update the affected files in this\nsubtree in the same PR. If you spot drift, open an issue or PR.\n\n<!-- File: skills/langextract-usage/references/prompt-validation.md (Tokens: ~416 | Category: anthropic-skill) -->\n# Prompt Validation Reference\n\nPrompt validation catches example problems (non-verbatim text, alignment\nmismatches) early, before expensive extraction runs.\n\n## Levels\n\n```python\nfrom langextract.prompt_validation import PromptValidationLevel\n\nresult = lx.extract(\n    text_or_documents=text,\n    examples=examples,\n    prompt_description=prompt,\n    model_id=\"gemini-2.5-flash\",\n    prompt_validation_level=PromptValidationLevel.ERROR,\n    prompt_validation_strict=True,\n)\n```\n\n- **`OFF`** — skip validation entirely.\n- **`WARNING`** (default) — log issues, continue running.\n- **`ERROR`** — raise on validation failure.\n\n## Strict mode\n\nWhen `prompt_validation_strict=True`, non-exact matches (fuzzy alignment,\n`accept_match_lesser`) also trigger failures in `ERROR` mode. Without strict\nmode, only completely unalignable extractions fail.\n\n## How it aligns with resolver_params\n\nPrompt validation uses the same alignment settings from `resolver_params`.\nSo if you've tuned `fuzzy_alignment_threshold` or\n`fuzzy_alignment_algorithm`, validation honors those same values when\ndeciding whether an example extraction is aligned.\n\n## When to use each level\n\n- **Development**: `ERROR` + `strict=True` forces you to write clean,\n  verbatim examples.\n- **Staging/CI**: `ERROR` (non-strict) catches truly broken examples\n  without failing on minor fuzzy matches.\n- **Production**: `WARNING` or `OFF` — you've already validated offline and\n  don't want runtime failures over example drift.\n\n## Common fixes\n\n- **\"Extraction text not found in example text\"**: your `extraction_text`\n  doesn't appear verbatim in the example `text`. Copy-paste the exact\n  substring rather than paraphrasing.\n- **\"Extraction text aligned fuzzily\"** (strict only): same issue but with\n  minor whitespace/punctuation differences. Fix the example to match\n  exactly.\n\n<!-- File: skills/langextract-usage/references/providers.md (Tokens: ~1046 | Category: anthropic-skill) -->\n# Provider Reference\n\nLangExtract ships with three built-in providers (Gemini, OpenAI, Ollama) and\nsupports custom providers via a plugin system.\n\n## Gemini (default, recommended)\n\n```python\nresult = lx.extract(\n    text_or_documents=text,\n    prompt_description=prompt,\n    examples=examples,\n    model_id=\"gemini-2.5-flash\",  # or \"gemini-2.5-pro\" for complex reasoning\n)\n```\n\nEnv: `GEMINI_API_KEY` (falls back to `LANGEXTRACT_API_KEY`).\n\n## OpenAI\n\n```python\nresult = lx.extract(\n    text_or_documents=text,\n    examples=examples,\n    prompt_description=prompt,\n    model_id=\"gpt-4o\",\n)\n```\n\nEnv: `OPENAI_API_KEY` (falls back to `LANGEXTRACT_API_KEY`).\n\nThe OpenAI provider uses JSON Schema constraints by default. For models\nwithout JSON Schema support, such as `gpt-3.5-turbo`, set\n`use_schema_constraints=False` to use JSON mode\n(`response_format={\"type\":\"json_object\"}`). Leave `fence_output` unset —\n`extract()` and the factory/provider layer auto-determine fence behavior\nfrom the provider's schema. The OpenAI provider parallelizes batched\nprompts with a `ThreadPoolExecutor` when `max_workers > 1`.\n\n**Auto-routing scope:** the built-in OpenAI provider matches GPT-3.5,\nGPT-4, GPT-5, and o-series model IDs (`^gpt-3\\.5`, `^gpt-4`, `^gpt4\\.`,\n`^gpt-5`, `^gpt5\\.`, `^o[1-9]`). Both GPT and o-series IDs use the\nenvironment API keys above. Routing does not guarantee that a model\nsupports every request option: o-series models currently require omitting\n`max_output_tokens`, which this provider maps to the unsupported\n`max_tokens` parameter.\n\nFor **OpenAI-compatible endpoints** (LiteLLM, local servers, custom base\nURLs) or model IDs outside these families, use `ModelConfig` with an\nexplicit provider and kwargs:\n\n```python\nfrom langextract.factory import ModelConfig\n\nresult = lx.extract(\n    text_or_documents=text,\n    examples=examples,\n    prompt_description=prompt,\n    config=ModelConfig(\n        model_id=\"my-openai-compatible-model\",\n        provider=\"openai\",\n        provider_kwargs={\"api_key\": \"sk-...\", \"base_url\": \"https://...\"},\n    ),\n)\n```\n\n## Ollama (local)\n\nNo API key needed. Requires a running Ollama server.\n\n```python\nresult = lx.extract(\n    text_or_documents=text,\n    examples=examples,\n    prompt_description=prompt,\n    model_id=\"gemma2:2b\",\n    model_url=\"http://localhost:11434\",\n)\n```\n\nThe Ollama provider exposes `FormatModeSchema` for JSON mode. Leave\n`fence_output` and `use_schema_constraints` unset so `extract()` and the\nfactory/provider layer auto-configure from the provider's schema. The\nOllama provider processes batched prompts sequentially — `max_workers > 1`\nwill not parallelize it.\n\n## ModelConfig (advanced)\n\nFor provider-specific kwargs (custom base_url, explicit api_key, etc.):\n\n```python\nfrom langextract.factory import ModelConfig\n\nresult = lx.extract(\n    text_or_documents=text,\n    examples=examples,\n    config=ModelConfig(\n        model_id=\"gpt-4o\",\n        provider_kwargs={\"api_key\": \"your_key\", \"base_url\": \"https://...\"},\n    ),\n)\n```\n\nModelConfig fields: `model_id`, `provider` (for disambiguation when multiple\nproviders match a model_id pattern), `provider_kwargs`.\n\n## Custom provider plugins\n\nSubclass `BaseLanguageModel` and register a regex pattern for the model_ids\nyour provider should handle:\n\n```python\nfrom langextract.core.base_model import BaseLanguageModel\nfrom langextract.providers import router\n\n@router.register(r\"^my-model\")\nclass MyProvider(BaseLanguageModel):\n    ...\n```\n\nFor external packages, declare an entry point in your `pyproject.toml` so\nLangExtract discovers the provider at model-creation time:\n\n```toml\n[project.entry-points.\"langextract.providers\"]\nmy-model = \"my_package.provider:MyProvider\"\n```\n\nPlugin loading is **lazy**: `load_plugins_once()` runs the first time a\nmodel is created via the factory, not at package import. Once loaded, any\nregistered provider whose pattern matches the requested `model_id` is\nselected automatically.\n\n`langextract.inference` and `langextract.providers.registry` still exist\nas backward-compatibility aliases, but new code should import from\n`langextract.core.base_model` and `langextract.providers.router` as shown\nabove. A complete working example lives at\n`examples/custom_provider_plugin/` in the repo.\n\n<!-- File: skills/langextract-usage/references/resolver-params.md (Tokens: ~690 | Category: anthropic-skill) -->\n# resolver_params Reference\n\n`resolver_params` is a dict passed to `lx.extract()` to fine-tune how the\nmodel's output is parsed and aligned to source text. Keys may change across\nversions — check the current `extract()` docstring if in doubt.\n\n## Full example\n\n```python\nresult = lx.extract(\n    text_or_documents=text,\n    examples=examples,\n    prompt_description=prompt,\n    model_id=\"gemini-2.5-flash\",\n    resolver_params={\n        \"suppress_parse_errors\": True,\n        \"extraction_index_suffix\": \"_index\",\n        \"enable_fuzzy_alignment\": True,\n        \"fuzzy_alignment_threshold\": 0.75,\n        \"fuzzy_alignment_algorithm\": \"lcs\",\n        \"fuzzy_alignment_min_density\": 1 / 3,\n        \"accept_match_lesser\": True,\n    },\n)\n```\n\n## Key descriptions\n\n- **`suppress_parse_errors`** (default True in `extract()`): on parse or\n  schema errors for a chunk, log a warning and return `[]` for that chunk\n  rather than raising. The chunk is effectively dropped; no partial output\n  is recovered from the malformed response.\n- **`extraction_index_suffix`**: attribute name suffix used to preserve\n  extraction ordering (e.g. `\"_index\"` looks for attributes like\n  `medication_index` and sorts extractions by that value).\n- **`enable_fuzzy_alignment`** (default True): attempt fuzzy alignment when\n  exact substring match fails.\n- **`fuzzy_alignment_threshold`** (default 0.75): minimum fraction of\n  extraction tokens that must be matched in the source span.\n- **`fuzzy_alignment_algorithm`** (default `\"lcs\"`): algorithm for fuzzy\n  alignment. `\"lcs\"` uses longest-common-subsequence DP (O(n*m²)); `\"legacy\"`\n  uses the older difflib-based approach and is deprecated.\n- **`fuzzy_alignment_min_density`** (default 1/3): minimum ratio of matched\n  tokens to the span length. Filters out sparse matches where only a few\n  tokens align across a very long source span.\n- **`accept_match_lesser`**: accept `MATCH_LESSER` alignments — partial\n  exact matches where the model's `extraction_text` is longer than the span\n  that exactly matched in the source (e.g. the model returned a few extra\n  tokens at the edges). This is distinct from fuzzy alignment: the matched\n  portion is still an exact substring. Use it for truncation or\n  extra-token cases, not as a substitute for lowering\n  `fuzzy_alignment_threshold`.\n\n## When to tune these\n\n- **Too many `char_interval=None` extractions**: lower\n  `fuzzy_alignment_threshold` (e.g. 0.6). Enable `accept_match_lesser`\n  only if the model is returning extraction_text that contains an exact\n  source substring plus extra tokens.\n- **Fuzzy alignment matching the wrong span**: raise\n  `fuzzy_alignment_min_density` (e.g. 0.5) so matches must be denser.\n- **Performance-sensitive pipelines on long documents**: stick with `\"lcs\"`\n  and consider lowering `max_char_buffer` rather than disabling fuzzy\n  alignment entirely.\n\n<!-- File: skills/langextract-usage/SKILL.md (Tokens: ~1592 | Category: anthropic-skill) -->\n---\nname: langextract-usage\ndescription: How to use LangExtract to extract structured information from text. Use when writing code that calls lx.extract(), building extraction pipelines, defining examples, or troubleshooting alignment issues.\n---\n\n# LangExtract Usage\n\nLangExtract extracts structured information from unstructured text using LLMs.\nThe main entry point is `lx.extract()`. Every extraction needs at least one\nexample and input text. `prompt_description` is optional but recommended.\n\n## Install\n\n```bash\npip install langextract\n\n# For OpenAI model support:\npip install langextract[openai]\n```\n\n## API keys\n\n```bash\n# Gemini (checks GEMINI_API_KEY then LANGEXTRACT_API_KEY)\nexport GEMINI_API_KEY=\"your_key\"\n\n# OpenAI (checks OPENAI_API_KEY then LANGEXTRACT_API_KEY)\nexport OPENAI_API_KEY=\"your_key\"\n\n# Ollama: no API key needed, just a running Ollama server\n```\n\nAuto-routing + env-default resolution is tuned for GPT-style model IDs\n(`gpt-4*`, `gpt-5*`). For OpenAI-compatible endpoints or non-GPT IDs,\npass an explicit `ModelConfig` — see `references/providers.md`.\n\n## Basic extraction\n\n```python\nimport langextract as lx\n\nexamples = [\n    lx.data.ExampleData(\n        text=\"Patient takes lisinopril 10mg daily for hypertension.\",\n        extractions=[\n            lx.data.Extraction(\n                extraction_class=\"medication\",\n                extraction_text=\"lisinopril\",\n                attributes={\"dose\": \"10mg\", \"frequency\": \"daily\"},\n            ),\n            lx.data.Extraction(\n                extraction_class=\"condition\",\n                extraction_text=\"hypertension\",\n                attributes={\"status\": \"active\"},\n            ),\n        ],\n    )\n]\n\nresult = lx.extract(\n    text_or_documents=\"Patient is prescribed metformin 500mg twice daily.\",\n    prompt_description=\"Extract medications and conditions with attributes.\",\n    examples=examples,\n    model_id=\"gemini-2.5-flash\",\n)\n\nfor e in result.extractions:\n    print(e.extraction_class, e.extraction_text)\n    print(f\"  char_interval: {e.char_interval}\")\n    print(f\"  attributes: {e.attributes}\")\n```\n\nSee `examples/basic_extraction.py` for a runnable version and\n`examples/relationship_extraction.py` for using `extraction_class` +\n`attributes` to encode relationships between entities.\n\n## Writing good examples\n\nExamples drive model behavior. Follow these rules:\n\n1. `extraction_text` must be verbatim from the example text, not paraphrased\n2. List extractions in order of appearance in the text\n3. Each `extraction_class` should be consistent across examples\n4. Include attributes that match what you want extracted at runtime\n\nLangExtract can raise prompt-alignment warnings when an example's\n`extraction_text` values don't align cleanly to the example's `text`\n(failed alignment, or fuzzy/lesser rather than exact). The validator does\nnot enforce rules 2–4 above — those are guidance to steer the model's\noutput, not checked invariants.\n\nTo fail fast on alignment issues during development, pass these kwargs\ndirectly to `lx.extract()` (both default to permissive):\n\n```python\nfrom langextract.prompt_validation import PromptValidationLevel\n\nresult = lx.extract(\n    ...,\n    prompt_validation_level=PromptValidationLevel.ERROR,  # default: WARNING\n    prompt_validation_strict=True,                          # default: False\n)\n```\n\nSee `references/prompt-validation.md` for level semantics and strict-mode\nbehavior.\n\n## Key parameters\n\n```python\nresult = lx.extract(\n    text_or_documents=text,          # str, URL, or list of Documents\n    fetch_urls=False,                 # True to fetch a URL input\n    prompt_description=prompt,        # what to extract (optional)\n    examples=examples,                # few-shot examples (required)\n    model_id=\"gemini-2.5-flash\",     # model to use\n    extraction_passes=1,              # >1 for higher recall (costs more)\n    max_char_buffer=1000,             # chunk size\n    batch_length=10,                  # chunks per batch\n    max_workers=10,                   # parallel workers (provider-dependent)\n    context_window_chars=None,        # cross-chunk context for coreference\n)\n```\n\n- `text_or_documents` accepts a URL string, which is fetched only when\n  `fetch_urls=True`; otherwise it is treated as text. Only enable fetching\n  for URLs from a trusted source, in a sandboxed process.\n- For full parallelism, keep `batch_length >= max_workers`. Parallel\n  processing via `max_workers` is provider-dependent; some providers\n  parallelize batched prompts, while others (such as the current Ollama\n  provider) process them sequentially.\n- `context_window_chars` includes characters from the previous chunk as\n  context for the current one, which helps with coreference and entity\n  continuity across chunk boundaries.\n- For multiple documents, pass a list of `lx.data.Document` — see\n  `examples/multiple_documents.py`.\n\n## Working with results\n\n```python\n# Filter to grounded extractions only (have source positions)\ngrounded = [e for e in result.extractions if e.char_interval]\n\n# Access source position\nfor e in grounded:\n    start = e.char_interval.start_pos\n    end = e.char_interval.end_pos\n    matched_text = result.text[start:end]\n\n# Save to JSONL\nlx.io.save_annotated_documents(\n    [result], output_name=\"results.jsonl\", output_dir=\".\"\n)\n\n# Visualize from JSONL (shows first document)\nhtml = lx.visualize(\"results.jsonl\")\nwith open(\"visualization.html\", \"w\", encoding=\"utf-8\") as f:\n    if hasattr(html, \"data\"):\n        f.write(html.data)  # Jupyter/Colab\n    else:\n        f.write(html)\n\n# Or visualize an AnnotatedDocument directly\nhtml = lx.visualize(result)\n```\n\n## Provider selection\n\nThe default is Gemini. For other providers, see `references/providers.md`,\nwhich covers:\n\n- OpenAI (JSON mode; fence behavior auto-configured)\n- Ollama (local models, `model_url`)\n- `ModelConfig` for advanced provider_kwargs (custom `base_url`, etc.)\n- Custom provider plugins via `router.register()`\n\n## Common issues\n\n**Extractions with `char_interval=None`**: the extraction could not be\nlocated in the source text. Common causes include paraphrased output,\nalignment misses, or hallucinated entities. Filter with\n`[e for e in result.extractions if e.char_interval]`. To tune alignment,\nsee `references/resolver-params.md`.\n\n**Prompt alignment warnings**: your examples have `extraction_text` that\ndoesn't match the example text verbatim. Fix the examples, or see\n`references/prompt-validation.md` to fail fast during development.\n\n**Slow on long documents**: `extraction_passes > 1` multiplies processing\ntime. Start with 1 and increase only if recall is insufficient.\n\n**Model selection**: `gemini-2.5-flash` is recommended for most tasks;\n`gemini-2.5-pro` for complex reasoning.\n\n## Further reading\n\n- `references/providers.md` — OpenAI, Ollama, ModelConfig, custom plugins\n- `references/resolver-params.md` — fuzzy alignment tuning\n- `references/prompt-validation.md` — catching example issues early\n- `examples/` — runnable scripts for each scenario above\n</yakaai_skills>"}