Building Agentic Systems¶
This section explores the capabilities and building blocks that Arshai provides for creating sophisticated agentic systems. The framework’s architecture enables you to build various coordination mechanisms and multi-agent systems without prescribing any specific approach.
Core Framework Capabilities¶
- Function Calling as Coordination Mechanism
The framework’s LLM function calling system enables agents to coordinate naturally through tool invocations. Agents can call other agents as tools, creating dynamic coordination patterns.
- Background Tasks for System Events
Background tasks allow agents to trigger system-wide events, logging, notifications, and coordination without blocking the conversation flow. This enables fire-and-forget coordination patterns.
- Direct Agent Communication
Agents can communicate directly by calling each other’s process methods, enabling peer-to-peer coordination and complex interaction patterns.
- Shared Context and Memory
The memory system and metadata propagation allow agents to share context and maintain system-wide state across multiple interactions.
- Flexible Response Types
Agents can return any data type - strings, structured objects, streams, or custom types - enabling rich information exchange between system components.
Framework Building Blocks for Agentic Systems¶
- BaseAgent Foundation
Every agent extends BaseAgent, providing a consistent interface while allowing complete customization of behavior, making agents composable system components.
- Tool Integration System
Any Python callable can be a tool, including other agents. This enables natural composition where agents become tools for other agents, creating hierarchical systems.
- Memory and Context Management
WorkingMemoryAgent and memory managers provide shared context across agents, enabling persistent conversations and coordinated decision-making.
- Asynchronous Execution
Full async support enables parallel agent execution, concurrent tool calling, and non-blocking system coordination.
- Metadata Propagation
Input metadata flows through the system, allowing agents to share context, user information, session data, and coordination signals.
Coordination Mechanisms the Framework Enables¶
- LLM-Driven Coordination
The function calling system allows LLMs to intelligently decide which agents to invoke, how to combine their results, and when to escalate or delegate tasks.
- Event-Driven Architecture
Background tasks enable agents to trigger system events, coordinate with external systems, and maintain system-wide awareness without blocking conversations.
- Sequential Processing
Agents can process tasks sequentially where each agent’s output becomes the next agent’s input, enabled by flexible response types and standardized interfaces.
- Hierarchical Decision Making
Master agents can coordinate specialist agents, with the framework handling the communication, context sharing, and result aggregation automatically.
- Parallel Processing
Multiple agents can process different aspects of a problem simultaneously, with results coordinated through the framework’s async capabilities.
- Dynamic Agent Selection
Agents can dynamically decide which other agents to invoke based on context, enabled by the tool integration system and function calling.
Real-World System Capabilities¶
- Multi-Expertise Systems
Combine specialized agents (research, analysis, writing, fact-checking) where each focuses on their domain expertise while the framework handles coordination.
- Scalable Processing Systems
Build systems that can process large volumes of requests by distributing work across multiple agent instances and coordinating results.
- Context-Aware Conversations
Maintain conversation state across multiple agents, allowing users to interact with a system that remembers context even as different agents handle different parts of the conversation.
- Adaptive System Behavior
Create systems that adapt their agent usage based on request complexity, user preferences, or system load, enabled by the framework’s flexible composition.
- Cross-Agent Learning
Share insights and context between agents through the memory system, enabling system-wide learning and improvement over time.
System Coordination Examples¶
Function-Based Agent Coordination
class SystemCoordinator(BaseAgent):
def __init__(self, llm_client, specialist_agents):
super().__init__(llm_client, "Coordinate specialists")
# Convert agents to callable tools
self.agent_tools = {
name: agent.process for name, agent in specialist_agents.items()
}
async def process(self, input: IAgentInput) -> str:
# LLM decides which agents to use via function calling
llm_input = ILLMInput(
system_prompt=self.system_prompt,
user_message=input.message,
regular_functions=self.agent_tools
)
result = await self.llm_client.chat(llm_input)
return result["llm_response"]
Background Task Coordination
def notify_system_event(event_type: str, agent_id: str, details: str = ""):
"""System-wide event notification (background task)"""
# Triggers coordination without blocking conversation
system_coordinator.handle_event(event_type, agent_id, details)
def update_shared_context(key: str, value: str, scope: str = "global"):
"""Update system-wide context (background task)"""
# Maintains shared state across agents
context_manager.update(key, value, scope)
class CoordinatedAgent(BaseAgent):
async def process(self, input: IAgentInput) -> str:
background_tasks = {
"notify_system": notify_system_event,
"update_context": update_shared_context
}
llm_input = ILLMInput(
system_prompt=self.system_prompt,
user_message=input.message,
background_tasks=background_tasks
)
# LLM can trigger system coordination automatically
result = await self.llm_client.chat(llm_input)
return result["llm_response"]
Memory-Coordinated Systems
class MemoryCoordinatedSystem:
def __init__(self, memory_manager, agents):
self.memory = memory_manager
self.agents = agents
async def process_with_coordination(self, request: str, user_id: str):
# Shared memory enables coordination
context = await self.memory.get_working_memory(user_id)
# Multiple agents can access shared context
for agent_name, agent in self.agents.items():
if self.should_involve_agent(agent_name, request, context):
agent_input = IAgentInput(
message=request,
metadata={"user_id": user_id, "shared_context": context}
)
result = await agent.process(agent_input)
# Update shared context with agent results
await self.memory.update_working_memory(
user_id, f"{agent_name}_result", result
)
Dynamic System Adaptation
class AdaptiveSystem:
def __init__(self, llm_client, agent_registry):
self.coordinator = self.create_coordinator(llm_client)
self.agent_registry = agent_registry
async def process_request(self, request: str, context: dict):
# System adapts agent selection based on context
available_agents = self.select_agents_for_context(context)
# Create tools from selected agents
agent_tools = {
name: agent.process
for name, agent in available_agents.items()
}
# Coordinator uses available agents dynamically
coordinator_input = IAgentInput(
message=request,
metadata={"available_capabilities": list(agent_tools.keys())}
)
# Update coordinator's tools dynamically
self.coordinator.update_tools(agent_tools)
return await self.coordinator.process(coordinator_input)
Parallel Agent Execution
class ParallelProcessingSystem:
def __init__(self, agents):
self.agents = agents
async def process_parallel(self, request: str, user_context: dict):
# Execute multiple agents concurrently
tasks = []
for agent_name, agent in self.agents.items():
agent_input = IAgentInput(
message=request,
metadata={"context": user_context, "agent_role": agent_name}
)
tasks.append(agent.process(agent_input))
# Gather results from all agents
results = await asyncio.gather(*tasks)
# Combine results using another agent
combiner_input = IAgentInput(
message=f"Combine these agent results: {results}",
metadata={"original_request": request}
)
return await self.result_combiner.process(combiner_input)
Framework Advantages for Agentic Systems¶
- Natural Composition
Agents are just Python objects with async process methods, making them naturally composable into larger systems without framework overhead.
- Flexible Communication
Multiple communication patterns (function calling, direct invocation, background tasks, shared memory) allow you to choose the right approach for each use case.
- Intelligent Coordination
LLM-driven function calling enables systems that adapt their coordination based on context and requirements rather than fixed rules.
- Scalable Architecture
Stateless agent design and async execution enable systems that scale horizontally by adding more agent instances.
- Observable Systems
Background tasks and metadata propagation provide natural hooks for monitoring, logging, and system observability.
- Testable Components
Each agent is independently testable, making complex systems easier to validate and debug.
Building Your Agentic System¶
- Start with Purpose
Define what your system needs to accomplish and identify the distinct capabilities required.
- Design Agent Responsibilities
Create focused agents that each handle one aspect well, rather than monolithic agents that do everything.
- Choose Coordination Mechanisms
Select coordination mechanisms based on your needs:
Function calling for intelligent delegation
Background tasks for system events
Shared memory for persistent context
Direct communication for simple interactions
- Implement Incrementally
Start with simple agent interactions and add coordination complexity as needed.
- Test System Behavior
Test not just individual agents but their interactions and coordination patterns.
- Monitor and Adapt
Use background tasks and metadata to monitor system behavior and adapt coordination over time.
Common System Architectures the Framework Enables¶
- Coordinator-Based Systems
Master agents coordinate specialists using function calling and intelligent delegation.
- Sequential Processing Systems
Step-by-step processing enabled by flexible input/output types and standardized interfaces.
- Peer-to-Peer Systems
Agents communicate directly using method calls and shared context.
- Hierarchical Systems
Multi-level coordination using nested function calling and context propagation.
- Event-Driven Systems
System-wide coordination using background tasks and event notification.
- Adaptive Systems
Dynamic behavior using metadata-driven agent selection and configuration.
Key Framework Principles¶
- You Control the Architecture
The framework provides capabilities; you decide how to use them for your specific agentic system.
- Composition Over Prescription
Build complex systems by composing simple agents rather than following rigid architectural patterns.
- Intelligence-Driven Coordination
Leverage LLM function calling for adaptive, context-aware coordination rather than fixed rules.
- Progressive Complexity
Start with simple agent interactions and add sophisticated coordination as your system evolves.
- Observable and Maintainable
Built-in hooks for monitoring, logging, and debugging complex multi-agent interactions.
The framework doesn’t prescribe specific agentic architectures but provides the foundational capabilities that make any architecture possible. Your system’s design emerges from your specific needs and the intelligent coordination enabled by the framework’s LLM-driven function calling and background task systems.