Add LLM token

This commit is contained in:
wangwei
2026-07-02 22:03:39 +08:00
parent e3afb8a07a
commit 52e67b0e7b
36 changed files with 2392 additions and 394 deletions
+60 -1
View File
@@ -20,7 +20,11 @@ from app.api.models import (
)
from app.config.settings import settings
from app.shared.async_utils import iter_in_thread
from app.shared.bootstrap import get_agent_conversation_service, get_agent_session_service
from app.shared.bootstrap import (
get_agent_conversation_service,
get_agent_session_service,
get_agentic_conversation_service,
)
# Keep route handlers close to their transport-layer wiring for easier auditing.
@@ -182,3 +186,58 @@ async def submit_feedback(request: FeedbackRequest):
return {"message": "反馈已提交", "session_id": result.session_id, "message_index": result.message_index}
except ValueError as exc:
raise HTTPException(status_code=404, detail=str(exc))
# ── P0-1: Agentic RAG endpoint ────────────────────────────────────────────────
@router.post("/agentic/stream")
async def agentic_stream(request: ChatRequest):
"""Stream an Agentic RAG response with live multi-step reasoning trace.
Unlike the standard ``/chat/stream`` endpoint this route runs a full pipeline:
intent analysis → query planning → iterative retrieval → grounding check →
answer generation.
Extra SSE event types beyond the standard ones:
* ``thinking`` — reasoning sub-step progress; data is a JSON object with
``step`` (intent_analysis / query_planning / retrieving / grounding_check),
``status`` (running / done), and step-specific fields.
The ``sources``, ``content``, and ``done`` events are identical to the standard
chat-stream contract so the existing frontend parser can handle them without
changes.
"""
async def generate_sse() -> AsyncGenerator[str, None]:
"""Handle SSE generation for the agentic chat endpoint."""
try:
session_id_, event_stream = get_agentic_conversation_service().stream_agentic_chat(
query=request.query,
session_id=request.session_id,
filters=request.filters,
provider=request.provider or settings.llm_provider,
model=request.model or settings.llm_model,
top_k=request.top_k or settings.rag_top_k,
context_text=request.context_text,
context_filename=request.context_filename,
)
yield f"event: session\ndata: {json.dumps({'session_id': session_id_})}\n\n"
async for event_data in iter_in_thread(event_stream):
event_type = event_data.get("event", "content")
data = event_data.get("data", "")
if isinstance(data, (dict, list)):
yield f"event: {event_type}\ndata: {json.dumps(data, ensure_ascii=False)}\n\n"
else:
yield f"event: {event_type}\ndata: {data}\n\n"
except Exception as exc:
yield f"event: error\ndata: {str(exc)}\n\n"
return StreamingResponse(
generate_sse(),
media_type="text/event-stream",
headers={
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"X-Accel-Buffering": "no",
},
)