- Added new endpoints to the analyst API for managing assets, including `GET /assets` to list assets and `POST /assets/{kind}/{asset_id}/publish` to publish assets.
- Introduced `DictAmbiguityCheckRequest` schema for checking metric ambiguities, enhancing the analyst's ability to clarify definitions and aliases.
- Implemented `detect_dict_ambiguity` function to analyze potential ambiguities in metrics, providing structured feedback for users.
- Updated `AnalystAgent` to support the new asset management functionalities and ambiguity detection logic, improving overall user experience.
- Enhanced existing schemas and services to accommodate new features, ensuring robust data handling and validation.
This update significantly improves the analyst API's capabilities, allowing for better asset management and clarity in metric definitions.
134 lines
4.0 KiB
Python
134 lines
4.0 KiB
Python
"""数据分析 Agent 请求/响应 Pydantic 模型(输出四件套,需求规格 §3 全局约定)。"""
|
||
from __future__ import annotations
|
||
|
||
from typing import Literal
|
||
|
||
from pydantic import BaseModel, Field
|
||
|
||
DISCLAIMER = (
|
||
"本内容仅为投资分析参考,不构成任何直接投资建议,不构成对任何产品的收益承诺,"
|
||
"据此操作风险自负,请谨慎对待。"
|
||
)
|
||
|
||
CUSTOMER_AI_RISK_NOTE = "AI 分析有风险,仅供参考。"
|
||
|
||
|
||
class ChatRequest(BaseModel):
|
||
question: str = Field(..., description="自然语言问题")
|
||
session_id: str | None = None
|
||
trace_id: str | None = None
|
||
interpret: bool = Field(
|
||
default=False,
|
||
description="true=问数后立即 LLM 解读;false=仅 SQL+表格(解读走 /interpret)",
|
||
)
|
||
|
||
|
||
class TableData(BaseModel):
|
||
columns: list[str] = Field(default_factory=list)
|
||
rows: list[list] = Field(default_factory=list)
|
||
|
||
|
||
class Meta(BaseModel):
|
||
exec_ms: int = 0
|
||
row_count: int = 0
|
||
cache_hit: bool = False
|
||
template_hit: bool = False
|
||
template_key: str | None = None
|
||
data_as_of: str | None = None
|
||
source: str = ""
|
||
cost_est: float = 0.0
|
||
|
||
|
||
class InterpretRequest(BaseModel):
|
||
"""按需解读:上下文仅本轮问数快照(看图说话)。"""
|
||
|
||
question: str
|
||
status: str
|
||
answer: str = ""
|
||
table: TableData = Field(default_factory=TableData)
|
||
sql: str = ""
|
||
trace_id: str | None = None
|
||
meta: Meta = Field(default_factory=Meta)
|
||
|
||
|
||
ChartType = Literal["line", "bar", "column", "pie", "none"]
|
||
AnalysisKind = Literal["text", "chart", "both", "none"]
|
||
|
||
|
||
class ChartSpec(BaseModel):
|
||
chart_type: ChartType
|
||
title: str = ""
|
||
reason: str | None = None
|
||
x_field: str | None = None
|
||
y_fields: list[str] = Field(default_factory=list)
|
||
series_field: str | None = None
|
||
|
||
|
||
class AnalyzeRequest(InterpretRequest):
|
||
"""分析助手:快照 + 用户提示词(文字/图表/both)。"""
|
||
|
||
analysis_prompt: str = Field(..., min_length=1, max_length=2000)
|
||
|
||
|
||
class ClarifyOption(BaseModel):
|
||
metric_key: str
|
||
metric_name: str
|
||
definition: str = ""
|
||
|
||
|
||
class ClarifyPayload(BaseModel):
|
||
term: str
|
||
options: list[ClarifyOption] = Field(default_factory=list)
|
||
llm_hint: str | None = None
|
||
|
||
|
||
class DictAmbiguityCheckRequest(BaseModel):
|
||
metric_key: str = Field(..., min_length=1, max_length=128)
|
||
metric_name: str = Field(..., min_length=1, max_length=128)
|
||
definition: str = Field(..., min_length=1)
|
||
aliases: str = Field(default="", description="逗号分隔或 JSON 数组字符串")
|
||
|
||
|
||
class AnalystResponse(BaseModel):
|
||
"""统一输出四件套 + 状态/错误信息。"""
|
||
|
||
answer: str = ""
|
||
table: TableData = Field(default_factory=TableData)
|
||
sql: str = ""
|
||
meta: Meta = Field(default_factory=Meta)
|
||
disclaimer: str = DISCLAIMER
|
||
status: str = "success" # success / clarify / deny / degrade / error / escalate
|
||
error_code: str | None = None
|
||
suggestions: list[str] | None = Field(
|
||
default=None, description="权限拒绝时的可查范围引导(D-08)"
|
||
)
|
||
trace_id: str | None = None
|
||
analysis_kind: AnalysisKind = "none"
|
||
chart: ChartSpec | None = None
|
||
clarify: ClarifyPayload | None = Field(default=None, description="status=clarify 时可选口径")
|
||
|
||
|
||
class AssetCreateRequest(BaseModel):
|
||
"""沉淀资产(D-11):few_shot / dict / template。"""
|
||
|
||
kind: str = Field(..., description="few_shot / dict / template")
|
||
payload: dict = Field(default_factory=dict)
|
||
publish: bool = Field(
|
||
False,
|
||
description="true 时写入 status=published 并立即参与问数(dict/few-shot/template)",
|
||
)
|
||
|
||
|
||
class EscalateRequest(BaseModel):
|
||
"""问数失败一键转人工(N-07)。"""
|
||
|
||
trace_id: str = Field(..., min_length=1, max_length=64)
|
||
question: str = Field(default="", max_length=2000)
|
||
reason: str = Field(default="", max_length=500)
|
||
|
||
|
||
class SampleRequest(BaseModel):
|
||
"""抽样明细(N-03)。"""
|
||
|
||
limit: int = Field(default=5, ge=1, le=20)
|