fix: aclose all async generators to fix OTel tracing context

See https://github.com/google/adk-python/issues/1670#issuecomment-3115891100

PiperOrigin-RevId: 794659547
This commit is contained in:
Kacper Jawoszek
2025-08-13 11:18:26 -07:00
committed by Copybara-Service
parent c5af44cfc0
commit a30c63c593
23 changed files with 735 additions and 514 deletions
+14 -11
View File
@@ -32,6 +32,7 @@ from pydantic import BaseModel
from pydantic import ValidationError
from ..agents.base_agent import BaseAgent
from ..utils.context_utils import Aclosing
from .constants import MISSING_EVAL_DEPENDENCIES_MESSAGE
from .eval_case import IntermediateData
from .eval_case import Invocation
@@ -538,10 +539,11 @@ class AgentEvaluator:
# Generate inferences
inference_results = []
for inference_request in inference_requests:
async for inference_result in eval_service.perform_inference(
inference_request=inference_request
):
inference_results.append(inference_result)
async with Aclosing(
eval_service.perform_inference(inference_request=inference_request)
) as agen:
async for inference_result in agen:
inference_results.append(inference_result)
# Evaluate metrics
# As we perform more than one run for an eval case, we collect eval results
@@ -551,14 +553,15 @@ class AgentEvaluator:
inference_results=inference_results,
evaluate_config=EvaluateConfig(eval_metrics=eval_metrics),
)
async for eval_result in eval_service.evaluate(
evaluate_request=evaluate_request
):
eval_id = eval_result.eval_id
if eval_id not in eval_results_by_eval_id:
eval_results_by_eval_id[eval_id] = []
async with Aclosing(
eval_service.evaluate(evaluate_request=evaluate_request)
) as agen:
async for eval_result in agen:
eval_id = eval_result.eval_id
if eval_id not in eval_results_by_eval_id:
eval_results_by_eval_id[eval_id] = []
eval_results_by_eval_id[eval_id].append(eval_result)
eval_results_by_eval_id[eval_id].append(eval_result)
return eval_results_by_eval_id
@@ -30,6 +30,7 @@ from ..runners import Runner
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 .eval_case import EvalCase
from .eval_case import IntermediateData
from .eval_case import Invocation
@@ -189,18 +190,25 @@ class EvaluationGenerator:
tool_uses = []
invocation_id = ""
async for event in runner.run_async(
user_id=user_id, session_id=session_id, new_message=user_content
):
invocation_id = (
event.invocation_id if not invocation_id else invocation_id
)
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 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)
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)
response_invocations.append(
Invocation(
+17 -15
View File
@@ -24,6 +24,7 @@ from ..models.base_llm import BaseLlm
from ..models.llm_request import LlmRequest
from ..models.llm_response import LlmResponse
from ..models.registry import LLMRegistry
from ..utils.context_utils import Aclosing
from .eval_case import Invocation
from .eval_metrics import EvalMetric
from .evaluator import EvaluationResult
@@ -109,21 +110,22 @@ class LlmAsJudge(Evaluator):
num_samples = self._judge_model_options.num_samples
invocation_result_samples = []
for _ in range(num_samples):
async for llm_response in self._judge_model.generate_content_async(
llm_request
):
# Non-streaming call, so there is only one response content.
score = self.convert_auto_rater_response_to_score(llm_response)
invocation_result_samples.append(
PerInvocationResult(
actual_invocation=actual,
expected_invocation=expected,
score=score,
eval_status=get_eval_status(
score, self._eval_metric.threshold
),
)
)
async with Aclosing(
self._judge_model.generate_content_async(llm_request)
) as agen:
async for llm_response in agen:
# Non-streaming call, so there is only one response content.
score = self.convert_auto_rater_response_to_score(llm_response)
invocation_result_samples.append(
PerInvocationResult(
actual_invocation=actual,
expected_invocation=expected,
score=score,
eval_status=get_eval_status(
score, self._eval_metric.threshold
),
)
)
if not invocation_result_samples:
continue
per_invocation_results.append(