mirror of
https://github.com/encounter/adk-python.git
synced 2026-07-09 18:19:28 -07:00
feat: Data model for storing App Details and data model for steps
Details: 1. Data model for storing App Details (the agentic system) As we move towards LLM as Judge metrics, we see that some of these metrics need information about the Agentic system that was used for inferencing. We add a data model to capture that. 2. Data model for Steps We refine the concept of intermediate data. Previously it stored data in the form of a multiple lists, thereby losing out on the chronological information. This information is needed for some of the metrics. So we refine the concept of intermediate data as series of logical steps that an Agent Take. PiperOrigin-RevId: 811122784
This commit is contained in:
committed by
Copybara-Service
parent
08f3b48305
commit
01923a9227
@@ -24,6 +24,7 @@ from pydantic import BaseModel
|
||||
from ..agents.llm_agent import Agent
|
||||
from ..artifacts.base_artifact_service import BaseArtifactService
|
||||
from ..artifacts.in_memory_artifact_service import InMemoryArtifactService
|
||||
from ..events.event import Event
|
||||
from ..memory.base_memory_service import BaseMemoryService
|
||||
from ..memory.in_memory_memory_service import InMemoryMemoryService
|
||||
from ..runners import Runner
|
||||
@@ -31,12 +32,17 @@ from ..sessions.base_session_service import BaseSessionService
|
||||
from ..sessions.in_memory_session_service import InMemorySessionService
|
||||
from ..sessions.session import Session
|
||||
from ..utils.context_utils import Aclosing
|
||||
from .app_details import AppDetails
|
||||
from .eval_case import EvalCase
|
||||
from .eval_case import IntermediateData
|
||||
from .eval_case import Invocation
|
||||
from .eval_case import InvocationEvent
|
||||
from .eval_case import InvocationEvents
|
||||
from .eval_case import SessionInput
|
||||
from .eval_set import EvalSet
|
||||
|
||||
_USER_AUTHOR = "user"
|
||||
_DEFAULT_AUTHOR = "agent"
|
||||
|
||||
|
||||
class EvalCaseResponses(BaseModel):
|
||||
"""Contains multiple responses associated with an EvalCase.
|
||||
@@ -174,8 +180,6 @@ class EvaluationGenerator:
|
||||
if callable(reset_func):
|
||||
reset_func()
|
||||
|
||||
response_invocations = []
|
||||
|
||||
async with Runner(
|
||||
app_name=app_name,
|
||||
agent=root_agent,
|
||||
@@ -183,42 +187,94 @@ class EvaluationGenerator:
|
||||
session_service=session_service,
|
||||
memory_service=memory_service,
|
||||
) as runner:
|
||||
events = []
|
||||
|
||||
for invocation in invocations:
|
||||
final_response = None
|
||||
user_content = invocation.user_content
|
||||
tool_uses = []
|
||||
invocation_id = ""
|
||||
invocation_id = None
|
||||
|
||||
async with Aclosing(
|
||||
runner.run_async(
|
||||
user_id=user_id, session_id=session_id, new_message=user_content
|
||||
)
|
||||
) as agen:
|
||||
|
||||
async for event in agen:
|
||||
invocation_id = (
|
||||
event.invocation_id if not invocation_id else invocation_id
|
||||
)
|
||||
if not invocation_id:
|
||||
invocation_id = event.invocation_id
|
||||
events.append(
|
||||
Event(
|
||||
content=user_content,
|
||||
author=_USER_AUTHOR,
|
||||
invocation_id=invocation_id,
|
||||
)
|
||||
)
|
||||
|
||||
if (
|
||||
event.is_final_response()
|
||||
and event.content
|
||||
and event.content.parts
|
||||
):
|
||||
final_response = event.content
|
||||
elif event.get_function_calls():
|
||||
for call in event.get_function_calls():
|
||||
tool_uses.append(call)
|
||||
events.append(event)
|
||||
|
||||
response_invocations.append(
|
||||
Invocation(
|
||||
invocation_id=invocation_id,
|
||||
user_content=user_content,
|
||||
final_response=final_response,
|
||||
intermediate_data=IntermediateData(tool_uses=tool_uses),
|
||||
)
|
||||
)
|
||||
return EvaluationGenerator.convert_events_to_eval_invocations(events)
|
||||
|
||||
return response_invocations
|
||||
@staticmethod
|
||||
def convert_events_to_eval_invocations(
|
||||
events: list[Event],
|
||||
) -> list[Invocation]:
|
||||
"""Converts a list of events to eval invocations."""
|
||||
# Group Events by invocation id. Events that share the same invocation id
|
||||
# belong to the same invocation.
|
||||
events_by_invocation_id: dict[str, list[Event]] = {}
|
||||
|
||||
for event in events:
|
||||
invocation_id = event.invocation_id
|
||||
|
||||
if invocation_id not in events_by_invocation_id:
|
||||
events_by_invocation_id[invocation_id] = []
|
||||
|
||||
events_by_invocation_id[invocation_id].append(event)
|
||||
|
||||
invocations = []
|
||||
for invocation_id, events in events_by_invocation_id.items():
|
||||
final_response = None
|
||||
user_content = ""
|
||||
invocation_timestamp = 0
|
||||
|
||||
events_to_add = []
|
||||
|
||||
for event in events:
|
||||
current_author = (event.author or _DEFAULT_AUTHOR).lower()
|
||||
|
||||
if current_author == _USER_AUTHOR:
|
||||
# If the author is the user, then we just identify it and move on
|
||||
# to the next event.
|
||||
user_content = event.content
|
||||
invocation_timestamp = event.timestamp
|
||||
continue
|
||||
|
||||
if event.content and event.content.parts:
|
||||
if event.is_final_response():
|
||||
final_response = event.content
|
||||
else:
|
||||
for p in event.content.parts:
|
||||
if p.function_call or p.function_response or p.text:
|
||||
events_to_add.append(event)
|
||||
break
|
||||
|
||||
invocation_events = [
|
||||
InvocationEvent(author=e.author, content=e.content)
|
||||
for e in events_to_add
|
||||
]
|
||||
invocations.append(
|
||||
Invocation(
|
||||
invocation_id=invocation_id,
|
||||
user_content=user_content,
|
||||
final_response=final_response,
|
||||
intermediate_data=InvocationEvents(
|
||||
invocation_events=invocation_events
|
||||
),
|
||||
creation_timestamp=invocation_timestamp,
|
||||
)
|
||||
)
|
||||
|
||||
return invocations
|
||||
|
||||
@staticmethod
|
||||
def _process_query_with_session(session_data, data):
|
||||
|
||||
Reference in New Issue
Block a user