mirror of
https://github.com/langgenius/dify.git
synced 2026-09-08 11:04:27 +08:00
evaluation runtime
This commit is contained in:
parent
61e87a4ff4
commit
8ea3729fe9
@ -126,7 +126,7 @@ class RagasEvaluator(BaseEvaluationInstance):
|
|||||||
samples = []
|
samples = []
|
||||||
for item in items:
|
for item in items:
|
||||||
sample = SingleTurnSample(
|
sample = SingleTurnSample(
|
||||||
user_input=self._inputs_to_query(item.inputs),
|
user_input=self._inputs_format(item.inputs, category),
|
||||||
response=item.expected_output or "",
|
response=item.expected_output or "",
|
||||||
retrieved_contexts=item.context or [],
|
retrieved_contexts=item.context or [],
|
||||||
)
|
)
|
||||||
@ -233,14 +233,15 @@ class RagasEvaluator(BaseEvaluationInstance):
|
|||||||
return 0.0
|
return 0.0
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _inputs_to_query(inputs: dict[str, Any]) -> str:
|
def _inputs_format(inputs: dict[str, Any], category: EvaluationCategory) -> str:
|
||||||
"""Convert input dict to a query string."""
|
"""Convert input dict to a prompt string."""
|
||||||
if "query" in inputs:
|
match category:
|
||||||
return str(inputs["query"])
|
case EvaluationCategory.LLM:
|
||||||
if "question" in inputs:
|
return str(inputs["prompt"])
|
||||||
return str(inputs["question"])
|
case EvaluationCategory.RETRIEVAL:
|
||||||
# Fallback: concatenate all input values
|
return str(inputs["query"])
|
||||||
return " ".join(str(v) for v in inputs.values())
|
case _:
|
||||||
|
return ""
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _build_ragas_metrics(requested_metrics: list[str]) -> list[Any]:
|
def _build_ragas_metrics(requested_metrics: list[str]) -> list[Any]:
|
||||||
|
|||||||
@ -75,17 +75,45 @@ class LLMEvaluationRunner(BaseEvaluationRunner):
|
|||||||
def _merge_results_into_items(
|
def _merge_results_into_items(
|
||||||
items: list[NodeRunResult],
|
items: list[NodeRunResult],
|
||||||
) -> list[EvaluationItemInput]:
|
) -> list[EvaluationItemInput]:
|
||||||
"""Create new items with actual_output set as expected_output context for metrics."""
|
"""Create new items from NodeRunResult for ragas evaluation.
|
||||||
|
|
||||||
|
Extracts prompts from process_data and concatenates them into a single
|
||||||
|
string with role prefixes (e.g. "system: ...\nuser: ...\nassistant: ...").
|
||||||
|
The last assistant message in outputs is used as the actual output.
|
||||||
|
"""
|
||||||
merged = []
|
merged = []
|
||||||
for item in items:
|
for i, item in enumerate(items):
|
||||||
|
prompt = _format_prompts(item.process_data.get("prompts", []))
|
||||||
|
output = _extract_llm_output(item.outputs)
|
||||||
merged.append(
|
merged.append(
|
||||||
EvaluationItemInput(
|
EvaluationItemInput(
|
||||||
index=item.index,
|
index=i,
|
||||||
inputs={
|
inputs={"prompt": prompt},
|
||||||
"prompt": item.prompt,
|
output=output,
|
||||||
},
|
|
||||||
output=item.output,
|
|
||||||
expected_output=item.expected_output,
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return merged
|
return merged
|
||||||
|
|
||||||
|
|
||||||
|
def _format_prompts(prompts: list[dict[str, Any]]) -> str:
|
||||||
|
"""Concatenate a list of prompt messages into a single string for evaluation.
|
||||||
|
|
||||||
|
Each message is formatted as "role: text" and joined with newlines.
|
||||||
|
"""
|
||||||
|
parts: list[str] = []
|
||||||
|
for msg in prompts:
|
||||||
|
role = msg.get("role", "unknown")
|
||||||
|
text = msg.get("text", "")
|
||||||
|
parts.append(f"{role}: {text}")
|
||||||
|
return "\n".join(parts)
|
||||||
|
|
||||||
|
|
||||||
|
def _extract_llm_output(outputs: Mapping[str, Any]) -> str:
|
||||||
|
"""Extract the LLM output text from NodeRunResult.outputs."""
|
||||||
|
if "text" in outputs:
|
||||||
|
return str(outputs["text"])
|
||||||
|
if "answer" in outputs:
|
||||||
|
return str(outputs["answer"])
|
||||||
|
# Fallback: first value
|
||||||
|
values = list(outputs.values())
|
||||||
|
return str(values[0]) if values else ""
|
||||||
|
|||||||
@ -33,48 +33,39 @@ class RetrievalEvaluationRunner(BaseEvaluationRunner):
|
|||||||
tenant_id: str,
|
tenant_id: str,
|
||||||
) -> list[EvaluationItemResult]:
|
) -> list[EvaluationItemResult]:
|
||||||
"""Compute retrieval evaluation metrics."""
|
"""Compute retrieval evaluation metrics."""
|
||||||
# Merge retrieved contexts into items
|
if not node_run_result_list:
|
||||||
result_by_index = {r.index: r for r in results}
|
return []
|
||||||
|
if not default_metric:
|
||||||
|
raise ValueError("Default metric is required for retrieval evaluation")
|
||||||
|
|
||||||
merged_items = []
|
merged_items = []
|
||||||
for item in items:
|
for i, node_result in enumerate(node_run_result_list):
|
||||||
result = result_by_index.get(item.index)
|
# Extract retrieved contexts from outputs
|
||||||
contexts = result.metadata.get("retrieved_contexts", []) if result else []
|
outputs = node_result.outputs
|
||||||
|
contexts = list(outputs.get("retrieved_contexts", []))
|
||||||
|
query = self._extract_query(dict(node_result.inputs))
|
||||||
|
# Extract retrieved content from result list
|
||||||
|
result_list = outputs.get("result", [])
|
||||||
|
output = "\n---\n".join(
|
||||||
|
str(item.get("content", "")) for item in result_list if item.get("content")
|
||||||
|
)
|
||||||
|
|
||||||
merged_items.append(
|
merged_items.append(
|
||||||
EvaluationItemInput(
|
EvaluationItemInput(
|
||||||
index=item.index,
|
index=i,
|
||||||
inputs=item.inputs,
|
inputs={"query": query},
|
||||||
expected_output=item.expected_output,
|
output=output,
|
||||||
context=contexts,
|
context=contexts,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
evaluated = self.evaluation_instance.evaluate_retrieval(
|
return self.evaluation_instance.evaluate_retrieval(
|
||||||
merged_items, default_metrics, model_provider, model_name, tenant_id
|
merged_items, default_metric.metric, model_provider, model_name, tenant_id
|
||||||
)
|
)
|
||||||
|
|
||||||
# Merge metrics back into original results (preserve actual_output and metadata)
|
|
||||||
eval_by_index = {r.index: r for r in evaluated}
|
|
||||||
final_results = []
|
|
||||||
for result in results:
|
|
||||||
if result.index in eval_by_index:
|
|
||||||
eval_result = eval_by_index[result.index]
|
|
||||||
final_results.append(
|
|
||||||
EvaluationItemResult(
|
|
||||||
index=result.index,
|
|
||||||
actual_output=result.actual_output,
|
|
||||||
metrics=eval_result.metrics,
|
|
||||||
metadata=result.metadata,
|
|
||||||
error=result.error,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
final_results.append(result)
|
|
||||||
return final_results
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _extract_query(inputs: dict[str, Any]) -> str:
|
def _extract_query(inputs: dict[str, Any]) -> str:
|
||||||
for key in ("query", "question", "input", "text"):
|
for key in ("query"):
|
||||||
if key in inputs:
|
if key in inputs:
|
||||||
return str(inputs[key])
|
return str(inputs[key])
|
||||||
values = list(inputs.values())
|
return ""
|
||||||
return str(values[0]) if values else ""
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user