| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- """
- Text2Mem 实战:实现一个最小可用的记忆操作引擎
- 运行:python text2mem_practice.py
- """
- import json
- from datetime import datetime
- from typing import ClassVar, Literal
- from pydantic import BaseModel, Field, field_validator, model_validator
- # ===== 结构与业务校验(生产环境可额外发布 JSON Schema) =====
- class MemMeta(BaseModel):
- timestamp: str = ""
- source: str = "user_direct"
- confidence: float = 1.0
- dry_run: bool = False
- confirmation: bool = False
- def model_post_init(self, __context):
- if not self.timestamp:
- self.timestamp = datetime.now().isoformat()
- class MemOp(BaseModel):
- """五元组 IR 操作"""
- stage: Literal["ENC", "RET", "STO"]
- op: str
- target: str
- args: dict = Field(default_factory=dict)
- meta: MemMeta = Field(default_factory=MemMeta)
- VALID_OPS: ClassVar[dict[str, set[str]]] = {
- "ENC": {"Encode"},
- "STO": {"Update", "Label", "Promote", "Demote", "Merge", "Split", "Delete", "Lock", "Expire"},
- "RET": {"Retrieve", "Summarize"},
- }
- @field_validator("op")
- @classmethod
- def op_must_be_valid(cls, v):
- all_ops = set()
- for ops in cls.VALID_OPS.values():
- all_ops |= ops
- if v not in all_ops:
- raise ValueError(f"Unknown op: {v}. Valid: {sorted(all_ops)}")
- return v
- @model_validator(mode="after")
- def op_stage_match(self):
- valid = self.VALID_OPS.get(self.stage, set())
- if self.op not in valid:
- raise ValueError(f"Op '{self.op}' not allowed in stage '{self.stage}'. Valid: {sorted(valid)}")
- return self
- # ===== 第二层:业务逻辑校验 =====
- class MemoryStore:
- """模拟记忆存储引擎;仅实现 Encode/Update/Lock/Delete/Retrieve。"""
- WRITE_OPS: ClassVar[set[str]] = {"Encode", "Update", "Lock", "Delete"}
- def __init__(self):
- self.memories: dict[str, dict] = {}
- def execute(self, ir: MemOp) -> dict:
- if ir.meta.dry_run:
- return {"status": "dry_run", "would_execute": ir.model_dump()}
- if ir.op in self.WRITE_OPS and not ir.meta.confirmation:
- return {"status": "pending_confirmation", "msg": "Write requires external confirmation"}
- handler = getattr(self, f"_exec_{ir.op.lower()}", None)
- if not handler:
- return {"status": "error", "msg": f"No handler for op '{ir.op}'"}
- return handler(ir)
- def _exec_encode(self, ir: MemOp) -> dict:
- mem_id = ir.target or f"mem_{len(self.memories) + 1:04d}"
- self.memories[mem_id] = {
- "id": mem_id, "content": ir.args.get("content", ""),
- "priority": ir.args.get("priority", "normal"),
- "locked": False, "tags": [],
- "created_at": ir.meta.timestamp, "updated_at": ir.meta.timestamp,
- }
- return {"status": "ok", "mem_id": mem_id}
- def _exec_update(self, ir: MemOp) -> dict:
- mem = self._get_or_error(ir.target)
- if isinstance(mem, dict) and "error" in mem:
- return mem
- if mem["locked"]:
- return {"status": "error", "msg": f"Memory '{ir.target}' is locked, cannot update"}
- fields = ir.args.get("fields", {})
- mem.update(fields)
- mem["updated_at"] = ir.meta.timestamp
- return {"status": "ok", "updated": list(fields.keys())}
- def _exec_lock(self, ir: MemOp) -> dict:
- mem = self._get_or_error(ir.target)
- if isinstance(mem, dict) and "error" in mem:
- return mem
- mem["locked"] = True
- return {"status": "ok", "locked": ir.target}
- def _exec_delete(self, ir: MemOp) -> dict:
- mem = self._get_or_error(ir.target)
- if isinstance(mem, dict) and "error" in mem:
- return mem
- if mem["locked"]:
- return {"status": "error", "msg": f"Memory '{ir.target}' is locked, cannot delete"}
- del self.memories[ir.target]
- return {"status": "ok", "deleted": ir.target}
- def _exec_retrieve(self, ir: MemOp) -> dict:
- keyword = ir.args.get("keyword", "")
- results = [m for m in self.memories.values() if keyword.lower() in m["content"].lower()]
- return {"status": "ok", "count": len(results), "results": results}
- def _get_or_error(self, target: str):
- if target not in self.memories:
- return {"status": "error", "msg": f"Memory '{target}' not found"}
- return self.memories[target]
- # ===== 运行演示 =====
- if __name__ == "__main__":
- store = MemoryStore()
- ops = [
- MemOp(stage="ENC", op="Encode", target="mem_user_lang",
- args={"content": "用户偏好 Python 写后端,TypeScript 写前端", "priority": "high"},
- meta=MemMeta(confirmation=True)),
- MemOp(stage="ENC", op="Encode", target="mem_project",
- args={"content": "当前项目:企业内部智能知识库,使用通义千问和 RAG"},
- meta=MemMeta(confirmation=True)),
- MemOp(stage="STO", op="Lock", target="mem_user_lang",
- args={"reason": "用户身份信息,禁止自动修改"},
- meta=MemMeta(confirmation=True)),
- MemOp(stage="STO", op="Update", target="mem_user_lang",
- args={"fields": {"content": "被篡改的内容"}}),
- MemOp(stage="STO", op="Update", target="mem_user_lang",
- args={"fields": {"content": "仍应被锁拦截"}},
- meta=MemMeta(confirmation=True)),
- MemOp(stage="STO", op="Update", target="mem_project",
- args={"fields": {"content": "当前项目:企业内部智能知识库,检索重排进度 75%"}},
- meta=MemMeta(confirmation=True)),
- MemOp(stage="RET", op="Retrieve", target="", args={"keyword": "知识库"}),
- MemOp(stage="STO", op="Delete", target="mem_project",
- args={}, meta=MemMeta(dry_run=True)),
- ]
- print("=" * 60)
- print("Text2Mem 实战:记忆操作引擎演示")
- print("=" * 60)
- for i, op in enumerate(ops, 1):
- print(f"\n--- 操作 {i}: {op.stage}/{op.op} ---")
- result = store.execute(op)
- print(f" 结果: {json.dumps(result, ensure_ascii=False, indent=2)}")
- print(f"\n最终记忆库状态({len(store.memories)} 条):")
- for mid, mem in store.memories.items():
- locked = " 🔒" if mem["locked"] else ""
- print(f" [{mid}]{locked}: {mem['content']}")
|