feat/ 导出开发容器内的数据用于评估
This commit is contained in:
83
api/app/features/evaluation/candidate_runner.py
Normal file
83
api/app/features/evaluation/candidate_runner.py
Normal file
@@ -0,0 +1,83 @@
|
||||
"""独立候选回放:多轮 user 链式调用 LLM,不走路由 WS / ChatOrchestrator。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
from typing import Any
|
||||
|
||||
from app.core.logging import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def _system_prompt_for_eval(version_config: dict | None) -> str:
|
||||
cfg = version_config or {}
|
||||
extra = (cfg.get("system_prompt_suffix") or "").strip()
|
||||
base = """你是「岁月留书」老年友好访谈员。语气温暖、耐心,先承接情绪再 gently 追问事实与感受;回答简洁分段,避免术语。"""
|
||||
if extra:
|
||||
return f"{base}\n\n{extra}"
|
||||
return base
|
||||
|
||||
|
||||
def _model_override(version_config: dict | None) -> str | None:
|
||||
if not version_config:
|
||||
return None
|
||||
m = version_config.get("model")
|
||||
return str(m).strip() if m else None
|
||||
|
||||
|
||||
class EvalCandidateRunner:
|
||||
"""使用 LangChain Chat 模型回放用户轮次。"""
|
||||
|
||||
def __init__(self, llm: Any) -> None:
|
||||
self._llm = llm
|
||||
|
||||
async def replay_utterances(
|
||||
self,
|
||||
utterances: list[str],
|
||||
*,
|
||||
version_config: dict | None = None,
|
||||
temperature: float = 0.7,
|
||||
) -> tuple[list[str], list[int]]:
|
||||
"""返回每轮 assistant 回复与耗时 ms。"""
|
||||
if not self._llm:
|
||||
raise RuntimeError(" replay: llm 未配置")
|
||||
from langchain_core.messages import AIMessage, HumanMessage, SystemMessage
|
||||
|
||||
sys_prompt = _system_prompt_for_eval(version_config)
|
||||
model = _model_override(version_config)
|
||||
lc_messages: list = [SystemMessage(content=sys_prompt)]
|
||||
replies: list[str] = []
|
||||
latencies: list[int] = []
|
||||
bound = (
|
||||
self._llm.bind(model=model, temperature=temperature)
|
||||
if model
|
||||
else self._llm.bind(temperature=temperature)
|
||||
)
|
||||
for u in utterances:
|
||||
text = (u or "").strip()
|
||||
if not text:
|
||||
continue
|
||||
lc_messages.append(HumanMessage(content=text))
|
||||
t0 = time.perf_counter()
|
||||
result = await bound.ainvoke(lc_messages)
|
||||
elapsed_ms = int((time.perf_counter() - t0) * 1000)
|
||||
reply = str(getattr(result, "content", "") or "").strip()
|
||||
replies.append(reply)
|
||||
latencies.append(elapsed_ms)
|
||||
lc_messages.append(AIMessage(content=reply))
|
||||
return replies, latencies
|
||||
|
||||
|
||||
def simple_memoir_from_transcript(utterances: list[str], replies: list[str]) -> str:
|
||||
"""轻量成稿:供评审用占位(非生产叙事管线)。"""
|
||||
lines = ["# 访谈摘录整理(评测占位稿)", ""]
|
||||
for i, u in enumerate(utterances):
|
||||
lines.append(f"## 片段 {i + 1}")
|
||||
lines.append("")
|
||||
lines.append(f"**用户:** {u.strip()}")
|
||||
if i < len(replies):
|
||||
lines.append("")
|
||||
lines.append(f"**访谈者:** {replies[i].strip()}")
|
||||
lines.append("")
|
||||
return "\n".join(lines)
|
||||
Reference in New Issue
Block a user