Using CrewAI with Elasticsearch

Learn how to create an Elasticsearch agent with CrewAI for your agent team and perform market research.

CrewAI is a framework for orchestrating agents that uses role-playing for them to work together on complex tasks.

If you want to read more about agents and how they work, I recommend you read this article.

CrewAI claims to be faster and simpler than similar frameworks like LangGraph since it does not need as much boilerplate code or additional code to orchestrate agents, like Autogen. Additionally, Langchain tools are compatible with CrewAI, opening many possibilities.

CrewAI has a variety of use cases, including research agents, stock market analysis, lead catchers, contract analysis, website generation, travel recommendations, etc.

In this article, you´ll create an agent that uses Elasticsearch as a data search tool to collaborate with other agents and conduct market research on our Elasticsearch products.

Based on a concept like summer clothes, an expert agent will search in Elasticsearch for the most semantically similar products, while a researcher agent will search online for websites and products. Finally, a writer agent will combine everything into a market analysis report.

You can find a Notebook with the complete example here.

To get the crew agent functioning, complete the following steps:

Steps

  1. Install and import packages
  2. Prepare data
  3. Create Elasticsearch CrewAI tool
  4. Configure Agents
  5. Configure tasks

Install and import packages

pip install elasticsearch==8.17 'crewai[tools]'
import json
import os
from getpass import getpass
from elasticsearch import Elasticsearch
from elasticsearch.helpers import bulk
from crewai import Agent, Crew, Task
from crewai.tools import tool
from crewai_tools import SerperDevTool, WebsiteSearchTool

We import SerperDevTool to search on the internet for websites related to our queries using the Serper API, and WebsiteSearchTool to do a RAG search within the found content.

Serper provides 2,500 free queries you can claim here.

Prepare data

Elasticsearch client

os.environ["ELASTIC_ENDPOINT"] = "your_es_url"
os.environ["ELASTIC_API_KEY"] = "es_api_key"
_client = Elasticsearch(
os.environ["ELASTIC_ENDPOINT"],
api_key=os.environ["ELASTIC_API_KEY"],
)

Create inference endpoint

To enable semantic search capabilities, you need to create an inference endpoint using ELSER:

_client.options(
request_timeout=60, max_retries=3, retry_on_timeout=True
).inference.put(
task_type="sparse_embedding",
inference_id="clothes-inference",
body={
"service": "elasticsearch",
"service_settings": {
"adaptive_allocations": {
"enabled": True
},
"num_threads": 1,
"model_id": ".elser_model_2"
}
}
)

Create mappings

Now, we are going to apply the ELSER model into a single semantic_text field to enable the agent to run hybrid queries.

_client.indices.create(
index="summer-clothes",
body={
"mappings": {
"properties": {
"title": {
"type": "text",
"copy_to": "semantic_field"
},
"description": {
"type": "text",
"copy_to": "semantic_field"
},
"price": {
"type": "float"
},
"semantic_field": {
"type": "semantic_text",
"inference_id": "clothes-inference"
}
}
}
}
)

Index data

We are going to store some data about clothes so we can compare our source with the information the researcher agent can find on the internet.

