feat(flywheel): 抽公共 EmbeddingProvider 并新增 FewShotSample 模型

- 从 knowledge_rag_runtime 抽出 embedding 调用逻辑为独立 EmbeddingProvider,
  复用现有 HTTP 纯函数,RAG 路径零回归
- 新增 FewShotSample 表模型(样本池),注册到 db/base.py 和 models/__init__.py
  供 few-shot 飞轮沉淀已确认风险观测
This commit is contained in:
caoxiaozhu
2026-07-03 13:55:39 +08:00
parent 08f023243e
commit 765cfb40f3
4 changed files with 196 additions and 0 deletions

View File

@@ -8,6 +8,7 @@ from app.models.budget import BudgetAllocation, BudgetReservation, BudgetTransac
from app.models.employee_change_log import EmployeeChangeLog
from app.models.employee_behavior_profile import EmployeeBehaviorProfileSnapshot
from app.models.employee import Employee
from app.models.few_shot_sample import FewShotSample
from app.models.financial_record import (
AccountsPayableRecord,
AccountsReceivableRecord,
@@ -49,6 +50,7 @@ __all__ = [
"EmployeeChangeLog",
"ExpenseClaim",
"ExpenseClaimItem",
"FewShotSample",
"HermesTaskConfig",
"HermesTaskExecutionLog",
"HermesRiskReport",

View File

@@ -0,0 +1,54 @@
from __future__ import annotations
import uuid
from datetime import datetime
from typing import Any
from sqlalchemy import DateTime, ForeignKey, Index, String, Text, func
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.types import JSON
from app.db.base_class import Base
class FewShotSample(Base):
"""已确认的风险观测样本,供 few-shot 检索注入使用。
数据来源是 ``RiskObservation`` 上人工确认为 confirmed / false_positive 的观测,
入库后同时写一份向量到 Qdrant 的 ``few_shot_samples`` collection。
"""
__tablename__ = "few_shot_samples"
__table_args__ = (
Index("ix_few_shot_samples_scene_label", "scene", "label"),
Index("ix_few_shot_samples_domain_risk_type", "domain", "risk_type"),
)
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
sample_key: Mapped[str] = mapped_column(String(160), unique=True, index=True)
source_observation_id: Mapped[str | None] = mapped_column(
ForeignKey("risk_observations.id"),
nullable=True,
index=True,
)
scene: Mapped[str] = mapped_column(String(50), default="risk_rule_generation", index=True)
domain: Mapped[str] = mapped_column(String(50), default="", index=True)
risk_type: Mapped[str] = mapped_column(String(80), default="", index=True)
risk_level: Mapped[str] = mapped_column(String(20), default="")
label: Mapped[str] = mapped_column(String(30), default="confirmed", index=True)
case_text: Mapped[str] = mapped_column(Text(), default="")
conclusion_text: Mapped[str] = mapped_column(Text(), default="")
payload_json: Mapped[dict[str, Any]] = mapped_column(JSON, default=dict)
vector_id: Mapped[str | None] = mapped_column(String(100), nullable=True)
status: Mapped[str] = mapped_column(String(20), default="active", index=True)
created_at: Mapped[datetime] = mapped_column(DateTime, default=func.now(), server_default=func.now())
updated_at: Mapped[datetime] = mapped_column(
DateTime,
default=func.now(),
onupdate=func.now(),
server_default=func.now(),
)