Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@
"en/tools/search-research/youtubevideosearchtool",
"en/tools/search-research/tavilysearchtool",
"en/tools/search-research/tavilyextractortool",
"en/tools/search-research/parallelsearchtool",
"en/tools/search-research/arxivpapertool",
"en/tools/search-research/serpapi-googlesearchtool",
"en/tools/search-research/serpapi-googleshoppingtool",
Expand Down
16 changes: 14 additions & 2 deletions docs/en/tools/search-research/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ These tools enable your agents to search the web, research topics, and find info
Extract structured content from web pages using the Tavily API.
</Card>

<Card title="Parallel Search Tool" icon="magnifying-glass" href="/en/tools/search-research/parallelsearchtool">
LLM-optimized web search with compressed excerpts via the Parallel API.
</Card>

<Card title="Arxiv Paper Tool" icon="box-archive" href="/en/tools/search-research/arxivpapertool">
Search arXiv and optionally download PDFs.
</Card>
Expand All @@ -76,19 +80,27 @@ These tools enable your agents to search the web, research topics, and find info
- **Academic Research**: Find scholarly articles and technical papers

```python
from crewai_tools import SerperDevTool, GitHubSearchTool, YoutubeVideoSearchTool, TavilySearchTool, TavilyExtractorTool
from crewai_tools import (
SerperDevTool,
GitHubSearchTool,
YoutubeVideoSearchTool,
TavilySearchTool,
TavilyExtractorTool,
ParallelSearchTool,
)

# Create research tools
web_search = SerperDevTool()
code_search = GitHubSearchTool()
video_research = YoutubeVideoSearchTool()
tavily_search = TavilySearchTool()
content_extractor = TavilyExtractorTool()
parallel_search = ParallelSearchTool()

# Add to your agent
agent = Agent(
role="Research Analyst",
tools=[web_search, code_search, video_research, tavily_search, content_extractor],
tools=[web_search, code_search, video_research, tavily_search, content_extractor, parallel_search],
goal="Gather comprehensive information on any topic"
)
```
288 changes: 288 additions & 0 deletions docs/en/tools/search-research/parallelsearchtool.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
---
title: "Parallel Search Tool"
description: "Perform LLM-optimized web searches using the Parallel Search API"
icon: "magnifying-glass"
mode: "wide"
---