documents = [
{
"title": "Twist-Detail Crop Top",
"description": "Fitted crop top in woven, patterned fabric with linen content. Wide shoulder straps, sweetheart neckline, and gathered side seams for a gently draped effect. Twisted detail at center bust, cut-out section at front, and wide smocking at back. Lined",
"price": 34.99
},
{
"title": "Rib-knit Tank Top",
"description": "Short, fitted top in a soft rib knit. Extra-narrow shoulder straps and a square neckline.",
"price": 7.49
},
{
"title": "Linen-blend Shorts",
"description": "Shorts in an airy, woven linen blend. High, ruffle-trimmed waist, narrow drawstring and covered elastic at waistband, and discreet side pockets.",
"price": 13.99
},
{
"title": "Twill Cargo Shorts",
"description": "Fitted shorts in cotton twill with a V-shaped yoke at front and back. High waist, zip fly with button, and patch front pockets.",
"price": 20.99
},
{
"title": "Slim Fit Ribbed Tank Top",
"description": "Slim-fit tank top in medium weight, ribbed cotton-blend jersey with a fitted silhouette. Straight-cut hem.",
"price": 8.49
},
{
"title": "Relaxed Fit Linen Resort Shirt",
"description": "Relaxed-fit shirt in airy linen. Resort collar, buttons without placket, yoke at back, and short sleeves. Straight-cut hem. Fabric made from linen is breathable, looks great when ironed or wrinkled, and softens over time.",
"price": 17.99
},
{
"title": "Swim Shorts",
"description": "Swim shorts in woven fabric. Drawstring and covered elastic at waistband, side pockets, and a back pocket with hook-loop fastener. Small slit at sides. Mesh liner shorts.",
"price": 14.99
},
{
"title": "Baggy Fit Cargo Shorts",
"description": "Baggy-fit cargo shorts in cotton canvas with a generous but not oversized silhouette. Zip fly with button, diagonal side pockets, back pockets with flap and snap fasteners, and bellows leg pockets with snap fasteners.",
"price": 20.99
},
{
"title": "Muslin Shorts",
"description": "Shorts in airy cotton muslin. High, ruffle-trimmed waist, covered elastic at waistband, and an extra-narrow drawstring with a bead at ends. Discreet side pockets.",
"price": 15.99
},
{
"title": "Oversized Lyocell-blend Dress",
"description": "Short, oversized dress in a woven lyocell blend. Gathered, low-cut V-neck with extra-narrow ties at front, 3/4-length, raglan-cut balloon sleeves with narrow elastic at cuffs, and seams at waist and hips with delicate piping. Unlined.",
"price": 38.99
}
]
def build_data():
for doc in documents:
yield {
"_index": "summer-clothes",
"_source": doc
}
try:
success, errors = bulk(_client, build_data())
print(f"{success} documents indexed successfully")
if errors:
print("Errors during indexing:", errors)
except Exception as e:
print(f"Error: {str(e)}")

Create Elasticsearch CrewAI tool

The CrewAI’s tool decorator simplifies turning regular Python functions into tools that agents can use. Here's how we create an Elasticsearch search tool:

@tool("es tool")
def elasticsearch_tool(question: str) -> str:
"""
Search in Elasticsearch using hybrid search capabilities.
Args:
question (str): The search query to be semantically matched
Returns:
str: Concatenated hits from Elasticsearch as string JSON
"""
response = _client.search(
index="summer-clothes",
body={
"size": 10,
"_source": {"includes": ["description", "title", "price"]},
"retriever": {
"rrf": {
"retrievers": [
{"standard": {"query": {"match": {"title": question}}}},
{
"standard": {
"query": {
"semantic": {
"field": "semantic_field",
"query": question,
}
}
}
},
]
}
},
},
)
hits = response["hits"]["hits"]
if not hits:
return ""
result = json.dumps([hit["_source"] for hit in hits], indent=2)
return result

Import other needed tools and credentials

Now, we instantiate the tools we prepared at the beginning to search on the internet and then do RAG within the found content.

You also need an OpenAI API Key for the LLM communication.

os.environ["SERPER_API_KEY"] = "your-key"
os.environ["OPENAI_API_KEY"] = "your-key"
search_tool = SerperDevTool()
web_rag_tool = WebsiteSearchTool()

Configure Agents

Now, you need to define the agents:

  • Retriever: able to search in Elasticsearch using the tool created before.
  • Researcher: uses search_tool to search on the internet.
  • Writer: summarizes the info from the other two agents into a Markdown blog file.
es_retriever_agent = Agent(
role="Retriever",
goal="Retrieve Elasticsearch documents",
backstory="You are an expert researcher",
tools=[elasticsearch_tool],
verbose=True,
)
internet_researcher_agent = Agent(
role="Research analyst",
goal="Provide up-to-date market analysis of the industry",
backstory="You are an expert analyst",
tools=[search_tool, web_rag_tool],
verbose=True,
)
writer_agent = Agent(
role="Content Writer",
goal="Craft engaging blog posts about the information gathered",
backstory="A skilled writer with a passion for writing about fashion",
tools=[],
verbose=True,
)

Configure tasks

Now that you have defined the agents and tools, you need to create tasks for each agent. You will specify the different tasks to include content sources so the writer agent can quote them to make sure both the retriever and researcher agent are contributing with information.

