agent 模式补充文件功能已经实现

This commit is contained in:
wandering
2026-06-15 10:39:01 +08:00
parent e252896de9
commit 7c137c5214
34 changed files with 1664 additions and 1651 deletions

View File

@@ -27,7 +27,6 @@ from typing import Any
from .. import get_logger
from ..doc.llm_extractor import (
CACHE_DIR_NAME,
build_extraction_user_message,
llm_query_text,
load_cache,
@@ -39,6 +38,7 @@ from ..doc.prompt import (
build_travel_info_system_prompt,
)
from ..doc.validator import validate_extracted_info
from ..pipeline_core import save_cache_info
log = get_logger("agent")
@@ -126,9 +126,26 @@ def load_agent_state(session_dir: Path) -> AgentSession | None:
AGENT_EVENT_LOG = "agent_events.log"
# 去重守卫:记录每个 session 上一次发射的事件类型,防止连续重复发射
# key: str(session_dir), value: 上一次的 event_type
_last_event_type: dict[str, str] = {}
def _emit_agent_event(session_dir: Path, event_type: str, **kwargs: Any) -> None:
"""向 agent_events.log 追加一行 JSON 事件。"""
"""向 agent_events.log 追加一行 JSON 事件。
同一 session 连续发射相同 event_type 时直接抛出 RuntimeError
强制调用方修复重复发射的代码,而非静默掩盖。
"""
session_key = str(session_dir)
prev = _last_event_type.get(session_key)
if prev == event_type:
raise RuntimeError(
f"事件重复发射: session={session_dir.name!r}, event_type={event_type!r}"
f"请检查调用链,确保每个事件类型只发射一次。"
)
_last_event_type[session_key] = event_type
event = {"type": event_type, **kwargs}
try:
event_path = session_dir / AGENT_EVENT_LOG
@@ -345,32 +362,16 @@ def run_agent_round(
log.info("检测到补充文件,加载上一轮分析结果作为历史上下文")
try:
if session.invoice_type == "travel":
should_reanalyze = not cache_map.get("travel_info") or is_supplement
if should_reanalyze:
session.extracted_info = _do_extraction_with_validation(
session_dir, session, previous_analysis=previous_analysis
)
# 提取后立即写入缓存,后续步骤依赖此数据
cache_dir = session_dir / CACHE_DIR_NAME
cache_dir.mkdir(parents=True, exist_ok=True)
with open(cache_dir / "travel_info.json", "w", encoding="utf-8") as f:
json.dump(session.extracted_info, f, ensure_ascii=False, indent=2)
else:
session.extracted_info = cache_map["travel_info"]
info_key = "travel_info" if session.invoice_type == "travel" else "normal_info"
should_reanalyze = not cache_map.get(info_key) or is_supplement
if should_reanalyze:
session.extracted_info = _do_extraction_with_validation(
session_dir, session, previous_analysis=previous_analysis
)
# 提取后立即写入缓存,后续步骤依赖此数据
save_cache_info(session_dir, info_key, session.extracted_info)
else:
should_reanalyze = not cache_map.get("normal_info") or is_supplement
if should_reanalyze:
session.extracted_info = _do_extraction_with_validation(
session_dir, session, previous_analysis=previous_analysis
)
# 提取后立即写入缓存,后续步骤依赖此数据
cache_dir = session_dir / CACHE_DIR_NAME
cache_dir.mkdir(parents=True, exist_ok=True)
with open(cache_dir / "normal_info.json", "w", encoding="utf-8") as f:
json.dump(session.extracted_info, f, ensure_ascii=False, indent=2)
else:
session.extracted_info = cache_map["normal_info"]
session.extracted_info = cache_map[info_key]
except Exception as e:
session.state = AgentState.ERROR
@@ -501,13 +502,9 @@ def process_user_text_supplement(
)
# Step 3: 保存到缓存
cache_dir = session_dir / CACHE_DIR_NAME
cache_dir.mkdir(parents=True, exist_ok=True)
info_file = "travel_info.json" if session.invoice_type == "travel" else "normal_info.json"
info_path = cache_dir / info_file
with open(info_path, "w", encoding="utf-8") as f:
json.dump(session.extracted_info, f, ensure_ascii=False, indent=2)
log.info("已更新 %s", info_file)
info_key = "travel_info" if session.invoice_type == "travel" else "normal_info"
save_cache_info(session_dir, info_key, session.extracted_info)
log.info("已更新 %s", info_key)
# Step 4: 重新执行 Agent 校验
session.state = AgentState.EXTRACTING