You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

runners.py 7.9 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. from abc import ABC, abstractmethod
  2. from datetime import datetime
  3. from typing import Any, Dict, Optional, Sequence, Type, Union
  4. from autogen_agentchat.base import TaskResult, Team
  5. from autogen_agentchat.messages import ChatMessage, MultiModalMessage, TextMessage
  6. from autogen_core import CancellationToken, Component, ComponentBase, ComponentModel, Image
  7. from autogen_core.models import ChatCompletionClient, UserMessage
  8. from pydantic import BaseModel
  9. from typing_extensions import Self
  10. from ..datamodel.eval import EvalRunResult, EvalTask
  11. class BaseEvalRunnerConfig(BaseModel):
  12. """Base configuration for evaluation runners."""
  13. name: str
  14. description: str = ""
  15. metadata: Dict[str, Any] = {}
  16. class BaseEvalRunner(ABC, ComponentBase[BaseEvalRunnerConfig]):
  17. """Base class for evaluation runners that defines the interface for running evaluations.
  18. This class provides the core interface that all evaluation runners must implement.
  19. Subclasses should implement the run method to define how a specific evaluation is executed.
  20. """
  21. component_type = "eval_runner"
  22. def __init__(self, name: str, description: str = "", metadata: Optional[Dict[str, Any]] = None):
  23. self.name = name
  24. self.description = description
  25. self.metadata = metadata or {}
  26. @abstractmethod
  27. async def run(self, task: EvalTask, cancellation_token: Optional[CancellationToken] = None) -> EvalRunResult:
  28. """Run the evaluation on the provided task and return a result.
  29. Args:
  30. task: The task to evaluate
  31. cancellation_token: Optional token to cancel the evaluation
  32. Returns:
  33. EvaluationResult: The result of the evaluation
  34. """
  35. pass
  36. def _to_config(self) -> BaseEvalRunnerConfig:
  37. """Convert the runner configuration to a configuration object for serialization."""
  38. return BaseEvalRunnerConfig(name=self.name, description=self.description, metadata=self.metadata)
  39. class ModelEvalRunnerConfig(BaseEvalRunnerConfig):
  40. """Configuration for ModelEvalRunner."""
  41. model_client: ComponentModel
  42. class ModelEvalRunner(BaseEvalRunner, Component[ModelEvalRunnerConfig]):
  43. """Evaluation runner that uses a single LLM to process tasks.
  44. This runner sends the task directly to a model client and returns the response.
  45. """
  46. component_config_schema = ModelEvalRunnerConfig
  47. component_type = "eval_runner"
  48. component_provider_override = "autogenstudio.eval.runners.ModelEvalRunner"
  49. def __init__(
  50. self,
  51. model_client: ChatCompletionClient,
  52. name: str = "Model Runner",
  53. description: str = "Evaluates tasks using a single LLM",
  54. metadata: Optional[Dict[str, Any]] = None,
  55. ):
  56. super().__init__(name, description, metadata)
  57. self.model_client = model_client
  58. async def run(self, task: EvalTask, cancellation_token: Optional[CancellationToken] = None) -> EvalRunResult:
  59. """Run the task with the model client and return the result."""
  60. # Create initial result object
  61. result = EvalRunResult()
  62. try:
  63. model_input = []
  64. if isinstance(task.input, str):
  65. text_message = UserMessage(content=task.input, source="user")
  66. model_input.append(text_message)
  67. elif isinstance(task.input, list):
  68. message_content = [x for x in task.input]
  69. model_input.append(UserMessage(content=message_content, source="user"))
  70. # Run with the model
  71. model_result = await self.model_client.create(messages=model_input, cancellation_token=cancellation_token)
  72. model_response = model_result.content if isinstance(model_result, str) else model_result.model_dump()
  73. task_result = TaskResult(
  74. messages=[TextMessage(content=str(model_response), source="model")],
  75. )
  76. result = EvalRunResult(result=task_result, status=True, start_time=datetime.now(), end_time=datetime.now())
  77. except Exception as e:
  78. result = EvalRunResult(status=False, error=str(e), end_time=datetime.now())
  79. return result
  80. def _to_config(self) -> ModelEvalRunnerConfig:
  81. """Convert to configuration object including model client configuration."""
  82. base_config = super()._to_config()
  83. return ModelEvalRunnerConfig(
  84. name=base_config.name,
  85. description=base_config.description,
  86. metadata=base_config.metadata,
  87. model_client=self.model_client.dump_component(),
  88. )
  89. @classmethod
  90. def _from_config(cls, config: ModelEvalRunnerConfig) -> Self:
  91. """Create from configuration object with serialized model client."""
  92. model_client = ChatCompletionClient.load_component(config.model_client)
  93. return cls(
  94. name=config.name,
  95. description=config.description,
  96. metadata=config.metadata,
  97. model_client=model_client,
  98. )
  99. class TeamEvalRunnerConfig(BaseEvalRunnerConfig):
  100. """Configuration for TeamEvalRunner."""
  101. team: ComponentModel
  102. class TeamEvalRunner(BaseEvalRunner, Component[TeamEvalRunnerConfig]):
  103. """Evaluation runner that uses a team of agents to process tasks.
  104. This runner creates and runs a team based on a team configuration.
  105. """
  106. component_config_schema = TeamEvalRunnerConfig
  107. component_type = "eval_runner"
  108. component_provider_override = "autogenstudio.eval.runners.TeamEvalRunner"
  109. def __init__(
  110. self,
  111. team: Union[Team, ComponentModel],
  112. name: str = "Team Runner",
  113. description: str = "Evaluates tasks using a team of agents",
  114. metadata: Optional[Dict[str, Any]] = None,
  115. ):
  116. super().__init__(name, description, metadata)
  117. self._team = team if isinstance(team, Team) else Team.load_component(team)
  118. async def run(self, task: EvalTask, cancellation_token: Optional[CancellationToken] = None) -> EvalRunResult:
  119. """Run the task with the team and return the result."""
  120. # Create initial result object
  121. result = EvalRunResult()
  122. try:
  123. team_task: Sequence[ChatMessage] = []
  124. if isinstance(task.input, str):
  125. team_task.append(TextMessage(content=task.input, source="user"))
  126. if isinstance(task.input, list):
  127. for message in task.input:
  128. if isinstance(message, str):
  129. team_task.append(TextMessage(content=message, source="user"))
  130. elif isinstance(message, Image):
  131. team_task.append(MultiModalMessage(source="user", content=[message]))
  132. # Run task with team
  133. team_result = await self._team.run(task=team_task, cancellation_token=cancellation_token)
  134. result = EvalRunResult(result=team_result, status=True, start_time=datetime.now(), end_time=datetime.now())
  135. except Exception as e:
  136. result = EvalRunResult(status=False, error=str(e), end_time=datetime.now())
  137. return result
  138. def _to_config(self) -> TeamEvalRunnerConfig:
  139. """Convert to configuration object including team configuration."""
  140. base_config = super()._to_config()
  141. return TeamEvalRunnerConfig(
  142. name=base_config.name,
  143. description=base_config.description,
  144. metadata=base_config.metadata,
  145. team=self._team.dump_component(),
  146. )
  147. @classmethod
  148. def _from_config(cls, config: TeamEvalRunnerConfig) -> Self:
  149. """Create from configuration object with serialized team configuration."""
  150. return cls(
  151. team=Team.load_component(config.team),
  152. name=config.name,
  153. description=config.description,
  154. metadata=config.metadata,
  155. )