feat(api)!: memory single chain — async MemoryService, strict eval closure
Route all memory ingest/retrieve/enrichment/compaction through async MemoryService. Remove legacy sync memory implementations (ingest/retrieve/compaction); Celery and memoir Phase2 call asyncio.run into MemoryService-backed helpers. Memoir Phase1 batch ingest uses MemoryService.ingest_transcripts_batch; drop chapters. evidence_bundle_json mirror (Alembic 0015). Evaluation uses snapshot/link-only bundles; raise EvidenceClosureMissing instead of partial/fallback lineage tiers. Split memoir state into NarrativeCoverageState and InterviewControlState; delete the _interview_meta_store adapter layer. Remove rolling-query and recent-fact fallback settings from config and evidence assembly. Update judges, docs, tests, and PlaygroundPage alignment. Made-with: Cursor
This commit is contained in:
@@ -36,7 +36,6 @@ from app.agents.stage_constants import (
|
||||
)
|
||||
from app.agents.state_schema import MemoirStateSchema
|
||||
from app.core.config import settings
|
||||
from app.core.dependencies import get_embedding_provider
|
||||
from app.core.logging import get_logger
|
||||
from app.features.conversation.lineage_schemas import aggregate_lineage_from_segments
|
||||
from app.features.memoir.chapter_evidence_snapshot import (
|
||||
@@ -60,7 +59,6 @@ from app.features.memoir.repo import (
|
||||
mark_chapter_dirty_sync,
|
||||
reorder_chapter_story_links_by_life_order_sync,
|
||||
)
|
||||
from app.features.memory.repo import retrieve_evidence_sync
|
||||
from app.features.story.models import Story, StoryVersion
|
||||
from app.features.story.sync_write import (
|
||||
append_story_version_sync,
|
||||
@@ -102,7 +100,7 @@ def _dialogue_lineage_dict_for_segment_ids(
|
||||
def _evidence_link_ids(
|
||||
evidence: dict,
|
||||
) -> tuple[list[str], list[str], list[str], list[str]]:
|
||||
"""从 retrieve_evidence_sync 结果提取稳定 ID 列表。"""
|
||||
"""从 MemoryService.retrieve 结果提取稳定 ID 列表。"""
|
||||
chunks: list[str] = []
|
||||
for c in evidence.get("relevant_chunks") or []:
|
||||
if isinstance(c, dict) and c.get("id"):
|
||||
@@ -960,6 +958,7 @@ def run_story_pipeline_for_category_batch(
|
||||
occupation: str = "",
|
||||
memoir_correlation_id: str | None = None,
|
||||
llm_fast: Any | None = None,
|
||||
memory_evidence: dict | None = None,
|
||||
) -> tuple[Chapter | None, bool, set[str]]:
|
||||
"""
|
||||
返回 (chapter, needs_cover_enqueue, story_ids_to_dispatch_after_commit)。
|
||||
@@ -979,8 +978,6 @@ def run_story_pipeline_for_category_batch(
|
||||
top_k = int(settings.evidence_top_k_default)
|
||||
if n_units > int(settings.evidence_large_batch_threshold):
|
||||
top_k = int(settings.evidence_top_k_large_batch)
|
||||
emb = get_embedding_provider()
|
||||
embedding_available = emb.is_available()
|
||||
|
||||
def _oral_job() -> tuple[str, float]:
|
||||
t_oral = time.perf_counter()
|
||||
@@ -991,23 +988,13 @@ def run_story_pipeline_for_category_batch(
|
||||
with ThreadPoolExecutor(max_workers=1) as pool:
|
||||
oral_future = pool.submit(_oral_job)
|
||||
_t_ev = time.perf_counter()
|
||||
try:
|
||||
evidence = retrieve_evidence_sync(
|
||||
session,
|
||||
user_id,
|
||||
combined_text,
|
||||
top_k=top_k,
|
||||
embedding_provider=emb,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning("Evidence 检索跳过: {}", e)
|
||||
evidence = {
|
||||
"relevant_chunks": [],
|
||||
"relevant_summaries": [],
|
||||
"relevant_facts": [],
|
||||
"timeline_hints": [],
|
||||
"relevant_stories": [],
|
||||
}
|
||||
evidence = memory_evidence or {
|
||||
"relevant_chunks": [],
|
||||
"relevant_summaries": [],
|
||||
"relevant_facts": [],
|
||||
"timeline_hints": [],
|
||||
"relevant_stories": [],
|
||||
}
|
||||
ev_elapsed = time.perf_counter() - _t_ev
|
||||
oral_for_memoir, oral_elapsed = oral_future.result()
|
||||
pipeline_phase_timings["evidence"] = ev_elapsed
|
||||
@@ -1017,13 +1004,13 @@ def run_story_pipeline_for_category_batch(
|
||||
)
|
||||
|
||||
logger.info(
|
||||
"memoir_evidence_retrieved user_id={} chunks={} facts={} summaries={} stories={} vector_ok={}",
|
||||
"memoir_evidence_retrieved user_id={} chunks={} facts={} summaries={} stories={} top_k={}",
|
||||
user_id,
|
||||
len(evidence.get("relevant_chunks") or []),
|
||||
len(evidence.get("relevant_facts") or []),
|
||||
len(evidence.get("relevant_summaries") or []),
|
||||
len(evidence.get("relevant_stories") or []),
|
||||
embedding_available,
|
||||
top_k,
|
||||
)
|
||||
|
||||
evidence_text = format_evidence_chunks_for_prompt(evidence)
|
||||
|
||||
Reference in New Issue
Block a user