mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-05-06 01:32:36 +00:00
feat: enhance agent adapters with structured output support
- Introduced BaseConverterAdapter as an abstract class for structured output handling. - Implemented LangGraphConverterAdapter and OpenAIConverterAdapter to manage structured output in their respective agents. - Updated BaseAgentAdapter to accept an agent configuration dictionary during initialization. - Enhanced LangGraphAgentAdapter to utilize the new converter and improved tool handling. - Added methods for configuring structured output and enhancing system prompts in converter adapters.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Any, List, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from pydantic import BaseModel
|
||||
from pydantic import PrivateAttr
|
||||
|
||||
from crewai.agent import BaseAgent
|
||||
from crewai.tools import BaseTool
|
||||
@@ -16,11 +16,13 @@ class BaseAgentAdapter(BaseAgent, ABC):
|
||||
"""
|
||||
|
||||
adapted_structured_output: bool = False
|
||||
_agent_config: Optional[Dict[str, Any]] = PrivateAttr(default=None)
|
||||
|
||||
model_config = {"arbitrary_types_allowed": True}
|
||||
|
||||
def __init__(self, **kwargs: Any):
|
||||
def __init__(self, agent_config: Optional[Dict[str, Any]] = None, **kwargs: Any):
|
||||
super().__init__(**kwargs)
|
||||
self._agent_config = agent_config
|
||||
|
||||
@abstractmethod
|
||||
def configure_tools(self, tools: Optional[List[BaseTool]] = None) -> None:
|
||||
|
||||
24
src/crewai/agents/agent_adapters/base_converter_adapter.py
Normal file
24
src/crewai/agents/agent_adapters/base_converter_adapter.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
|
||||
class BaseConverterAdapter(ABC):
|
||||
def __init__(self, agent_adapter):
|
||||
self.agent_adapter = agent_adapter
|
||||
|
||||
@abstractmethod
|
||||
def configure_structured_output(self, task) -> None:
|
||||
"""Configure agents to return structured output.
|
||||
Must support json and pydantic output.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def enhance_system_prompt(self, base_prompt: str) -> str:
|
||||
"""Enhance the system prompt with structured output instructions."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def post_process_result(self, result: str) -> str:
|
||||
"""Post-process the result to ensure it matches the expected format."""
|
||||
# Transform the string result to the expected format.
|
||||
pass
|
||||
@@ -45,9 +45,10 @@ class LangGraphAgentAdapter(BaseAgentAdapter):
|
||||
role: str,
|
||||
goal: str,
|
||||
backstory: str,
|
||||
tools: Optional[List[BaseTool]] = None,
|
||||
tools: Optional[List[BaseTool]] = [],
|
||||
llm: Any = None,
|
||||
max_iterations: int = 10,
|
||||
agent_config: Optional[Dict[str, Any]] = None,
|
||||
**kwargs,
|
||||
):
|
||||
"""Initialize the LangGraph agent adapter."""
|
||||
@@ -57,9 +58,10 @@ class LangGraphAgentAdapter(BaseAgentAdapter):
|
||||
backstory=backstory,
|
||||
tools=tools,
|
||||
llm=llm or self.model,
|
||||
agent_config=agent_config,
|
||||
**kwargs,
|
||||
)
|
||||
self._tool_adapter = LangGraphToolAdapter(tools=tools)
|
||||
self._tool_adapter = LangGraphToolAdapter(tools=tools or [])
|
||||
self._converter_adapter = LangGraphConverterAdapter(self)
|
||||
self._max_iterations = max_iterations
|
||||
self._setup_graph()
|
||||
@@ -70,15 +72,13 @@ class LangGraphAgentAdapter(BaseAgentAdapter):
|
||||
# Initialize memory for the agent
|
||||
self._memory = MemorySaver()
|
||||
|
||||
# Convert CrewAI tools to LangGraph/LangChain compatible tools
|
||||
converted_tools = self._tool_adapter.converted_tools
|
||||
print("langgraph converted_tools", converted_tools)
|
||||
|
||||
# Create the agent graph with ReAct pattern
|
||||
self._graph = create_react_agent(
|
||||
model=self.llm,
|
||||
tools=converted_tools,
|
||||
checkpointer=self._memory,
|
||||
debug=self.verbose,
|
||||
)
|
||||
|
||||
except ImportError as e:
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import json
|
||||
|
||||
from crewai.agents.agent_adapters.base_converter_adapter import BaseConverterAdapter
|
||||
from crewai.utilities.converter import generate_model_description
|
||||
|
||||
|
||||
class LangGraphConverterAdapter:
|
||||
class LangGraphConverterAdapter(BaseConverterAdapter):
|
||||
"""Adapter for handling structured output conversion in LangGraph agents"""
|
||||
|
||||
def __init__(self, agent_adapter):
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import json
|
||||
import re
|
||||
|
||||
from crewai.agents.agent_adapters.base_converter_adapter import BaseConverterAdapter
|
||||
from crewai.utilities.converter import generate_model_description
|
||||
|
||||
|
||||
class OpenAIConverterAdapter:
|
||||
class OpenAIConverterAdapter(BaseConverterAdapter):
|
||||
"""
|
||||
Adapter for handling structured output conversion in OpenAI agents.
|
||||
|
||||
@@ -53,6 +54,28 @@ class OpenAIConverterAdapter:
|
||||
self._output_model = task.output_pydantic
|
||||
self.agent_adapter._openai_agent.output_type = task.output_pydantic
|
||||
|
||||
def enhance_system_prompt(self, base_prompt: str) -> str:
|
||||
"""
|
||||
Enhance the base system prompt with structured output requirements if needed.
|
||||
|
||||
Args:
|
||||
base_prompt: The original system prompt
|
||||
|
||||
Returns:
|
||||
Enhanced system prompt with output format instructions if needed
|
||||
"""
|
||||
if not self._output_format:
|
||||
return base_prompt
|
||||
|
||||
output_instructions = f"""
|
||||
Your response MUST conform to the following {self._output_format.upper()} schema:
|
||||
{self._schema}
|
||||
|
||||
Ensure your final response is properly formatted according to this schema.
|
||||
"""
|
||||
|
||||
return f"{base_prompt}\n\n{output_instructions}"
|
||||
|
||||
def post_process_result(self, result: str) -> str:
|
||||
"""
|
||||
Post-process the result to ensure it matches the expected format.
|
||||
@@ -65,10 +88,8 @@ class OpenAIConverterAdapter:
|
||||
Returns:
|
||||
Processed result conforming to the expected output format
|
||||
"""
|
||||
print("result", result)
|
||||
if not self._output_format:
|
||||
return result
|
||||
print("self._output_format", self._output_format)
|
||||
# Try to extract valid JSON if it's wrapped in code blocks or other text
|
||||
if isinstance(result, str) and self._output_format in ["json", "pydantic"]:
|
||||
# First, try to parse as is
|
||||
|
||||
Reference in New Issue
Block a user