The `ParallelSearchTool` provides an interface to the [Parallel Search API](https://docs.parallel.ai/search/search-quickstart), enabling CrewAI agents to perform web searches that return ranked results with compressed excerpts optimized for LLMs. It replaces the traditional search → scrape → extract pipeline with a single, low-latency API call.

## Installation

To use the `ParallelSearchTool`, you need to install the `parallel-web` library:

```shell
pip install 'crewai[tools]' parallel-web
```

## Environment Variables

Ensure your Parallel API key is set as an environment variable:

```bash
export PARALLEL_API_KEY='your_parallel_api_key'
```

Get an API key at [platform.parallel.ai](https://platform.parallel.ai).

## Example Usage

Here's how to initialize and use the `ParallelSearchTool` within a CrewAI agent:

```python
from crewai import Agent, Task, Crew
from crewai_tools import ParallelSearchTool

# Initialize the tool
parallel_tool = ParallelSearchTool()

# Create an agent that uses the tool
researcher = Agent(
role='Market Researcher',
goal='Find information about the latest AI trends',
backstory='An expert market researcher specializing in technology.',
tools=[parallel_tool],
verbose=True
)

# Create a task for the agent
research_task = Task(
description='Search for the top 3 AI trends in 2024.',
expected_output='A JSON report summarizing the top 3 AI trends found.',
agent=researcher
)

# Form the crew and kick it off
crew = Crew(
agents=[researcher],
tasks=[research_task],
verbose=True
)

result = crew.kickoff()
print(result)
```

## Configuration Options

The `ParallelSearchTool` accepts the following arguments during initialization:

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `api_key` | str | env var | Parallel API key (defaults to `PARALLEL_API_KEY` env var) |
| `mode` | str | None | `"one-shot"` (comprehensive results) or `"agentic"` (concise, token-efficient for multi-step workflows) |
| `max_results` | int | 10 | Maximum number of results to return (1-20) |
| `excerpts` | dict | None | Excerpt configuration, e.g., `{"max_chars_per_result": 10000, "max_chars_total": 50000}` |
| `fetch_policy` | dict | None | Content freshness control, e.g., `{"max_age_seconds": 3600}` |
| `source_policy` | dict | None | Domain inclusion/exclusion policy |

## Run Parameters

When calling `run()`, pass these parameters:

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `objective` | str | At least one required | Natural-language research goal (<= 5000 chars) |
| `search_queries` | list[str] | At least one required | Up to 5 keyword queries (each <= 200 chars) |
| `max_results` | int | No | Override the default max results for this search (1-20) |
| `source_policy` | dict | No | Override the default source policy for this search |

<Note>
At least one of `objective` or `search_queries` is required. The `max_results` and `source_policy` parameters can be set at initialization (as defaults) or overridden per-search at runtime.
</Note>

## Advanced Usage

You can configure the tool with custom parameters:

```python
# Example: Initialize with specific parameters
custom_parallel_tool = ParallelSearchTool(
mode='agentic',
max_results=5,
excerpts={"max_chars_per_result": 10000}
)

# The agent will use these defaults
agent_with_custom_tool = Agent(
role="Advanced Researcher",
goal="Conduct detailed research with comprehensive results",
tools=[custom_parallel_tool]
)
```

### Domain Filtering

Restrict searches to specific domains. You can set defaults at initialization or override per-search:

```python
# Set default source policy at initialization
parallel_tool = ParallelSearchTool(
max_results=5,
source_policy={
"allow": {"domains": ["un.org", "who.int"]},
}
)

# Use the default source policy
result = parallel_tool.run(
objective="When was the United Nations established?"
)

# Override source policy for a specific search
result = parallel_tool.run(
objective="Latest WHO health guidelines",
source_policy={"allow": {"domains": ["who.int"]}},
max_results=3 # Also override max_results for this search
)
```

### Fresh Content

Request recent content only:

```python
parallel_tool = ParallelSearchTool(
fetch_policy={"max_age_seconds": 3600}, # Content no older than 1 hour
max_results=10
)

result = parallel_tool.run(
objective="Latest news on AI regulation"
)
```

### Agentic Mode

For multi-step reasoning workflows, use `agentic` mode for more concise, token-efficient results:

```python
parallel_tool = ParallelSearchTool(
mode="agentic",
max_results=5
)

result = parallel_tool.run(
objective="Find recent research on quantum error correction",
search_queries=["quantum error correction 2024", "QEC algorithms"]
)
```

## Complete Agent Example

Here's a complete example that uses `ParallelSearchTool` with a CrewAI agent to research a topic and produce a cited answer.

**Additional requirements:**

```shell
uv add "crewai[anthropic]"
```

**Environment variable:**
- `ANTHROPIC_API_KEY` (for the LLM)

```python
import os
from crewai import Agent, Task, Crew, LLM, Process
from crewai_tools import ParallelSearchTool

# Configure Claude as the LLM
llm = LLM(
model="anthropic/claude-opus-4-5-20251101",
temperature=0.5,
max_tokens=4096,
api_key=os.getenv("ANTHROPIC_API_KEY"),
)

# Initialize ParallelSearchTool with agentic mode for multi-step workflows
search = ParallelSearchTool(
mode="agentic",
max_results=10,
excerpts={"max_chars_per_result": 10000},
)

# User query
query = "What are current best practices for LLM evaluation and benchmarking?"

# Create a researcher agent
researcher = Agent(
role="Web Researcher",
backstory="You are an expert web researcher who finds and synthesizes information from multiple sources.",
goal="Find high-quality, cited sources and provide accurate, well-sourced answers.",
tools=[search],
llm=llm,
verbose=True,
)

# Define the research task
task = Task(
description=f"Research: {query}\n\nProvide a comprehensive answer with citations.",
expected_output="A concise answer with inline citations in the format: [claim] - [source URL]",
agent=researcher,
output_file="research_output.md",
)

# Create and run the crew
crew = Crew(
agents=[researcher],
tasks=[task],
verbose=True,
process=Process.sequential,
)

result = crew.kickoff()
print(result)
```

<Accordion title="Example output">
```markdown
# Current Best Practices for LLM Evaluation and Benchmarking

## Overview

LLM evaluation is the systematic process of assessing the performance of Large Language
Models to determine their effectiveness, reliability, and efficiency, helping developers
understand the model's strengths and weaknesses while ensuring it functions as expected
in real-world applications - https://www.singlestore.com/blog/complete-guide-to-evaluating-large-language-models/

## Key Evaluation Methodologies

### 1. Multiple-Choice Benchmarks

Multiple-choice benchmarks like MMLU test an LLM's knowledge recall in a straightforward,
quantifiable way similar to standardized tests, measuring accuracy as the fraction of
correctly answered questions - https://magazine.sebastianraschka.com/p/llm-evaluation-4-approaches

...
```
</Accordion>

<Tip>
- Use `mode="agentic"` for multi-step reasoning workflows (more concise, token-efficient results)
- Use `mode="one-shot"` for single comprehensive searches
- Increase `excerpts={"max_chars_per_result": N}` for more detailed source content
</Tip>

## Features

- **Single-Call Pipeline**: Replaces search → scrape → extract with one API call
- **LLM-Optimized**: Returns compressed excerpts designed for LLM prompts
- **Flexible Modes**: Choose between comprehensive (`one-shot`) or concise (`agentic`) results
- **Domain Control**: Include or exclude specific domains via `source_policy`
- **Freshness Control**: Limit results to recent content via `fetch_policy`
- **Built-in Reliability**: SDK includes retries, timeouts, and error handling

## Response Format

The tool returns search results as a JSON string containing:
- `search_id`: Unique identifier for the search
- `results`: Array of ranked results, each with:
- `url`: Source URL
- `title`: Page title
- `excerpts`: Compressed, relevant excerpts from the page

## References

- [Search API Quickstart](https://docs.parallel.ai/search/search-quickstart)
- [Search API Best Practices](https://docs.parallel.ai/search/best-practices)
- [Parallel Platform](https://platform.parallel.ai)
3 changes: 3 additions & 0 deletions lib/crewai-tools/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ linkup-sdk = [
tavily-python = [
"tavily-python>=0.5.4",
]
parallel-web = [
"parallel-web>=0.3.4",
]
hyperbrowser = [
"hyperbrowser>=0.18.0",
]
Expand Down
Loading