初始化提交
This commit is contained in:
commit
887c1f449e
963 files changed
+166869
No files matched your search
@@ -0,0 +1 @@
|
||||
"""大周天演化候选领域纯逻辑(造消息 / 解析候选草稿,禁止 IO)。"""
|
||||
@@ -0,0 +1,114 @@
|
||||
"""解析模型返回为演化候选草稿(纯函数,无 IO)。
|
||||
|
||||
模型可能返回纯 JSON、markdown 代码块或夹杂解释文本;本模块容错提取首个 JSON
|
||||
数组,并归一化为演化候选草稿。``evidence`` 序号由 application 映射为记忆 ID。
|
||||
|
||||
缺省字段取**安全悲观默认**:``level=L4``(必须人工确认)、``auto_apply_allowed=False``,
|
||||
避免模型漏字段时误自动应用高风险演化。
|
||||
"""
|
||||
|
||||
import json
|
||||
import re
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any
|
||||
|
||||
|
||||
@dataclass
|
||||
class EvolutionCandidateDraft:
|
||||
type: str
|
||||
title: str
|
||||
proposal: str
|
||||
level: str = "L4"
|
||||
scope: str = "character_scope"
|
||||
source: str = "big_cycle"
|
||||
delta: dict[str, Any] = field(default_factory=dict)
|
||||
confidence: float = 0.5
|
||||
benefit_score: float = 0.5
|
||||
risk_score: float = 0.5
|
||||
drift_score: float = 0.0
|
||||
auto_apply_allowed: bool = False
|
||||
evidence: list[int] = field(default_factory=list)
|
||||
|
||||
|
||||
def parse_evolution_candidates(raw: str) -> list[EvolutionCandidateDraft]:
|
||||
drafts: list[EvolutionCandidateDraft] = []
|
||||
for item in _extract_json_array(raw):
|
||||
if not isinstance(item, dict):
|
||||
continue
|
||||
type_ = str(item.get("type", "")).strip()
|
||||
title = str(item.get("title", "")).strip()
|
||||
proposal = str(item.get("proposal", "")).strip()
|
||||
if not type_ or not title or not proposal:
|
||||
continue
|
||||
drafts.append(
|
||||
EvolutionCandidateDraft(
|
||||
type=type_,
|
||||
title=title,
|
||||
proposal=proposal,
|
||||
level=_level(item.get("level")),
|
||||
scope=_scope(item.get("scope")),
|
||||
source=str(item.get("source", "big_cycle")).strip() or "big_cycle",
|
||||
delta=_dict(item.get("delta")),
|
||||
confidence=_clamp_float(item.get("confidence"), 0.5),
|
||||
benefit_score=_clamp_float(item.get("benefit_score"), 0.5),
|
||||
risk_score=_clamp_float(item.get("risk_score"), 0.5),
|
||||
drift_score=_clamp_float(item.get("drift_score"), 0.0),
|
||||
auto_apply_allowed=bool(item.get("auto_apply_allowed", False)),
|
||||
evidence=_int_list(item.get("evidence")),
|
||||
)
|
||||
)
|
||||
return drafts
|
||||
|
||||
|
||||
def _extract_json_array(raw: str) -> list[Any]:
|
||||
text = raw.strip()
|
||||
matched = re.search(r"```(?:json)?\s*(\[.*?\])\s*```", text, re.DOTALL)
|
||||
if matched:
|
||||
text = matched.group(1)
|
||||
else:
|
||||
start, end = text.find("["), text.rfind("]")
|
||||
if start != -1 and end > start:
|
||||
text = text[start : end + 1]
|
||||
try:
|
||||
data = json.loads(text)
|
||||
except json.JSONDecodeError:
|
||||
return []
|
||||
return data if isinstance(data, list) else []
|
||||
|
||||
|
||||
_VALID_LEVELS = {"L0", "L1", "L2", "L3", "L4"}
|
||||
_VALID_SCOPES = {"character_scope", "user_scope", "task_scope", "global_scope"}
|
||||
|
||||
|
||||
def _level(value: Any) -> str:
|
||||
text = str(value or "").strip().upper()
|
||||
return text if text in _VALID_LEVELS else "L4"
|
||||
|
||||
|
||||
def _scope(value: Any) -> str:
|
||||
text = str(value or "").strip()
|
||||
return text if text in _VALID_SCOPES else "character_scope"
|
||||
|
||||
|
||||
def _dict(value: Any) -> dict[str, Any]:
|
||||
return value if isinstance(value, dict) else {}
|
||||
|
||||
|
||||
def _clamp_float(value: Any, default: float) -> float:
|
||||
try:
|
||||
num = float(value)
|
||||
except (TypeError, ValueError):
|
||||
return default
|
||||
return max(0.0, min(1.0, num))
|
||||
|
||||
|
||||
def _int_list(value: Any) -> list[int]:
|
||||
if not isinstance(value, list):
|
||||
return []
|
||||
result: list[int] = []
|
||||
for item in value:
|
||||
try:
|
||||
result.append(int(item))
|
||||
except (TypeError, ValueError):
|
||||
continue
|
||||
return result
|
||||
@@ -0,0 +1,78 @@
|
||||
"""大周天演化候选 prompt 构建(纯函数,无 IO)。
|
||||
|
||||
接收 ``EvaluationSnapshot``(由 application 阶段从 ORM 组装的态势快照),产出
|
||||
``(system, user)`` 消息对,喂给模型网关。模型返回的 JSON 由 ``extract`` 模块解析。
|
||||
|
||||
枚举取值以 [契约字典](../../docs/contracts/contract-glossary.md) §12 与
|
||||
[自我演化机制设计](../../docs/domain/core-domains.md) §11 为准。
|
||||
"""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
from app.modules.evolution import LEVELS as EVOLUTION_LEVELS
|
||||
from app.modules.evolution import SCOPES as EVOLUTION_SCOPES
|
||||
from app.modules.evolution import TYPES as EVOLUTION_TYPES
|
||||
|
||||
EVOLUTION_TYPES = EVOLUTION_TYPES
|
||||
EVOLUTION_LEVELS = EVOLUTION_LEVELS
|
||||
EVOLUTION_SCOPES = EVOLUTION_SCOPES
|
||||
|
||||
|
||||
@dataclass
|
||||
class EvaluationSnapshot:
|
||||
"""大周天自我评估态势快照(application 组装,供候选生成消费)。"""
|
||||
|
||||
character_id: str
|
||||
memory_count: int
|
||||
recent_memories: list[tuple[str, str]] # (title, content)
|
||||
personality_summary: str
|
||||
world_entity_count: int
|
||||
conclusion: str
|
||||
evidence_ids: list[str] = field(default_factory=list) # 记忆 ID,供 evidence 序号映射
|
||||
cumulative_drift: float = 0.0 # 最近大周天的累积漂移值
|
||||
drift_budget_remaining: float = 0.0 # 剩余漂移预算
|
||||
|
||||
|
||||
def build_evolution_extraction_messages(
|
||||
snapshot: EvaluationSnapshot,
|
||||
) -> tuple[str, str]:
|
||||
system = (
|
||||
"你是魂镜的大周天自我演化引擎。基于本轮自我评估的态势快照,生成轻量、可解释、"
|
||||
"可回滚的演化候选——只调整人格表达、程序记忆、工具策略等轻量参数,"
|
||||
"不改变核心使命、安全边界或高敏关系判断。"
|
||||
f"type 取自:{', '.join(EVOLUTION_TYPES)}。"
|
||||
f"level 取自:{', '.join(EVOLUTION_LEVELS)}"
|
||||
"(L0-L3 低风险可半自动,L4 核心人格/使命/安全边界必须人工确认)。"
|
||||
f"scope 取自:{', '.join(EVOLUTION_SCOPES)}。"
|
||||
'以 JSON 数组返回,每个元素:{"type": str, "source": "big_cycle", '
|
||||
'"level": str, "scope": str, "title": str, "proposal": str, '
|
||||
'"delta": 对象, "confidence": 0~1, "benefit_score": 0~1, '
|
||||
'"risk_score": 0~1, "auto_apply_allowed": bool, "evidence": [记忆序号]}。'
|
||||
"delta 为具体增量(如人格字段覆盖对象、程序记忆 title/content)。"
|
||||
"evidence 为下方记忆摘要的序号([0]/[1]…)列表。"
|
||||
"仅在态势充分支撑时提议,宁缺毋滥。若本轮无需演化返回 []。"
|
||||
"只返回 JSON 数组,不要解释或 markdown。"
|
||||
)
|
||||
user = (
|
||||
f"记忆总数:{snapshot.memory_count}\n"
|
||||
f"世界实体数:{snapshot.world_entity_count}\n"
|
||||
f"自我评估结论:{snapshot.conclusion or '(无明显态势)'}\n"
|
||||
f"当前人格摘要:\n{snapshot.personality_summary or '(尚未形成)'}\n"
|
||||
f"近期记忆摘要:\n{_format_memories(snapshot.recent_memories)}"
|
||||
)
|
||||
# 人格权重向量:将漂移信息注入 prompt,引导 LLM 保守生成
|
||||
if snapshot.cumulative_drift > 0:
|
||||
user += (
|
||||
f"\n\n⚠️ 人格漂移警告:累积漂移 {snapshot.cumulative_drift:.2f} / "
|
||||
f"预算 {snapshot.drift_budget_remaining + snapshot.cumulative_drift:.1f}。"
|
||||
f"剩余漂移预算 {snapshot.drift_budget_remaining:.1f}。"
|
||||
f"请尽可能保守,减少高风险 proposal,优先微调而非大幅改动。"
|
||||
)
|
||||
return system, user
|
||||
|
||||
|
||||
def _format_memories(memories: list[tuple[str, str]]) -> str:
|
||||
if not memories:
|
||||
return "(暂无)"
|
||||
lines = [f"[{idx}] {title}:{content}" for idx, (title, content) in enumerate(memories)]
|
||||
return "\n".join(lines)
|
||||
Reference in new issue
Block a user