Legal discovery is undergoing a rapid transformation. AI-powered workflows are now essential for handling the ever-increasing scale and complexity of evidence, communications, and contracts. As we covered in our complete guide to AI workflow automation for legal discovery, building robust, compliant, and efficient processes for data curation, preservation, and review is now a top priority for legal teams in 2026.
This deep-dive tutorial is your hands-on blueprint for implementing these AI workflows, covering the tools, code, and best practices you need to get started. Whether you're a legal technologist, developer, or IT lead, you'll learn how to:
- Curate and filter large data sets using AI
- Implement defensible preservation workflows
- Automate and accelerate the review process with LLMs and custom prompts
For more specialized workflows, see our guides on AI tools for automating legal contract reviews and legal prompt engineering for discovery.
Prerequisites
- Technical Skills: Basic Python scripting, command line usage, and familiarity with legal discovery concepts
- Tools & Platforms:
- Python 3.11+
- Jupyter Notebook or VSCode (optional, for code testing)
- Pandas & OpenAI Python SDK (
openaiv1.2+) - Elasticsearch 8.x (for search and indexing)
- Sample data set (emails, contracts, or chat logs in CSV/JSON format)
- Basic understanding of eDiscovery and data retention obligations
- Cloud/Infra: Access to a secure server or cloud VM (AWS, Azure, or on-prem) for running scripts and storing data
-
Set Up Your Environment
Start by preparing your workspace and installing the required tools.
1.1. Create a Python Virtual Environment
python3 -m venv venv source venv/bin/activate1.2. Install Required Packages
pip install pandas openai elasticsearch jupyter1.3. (Optional) Launch Jupyter Notebook
jupyter notebookScreenshot description: A Jupyter notebook with a code cell showing
import pandas as pdandimport openaisuccessfully executed. -
Ingest and Curate Data with AI
Data curation is the backbone of legal discovery workflows. We'll use Pandas for data wrangling, and OpenAI's GPT-4 for intelligent filtering and deduplication.
2.1. Load Your Data
import pandas as pd df = pd.read_csv('sample_emails.csv') # Replace with your data file print(df.head())2.2. Use GPT-4 to Identify Relevant Documents
We'll define a function that sends document text to GPT-4 via the OpenAI API, asking it to classify whether each document is potentially relevant to a given case.
import openai openai.api_key = 'sk-...' # Replace with your API key def classify_relevance(text, case_description): prompt = f"""You are a legal discovery assistant. Given the following case description: {case_description} Is the following document relevant? Reply 'Yes' or 'No' and briefly explain why. Document: {text} """ response = openai.chat.completions.create( model="gpt-4", messages=[{"role": "user", "content": prompt}], max_tokens=100 ) return response.choices[0].message.content case_desc = "A breach of contract dispute involving missed software delivery deadlines." df['gpt_relevance'] = df['body'].apply(lambda x: classify_relevance(x, case_desc)) print(df[['subject', 'gpt_relevance']].head())Screenshot description: DataFrame preview with a new
gpt_relevancecolumn showing "Yes - mentions delivery delays" or "No - unrelated topic".2.3. Filter and Deduplicate
df_filtered = df[df['gpt_relevance'].str.startswith('Yes')].drop_duplicates(subset=['body']) df_filtered.to_csv('curated_emails.csv', index=False) -
Preserve Data with Immutable Storage and Audit Trails
Defensible preservation is a core legal requirement. We'll use a combination of cryptographic hashing and Elasticsearch to ensure data integrity and auditability.
3.1. Generate Hashes for Chain-of-Custody
import hashlib def hash_document(text): return hashlib.sha256(text.encode('utf-8')).hexdigest() df_filtered['sha256'] = df_filtered['body'].apply(hash_document) df_filtered.to_csv('preserved_emails.csv', index=False)3.2. Index Documents in Elasticsearch
from elasticsearch import Elasticsearch es = Elasticsearch("http://localhost:9200") # Adjust for your infra for _, row in df_filtered.iterrows(): doc = { "subject": row['subject'], "body": row['body'], "sha256": row['sha256'], "timestamp": row['date'], "preserved_at": pd.Timestamp.now().isoformat() } es.index(index="legal_discovery_2026", document=doc)Screenshot description: Elasticsearch dashboard showing indexed documents with fields for
sha256,preserved_at, andsubject.For advanced litigation hold automation, see our guide to AI workflow automation for litigation hold.
-
Automate Document Review with LLMs
Large Language Models (LLMs) can accelerate first-pass review, privilege detection, and evidence tagging.
4.1. Build a Custom Review Prompt
def review_for_privilege(text): prompt = f"""You are a legal reviewer. Does the following email contain attorney-client privileged information? Reply 'Privileged', 'Not Privileged', or 'Unclear', and explain briefly. Email: {text} """ response = openai.chat.completions.create( model="gpt-4", messages=[{"role": "user", "content": prompt}], max_tokens=100 ) return response.choices[0].message.content df_filtered['privilege_flag'] = df_filtered['body'].apply(review_for_privilege) print(df_filtered[['subject', 'privilege_flag']].head())4.2. Tag and Export Results
df_filtered.to_csv('reviewed_emails.csv', index=False)Screenshot description: DataFrame with new
privilege_flagcolumn, showing "Privileged" or "Not Privileged" tags.For hands-on prompt engineering tips, see our 2026 guide to legal prompt engineering.
-
Audit, Trace, and Document the Workflow
Legal defensibility demands a clear audit trail. Record every step and store logs securely.
5.1. Log Actions and Results
import logging logging.basicConfig(filename='discovery_workflow.log', level=logging.INFO) def log_action(action, details): logging.info(f"{pd.Timestamp.now().isoformat()} - {action}: {details}") log_action("Curated", f"{len(df_filtered)} documents curated") log_action("Preserved", "Documents hashed and saved") log_action("Reviewed", "Privilege review complete")5.2. Store Chain-of-Custody Records
df_filtered[['sha256', 'subject', 'date', 'privilege_flag']].to_csv('chain_of_custody.csv', index=False)Screenshot description: A log file showing timestamps and actions, plus a
chain_of_custody.csvfile with hashes and review results.For privacy and compliance automation, see our regulatory essentials for discovery data privacy in 2026.
Common Issues & Troubleshooting
- OpenAI API Rate Limits: If you hit rate limits, batch your requests or add
time.sleep()between calls. - Elasticsearch Connection Errors: Ensure Elasticsearch is running and accessible. Check firewall and port settings.
- Data Format Issues: If your CSV/JSON structure differs, adjust field names in the code accordingly.
- Hash Mismatches: Always hash the exact text being preserved. Any whitespace or encoding changes will alter the hash.
- Privilege Review Inaccuracy: LLMs are not legal experts; always perform human validation on flagged documents. For best practices, see our article on AI workflows and human oversight.
Next Steps
You've now built the core of a modern, defensible AI-powered legal discovery workflow. From here, you can:
- Integrate with AI-powered evidence classification for advanced tagging and search.
- Expand to contract review automation—see 2026’s best tools for legal discovery AI workflows.
- Explore cross-domain AI workflow automation, such as finance or compliance workflows.
- Develop robust change management playbooks—see our guide on AI workflow automation change management.
For a full strategic overview, revisit the 2026 pillar guide to AI workflow automation for legal discovery.