初始化提交
This commit is contained in:
commit
887c1f449e
963 files changed
+166869
No files matched your search
@@ -0,0 +1,150 @@
|
||||
"""小周天每轮记忆候选 + 返照反思(异步后台任务,跨 modules + ai_provider)。
|
||||
|
||||
言灵表达(流式回复完成)后触发:从本轮对话抽取记忆候选(待审核)+ 生成反思
|
||||
(直接建 memory type=reflection)。失败静默,不影响主流程。仅适用单进程;
|
||||
多 worker 部署需替换为跨进程任务队列。
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
|
||||
from app.ai_provider import ProviderManager, ProviderManagerFactory
|
||||
from app.core.config import settings
|
||||
from app.core.logging import logger
|
||||
from app.db.session import AsyncSessionLocal
|
||||
from app.models.candidates import MemoryCandidate
|
||||
from app.models.memory import Memory
|
||||
from app.modules.reflection.extract import parse_reflection
|
||||
from app.modules.reflection.prompts import build_reflection_messages
|
||||
|
||||
_running_reflection_tasks: set[asyncio.Task[None]] = set()
|
||||
|
||||
_provider_manager: ProviderManager | None = None
|
||||
|
||||
|
||||
def _get_provider_manager() -> ProviderManager:
|
||||
global _provider_manager
|
||||
if _provider_manager is None:
|
||||
_provider_manager = ProviderManagerFactory.create()
|
||||
return _provider_manager
|
||||
|
||||
|
||||
async def drain_pending_reflections() -> None:
|
||||
"""等待所有进行中的反思任务完成(测试断言 / 优雅停机用)。"""
|
||||
if _running_reflection_tasks:
|
||||
await asyncio.gather(*_running_reflection_tasks, return_exceptions=True)
|
||||
|
||||
|
||||
def start_reflection_after_turn(
|
||||
character_id: str,
|
||||
session_id: str,
|
||||
user_content: str,
|
||||
assistant_content: str,
|
||||
) -> None:
|
||||
"""每轮对话后启动反思抽取(后台任务);session_id 留作未来事件回写。"""
|
||||
task = asyncio.create_task(
|
||||
_run_reflection(character_id, session_id, user_content, assistant_content)
|
||||
)
|
||||
_running_reflection_tasks.add(task)
|
||||
task.add_done_callback(_running_reflection_tasks.discard)
|
||||
|
||||
|
||||
async def _run_reflection(
|
||||
character_id: str,
|
||||
session_id: str,
|
||||
user_content: str,
|
||||
assistant_content: str,
|
||||
) -> None:
|
||||
async with AsyncSessionLocal() as session:
|
||||
try:
|
||||
system, user = build_reflection_messages(user_content, assistant_content)
|
||||
raw = await _call_model(system, user, character_id)
|
||||
memory_drafts, reflection_text = parse_reflection(raw)
|
||||
memory_drafts = memory_drafts[: settings.big_cycle_max_candidates]
|
||||
|
||||
# 小周天记忆候选:高置信度(≥0.7)低敏感度直接落地为 Memory,
|
||||
# 其余留 pending 待大周天统一审核
|
||||
auto_memories = 0
|
||||
pending_count = 0
|
||||
for draft in memory_drafts:
|
||||
if draft.confidence >= 0.7 and draft.sensitivity in ("low", "none"):
|
||||
session.add(
|
||||
Memory(
|
||||
character_id=character_id,
|
||||
type=draft.type,
|
||||
title=draft.title,
|
||||
content=draft.content,
|
||||
source="reflection",
|
||||
importance=draft.importance,
|
||||
sensitivity=draft.sensitivity,
|
||||
confidence=draft.confidence,
|
||||
)
|
||||
)
|
||||
auto_memories += 1
|
||||
else:
|
||||
session.add(
|
||||
MemoryCandidate(
|
||||
character_id=character_id,
|
||||
type=draft.type,
|
||||
title=draft.title,
|
||||
content=draft.content,
|
||||
confidence=draft.confidence,
|
||||
importance=draft.importance,
|
||||
sensitivity=draft.sensitivity,
|
||||
reason=draft.reason,
|
||||
status="pending",
|
||||
)
|
||||
)
|
||||
pending_count += 1
|
||||
if reflection_text:
|
||||
title = reflection_text[:60] + ("…" if len(reflection_text) > 60 else "")
|
||||
session.add(
|
||||
Memory(
|
||||
character_id=character_id,
|
||||
type="reflection",
|
||||
title=title,
|
||||
content=reflection_text,
|
||||
source="reflection",
|
||||
importance=0.5,
|
||||
sensitivity="low",
|
||||
)
|
||||
)
|
||||
await session.commit()
|
||||
logger.info(
|
||||
f"小周天反思 character={character_id} session={session_id} "
|
||||
f"auto={auto_memories} pending={pending_count} "
|
||||
f"reflection={'yes' if reflection_text else 'no'}"
|
||||
)
|
||||
|
||||
# 推送反思完成事件(供叩心枢/前端观测)
|
||||
try:
|
||||
from app.modules.runtime.events import Event
|
||||
from app.services.event_store import DbEventStore
|
||||
|
||||
store = DbEventStore(AsyncSessionLocal)
|
||||
await store.append(
|
||||
Event(
|
||||
type="reflection.completed",
|
||||
source="reflection",
|
||||
visibility="public",
|
||||
character_id=character_id,
|
||||
payload={
|
||||
"session_id": session_id,
|
||||
"auto_memories": auto_memories,
|
||||
"pending_count": pending_count,
|
||||
"has_reflection": bool(reflection_text),
|
||||
"reflection_preview": (reflection_text or "")[:100],
|
||||
},
|
||||
)
|
||||
)
|
||||
except Exception: # noqa: BLE001
|
||||
logger.warning("推送 reflection.completed 事件失败")
|
||||
|
||||
except Exception as exc: # noqa: BLE001 — 后台任务失败静默
|
||||
logger.warning(f"小周天反思失败 character={character_id}: {exc}")
|
||||
|
||||
|
||||
async def _call_model(system: str, user: str, _character_id: str) -> str:
|
||||
manager = _get_provider_manager()
|
||||
messages = manager.to_message_list([system], [("user", user)])
|
||||
response = await manager.chat(messages, model_hint=settings.big_cycle_model)
|
||||
return response.content
|
||||
Reference in new issue
Block a user