7.3 Framework Interface Implementation
In the previous section, we built HelloAgentsLLM, a core component that solves the key problem of communicating with large language models. However, it still needs a series of supporting interfaces and components to handle data flow, manage configuration, handle exceptions, and provide a clear, unified structure for upper-layer application construction. This section will cover the following three core files:
message.py: Defines the unified message format within the framework, ensuring standardization of information transfer between agents and models.config.py: Provides a centralized configuration management solution, making framework behavior easy to adjust and extend.agent.py: Defines the abstract base class (Agent) for all agents, providing a unified interface and specification for implementing different types of agents in the future.
7.3.1 Message Class
In the interaction between agents and large language models, conversation history is crucial context. To manage this information in a standardized way, we designed a simple Message class. It will be extended in the subsequent context engineering chapter.
"""Message system"""
from typing import Optional, Dict, Any, Literal
from datetime import datetime
from pydantic import BaseModel
# Define message role type, restricting its values
MessageRole = Literal["user", "assistant", "system", "tool"]
class Message(BaseModel):
"""Message class"""
content: str
role: MessageRole
timestamp: datetime = None
metadata: Optional[Dict[str, Any]] = None
def __init__(self, content: str, role: MessageRole, **kwargs):
super().__init__(
content=content,
role=role,
timestamp=kwargs.get('timestamp', datetime.now()),
metadata=kwargs.get('metadata', {})
)
def to_dict(self) -> Dict[str, Any]:
"""Convert to dictionary format (OpenAI API format)"""
return {
"role": self.role,
"content": self.content
}
def __str__(self) -> str:
return f"[{self.role}] {self.content}"The design of this class has several key points. First, we strictly limit the values of the role field to four types: "user", "assistant", "system", "tool" through typing.Literal, which directly corresponds to the OpenAI API specification and ensures type safety. In addition to the two core fields content and role, we also added timestamp and metadata, reserving space for logging and future feature expansion. Finally, the to_dict() method is one of its core functions, responsible for converting the internally used Message object to a dictionary format compatible with the OpenAI API, embodying the design principle of "rich internally, compatible externally."
7.3.2 Config Class
The responsibility of the Config class is to centralize hard-coded configuration parameters in the code and support reading from environment variables.
"""Configuration management"""
import os
from typing import Optional, Dict, Any
from pydantic import BaseModel
class Config(BaseModel):
"""HelloAgents configuration class"""
# LLM configuration
default_model: str = "gpt-3.5-turbo"
default_provider: str = "openai"
temperature: float = 0.7
max_tokens: Optional[int] = None
# System configuration
debug: bool = False
log_level: str = "INFO"
# Other configuration
max_history_length: int = 100
@classmethod
def from_env(cls) -> "Config":
"""Create configuration from environment variables"""
return cls(
debug=os.getenv("DEBUG", "false").lower() == "true",
log_level=os.getenv("LOG_LEVEL", "INFO"),
temperature=float(os.getenv("TEMPERATURE", "0.7")),
max_tokens=int(os.getenv("MAX_TOKENS")) if os.getenv("MAX_TOKENS") else None,
)
def to_dict(self) -> Dict[str, Any]:
"""Convert to dictionary"""
return self.dict()First, we divide configuration items logically into LLM configuration, System configuration, etc., making the structure clear at a glance. Second, each configuration item has a reasonable default value, ensuring that the framework can work with zero configuration. The most core is the from_env() class method, which allows users to override default configurations by setting environment variables without modifying code, which is especially useful when deploying to different environments.
7.3.3 Agent Abstract Base Class
The Agent class is the top-level abstraction of the entire framework. It defines the common behaviors and attributes that an agent should have but does not care about specific implementation methods. We implement it through Python's abc (Abstract Base Classes) module, which forces all concrete agent implementations (such as SimpleAgent, ReActAgent, etc. in subsequent chapters) to follow the same "interface."
"""Agent base class"""
from abc import ABC, abstractmethod
from typing import Optional, Any
from .message import Message
from .llm import HelloAgentsLLM
from .config import Config
class Agent(ABC):
"""Agent base class"""
def __init__(
self,
name: str,
llm: HelloAgentsLLM,
system_prompt: Optional[str] = None,
config: Optional[Config] = None
):
self.name = name
self.llm = llm
self.system_prompt = system_prompt
self.config = config or Config()
self._history: list[Message] = []
@abstractmethod
def run(self, input_text: str, **kwargs) -> str:
"""Run Agent"""
pass
def add_message(self, message: Message):
"""Add message to history"""
self._history.append(message)
def clear_history(self):
"""Clear history"""
self._history.clear()
def get_history(self) -> list[Message]:
"""Get history"""
return self._history.copy()
def __str__(self) -> str:
return f"Agent(name={self.name}, provider={self.llm.provider})"The design of this class embodies the abstraction principle in object-oriented programming. First, it is defined as an abstract class that cannot be directly instantiated by inheriting ABC. Its constructor __init__ clearly defines the core dependencies of an Agent: name, LLM instance, system prompt, and configuration. The most important part is the run method decorated with @abstractmethod, which forces all subclasses to implement this method, thereby ensuring that all agents have a unified execution entry point. In addition, the base class also provides common history management methods, which work in coordination with the Message class, reflecting the connection between components.
At this point, we have completed the design and implementation of the core basic components of the HelloAgents framework.