Add prompt improvement button in drawer
This commit is contained in:
@@ -15,7 +15,6 @@ from services.test_runs.text_runner import RawToolCall, RawTurnResult, TextCaseR
|
||||
from test_schemas import (
|
||||
BatchEvaluationResult,
|
||||
BatchTurnResult,
|
||||
FixedInputTurn,
|
||||
OverallCriterion,
|
||||
ReplyExpectedBehavior,
|
||||
TestCaseDefinition,
|
||||
@@ -32,9 +31,7 @@ class EvaluatedCase:
|
||||
@property
|
||||
def passed(self) -> bool:
|
||||
evaluations = [
|
||||
item
|
||||
for turn in self.turns
|
||||
for item in turn.evaluations
|
||||
item for turn in self.turns for item in turn.evaluations
|
||||
] + self.overall_criteria
|
||||
return all(item.status == "pass" for item in evaluations)
|
||||
|
||||
@@ -93,29 +90,47 @@ class LLMJudge:
|
||||
)
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=self._timeout_seconds) as client:
|
||||
response = await client.post(
|
||||
f"{base_url}/chat/completions",
|
||||
headers={
|
||||
"Authorization": f"Bearer {api_key}",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
json=payload,
|
||||
)
|
||||
response.raise_for_status()
|
||||
body = response.json()
|
||||
content = body["choices"][0]["message"]["content"]
|
||||
if isinstance(content, list):
|
||||
content = "".join(
|
||||
str(part.get("text") or "")
|
||||
for part in content
|
||||
if isinstance(part, dict)
|
||||
)
|
||||
parsed = self._parse_json(str(content or ""))
|
||||
return (
|
||||
bool(parsed.get("passed")),
|
||||
str(parsed.get("reason") or "LLM 未提供判断理由"),
|
||||
str(parsed.get("actual") or ""),
|
||||
)
|
||||
for attempt in range(2):
|
||||
request_payload = dict(payload)
|
||||
if attempt:
|
||||
request_payload["messages"] = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": (
|
||||
f"{prompt}\n\n格式修正:上一次响应无法解析。"
|
||||
"请只返回一个完整 JSON 对象,不要重复输出、"
|
||||
"不要添加解释或 Markdown。"
|
||||
),
|
||||
}
|
||||
]
|
||||
response = await client.post(
|
||||
f"{base_url}/chat/completions",
|
||||
headers={
|
||||
"Authorization": f"Bearer {api_key}",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
json=request_payload,
|
||||
)
|
||||
response.raise_for_status()
|
||||
try:
|
||||
body = response.json()
|
||||
content = body["choices"][0]["message"]["content"]
|
||||
if isinstance(content, list):
|
||||
content = "".join(
|
||||
str(part.get("text") or "")
|
||||
for part in content
|
||||
if isinstance(part, dict)
|
||||
)
|
||||
parsed = self._parse_json(str(content or ""))
|
||||
except (KeyError, IndexError, TypeError, ValueError):
|
||||
if attempt == 0:
|
||||
continue
|
||||
raise
|
||||
return (
|
||||
bool(parsed.get("passed")),
|
||||
str(parsed.get("reason") or "LLM 未提供判断理由"),
|
||||
str(parsed.get("actual") or ""),
|
||||
)
|
||||
except TestExecutionError:
|
||||
raise
|
||||
except (httpx.HTTPError, KeyError, IndexError, TypeError, ValueError) as exc:
|
||||
@@ -133,14 +148,10 @@ class LLMJudge:
|
||||
text = re.sub(r"^```(?:json)?\s*", "", text)
|
||||
text = re.sub(r"\s*```$", "", text)
|
||||
start = text.find("{")
|
||||
end = text.rfind("}")
|
||||
if start < 0 or end < start:
|
||||
if start < 0:
|
||||
raise ValueError("评估模型没有返回 JSON")
|
||||
parsed = json.loads(text[start : end + 1])
|
||||
if (
|
||||
not isinstance(parsed, dict)
|
||||
or not isinstance(parsed.get("passed"), bool)
|
||||
):
|
||||
parsed, _end = json.JSONDecoder().raw_decode(text[start:])
|
||||
if not isinstance(parsed, dict) or not isinstance(parsed.get("passed"), bool):
|
||||
raise ValueError("评估模型返回格式不正确")
|
||||
return parsed
|
||||
|
||||
@@ -221,7 +232,9 @@ class EvaluationEngine:
|
||||
)
|
||||
|
||||
normalized_reply = reply.casefold()
|
||||
matches = [keyword.casefold() in normalized_reply for keyword in behavior.keywords]
|
||||
matches = [
|
||||
keyword.casefold() in normalized_reply for keyword in behavior.keywords
|
||||
]
|
||||
matched = all(matches) if behavior.keyword_match_mode == "all" else any(matches)
|
||||
passed = not matched if behavior.negate_keywords else matched
|
||||
relation = (
|
||||
|
||||
Reference in New Issue
Block a user