feat: stabilize rag chat conversations and auto title sync

This commit is contained in:
wren
2026-05-19 15:52:05 +08:00
parent 564f2bebc8
commit afaba4dd99
19 changed files with 1988 additions and 93 deletions
@@ -1,6 +1,6 @@
from __future__ import annotations
from fastapi_admin.config._settings import llm
from fastapi_admin.config._settings import embedding, llm
def _get_str(name: str, default: str = "") -> str:
@@ -36,11 +36,23 @@ RAG_CONFIG = {
"CHROMA_PORT": _get_int("RAG_CHROMA_PORT", 8010),
"CHROMA_TOKEN": _get_str("RAG_CHROMA_TOKEN", ""),
"CHROMA_AUTH_HEADER": _get_str("RAG_CHROMA_AUTH_HEADER", "X-Chroma-Token"),
"EMBED_URL": _get_str("RAG_EMBED_URL", _get_str("GRAPH_RAG_EMBED_URL", "")),
"EMBED_KEY": _get_str("RAG_EMBED_KEY", _get_str("GRAPH_RAG_EMBED_KEY", "")),
"EMBED_MODEL": _get_str("RAG_EMBED_MODEL", _get_str("GRAPH_RAG_EMBED_MODEL", "")),
"EMBED_DIM": _get_int("RAG_EMBED_DIM", 1024),
"EMBED_BATCH_SIZE": _get_int("RAG_EMBED_BATCH_SIZE", 10),
"EMBED_URL": _get_str(
"RAG_EMBED_URL",
_get_str("GRAPH_RAG_EMBED_URL", _get_str("EMBEDDING_BASE_URL", embedding.EMBEDDING_BASE_URL)),
),
"EMBED_KEY": _get_str(
"RAG_EMBED_KEY",
_get_str("GRAPH_RAG_EMBED_KEY", _get_str("EMBEDDING_API_KEY", embedding.EMBEDDING_API_KEY)),
),
"EMBED_MODEL": _get_str(
"RAG_EMBED_MODEL",
_get_str("GRAPH_RAG_EMBED_MODEL", _get_str("EMBEDDING_MODEL", embedding.EMBEDDING_MODEL)),
),
"EMBED_DIM": _get_int("RAG_EMBED_DIM", _get_int("EMBEDDING_DIM", embedding.EMBEDDING_DIM)),
"EMBED_BATCH_SIZE": _get_int(
"RAG_EMBED_BATCH_SIZE",
_get_int("EMBEDDING_BATCH_SIZE", embedding.EMBEDDING_BATCH_SIZE),
),
"RERANKER_URL": _get_str("RAG_RERANKER_URL", _get_str("GRAPH_RAG_RERANKER_URL", "")),
"RERANKER_KEY": _get_str("RAG_RERANKER_KEY", _get_str("GRAPH_RAG_RERANKER_KEY", "")),
"RERANKER_MODEL": _get_str("RAG_RERANKER_MODEL", _get_str("GRAPH_RAG_RERANKER_MODEL", "")),
@@ -58,3 +70,34 @@ RAG_CONFIG = {
"HYBRID_SEARCH": _get_bool("RAG_HYBRID_SEARCH", True),
"RERANKING": _get_bool("RAG_RERANKING", True),
}
def build_openai_chat_completions_url(base_url: str) -> str:
normalized = (base_url or "").strip().rstrip("/")
if not normalized:
return "/chat/completions"
if normalized.endswith("/chat/completions"):
return normalized
return f"{normalized}/chat/completions"
def build_openai_embeddings_url(base_url: str) -> str:
normalized = (base_url or "").strip().rstrip("/")
if not normalized:
return "/embeddings"
if normalized.endswith("/chat/completions"):
normalized = normalized[:-len("/chat/completions")]
if normalized.endswith("/embeddings"):
return normalized
return f"{normalized}/embeddings"
def normalize_openai_base_url(base_url: str) -> str:
normalized = (base_url or "").strip().rstrip("/")
if not normalized:
return ""
if normalized.endswith("/chat/completions"):
return normalized[:-len("/chat/completions")]
if normalized.endswith("/embeddings"):
return normalized[:-len("/embeddings")]
return normalized
@@ -7,7 +7,7 @@ from typing import AsyncGenerator
import httpx
from fastapi_modules.fastapi_leaudit.rag_engine.config import RAG_CONFIG
from fastapi_modules.fastapi_leaudit.rag_engine.config import RAG_CONFIG, build_openai_chat_completions_url
DEFAULT_SYSTEM_PROMPT = """你是烟草行业智慧法务小助手,专注于烟草专卖法规、合同管理、行政处罚等相关法律法规。\n\n回答要求:\n- 先用一句话直接回答,再展开详细说明\n- 多个要点用编号列表\n- 关键法条和数字用 **加粗**\n- 分类信息用表格\n- 层级结构用缩进子列表\n- 不要加标题,直接输出正文"""
@@ -17,13 +17,14 @@ async def generate_stream(
context_chunks: list[dict],
conversation_id: str,
message_id: str,
task_id: str | None = None,
system_prompt: str = "",
model: str = "",
temperature: float | None = None,
max_tokens: int | None = None,
dataset_name: str = "",
) -> AsyncGenerator[str, None]:
task_id = str(uuid.uuid4())
task_id = task_id or str(uuid.uuid4())
created_at = int(time.time())
_model = model or RAG_CONFIG["LLM_MODEL"]
_temp = temperature if temperature is not None else RAG_CONFIG["LLM_TEMPERATURE"]
@@ -55,7 +56,7 @@ async def generate_stream(
async with httpx.AsyncClient(timeout=RAG_CONFIG["LLM_TIMEOUT"]) as client:
async with client.stream(
"POST",
f"{RAG_CONFIG['LLM_BASE_URL'].rstrip('/')}" + "/chat/completions",
build_openai_chat_completions_url(RAG_CONFIG["LLM_BASE_URL"]),
json={
"model": _model,
"messages": messages,
@@ -4,7 +4,7 @@ import json
import httpx
from fastapi_modules.fastapi_leaudit.rag_engine.config import RAG_CONFIG
from fastapi_modules.fastapi_leaudit.rag_engine.config import RAG_CONFIG, build_openai_chat_completions_url
async def generate_followups(query: str, answer: str) -> list[str]:
@@ -15,7 +15,7 @@ async def generate_followups(query: str, answer: str) -> list[str]:
)
async with httpx.AsyncClient(timeout=30.0) as client:
resp = await client.post(
f"{RAG_CONFIG['LLM_BASE_URL'].rstrip('/')}" + "/chat/completions",
build_openai_chat_completions_url(RAG_CONFIG["LLM_BASE_URL"]),
json={
"model": RAG_CONFIG["LLM_MODEL"],
"messages": [{"role": "user", "content": prompt}],