es_retriever_task = Task(
description="Retrieve documents from the Elasticsearch index.",
expected_output="A list of documents retrieved from the Elasticsearch index based on the query.",
agent=es_retriever_agent,
)
internet_research_task = Task(
description="Conduct research on the latest fashion trends for summer 2025. Identify five key trends that are shaping the industry, including popular colors, fabrics, and styles. Use reliable sources such as fashion magazines, retail market reports, and industry analyses. For each trend, provide a concise summary explaining its significance and why it is gaining popularity. Clearly cite your sources using a format like [Source Name]. Your response should be structured and fact-based",
expected_output="A structured summary of the top five fashion trends for summer 2025, including citations for each trend in the format [Source Name]",
agent=internet_researcher_agent,
)
write_task = Task(
description="Compare the fashion trends from the Research Agent with product listings from Elasticsearch. Write a short report highlighting how the store's products align with trends. Use '[Elasticsearch]' for database references and '[Source Name]' for external sources",
expected_output="A short, structured report combining trend insights with product recommendations, with clearly marked references",
agent=writer_agent,
output_file="blog-posts/new_post.md",
)

Now, you only need to instance the crew with all agents and tasks and run them:

# Use in a crew
crew = Crew(
agents=[es_retriever_agent, internet_researcher_agent, writer_agent],
tasks=[
es_retriever_task,
internet_research_task,
write_task,
],
)
# Execute tasks
crew.kickoff()

We can see the result in the new_post.md file:

“**Short Report on Fashion Trends and Product Alignment**

In this report, we will explore how the current fashion trends for summer 2025 align with the offerings in our store, as evidenced by product listings from [Elasticsearch]. The analysis focuses on five prominent trends and identifies specific products that reflect these aesthetics.

**1. Romantic Florals with Kitsch Twist**

The resurgence of floral patterns, particularly those that are intricate rather than large, embodies a whimsical approach to summer fashion. While our current inventory lacks offerings specifically featuring floral designs, there is an opportunity to curate products that align with this trend, potentially expanding into tops or dresses adorned with delicate floral patterns. [Source: Teen Vogue]

**2. High Waisted and Baggy Silhouettes**

High-waisted styles are a key trend for summer 2025, emphasizing comfort without sacrificing style. Among our offerings, the following products fit this criterion:

- **Baggy Fit Cargo Shorts** ($20.99): These cargo shorts present a relaxed, generous silhouette, complementing the cultural shift towards practical fashion that allows ease of movement.

- **Twill Cargo Shorts** ($20.99): These fitted options also embrace the high-waisted trend, providing versatility for various outfits.

**3. Bold Colors: Turquoise and Earthy Tones**

This summer promises a palette of vibrant turquoise alongside earthy tones. While our current collection does not showcase products that specifically reflect these colors, introducing pieces such as tops, dresses, or accessories in these hues could strategically cater to this emerging aesthetic. [Source: Heuritech]

**4. Textured Fabrics**

As textured fabrics gain popularity, we recognize an opportunity in our offerings:

- **Oversized Lyocell-blend Dress** ($38.99): This dress showcases unique fabric quality with gathered seams and balloon sleeves, making it a textural delight that speaks to the trend of tactile experiences in fashion.

- **Twist-Detail Crop Top** ($34.99): Featuring gathered side seams and a twist detail, it embraces the layered, visually engaging designs consumers are seeking.

**5. Quiet Luxury**

Quiet luxury resonates with those prioritizing quality and sustainability over fast fashion. Our offerings in this category include:

- **Relaxed Fit Linen Resort Shirt** ($17.99): This piece’s breathable linen fabric and classic design underline a commitment to sustainable, timeless pieces that exemplify understated elegance.

In conclusion, our current product listings from [Elasticsearch] demonstrate alignment with several key summer fashion trends for 2025. There are unique opportunities to further harness these trends by expanding our collection to include playful floral designs and vibrant colors. Additionally, leveraging the existing offerings that emphasize comfort and quality can enhance our customer appeal in the face of evolving consumer trends.

We are well positioned to make strategic enhancements to our inventory, ensuring we stay ahead in the fast-evolving fashion landscape.”

Conclusion

CrewAI simplifies the process of instantiating an agent workflow with role-playing and supports Langchain tools, including custom tools, making their creation easier with abstractions like the tool decorator.

This agent crew demonstrates the ability to execute complex tasks that combine local data sources and internet searches.

If you want to continue improving this workflow, you could try creating a new agent to write the writer_agent results into Elasticsearch!

Want to get Elastic certified? Find out when the next Elasticsearch Engineer training is running!

Elasticsearch is packed with new features to help you build the best search solutions for your use case. Dive into our sample notebooks to learn more, start a free cloud trial, or try Elastic on your local machine now.

Related content

Ready to build state of the art search experiences?

Sufficiently advanced search isn’t achieved with the efforts of one. Elasticsearch is powered by data scientists, ML ops, engineers, and many more who are just as passionate about search as your are. Let’s connect and work together to build the magical search experience that will get you the results you want.

Try it yourself