"""独立候选回放:多轮 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)