mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-10 16:48:30 +00:00
KISS: Refactor LiteAgent integration in flows to use Agents instead. … (#2556)
* KISS: Refactor LiteAgent integration in flows to use Agents instead. Update documentation and examples to reflect changes in class usage, including async support and structured output handling. Enhance tests for Agent functionality and ensure compatibility with new features. * lint fix * dropped for clarity
This commit is contained in:
@@ -545,16 +545,20 @@ The `third_method` and `fourth_method` listen to the output of the `second_metho
|
||||
|
||||
When you run this Flow, the output will change based on the random boolean value generated by the `start_method`.
|
||||
|
||||
## Adding LiteAgent to Flows
|
||||
## Adding Agents to Flows
|
||||
|
||||
LiteAgents can be seamlessly integrated into your flows, providing a lightweight alternative to full Crews when you need simpler, focused task execution. Here's an example of how to use a LiteAgent within a flow to perform market research:
|
||||
Agents can be seamlessly integrated into your flows, providing a lightweight alternative to full Crews when you need simpler, focused task execution. Here's an example of how to use an Agent within a flow to perform market research:
|
||||
|
||||
```python
|
||||
from typing import List, cast
|
||||
from crewai_tools.tools.website_search.website_search_tool import WebsiteSearchTool
|
||||
import asyncio
|
||||
from typing import Any, Dict, List
|
||||
|
||||
from crewai_tools import SerperDevTool
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from crewai.agent import Agent
|
||||
from crewai.flow.flow import Flow, listen, start
|
||||
from crewai.lite_agent import LiteAgent
|
||||
|
||||
|
||||
# Define a structured output format
|
||||
class MarketAnalysis(BaseModel):
|
||||
@@ -562,28 +566,30 @@ class MarketAnalysis(BaseModel):
|
||||
market_size: str = Field(description="Estimated market size")
|
||||
competitors: List[str] = Field(description="Major competitors in the space")
|
||||
|
||||
|
||||
# Define flow state
|
||||
class MarketResearchState(BaseModel):
|
||||
product: str = ""
|
||||
analysis: MarketAnalysis | None = None
|
||||
|
||||
|
||||
# Create a flow class
|
||||
class MarketResearchFlow(Flow[MarketResearchState]):
|
||||
@start()
|
||||
def initialize_research(self):
|
||||
def initialize_research(self) -> Dict[str, Any]:
|
||||
print(f"Starting market research for {self.state.product}")
|
||||
return {"product": self.state.product}
|
||||
|
||||
@listen(initialize_research)
|
||||
def analyze_market(self):
|
||||
# Create a LiteAgent for market research
|
||||
analyst = LiteAgent(
|
||||
async def analyze_market(self) -> Dict[str, Any]:
|
||||
# Create an Agent for market research
|
||||
analyst = Agent(
|
||||
role="Market Research Analyst",
|
||||
goal=f"Analyze the market for {self.state.product}",
|
||||
backstory="You are an experienced market analyst with expertise in "
|
||||
"identifying market trends and opportunities.",
|
||||
llm="gpt-4o",
|
||||
tools=[WebsiteSearchTool()],
|
||||
tools=[SerperDevTool()],
|
||||
verbose=True,
|
||||
response_format=MarketAnalysis,
|
||||
)
|
||||
|
||||
# Define the research query
|
||||
@@ -592,49 +598,65 @@ class MarketResearchFlow(Flow[MarketResearchState]):
|
||||
1. Key market trends
|
||||
2. Market size
|
||||
3. Major competitors
|
||||
|
||||
|
||||
Format your response according to the specified structure.
|
||||
"""
|
||||
|
||||
# Execute the analysis
|
||||
result = analyst.kickoff(query)
|
||||
self.state.analysis = cast(MarketAnalysis, result.pydantic)
|
||||
return result.pydantic
|
||||
# Execute the analysis with structured output format
|
||||
result = await analyst.kickoff_async(query, response_format=MarketAnalysis)
|
||||
if result.pydantic:
|
||||
print("result", result.pydantic)
|
||||
else:
|
||||
print("result", result)
|
||||
|
||||
# Return the analysis to update the state
|
||||
return {"analysis": result.pydantic}
|
||||
|
||||
@listen(analyze_market)
|
||||
def present_results(self):
|
||||
analysis = self.state.analysis
|
||||
if analysis is None:
|
||||
print("No analysis results available")
|
||||
return
|
||||
|
||||
def present_results(self, analysis) -> None:
|
||||
print("\nMarket Analysis Results")
|
||||
print("=====================")
|
||||
|
||||
print("\nKey Market Trends:")
|
||||
for trend in analysis.key_trends:
|
||||
print(f"- {trend}")
|
||||
if isinstance(analysis, dict):
|
||||
# If we got a dict with 'analysis' key, extract the actual analysis object
|
||||
market_analysis = analysis.get("analysis")
|
||||
else:
|
||||
market_analysis = analysis
|
||||
|
||||
print(f"\nMarket Size: {analysis.market_size}")
|
||||
if market_analysis and isinstance(market_analysis, MarketAnalysis):
|
||||
print("\nKey Market Trends:")
|
||||
for trend in market_analysis.key_trends:
|
||||
print(f"- {trend}")
|
||||
|
||||
print(f"\nMarket Size: {market_analysis.market_size}")
|
||||
|
||||
print("\nMajor Competitors:")
|
||||
for competitor in market_analysis.competitors:
|
||||
print(f"- {competitor}")
|
||||
else:
|
||||
print("No structured analysis data available.")
|
||||
print("Raw analysis:", analysis)
|
||||
|
||||
print("\nMajor Competitors:")
|
||||
for competitor in analysis.competitors:
|
||||
print(f"- {competitor}")
|
||||
|
||||
# Usage example
|
||||
flow = MarketResearchFlow()
|
||||
result = flow.kickoff(inputs={"product": "AI-powered chatbots"})
|
||||
async def run_flow():
|
||||
flow = MarketResearchFlow()
|
||||
result = await flow.kickoff_async(inputs={"product": "AI-powered chatbots"})
|
||||
return result
|
||||
|
||||
|
||||
# Run the flow
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(run_flow())
|
||||
```
|
||||
|
||||
This example demonstrates several key features of using LiteAgents in flows:
|
||||
This example demonstrates several key features of using Agents in flows:
|
||||
|
||||
1. **Structured Output**: Using Pydantic models to define the expected output format (`MarketAnalysis`) ensures type safety and structured data throughout the flow.
|
||||
|
||||
2. **State Management**: The flow state (`MarketResearchState`) maintains context between steps and stores both inputs and outputs.
|
||||
|
||||
3. **Tool Integration**: LiteAgents can use tools (like `WebsiteSearchTool`) to enhance their capabilities.
|
||||
|
||||
If you want to learn more about LiteAgents, check out the [LiteAgent](/concepts/lite-agent) page.
|
||||
3. **Tool Integration**: Agents can use tools (like `WebsiteSearchTool`) to enhance their capabilities.
|
||||
|
||||
## Adding Crews to Flows
|
||||
|
||||
|
||||
@@ -1,242 +0,0 @@
|
||||
---
|
||||
title: LiteAgent
|
||||
description: A lightweight, single-purpose agent for simple autonomous tasks within the CrewAI framework.
|
||||
icon: feather
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
A `LiteAgent` is a streamlined version of CrewAI's Agent, designed for simpler, standalone tasks that don't require the full complexity of a crew-based workflow. It's perfect for quick automations, single-purpose tasks, or when you need a lightweight solution.
|
||||
|
||||
<Tip>
|
||||
Think of a LiteAgent as a specialized worker that excels at individual tasks.
|
||||
While regular Agents are team players in a crew, LiteAgents are solo
|
||||
performers optimized for specific operations.
|
||||
</Tip>
|
||||
|
||||
## LiteAgent Attributes
|
||||
|
||||
| Attribute | Parameter | Type | Description |
|
||||
| :------------------------------- | :---------------- | :--------------------- | :-------------------------------------------------------------- |
|
||||
| **Role** | `role` | `str` | Defines the agent's function and expertise. |
|
||||
| **Goal** | `goal` | `str` | The specific objective that guides the agent's actions. |
|
||||
| **Backstory** | `backstory` | `str` | Provides context and personality to the agent. |
|
||||
| **LLM** _(optional)_ | `llm` | `Union[str, LLM, Any]` | Language model powering the agent. Defaults to "gpt-4". |
|
||||
| **Tools** _(optional)_ | `tools` | `List[BaseTool]` | Capabilities available to the agent. Defaults to an empty list. |
|
||||
| **Verbose** _(optional)_ | `verbose` | `bool` | Enable detailed execution logs. Default is False. |
|
||||
| **Response Format** _(optional)_ | `response_format` | `Type[BaseModel]` | Pydantic model for structured output. Optional. |
|
||||
|
||||
## Creating a LiteAgent
|
||||
|
||||
Here's a simple example of creating and using a standalone LiteAgent:
|
||||
|
||||
```python
|
||||
from typing import List, cast
|
||||
|
||||
from crewai_tools import SerperDevTool
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from crewai.lite_agent import LiteAgent
|
||||
|
||||
|
||||
# Define a structured output format
|
||||
class MovieReview(BaseModel):
|
||||
title: str = Field(description="The title of the movie")
|
||||
rating: float = Field(description="Rating out of 10")
|
||||
pros: List[str] = Field(description="List of positive aspects")
|
||||
cons: List[str] = Field(description="List of negative aspects")
|
||||
|
||||
|
||||
# Create a LiteAgent
|
||||
critic = LiteAgent(
|
||||
role="Movie Critic",
|
||||
goal="Provide insightful movie reviews",
|
||||
backstory="You are an experienced film critic known for balanced, thoughtful reviews.",
|
||||
tools=[SerperDevTool()],
|
||||
verbose=True,
|
||||
response_format=MovieReview,
|
||||
)
|
||||
|
||||
# Use the agent
|
||||
query = """
|
||||
Review the movie 'Inception'. Include:
|
||||
1. Your rating out of 10
|
||||
2. Key positive aspects
|
||||
3. Areas that could be improved
|
||||
"""
|
||||
|
||||
result = critic.kickoff(query)
|
||||
|
||||
|
||||
# Access the structured output
|
||||
review = cast(MovieReview, result.pydantic)
|
||||
print(f"\nMovie Review: {review.title}")
|
||||
print(f"Rating: {review.rating}/10")
|
||||
print("\nPros:")
|
||||
for pro in review.pros:
|
||||
print(f"- {pro}")
|
||||
print("\nCons:")
|
||||
for con in review.cons:
|
||||
print(f"- {con}")
|
||||
|
||||
```
|
||||
|
||||
This example demonstrates the core features of a LiteAgent:
|
||||
|
||||
- Structured output using Pydantic models
|
||||
- Tool integration with WebSearchTool
|
||||
- Simple execution with `kickoff()`
|
||||
- Easy access to both raw and structured results
|
||||
|
||||
## Using LiteAgent in a Flow
|
||||
|
||||
For more complex scenarios, you can integrate LiteAgents into a Flow. Here's an example of a market research flow:
|
||||
|
||||
````python
|
||||
from typing import List
|
||||
from pydantic import BaseModel, Field
|
||||
from crewai.flow.flow import Flow, start, listen
|
||||
from crewai.lite_agent import LiteAgent
|
||||
from crewai.tools import WebSearchTool
|
||||
|
||||
# Define a structured output format
|
||||
class MarketAnalysis(BaseModel):
|
||||
key_trends: List[str] = Field(description="List of identified market trends")
|
||||
market_size: str = Field(description="Estimated market size")
|
||||
competitors: List[str] = Field(description="Major competitors in the space")
|
||||
|
||||
# Define flow state
|
||||
class MarketResearchState(BaseModel):
|
||||
product: str = ""
|
||||
analysis: MarketAnalysis = None
|
||||
|
||||
# Create a flow class
|
||||
class MarketResearchFlow(Flow[MarketResearchState]):
|
||||
@start()
|
||||
def initialize_research(self, product: str):
|
||||
print(f"Starting market research for {product}")
|
||||
self.state.product = product
|
||||
|
||||
@listen(initialize_research)
|
||||
async def analyze_market(self):
|
||||
# Create a LiteAgent for market research
|
||||
analyst = LiteAgent(
|
||||
role="Market Research Analyst",
|
||||
goal=f"Analyze the market for {self.state.product}",
|
||||
backstory="You are an experienced market analyst with expertise in "
|
||||
"identifying market trends and opportunities.",
|
||||
tools=[WebSearchTool()],
|
||||
verbose=True,
|
||||
response_format=MarketAnalysis
|
||||
)
|
||||
|
||||
# Define the research query
|
||||
query = f"""
|
||||
Research the market for {self.state.product}. Include:
|
||||
1. Key market trends
|
||||
2. Market size
|
||||
3. Major competitors
|
||||
|
||||
Format your response according to the specified structure.
|
||||
"""
|
||||
|
||||
# Execute the analysis
|
||||
result = await analyst.kickoff_async(query)
|
||||
self.state.analysis = result.pydantic
|
||||
return result.pydantic
|
||||
|
||||
@listen(analyze_market)
|
||||
def present_results(self):
|
||||
analysis = self.state.analysis
|
||||
print("\nMarket Analysis Results")
|
||||
print("=====================")
|
||||
|
||||
print("\nKey Market Trends:")
|
||||
for trend in analysis.key_trends:
|
||||
print(f"- {trend}")
|
||||
|
||||
print(f"\nMarket Size: {analysis.market_size}")
|
||||
|
||||
print("\nMajor Competitors:")
|
||||
for competitor in analysis.competitors:
|
||||
print(f"- {competitor}")
|
||||
|
||||
# Usage example
|
||||
import asyncio
|
||||
|
||||
async def run_flow():
|
||||
flow = MarketResearchFlow()
|
||||
result = await flow.kickoff(inputs={"product": "AI-powered chatbots"})
|
||||
return result
|
||||
|
||||
# Run the flow
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(run_flow())
|
||||
|
||||
## Key Features
|
||||
|
||||
### 1. Simplified Setup
|
||||
Unlike regular Agents, LiteAgents are designed for quick setup and standalone operation. They don't require crew configuration or task management.
|
||||
|
||||
### 2. Structured Output
|
||||
LiteAgents support Pydantic models for response formatting, making it easy to get structured, type-safe data from your agent's operations.
|
||||
|
||||
### 3. Tool Integration
|
||||
Just like regular Agents, LiteAgents can use tools to enhance their capabilities:
|
||||
```python
|
||||
from crewai.tools import SerperDevTool, CalculatorTool
|
||||
|
||||
agent = LiteAgent(
|
||||
role="Research Assistant",
|
||||
goal="Find and analyze information",
|
||||
tools=[SerperDevTool(), CalculatorTool()],
|
||||
verbose=True
|
||||
)
|
||||
````
|
||||
|
||||
### 4. Async Support
|
||||
|
||||
LiteAgents support asynchronous execution through the `kickoff_async` method, making them suitable for non-blocking operations in your application.
|
||||
|
||||
## Response Formatting
|
||||
|
||||
LiteAgents support structured output through Pydantic models using the `response_format` parameter. This feature ensures type safety and consistent output structure, making it easier to work with agent responses in your application.
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
class SearchResult(BaseModel):
|
||||
title: str = Field(description="The title of the found content")
|
||||
summary: str = Field(description="A brief summary of the content")
|
||||
relevance_score: float = Field(description="Relevance score from 0 to 1")
|
||||
|
||||
agent = LiteAgent(
|
||||
role="Search Specialist",
|
||||
goal="Find and summarize relevant information",
|
||||
response_format=SearchResult
|
||||
)
|
||||
|
||||
result = await agent.kickoff_async("Find information about quantum computing")
|
||||
print(f"Title: {result.pydantic.title}")
|
||||
print(f"Summary: {result.pydantic.summary}")
|
||||
print(f"Relevance: {result.pydantic.relevance_score}")
|
||||
```
|
||||
|
||||
### Handling Responses
|
||||
|
||||
When using `response_format`, the agent's response will be available in two forms:
|
||||
|
||||
1. **Raw Response**: Access the unstructured string response
|
||||
|
||||
```python
|
||||
result = await agent.kickoff_async("Analyze the market")
|
||||
print(result.raw) # Original LLM response
|
||||
```
|
||||
|
||||
2. **Structured Response**: Access the parsed Pydantic model
|
||||
```python
|
||||
print(result.pydantic) # Parsed response as Pydantic model
|
||||
print(result.pydantic.dict()) # Convert to dictionary
|
||||
```
|
||||
@@ -66,7 +66,6 @@
|
||||
"concepts/tasks",
|
||||
"concepts/crews",
|
||||
"concepts/flows",
|
||||
"concepts/lite-agent",
|
||||
"concepts/knowledge",
|
||||
"concepts/llms",
|
||||
"concepts/processes",
|
||||
@@ -231,4 +230,4 @@
|
||||
"reddit": "https://www.reddit.com/r/crewAIInc/"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user