feat: connect chat endpoint to verified retrieval
This commit is contained in:
@@ -1,15 +1,34 @@
|
||||
from fastapi import APIRouter
|
||||
from fastapi import APIRouter, Depends
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.db.session import get_db
|
||||
from app.schemas.chat import ChatRequest, ChatResponse
|
||||
from app.schemas.retrieval import RetrievalRequest
|
||||
from app.services.retrieval import retrieve
|
||||
|
||||
router = APIRouter(tags=["chat"])
|
||||
|
||||
|
||||
@router.post("/chat", response_model=ChatResponse)
|
||||
def chat(payload: ChatRequest) -> ChatResponse:
|
||||
# TODO: retrieval -> context assembly -> LLM -> evidence/source checks
|
||||
def chat(payload: ChatRequest, db: Session = Depends(get_db)) -> ChatResponse:
|
||||
"""运行可复核的关键词检索;模型未配置时绝不伪造生成式回答。"""
|
||||
result = retrieve(db, RetrievalRequest(query=payload.question, top_k=5))
|
||||
if result.status == "no_evidence":
|
||||
return ChatResponse(
|
||||
answer="未检索到可用的已核验知识依据。请补充更具体的关键词,或由管理员补充并审核资料。",
|
||||
status="no_evidence",
|
||||
sources=[],
|
||||
retrieval_run_id=result.run_id,
|
||||
)
|
||||
return ChatResponse(
|
||||
answer=f"已收到问题:{payload.question}。当前为基础壳子,尚未接入知识检索或大语言模型。",
|
||||
status="stub",
|
||||
sources=[],
|
||||
answer=(
|
||||
f"已检索到 {result.total_hits} 条已核验知识依据。当前尚未配置大语言模型,"
|
||||
"因此系统仅返回可追溯证据,不生成或改写答案。"
|
||||
),
|
||||
status="retrieval_only",
|
||||
sources=[
|
||||
{"title": hit.title, "source_url": hit.source_url}
|
||||
for hit in result.results
|
||||
],
|
||||
retrieval_run_id=result.run_id,
|
||||
)
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
from typing import Literal
|
||||
from uuid import UUID
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
@@ -12,5 +15,6 @@ class SourcePreview(BaseModel):
|
||||
|
||||
class ChatResponse(BaseModel):
|
||||
answer: str
|
||||
status: str
|
||||
status: Literal["retrieval_only", "no_evidence"]
|
||||
sources: list[SourcePreview] = []
|
||||
retrieval_run_id: UUID
|
||||
|
||||
@@ -271,7 +271,9 @@ def test_all_management_routes_require_admin_and_history_is_private(anonymous_cl
|
||||
for method, path in paths:
|
||||
assert c.request(method, path, json={}).status_code == 403, path
|
||||
assert c.post("/api/retrieval", json={"query": "占位"}).json()["status"] == "no_evidence"
|
||||
assert c.post("/api/chat", json={"question": "占位"}).json()["status"] == "stub"
|
||||
response = c.post("/api/chat", json={"question": "占位"})
|
||||
assert response.status_code == 200
|
||||
assert response.json()["status"] == "no_evidence"
|
||||
|
||||
|
||||
def test_admin_access_live_role_and_no_csrf_bypass(client, migrated_database):
|
||||
|
||||
@@ -59,12 +59,28 @@ def review(client, item, status="verified"):
|
||||
)
|
||||
|
||||
|
||||
def test_health_docs_and_stub(client):
|
||||
def test_health_docs_and_chat_without_evidence(client):
|
||||
assert client.get("/api/health").json()["status"] == "ok"
|
||||
assert client.get("/api/ready").json()["database"] == "connected"
|
||||
assert client.get("/docs").status_code == 200
|
||||
assert "/api/knowledge/{item_id}/review" in client.get("/openapi.json").json()["paths"]
|
||||
assert client.post("/api/chat", json={"question": "测试"}).json()["status"] == "stub"
|
||||
response = client.post("/api/chat", json={"question": "测试"})
|
||||
assert response.status_code == 200
|
||||
assert response.json()["status"] == "no_evidence"
|
||||
|
||||
|
||||
def test_chat_returns_real_retrieval_evidence_without_generation(client):
|
||||
item = knowledge(client, title="那拉提测试资料", content="那拉提文旅服务测试依据")
|
||||
assert review(client, item).status_code == 200
|
||||
|
||||
response = client.post("/api/chat", json={"question": "那拉提文旅服务"})
|
||||
|
||||
assert response.status_code == 200
|
||||
body = response.json()
|
||||
assert body["status"] == "retrieval_only"
|
||||
assert "不生成" in body["answer"]
|
||||
assert body["retrieval_run_id"]
|
||||
assert body["sources"] == [{"title": "那拉提测试资料", "source_url": "https://example.com/"}]
|
||||
|
||||
|
||||
def test_legacy_create_and_missing_evidence(client):
|
||||
|
||||
Reference in New Issue
Block a user