# A2A + CrewAI + OpenRouter Chart Generation Agent Tutorial **Published by:** [czmilo](https://paragraph.com/@zhangcheng/) **Published on:** 2025-06-27 **URL:** https://paragraph.com/@zhangcheng/a2a-crewai-openrouter-chart-generation-agent-tutorial ## Content Tutorial FocusThis tutorial will guide you through practicing the following core skills:Integrating OpenRouter + CrewAI + A2A: Complete end-to-end Agent development using OpenRouter as LLM provider, CrewAI as Agent framework, and A2A protocol as standardized interfacePracticing A2A Agent Image Data Return: Learn how to make Agents generate and return image data, not just text responsesUsing A2A Inspector to Debug A2A Applications: Master professional debugging tools to test and validate your Agent applicationsQuick Start1. Clone the Codegit clone git@github.com:sing1ee/a2a-crewai-charts-agent.git cd a2a-crewai-charts-agent 2. Create Environment ConfigurationCreate .env file:OPENROUTER_API_KEY=sk-or-v1-your-api-key-here OPENAI_MODEL_NAME=openrouter/anthropic/claude-3.7-sonnet 3. Environment Setup and Run# Create virtual environment uv venv # Activate virtual environment source .venv/bin/activate # Run application uv run . The application will start at http://localhost:10011.Debug with A2A InspectorA2A Inspector is a powerful tool specifically designed for debugging A2A applications.Debugging Steps:Access A2A Inspector: Open https://inspector.a2aprotocol.aiConnect to Your Agent:Enter your Agent address in Inspector: http://localhost:10011Click "Connect" to establish connectionTest Agent Functionality:Send test message: "Generate a chart of revenue: Jan,1000 Feb,2000 Mar,1500"Observe the complete A2A protocol interaction processView returned image dataDebug and Monitor:Check Agent's capabilities and skillsMonitor complete request and response flowVerify correct image data transmissionRefer to A2A Inspector Documentation for more detailed debugging guides.Main Process and Code IntroductionSystem Architecture Sequence DiagramsequenceDiagram participant U as User participant A2A as A2A Inspector participant S as A2A Server participant H as DefaultRequestHandler participant E as ChartGenerationAgentExecutor participant CA as ChartGenerationAgent participant Crew as CrewAI Crew participant Tool as ChartGenerationTool participant MP as Matplotlib participant Cache as InMemoryCache U->>A2A: Send prompt "Generate chart: A,100 B,200" A2A->>S: HTTP POST /tasks with A2A message S->>H: Handle request with RequestContext H->>E: execute(context, event_queue) E->>CA: invoke(query, session_id) CA->>Crew: kickoff with inputs Crew->>Tool: generate_chart_tool(prompt, session_id) Tool->>Tool: Parse CSV data Tool->>MP: Create bar chart with matplotlib MP-->>Tool: Return PNG bytes Tool->>Cache: Store image with ID Cache-->>Tool: Confirm storage Tool-->>Crew: Return image ID Crew-->>CA: Return image ID CA-->>E: Return image ID E->>CA: get_image_data(session_id, image_key) CA->>Cache: Retrieve image data Cache-->>CA: Return Imagedata CA-->>E: Return Imagedata E->>H: Create FilePart with image bytes H->>S: enqueue completed_task event S-->>A2A: Return A2A response with image A2A-->>U: Display generated chart Core Component Details1. A2A Server Initialization (__main__.py)# Define Agent capabilities and skills capabilities = AgentCapabilities(streaming=False) skill = AgentSkill( id='chart_generator', name='Chart Generator', description='Generate a chart based on CSV-like data passed in', tags=['generate image', 'edit image'], examples=['Generate a chart of revenue: Jan,$1000 Feb,$2000 Mar,$1500'], ) # Create Agent card agent_card = AgentCard( name='Chart Generator Agent', description='Generate charts from structured CSV-like data input.', url=f'http://{host}:{port}/', version='1.0.0', defaultInputModes=ChartGenerationAgent.SUPPORTED_CONTENT_TYPES, defaultOutputModes=ChartGenerationAgent.SUPPORTED_CONTENT_TYPES, capabilities=capabilities, skills=[skill], ) Key Points:AgentCapabilities defines supported Agent functions (streaming disabled here)AgentSkill describes specific Agent skills and usage examplesAgentCard is the Agent's identity in A2A protocol2. CrewAI Agent Implementation (agent.py)class ChartGenerationAgent: def __init__(self): # Create specialized chart generation Agent self.chart_creator_agent = Agent( role='Chart Creation Expert', goal='Generate a bar chart image based on structured CSV input.', backstory='You are a data visualization expert who transforms structured data into visual charts.', verbose=False, allow_delegation=False, tools=[generate_chart_tool], ) # Define task self.chart_creation_task = Task( description=( "You are given a prompt: '{user_prompt}'.\n" "If the prompt includes comma-separated key:value pairs (e.g. 'a:100, b:200'), " "reformat it into CSV with header 'Category,Value'.\n" "Ensure it becomes two-column CSV, then pass that to the 'ChartGenerationTool'.\n" "Use session ID: '{session_id}' when calling the tool." ), expected_output='The id of the generated chart image', agent=self.chart_creator_agent, ) Key Points:CrewAI's Agent class defines AI assistant roles and capabilitiesTask class describes specific task execution logicCustom tools are integrated into Agent through tools parameter3. Chart Generation Tool@tool('ChartGenerationTool') def generate_chart_tool(prompt: str, session_id: str) -> str: """Generates a bar chart image from CSV-like input using matplotlib.""" # Parse CSV data df = pd.read_csv(StringIO(prompt)) df.columns = ['Category', 'Value'] df['Value'] = pd.to_numeric(df['Value'], errors='coerce') # Generate bar chart fig, ax = plt.subplots() ax.bar(df['Category'], df['Value']) ax.set_xlabel('Category') ax.set_ylabel('Value') ax.set_title('Bar Chart') # Save as PNG bytes buf = BytesIO() plt.savefig(buf, format='png') plt.close(fig) buf.seek(0) image_bytes = buf.read() # Encode and cache image data = Imagedata( bytes=base64.b64encode(image_bytes).decode('utf-8'), mime_type='image/png', name='generated_chart.png', id=uuid4().hex, ) # Store image in cache session_data = cache.get(session_id) or {} session_data[data.id] = data cache.set(session_id, session_data) return data.id Key Points:Use @tool decorator to convert function into CrewAI toolUse pandas to parse CSV data, matplotlib to generate chartsImages stored as base64 encoding for network transmissionUse session IDs to manage data isolation for multiple users4. A2A Executor (agent_executor.py)class ChartGenerationAgentExecutor(AgentExecutor): async def execute(self, context: RequestContext, event_queue: EventQueue) -> None: # Get user input query = context.get_user_input() # Call CrewAI Agent result = self.agent.invoke(query, context.context_id) # Get generated image data data = self.agent.get_image_data( session_id=context.context_id, image_key=result.raw ) if data and not data.error: # Create file part containing image bytes parts = [ Part( root=FilePart( file=FileWithBytes( bytes=data.bytes, mimeType=data.mime_type, name=data.name, ) ) ) ] else: # Return text message in error case parts = [Part(root=TextPart(text=data.error or 'Failed to generate chart image.'))] # Add completed task to event queue event_queue.enqueue_event( completed_task( context.task_id, context.context_id, [new_artifact(parts, f'chart_{context.task_id}')], [context.message], ) ) Key Points:AgentExecutor is A2A protocol execution layerGet user requests through RequestContextConvert CrewAI responses to A2A protocol formatSupport returning file-type data (images)5. Cache System (utils.py)class InMemoryCache: """Simple thread-safe in-memory cache with no expiration.""" def __init__(self): self._lock = threading.Lock() self._store: dict[str, Any] = {} def get(self, key: str) -> Any | None: with self._lock: return self._store.get(key) def set(self, key: str, value: Any) -> None: with self._lock: self._store[key] = value Key Points:Thread-safe in-memory cache implementationUsed to store generated image dataSupports session isolation to avoid user data confusionTechnology Stack SummaryA2A Protocol: Standardized Agent communication protocolCrewAI: Multi-Agent collaboration frameworkOpenRouter: LLM API aggregation serviceMatplotlib: Python chart generation libraryPandas: Data processing libraryUV: Modern Python package managerExtension SuggestionsSupport More Chart Types: Pie charts, line charts, scatter plots, etc.Add Data Validation: Stronger input data validation and error handlingPersistent Cache: Use Redis or file system to store imagesStreaming Support: Support real-time chart generation progressMultimodal Input: Support uploading CSV files instead of text-only inputThrough this tutorial, you have mastered the core skills of building practical Agents using modern AI technology stack. This chart generation Agent can serve as the foundation for more complex data analysis applications. https://a2aprotocol.ai/blog/a2a-crewai-analysis-chart-agentSystem Prompt for AIYou are a professional assistant based on the CrewAI chart generation agent tutorial. This tutorial provides a comprehensive guide on building a complete AI chart generation application. I can help you with: ## What I Can Help You With: - **Quick Start**: Guide you from scratch to build an agent application using OpenRouter + CrewAI + A2A protocol - **Solve Technical Issues**: Answer specific questions about environment setup, code implementation, and debugging - **Understand Core Concepts**: Explain how A2A protocol, CrewAI framework, and agent architecture work - **Practical Guidance**: Provide best practices for image data handling, tool integration, and cache design - **Debug Support**: Teach you to use A2A Inspector for professional debugging and troubleshooting ## You Can Ask Me: - "How to configure OpenRouter API keys?" - "How do CrewAI Agents and Tasks work?" - "How to return image data after chart generation?" - "How to connect and test my agent with A2A Inspector?" - "How is the cache system implemented in the code?" - "How to extend support for more chart types?" I'll provide accurate, practical answers based on the tutorial content to help you quickly master modern AI agent development skills. You can visit [A2AProtocol.ai](https://a2aprotocol.ai/) for more tutorials. ## Publication Information - [czmilo](https://paragraph.com/@zhangcheng/): Publication homepage - [All Posts](https://paragraph.com/@zhangcheng/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@zhangcheng): Subscribe to updates