"""Keyword matching evaluation rule.""" from agenteval.evaluation.rules.base import EvalRule, RuleResult, register_rule from agenteval.models import Case, Turn def _extract_text(reply) -> str: """Extract plain text from a reply object for matching.""" if reply is None: return "" if isinstance(reply, str): return reply if isinstance(reply, dict): # Tutu-api message structure: msgBody.content body = reply.get("msgBody") or reply.get("content", "") if isinstance(body, dict): return body.get("content", "") return str(body) return str(reply) @register_rule class KeywordMatchRule(EvalRule): """Check whether the reply contains required keywords and excludes forbidden ones.""" name = "keyword_match" def evaluate(self, case: Case, dialog: list[Turn]) -> RuleResult: if not dialog: return RuleResult(passed=False, reason="无回复记录") last_turn = dialog[-1] reply = last_turn.reply text = _extract_text(reply).lower() params = self.params include = [k.lower() for k in params.get("keywords", [])] exclude = [k.lower() for k in params.get("exclude_keywords", [])] missing = [k for k in include if k not in text] found_excluded = [k for k in exclude if k in text] if missing or found_excluded: reasons = [] if missing: reasons.append(f"缺少关键词: {missing}") if found_excluded: reasons.append(f"包含禁用词: {found_excluded}") return RuleResult(passed=False, reason="; ".join(reasons)) match_count = sum(1 for k in include if k in text) score = 1.0 if not include else match_count / len(include) return RuleResult(passed=True, score=score, reason="关键词匹配通过")