优化案例查询和方案思考过程
This commit is contained in:
parent
736a6653de
commit
4a8f4e03d3
@ -14,6 +14,7 @@ from app.schemas.conversation import (
|
|||||||
ConversationData,
|
ConversationData,
|
||||||
ConversationMessageCreateRequest,
|
ConversationMessageCreateRequest,
|
||||||
ConversationSummary,
|
ConversationSummary,
|
||||||
|
DirectQueryRequest,
|
||||||
)
|
)
|
||||||
from app.services.conversations import ConversationService
|
from app.services.conversations import ConversationService
|
||||||
|
|
||||||
@ -39,6 +40,15 @@ async def create_conversation(
|
|||||||
return ApiResponse(data=await ConversationService(session).create(current_user, payload.title))
|
return ApiResponse(data=await ConversationService(session).create(current_user, payload.title))
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/direct-query", response_model=ApiResponse[dict])
|
||||||
|
async def direct_query(
|
||||||
|
payload: DirectQueryRequest,
|
||||||
|
session: DatabaseSession,
|
||||||
|
_current_user: Annotated[UserAccount, Depends(require_permission("risk.assess", operate=True))],
|
||||||
|
) -> ApiResponse[dict]:
|
||||||
|
return ApiResponse(data=await ConversationService(session).direct_query(payload.kind, payload.query))
|
||||||
|
|
||||||
|
|
||||||
@router.get("/{conversation_id}", response_model=ApiResponse[ConversationData])
|
@router.get("/{conversation_id}", response_model=ApiResponse[ConversationData])
|
||||||
async def get_conversation(
|
async def get_conversation(
|
||||||
conversation_id: int,
|
conversation_id: int,
|
||||||
|
|||||||
@ -19,6 +19,11 @@ class ConversationMessageCreateRequest(ApiSchema):
|
|||||||
message_type: Literal["text", "image", "file", "audio"] = "text"
|
message_type: Literal["text", "image", "file", "audio"] = "text"
|
||||||
|
|
||||||
|
|
||||||
|
class DirectQueryRequest(ApiSchema):
|
||||||
|
kind: Literal["supplier", "material", "cases", "solution"]
|
||||||
|
query: str = Field(min_length=1, max_length=2000)
|
||||||
|
|
||||||
|
|
||||||
class ConversationListQuery(ApiSchema):
|
class ConversationListQuery(ApiSchema):
|
||||||
limit: int = Field(default=50, ge=1, le=100)
|
limit: int = Field(default=50, ge=1, le=100)
|
||||||
|
|
||||||
|
|||||||
@ -128,6 +128,49 @@ class ConversationService:
|
|||||||
raise AppException("对话创建失败", code=500, status_code=500)
|
raise AppException("对话创建失败", code=500, status_code=500)
|
||||||
return self._data(persisted, messages=[], total=0, offset=0)
|
return self._data(persisted, messages=[], total=0, offset=0)
|
||||||
|
|
||||||
|
async def direct_query(self, kind: str, query: str) -> dict[str, Any]:
|
||||||
|
"""Build a shortcut result without creating a conversation message."""
|
||||||
|
text = query.strip()
|
||||||
|
if not text:
|
||||||
|
raise AppException("查询内容不能为空", code=422, status_code=422)
|
||||||
|
if kind == "supplier":
|
||||||
|
return await self._supplier_card(text, {"supplier": text})
|
||||||
|
if kind == "material":
|
||||||
|
return await self._material_card(text, {"packaging": text})
|
||||||
|
if kind == "solution":
|
||||||
|
semantics = self._normalize_semantics(
|
||||||
|
text,
|
||||||
|
await self.llm.extract_semantics(text, history=[]),
|
||||||
|
)
|
||||||
|
return await self._solution_card(text, semantics)
|
||||||
|
results = await self._similar_cases(
|
||||||
|
text,
|
||||||
|
category=None,
|
||||||
|
material=None,
|
||||||
|
supplier=None,
|
||||||
|
factory=None,
|
||||||
|
stage=None,
|
||||||
|
anomaly_type=None,
|
||||||
|
)
|
||||||
|
top_cases = list(results[:3])
|
||||||
|
# Keep the same similarity signal used by the risk assessment card.
|
||||||
|
# Vector retrieval populates it in RAG; lexical fallback still gets a
|
||||||
|
# deterministic score so the shortcut card never loses that field.
|
||||||
|
for item in top_cases:
|
||||||
|
if item.case.similarity is None:
|
||||||
|
item.case.similarity = round(max(0.0, min(1.0, item.score / 100)), 3)
|
||||||
|
return {
|
||||||
|
"type": "cases",
|
||||||
|
"title": "案例检索",
|
||||||
|
"query": text,
|
||||||
|
"cases": [item.case.model_dump(mode="json", by_alias=True) for item in top_cases],
|
||||||
|
"matchedCount": len(top_cases),
|
||||||
|
"suggestions": [
|
||||||
|
"同类问题优先复用历史方案,再按判定标准复测验证",
|
||||||
|
"如已出货,准备客诉应对预案并对同批次抽检",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
async def delete(self, conversation_id: int, user: UserAccount) -> None:
|
async def delete(self, conversation_id: int, user: UserAccount) -> None:
|
||||||
"""Delete one user-owned conversation and retain an audit trail."""
|
"""Delete one user-owned conversation and retain an audit trail."""
|
||||||
|
|
||||||
@ -876,6 +919,12 @@ class ConversationService:
|
|||||||
"type": "solution",
|
"type": "solution",
|
||||||
"title": "AI 案例推理生成",
|
"title": "AI 案例推理生成",
|
||||||
"confidence": "中",
|
"confidence": "中",
|
||||||
|
"thinkingSummary": [
|
||||||
|
f"识别产品场景:{category},提取包装、供应链和风险问题等关键信息",
|
||||||
|
f"检索历史异常案例,匹配到 {len(similar_cases)} 条相似案例并进行相似度排序",
|
||||||
|
f"关联判定标准库 {len(standards)} 条规则,完成规则引擎兜底校验",
|
||||||
|
f"综合历史案例与标准规则,整理 {len(suggestions)} 条可执行建议",
|
||||||
|
],
|
||||||
"analysisBase": (
|
"analysisBase": (
|
||||||
f"目标品类「{category}」当前命中历史异常 {direct_count} 条;"
|
f"目标品类「{category}」当前命中历史异常 {direct_count} 条;"
|
||||||
"方案结合已导入异常案例和标准规则生成。"
|
"方案结合已导入异常案例和标准规则生成。"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user