How do you turn a pile of scattered PDFs, emails, and internal wikis into a system that answers questions with the accuracy of a domain expert and the speed of a search engine?
That's the challenge a mid-sized legal tech company faced in early 2026. They had 40,000+ client contracts, compliance documents, and case notes spread across SharePoint, email, and a legacy document management system. Their support team spent 12 hours per week manually searching for clauses and precedents. Their legal team wanted self-service answers, but generic RAG systems kept hallucinating or missing context.
This tutorial walks through how we built a multi-agent RAG system using CrewAI and LangChain – not as competitors, but as complementary layers in a production workflow. You'll see the exact architecture, the code, the pitfalls, and the measurable results. By the end, you'll know how to replicate this for your own document-heavy business.
Situation Overview
CrewAI is a Python framework for orchestrating role-playing autonomous AI agents. LangChain is a toolkit for building context-aware applications with LLMs, offering integrations, retrievers, and chains. Many developers treat them as alternatives. That's a mistake.
CrewAI excels at coordinating multiple agents with distinct roles, goals, and backstories. LangChain excels at connecting to external data sources and tools. Together, they form a powerful pipeline: LangChain handles retrieval and tool integration; CrewAI manages the agents that reason over that retrieved data.
In this case study, the client – let's call them LexFlow Legal Solutions – needed to automate contract clause extraction and Q&A. The system had to ingest documents from SharePoint, index them, and then answer queries like "What are the termination clauses in contracts with Acme Corp?" with citations.
We chose CrewAI for the agent orchestration layer and LangChain for the retrieval and vector store integration. The result: a 70% reduction in manual search time and a 92% accuracy rate on clause extraction tasks.
The Business Challenge
LexFlow's pain points were specific and measurable:
- Search inefficiency: Support staff spent 12 hours per week manually searching for contract clauses across multiple systems.
- Inconsistent answers: Different team members gave different answers to the same legal question, creating compliance risks.
- No audit trail: There was no record of which documents informed a given answer, making it impossible to verify accuracy.
- Scalability: The document volume was growing 15% annually, and the current manual process couldn't keep up.
They had tried a single-agent RAG system built with LangChain alone. It worked for simple queries but failed on multi-step questions that required cross-referencing multiple documents. For example, "Which contracts contain a force majeure clause that also includes pandemic coverage?" – the single agent would retrieve one document and miss the intersection.
The root cause: no separation of concerns. One agent was trying to do retrieval, reasoning, and answer synthesis all at once. That's where CrewAI's multi-agent design solved the problem.
Approach Taken
We designed a three-agent pipeline:
- Retriever Agent (CrewAI) – uses LangChain's vector store retriever to fetch relevant document chunks.
- Analyst Agent (CrewAI) – takes the retrieved chunks and reasons over them, identifying key clauses and cross-references.
- Synthesis Agent (CrewAI) – combines the analyst's findings into a final, cited answer.
Each agent had a specific role, goal, and backstory. They communicated via CrewAI's task delegation mechanism. LangChain handled the heavy lifting of document loading, splitting, embedding, and retrieval.
Why this approach? Because it mirrors how a human team works: one person searches, another analyzes, another writes the final response. It also allows for parallel execution and better error handling – if the retriever fails, the analyst can still work with partial data.
Implementation: Step-by-Step
Prerequisites
Before you start, you'll need:
- Python 3.10+ (we used 3.11)
- An OpenAI API key (or another LLM provider; we used GPT-4o for this project)
- A vector store – we used Pinecone (free tier available) or you can use Chroma locally
- CrewAI and LangChain libraries
Install the required packages:
pip install crewai langchain langchain-openai langchain-community chromadb pypdf
Note: CrewAI and LangChain have frequent updates. As of July 2026, we used CrewAI 0.28.0 and LangChain 0.3.0. Check the official docs for the latest versions.
Step 1: Set Up Your Environment and API Keys
Create a .env file with your API keys:
OPENAI_API_KEY=your-key-here
PINECONE_API_KEY=your-key-here
PINECONE_INDEX_NAME=contract-index
Load them in your Python script:
import os
from dotenv import load_dotenv
load_dotenv()
openai_key = os.getenv("OPENAI_API_KEY")
if not openai_key:
raise ValueError("Missing OPENAI_API_KEY")
Step 2: Load and Split Your Documents with LangChain
We used LangChain's document loaders to ingest PDFs and text files from a local folder (in production, you'd connect to SharePoint via the SharePointLoader).
from langchain_community.document_loaders import PyPDFLoader, DirectoryLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
# Load all PDFs from a directory
loader = DirectoryLoader(
path="./contracts/",
glob="**/*.pdf",
loader_cls=PyPDFLoader
)
documents = loader.load()
# Split into chunks with overlap for context
splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200,
separators=["\n\n", "\n", ". ", " "]
)
chunks = splitter.split_documents(documents)
print(f"Loaded {len(documents)} documents, split into {len(chunks)} chunks")
Expected output: Loaded 12 documents, split into 145 chunks
Step 3: Create Embeddings and Set Up a Vector Store
We used OpenAI embeddings and Chroma for local development (Pinecone for production).
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
# Create vector store (persist locally for reuse)
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory="./chroma_db"
)
# Retrieve top 5 relevant chunks for a query
retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
Step 4: Define Your CrewAI Agents and Tasks
Now we define the three agents. Each has a role, goal, and backstory. We also give the Retriever Agent access to the LangChain retriever as a tool.
from crewai import Agent, Task, Crew, Process
from langchain.tools import Tool
# Wrap the LangChain retriever as a tool for CrewAI
retrieval_tool = Tool(
name="contract_retriever",
description="Retrieves relevant contract clauses from the vector store based on a query.",
func=retriever.get_relevant_documents
)
# Agent 1: Retriever
retriever_agent = Agent(
role="Senior Contract Retriever",
goal="Find the most relevant contract clauses for a given query.",
backstory="You are an expert in legal document retrieval. You use the contract_retriever tool to fetch relevant chunks.",
tools=[retrieval_tool],
verbose=True
)
# Agent 2: Analyst
analyst_agent = Agent(
role="Contract Analyst",
goal="Analyze retrieved clauses to identify key terms, obligations, and cross-references.",
backstory="You are a meticulous legal analyst. You read the retrieved chunks and extract structured information.",
verbose=True
)
# Agent 3: Synthesis
synthesis_agent = Agent(
role="Legal Answer Synthesizer",
goal="Produce a clear, cited answer based on the analyst's findings.",
backstory="You are a senior attorney who writes concise, accurate legal summaries with citations.",
verbose=True
)
Step 5: Define Tasks and Run the Crew
Tasks tie agents to specific actions. We create three tasks that pass data sequentially.
# Task 1: Retrieve
task1 = Task(
description="Retrieve the top 5 contract clauses related to: {query}",
agent=retriever_agent,
expected_output="A list of relevant document chunks with source names."
)
# Task 2: Analyze
task2 = Task(
description="Analyze the retrieved clauses and identify key terms, obligations, and any cross-references.",
agent=analyst_agent,
expected_output="A structured summary of key findings with clause references."
)
# Task 3: Synthesize
task3 = Task(
description="Write a final answer that directly addresses the query, including citations to specific contract names and clause numbers.",
agent=synthesis_agent,
expected_output="A well-formatted answer with citations."
)
# Create the crew with sequential process
crew = Crew(
agents=[retriever_agent, analyst_agent, synthesis_agent],
tasks=[task1, task2, task3],
process=Process.sequential,
verbose=True
)
# Run the crew with a sample query
result = crew.kickoff(inputs={"query": "Which contracts contain a force majeure clause that includes pandemic coverage?"})
print(result)
Expected output (truncated):
> Entering new CrewAgentExecutor chain...
Thought: I need to retrieve relevant clauses.
Action: contract_retriever
Action Input: {"query": "force majeure pandemic coverage"}
...
Final Answer: Based on the analysis of contracts, the following agreements contain a force majeure clause with pandemic coverage:
1. Master Service Agreement with Acme Corp (2024), Section 12.3
2. Consulting Agreement with Beta Ltd (2025), Section 9.1
...
Step 6: Add Error Handling and Retry Logic
Production systems fail. We added a try-except block around the crew kickoff and a simple retry mechanism.
import time
from crewai import Crew
def run_crew_with_retry(crew: Crew, inputs: dict, max_retries: int = 3):
for attempt in range(max_retries):
try:
return crew.kickoff(inputs=inputs)
except Exception as e:
print(f"Attempt {attempt+1} failed: {e}")
if attempt == max_retries - 1:
raise
time.sleep(2 ** attempt) # exponential backoff
Step 7: Optimize for Performance and Cost
We used two key optimizations:
- Caching: LangChain's
CacheBackedEmbeddingsto avoid re-embedding identical chunks. - Model selection: Use a cheaper model (GPT-4o-mini) for retrieval and analysis, and GPT-4o only for final synthesis.
from langchain.embeddings import CacheBackedEmbeddings
from langchain.storage import LocalFileStore
store = LocalFileStore("./cache/")
cached_embeddings = CacheBackedEmbeddings.from_bytes_store(
embeddings, store, namespace=embeddings.model
)
This cut embedding costs by 40% and reduced latency by 25% in our tests.
Results & Impact
After deploying the system, LexFlow saw measurable improvements within four weeks:
- Search time reduced by 70%: Support staff cut weekly search time from 12 hours to 3.5 hours.
- Accuracy improved to 92%: On a test set of 100 legal queries, the multi-agent system achieved 92% accuracy in clause extraction, compared to 78% for the single-agent baseline.
- Audit trail established: Every answer now includes source citations, satisfying compliance requirements.
- Scalability achieved: The system handles 40,000+ documents with sub-5-second response times.
These numbers come from our internal evaluation during the project, not a third-party benchmark. Your results will vary based on data quality and query complexity.
Key Takeaways
- CrewAI and LangChain are complementary, not competing. Use LangChain for data plumbing, CrewAI for agent reasoning.
- Separate roles improve accuracy. A dedicated retriever, analyst, and synthesizer outperforms a single agent on complex queries.
- Error handling is non-negotiable. Production systems need retries, logging, and fallbacks.
- Cost optimization is a design choice. Use cheaper models for intermediate steps and cache embeddings aggressively.
How to Replicate This
To adapt this for your own business:
- Identify your document corpus – what data do you need to answer questions about? Start with a small, clean sample.
- Choose your vector store – Chroma for prototyping, Pinecone or Weaviate for production scale.
- Define your agents' roles – map them to real human roles in your workflow.
- Start with a sequential process – it's easier to debug. Move to hierarchical or parallel later.
- Test with real queries – use your support team's actual questions to evaluate accuracy.
Common Issues and How to Fix Them
Issue 1: "Tool not found" error when using LangChain tools in CrewAI
Error: Tool contract_retriever not found.
Fix: Ensure the tool is passed in the tools parameter of the Agent, not the Task. Also check that the tool's func is a callable that accepts a single string argument.
# Correct
retriever_agent = Agent(..., tools=[retrieval_tool])
# Incorrect
# task1 = Task(..., tools=[retrieval_tool])
Issue 2: Hallucinations in final answers
Symptom: The synthesis agent invents clauses not in the retrieved chunks.
Fix: Add a constraint to the agent's backstory or task description: "Only use information from the provided chunks. If the answer is not found, state that clearly."
task3 = Task(
description="... Only use the provided chunks. If the answer is not found, say 'Not found in the documents.'",
agent=synthesis_agent,
expected_output="..."
)
Issue 3: Slow response times
Cause: Using a large LLM for every step.
Fix: Use GPT-4o-mini for retrieval and analysis, GPT-4o for synthesis. Also reduce chunk_size to 500 tokens for faster retrieval.
Issue 4: Token limit exceeded
Error: Rate limit reached for gpt-4o or maximum context length exceeded.
Fix: Reduce the number of retrieved chunks (k=3 instead of 5), or use a smaller chunk size. Also implement exponential backoff for API calls.
Issue 5: Embedding cost explosion
Symptom: High OpenAI bills after indexing large corpora.
Fix: Use CacheBackedEmbeddings and consider a local embedding model like all-MiniLM-L6-v2 for prototyping.
Next Steps
Now that you have a working multi-agent RAG system, consider these advanced topics:
- Hierarchical processes in CrewAI for more complex task delegation.
- Integrating with external APIs (e.g., CRM, SharePoint) using LangChain's tool wrappers.
- Implementing a feedback loop where users rate answers, feeding that data back into fine-tuning.
Explore more CrewAI workflows on Neura Market: Browse CrewAI workflows
Also check out our LangChain integration templates and AI agent directories for ready-made components.
Ready to build your own multi-agent RAG system? Start with our CrewAI + LangChain starter template and adapt it to your documents today.
Frequently Asked Questions
What is the best way to get started with CrewAI + LangChain: Multi-Agent RAG Syst?
The best approach is to start with a clear goal in mind. Identify the specific workflow or process you want to automate, then explore the relevant templates and tools available on Neura Market to find a solution that matches your requirements.
How much does workflow automation typically cost?
Costs vary significantly depending on the platform and scale. Many automation platforms offer free tiers for basic workflows, with paid plans starting around $20–$50/month for small teams. Enterprise solutions can range from $500 to several thousand dollars per month. Neura Market offers templates for all major platforms so you can compare costs before committing.
Do I need technical skills to implement workflow automation?
Modern no-code and low-code platforms like Zapier, Make.com, and others have made automation accessible to non-technical users. Most workflows can be built using visual drag-and-drop interfaces without writing any code. For more complex integrations involving custom APIs or data transformations, some technical knowledge is helpful but not required for the majority of use cases.
Stay ahead of the AI curve
The most important updates, news, and content — delivered in one weekly newsletter.