Use prompt history for online mining records

This commit is contained in:
wuyang6
2026-05-14 17:42:08 +08:00
parent f1dc7e4b91
commit 87dd67c76a
10 changed files with 219 additions and 97 deletions
@@ -89,9 +89,32 @@ def source_config(source: str) -> dict[str, Any]:
return SOURCE_CONFIGS[source]
def date_range_ms(date_str: str | None) -> tuple[int, int]:
def parse_date(value: str) -> datetime:
text = str(value).strip()
for fmt in ("%Y%m%d", "%Y-%m-%d"):
try:
return datetime.strptime(text, fmt)
except ValueError:
continue
raise OnlineMiningError("date must be YYYYMMDD or YYYY-MM-DD")
def date_range_ms(date_str: str | None, *, date_from: str | None = None, date_to: str | None = None, lookback_days: int | None = None) -> tuple[int, int]:
if date_from or date_to:
if not date_from or not date_to:
raise OnlineMiningError("date_from and date_to must be provided together")
start_obj = parse_date(date_from)
end_obj = parse_date(date_to) + timedelta(days=1)
if end_obj <= start_obj:
raise OnlineMiningError("date_to must be greater than or equal to date_from")
return int(start_obj.timestamp() * 1000), int(end_obj.timestamp() * 1000) - 1
if lookback_days is not None:
if lookback_days <= 0 or lookback_days > 31:
raise OnlineMiningError("lookback_days must be between 1 and 31")
end = datetime.now()
return int((end - timedelta(days=lookback_days)).timestamp() * 1000), int(end.timestamp() * 1000)
if date_str:
date_obj = datetime.strptime(str(date_str), "%Y%m%d")
date_obj = parse_date(date_str)
start_ms = int(date_obj.timestamp() * 1000)
end_ms = int((date_obj + timedelta(days=1)).timestamp() * 1000) - 1
else:
@@ -266,10 +289,13 @@ def search_docs(
date: str | None,
size: int,
query_filters: list[dict[str, Any]] | None = None,
date_from: str | None = None,
date_to: str | None = None,
lookback_days: int | None = None,
) -> list[dict[str, Any]]:
config = source_config(source)
client = build_client(source)
start_ms, end_ms = date_range_ms(date)
start_ms, end_ms = date_range_ms(date, date_from=date_from, date_to=date_to, lookback_days=lookback_days)
filters = [{"range": {str(config["time_field"]): {"gte": start_ms, "lte": end_ms}}}]
filters.extend(deepcopy(query_filters or []))
body = {
@@ -281,7 +307,15 @@ def search_docs(
return [deep_parse(hit.get("_source", {})) for hit in response.get("hits", {}).get("hits", [])]
def fetch_one_by_request_id(source: str, request_id: str, date: str | None = None) -> dict[str, Any] | None:
def fetch_one_by_request_id(
source: str,
request_id: str,
date: str | None = None,
*,
date_from: str | None = None,
date_to: str | None = None,
lookback_days: int | None = None,
) -> dict[str, Any] | None:
config = source_config(source)
id_field = str(config["id_field"])
# 精确查优先用 .keyword;部分索引字段本身就是 keyword,所以再兜底原字段。
@@ -292,56 +326,20 @@ def fetch_one_by_request_id(source: str, request_id: str, date: str | None = Non
{"wildcard": {id_field: {"value": f"{request_id}*"}}},
]
for query_filter in attempts:
docs = search_docs(source=source, date=date, size=1, query_filters=[query_filter])
docs = search_docs(
source=source,
date=date,
size=1,
query_filters=[query_filter],
date_from=date_from,
date_to=date_to,
lookback_days=lookback_days,
)
if docs:
return docs[0]
return None
def fetch_session_turns(
*,
session_id: str,
before_timestamp: int,
date: str | None = None,
limit: int = 10,
) -> list[dict[str, Any]]:
"""按主表 session_id 拉当前请求之前的多轮上下文。"""
if not session_id or not before_timestamp:
return []
docs: list[dict[str, Any]] = []
# arch-flat-nlp-log-f-* 里 session_id 在部分索引没有 .keyword 子字段,
# 所以必须先试 keyword,再兜底原字段。
for session_field in ("session_id.keyword", "session_id"):
filters = [
{"term": {session_field: session_id}},
{"range": {"timestamp": {"lt": before_timestamp}}},
]
docs = search_docs(source="main", date=date, size=max(limit * 3, limit), query_filters=filters)
if docs:
break
cases = [extract_main_case(doc) for doc in docs]
cases = [
case
for case in cases
if str(case.get("session_id") or "") == session_id
and isinstance(case.get("timestamp"), (int, str))
and int(case.get("timestamp") or 0) < before_timestamp
and str(case.get("query") or "").strip()
]
cases.sort(key=lambda item: int(item.get("timestamp") or 0))
return cases[-limit:]
def fetch_session_turns_for_case(case: dict[str, Any], *, date: str | None = None, limit: int = 10) -> list[dict[str, Any]]:
session_id = str(case.get("session_id") or "").strip()
try:
timestamp = int(case.get("timestamp") or 0)
except (TypeError, ValueError):
timestamp = 0
return fetch_session_turns(session_id=session_id, before_timestamp=timestamp, date=date, limit=limit)
def fetch_by_terms(source: str, *, field: str, value: str, date: str | None = None, size: int = 10) -> list[dict[str, Any]]:
"""小范围精确字段查询,供脚本探测 session/request 字段时使用。"""