Understand DocETL caching
mainDocETL caches all LLM calls and partially-optimized plans to avoid redundant API calls and costs. Caches are stored in your home directory at:
.cache/docetl/general.cache/docetl/llm
repository·main·Indexed 26 days ago
https://github.com/ucbepic/docetlA declarative and agentic framework for processing large collections of structured and unstructured data using LLMs. Version 0.3.0 provides operators such as map, reduce, and filter, and includes a reasoning optimizer that automatically optimizes pipelines for cost and accuracy using directives. It supports a Python API, YAML-based low-code configurations, and the DocWrangler visual playground for interactive prompt development.
DocETL caches all LLM calls and partially-optimized plans to avoid redundant API calls and costs. Caches are stored in your home directory at:
.cache/docetl/general.cache/docetl/llmDocETL automatically applies equivalence-preserving rewrites to your pipeline's logical plan before execution. These rewrites reorder operations to reduce LLM costs without changing the final output. Unlike MOAR, which optimizes for accuracy/cost trade-offs offline, plan rewrites are applied automatically at the start of every run.
Key rewrite types include:
keep (filter) operation below an LLM summarize (map) operation if the filter does not depend on fields written by the map. This ensures the LLM only processes rows that will ultimately be kept.sample with method: first) below one-to-one operations so upstream LLM calls only run on the rows that survive the head.DocETL automatically performs plan rewrites at the start of every run. This mechanism reorders your pipeline when DocETL can prove the output remains unchanged. For example, it may move a filter before an expensive map so the map only processes rows that pass the filter.
Key Characteristics:
The unnest operation expands an array field or a dictionary in the input data into multiple items, allowing individual elements to be processed separately in subsequent steps.
Behavioral differences:
expand_fields parameter. The original nested dictionary is also preserved.Note that unnest does not have an output schema; it modifies the data structure in place.
The topk operation retrieves the most relevant items from a dataset. It is used for tasks like finding documents for a query, filtering datasets, RAG pipelines, or recommendations.
Supported retrieval methods:
embedding: Semantic similarity (meaning-based).fts: Keyword-based retrieval using BM25.llm_compare: LLM-based ranking for complex reasoning or multi-factor comparison.Note: In the Python API, topk does not have a dedicated Frame method. Instead, you define it within the config["operations"] dictionary and reference it in a pipeline step using DSLRunner.
A retriever indexes a dataset once and, for each item an operation processes, searches the index and injects the top matches into the prompt as {{ retrieval_context }}. This is useful for providing relevant information from a large knowledge base without exceeding context windows.
Key characteristics:
{{ retrieval_context }}, DocETL appends the retrieved matches to the prompt automatically.The fastest way to start the DocWrangler playground is using Docker. This method sets up a persistent Docker volume, builds the DocETL image, and runs both the UI (at http://localhost:3000) and the API (at http://localhost:8000).
Create a .env file in the root directory for the FastAPI backend:
# Required: API key for your preferred LLM provider (OpenAI, Anthropic, etc)
OPENAI_API_KEY=your_api_key_here
BACKEND_ALLOW_ORIGINS=http://localhost:3000,http://127.0.0.1:3000
BACKEND_HOST=localhost
BACKEND_PORT=8000
BACKEND_RELOAD=True
FRONTEND_HOST=localhost
FRONTEND_PORT=3000Create a .env.local file in the website directory for the frontend:
# Optional: Required for AI assistant chatbot and prompt engineering tools (OpenAI only)
OPENAI_API_KEY=sk-xxx
OPENAI_API_BASE=https://api.openai.com/v1
MODEL_NAME=gpt-4o-mini
NEXT_PUBLIC_BACKEND_HOST=localhost
NEXT_PUBLIC_BACKEND_PORT=8000To start the playground:
make dockerTo remove all Docker resources (including the persistent data volume):
make docker-cleanThe .semantic accessor allows you to run DocETL operations directly on pandas DataFrames. It serves as a convenience layer for quick, single-operation tasks. For complex, multi-step pipelines where optimization is required, use the DocETL Python API or YAML instead.
To use it, install docetl via pip and ensure you have pandas installed.
pip install docetlDocWrangler is a visual playground for interactive prompt development. It allows you to edit prompts and see results in real time.
When groups are too large for full processing, use value_sampling to select a representative subset of the data.
Available Methods:
random: Randomly select a subset of values.first_n: Select the first N values.cluster: Use K-means clustering to select representative samples.sem_sim: Select samples based on semantic similarity to a query.For sem_sim (semantic similarity), you must provide embedding_model, embedding_keys (the fields to embed), and query_text.
frame = frame.reduce(
name="sampled_reduce_sem_sim",
reduce_key="product_id",
prompt="""Summarize the reviews for product {{ inputs[0].product_id }}, focusing on comments about battery life and performance:
{% for item in inputs %}
Review {{ loop.index }}: {{ item.review }}
{% endfor %}",""",
value_sampling={
"enabled": True,
"method": "sem_sim",
"sample_size": 30,
"embedding_model": "text-embedding-3-small",
"embedding_keys": ["review"],
"query_text": "Battery life and performance",
},
output={"schema": {"summary": "string"}},
)The Python API is recommended for production code, notebooks, and scripting. You can define pipelines using operators like map and reduce.
Key features include:
default_model.rate_limits for llm_call and llm_tokens.read_json to load data..map() for per-item operations with a prompt and output schema..reduce() to aggregate data based on a reduce_key..show() (for a sample) or .collect() (for a full run).pipeline.total_cost to see the execution cost.import docetl
docetl.default_model = "gpt-4o-mini"
docetl.rate_limits = {
"llm_call": [{"count": 500, "per": 1, "unit": "minute"}],
"llm_tokens": [{"count": 200_000, "per": 1, "unit": "minute"}],
}
# Classify support tickets, then summarize each category
pipeline = docetl.read_json("tickets.json")
pipeline = pipeline.map(
prompt="Classify this support ticket: {{ input.text }}",
output={"schema": {"category": "str", "priority": "str"}},
)
pipeline = pipeline.reduce(
reduce_key="category",
prompt="Summarize these tickets: {% for t in inputs %}{{ t.text }}{% endfor %}",
output={"schema": {"summary": "str"}},
)
pipeline.schema() # {'category': 'str', 'summary': 'str'}
pipeline.show() # run on 5 docs and print results
rows = pipeline.collect() # full run
print(f"Cost: ${pipeline.total_cost:.4f}")To optimize your DocETL pipeline using MOAR, you must provide an evaluation function that reads pipeline output and returns numeric metrics. MOAR uses a specific metric from your returned dictionary (defined by metric_key) as the accuracy metric for optimization.
Single-argument signature: Use this if you only need the pipeline output. The function receives results_path (the path to the JSON file containing pipeline output).
Note: Pipeline output often includes original input data (e.g., a src attribute), so you may not need the original dataset file separately.
Two-argument signature: Use this if you need to compare output against the original dataset. The function receives dataset_path and results_path automatically.
Your function must return a dictionary of numeric metrics. The key provided to metric_key during optimization must exist in this dictionary.