The Python API lets you build, run, and optimize DocETL pipelines with chainable operations.
Deprecated: the typed Pipeline class
The older object API (from docetl.api import Pipeline with MapOp, ReduceOp, etc.) is deprecated in favor of the Frame API documented on this page.
Set global defaults as module-level attributes:
| docetl.default_model | str | None | Default LLM model for all operations |
| docetl.agent_model | str | None | Model for optimizer rewrites |
| docetl.max_threads | int | cpu_count * 4 | Concurrent threads |
| docetl.bypass_cache | bool | False | Skip LLM cache |
| docetl.intermediate_dir | str | None | Directory for intermediate results (a relative path resolves against the working directory at run time) |
| docetl.rate_limits | dict | None | Rate limits per model |
| docetl.fallback_models | list[str] | None | Fallback chain on failure |
| docetl.fallback_embedding_models | list[str] | None | Fallback embedding models |
| docetl.system_prompt | dict | None | {"dataset_description": ..., "persona": ...} applied to all operations |
Precedence. Settings layer from most to least specific: a per-operation parameter (e.g. model= on .map()) beats per-pipeline settings carried by a Frame (set when loading a YAML via Frame.from_yaml), which beat the module-level docetl.* globals above, which beat built-in defaults. Loading a YAML never changes the globals — its settings travel with that Frame only.
| docetl.read_json(path) | Load from JSON file |
| docetl.read_csv(path) | Load from CSV file |
| docetl.read_parquet(path) | Load from Parquet file |
| docetl.read_dir(path) | One row per file in a directory (recursive): text is the file's content, plus filename and path. PDF/Word/PowerPoint/Excel are converted to text; other files read as UTF-8 |
| docetl.from_list(data) | Load from a list of dicts |
| docetl.Frame.from_yaml(path) | Load from a YAML pipeline config |
All return a Frame.
A lazy pipeline — operations are recorded but not executed until a terminal action is called. Frames are immutable; every operation returns a new Frame.
Applies an LLM prompt to each document independently.
| prompt | str | — | Jinja2 template. Access fields via {{ input.key }}. |
| output | dict | — | Output schema, e.g. {"schema": {"field": "str"}} |
| model | str | None | Override default model |
| validate | list[str \| callable] | None | Validators: expression strings over output, or callables taking the output dict (callables can't be exported to YAML) |
| num_retries_on_validate_failure | int | None | Retries on validation failure |
| sample | int | None | Process only N documents |
| agent | docetl.Agent | None | Tool-equipped agent using the OpenAI Agents SDK |
| drop_keys | list[str] | None | Keys to remove from output |
| timeout | int | None | Timeout per LLM call (seconds) |
| max_batch_size | int | None | Batch size for batch processing |
| batch_prompt | str | None | Jinja2 template for batch mode |
| retriever | Retriever | None | Retriever for context augmentation |
| optimize | bool | None | Mark for optimization |
| limit | int | None | Max documents to process |
Keeps or removes documents based on an LLM prompt. Output schema must have one boolean field.
| prompt | str | — | Jinja2 template |
| output | dict | — | Schema with one boolean field |
| model | str | None | Override default model |
| validate | list[str \| callable] | None | Validators: expression strings or callables over the output dict |
| agent | docetl.Agent | None | Tool-equipped agent using the OpenAI Agents SDK |
| retriever | Retriever | None | Retriever for context augmentation |
| cascade | dict | None | Model cascade: run a cheap proxy (chat or embedding model) on all items and escalate only uncertain ones, with a statistical guarantee. Also available on resolve and equijoin. |
Groups documents by key and reduces each group with an LLM.
| reduce_key | str \| list[str] | — | Key(s) to group by. Use "_all" for one group. |
| prompt | str | — | Jinja2 template. Iterate with {% for item in inputs %}. |
| output | dict | — | Output schema |
| fold_prompt | str | None | Prompt for incremental folding |
| fold_batch_size | int | None | Items per fold iteration |
| merge_prompt | str | None | Prompt for merging fold results |
| pass_through | bool | None | Pass through non-reduced keys |
| associative | bool | None | Enable parallel reduction |
| agent | docetl.Agent | None | Tool-equipped agent using the OpenAI Agents SDK |
| retriever | Retriever | None | Retriever for context augmentation |
Use docetl.Agent when an operation should call tools over multiple turns before returning DocETL's structured output. DocETL adapts Python functions into OpenAI Agents SDK tools and routes the operation's LiteLLM model through the SDK's LiteLLM integration.
The model is still specified on the operation (model=) or through docetl.default_model; use LiteLLM model names such as azure/gpt-4o-mini, anthropic/..., or together_ai/.... The selected model/provider must work with the OpenAI Agents SDK LiteLLM integration and the requested tools. Plain Python function tools execute as trusted Python in your process; OpenAI Agents SDK sandbox/native tools may provide isolation where that SDK/backend supports it. Agent configs are Python-only and cannot be exported to YAML. See OpenAI's Agents SDK guide and tools guide for hosted tool behavior.
Agents can also expose specialist agents as tools. Use this when a manager agent should keep ownership of the DocETL output while delegating a bounded task:
The specialist uses the same operation-level LiteLLM model as the manager unless you pass an SDK-native tool object with its own model configuration. This follows OpenAI's agents-as-tools orchestration pattern.
For a persistent shell/sandbox filesystem on OpenAI, create a hosted container once and bind shell tools to it:
Reuse bash across a manager and its specialist subagents when they should read and write the same hosted filesystem. If you only need an ephemeral shell tool, use docetl.tools.bash(...), which uses container_auto. Pass durable data between DocETL operations through output schemas, not only through hidden sandbox files.
docetl.tools.Sandbox.create(...) is OpenAI-specific: it calls the OpenAI Containers API and returns shell tools using container_reference. It is not portable to Claude, Together, or other LiteLLM providers. For provider-portable tooling, use @docetl.tool Python functions, MCP tools, or provider-native SDK tools. See OpenAI's sandbox agents guide.
For an end-to-end example, see the Tool-Equipped Agents tutorial.
Deduplicates entities by pairwise LLM comparison.
| comparison_prompt | str | — | Jinja2 template comparing {{ input1 }} and {{ input2 }} |
| resolution_prompt | str | None | Prompt for resolving matched groups |
| output | dict | None | Output schema |
| blocking_keys | list[str] | None | Keys for blocking |
| blocking_threshold | float | None | Similarity threshold |
| embedding_model | str | None | Model for blocking embeddings |
| optimize | bool | None | Mark for optimization |
Extracts information from documents with line-level precision.
| prompt | str | — | Extraction prompt |
| document_keys | list[str] | — | Keys containing document text |
| retriever | Retriever | None | Retriever for context augmentation |
Runs multiple prompts on each document in parallel.
Joins two datasets by LLM comparison.
| .split(split_key, method, method_kwargs) | Split documents into chunks |
| .gather(content_key, doc_id_key, order_key) | Add surrounding context to chunks |
| .unnest(unnest_key) | Flatten a list field into separate rows |
| .cluster(embedding_keys) | Cluster documents by embedding similarity |
| .sample(samples, method) | Sample a subset of documents |
code takes any callable, e.g., a lambda, or a string of Python source defining a transform function (the YAML form).
| .code_map(code=lambda doc: {...}) | Per-document Python transform |
| .code_filter(code=lambda doc: bool(...)) | Per-document Python filter (return bool) |
| .code_reduce(reduce_key, code=lambda items: {...}) | Per-group Python aggregation |
Augment LLM operations with retrieved context from a LanceDB index.
| data | str \| list[dict] | — | File path or in-memory records to index (alternative to dataset) |
| dataset | str | — | Name of an existing pipeline dataset or step output to index |
| index_dir | str | — | Directory for the LanceDB index |
| index_types | list[str] | — | ["fts"], ["embedding"], or both |
| fts | dict | None | Full-text search config (index_phrase, query_phrase) |
| embedding | dict | None | Embedding config (model, index_phrase, query_phrase) |
| query | dict | None | Query config (mode, top_k) |
| build_index | str | "if_missing" | "if_missing", "always", or "never" |
Pass to any LLM operation via retriever=. Retrieved context is available as {{ retrieval_context }} in prompts.
Pass exactly one of data (a file path or list of dicts to index) or dataset (the name of an existing pipeline dataset — the frame's own input or a previous step's output, step_<operation_name>). See the Retrievers guide.
| frame.schema() | dict[str, str] | Output schema from operation definitions, including structural ops (split/unnest/gather/extract). Best-effort: code_* op outputs can't be known statically |
| frame.count() | int | Input count (no ops) or output count (executes if ops present) |
| frame.to_yaml() | str | Export pipeline as YAML config |
| frame.to_yaml(path) | str | Also write YAML to file |
| frame.to_python() | str | Export as Python source code |
| frame.show(max=5) | DataFrame | Run on a sample and print results. Works on bare datasets too. |
| frame.collect() | list[dict] | Execute the pipeline, return the result rows |
| frame.to_pandas() | DataFrame | Execute the pipeline, return a pandas DataFrame |
| frame.write_json(path) | None | Execute and write to JSON |
| frame.write_csv(path) | None | Execute and write to CSV |
| frame.write_parquet(path) | None | Execute and write to Parquet |
Terminal actions are memoized on the Frame: repeated calls with an unchanged configuration reuse the previous result instead of re-running the pipeline. Changing ops, in-memory data, or docetl.* settings invalidates the memo; edits to input files between calls are not detected.
| eval_fn | Callable | required | Scores pipeline output. Returns a dict of metrics. |
| metric_key | str | required | Key in eval_fn's return dict to optimize |
| models | list[str] | Auto-detect | LiteLLM model names to explore |
| agent_model | str | Auto-select | Model for rewrite agent |
| max_iterations | int | 20 | Search budget |
| save_dir | str | Temp dir | Where to save results |
| exploration_weight | float | 1.414 | UCB exploration constant |
| dataset_path | str | Pipeline's dataset | Sample dataset for optimization |
| max_threads | int | None | Max concurrent LLM calls per run |
| max_concurrent_agents | int | 3 | Parallel MCTS search agents |
Returns an optimized Frame. Access search results via optimized.search_results:
| .best() | OptimizedPipeline | Highest-accuracy solution |
| .cheapest() | OptimizedPipeline | Lowest-cost solution |
| .frontier | list[OptimizedPipeline] | All Pareto-optimal solutions |
| .to_df() | DataFrame | All explored plans |