dce9e31bde
- 新增 JWT 认证模块,支持登录/注册/用户管理 - 新增文件上传接口,支持 .txt/.md/.html/.pdf/.docx 等格式解析入库 - 新增检索结果 AI 总结功能 - 新增文本去重缓存机制 - 新增全局认证夹具简化测试 - 新增配置项与环境变量支持 - 完善文档与测试覆盖
67 lines
2.4 KiB
Python
67 lines
2.4 KiB
Python
"""检索结果 AI 总结
|
|
|
|
对检索返回的 chunk 命中结果,调用 Ollama 本地模型生成一段针对用户 query 的总结回答。
|
|
仅基于检索结果内容,不编造未提及的信息。
|
|
"""
|
|
|
|
import structlog
|
|
|
|
from app.config import settings
|
|
from app.models.search import SearchHit
|
|
from app.services.ollama import OllamaClient
|
|
|
|
logger = structlog.get_logger()
|
|
|
|
|
|
class ResultSummarizer:
|
|
"""检索结果总结器"""
|
|
|
|
def __init__(self, ollama: OllamaClient | None = None) -> None:
|
|
self.ollama = ollama or OllamaClient()
|
|
|
|
async def summarize(self, query: str, hits: list[SearchHit]) -> str:
|
|
"""对检索结果生成针对 query 的总结
|
|
|
|
取前 settings.result_summary_max_hits 条命中拼接为上下文,
|
|
无命中时返回空字符串(不调 LLM)。
|
|
"""
|
|
if not hits:
|
|
return ""
|
|
max_hits = settings.result_summary_max_hits
|
|
selected = hits[:max_hits]
|
|
context = self._build_context(selected)
|
|
prompt = self._build_prompt(query, context)
|
|
try:
|
|
summary = await self.ollama.generate(prompt)
|
|
except Exception:
|
|
logger.warning("检索结果总结生成失败,返回空字符串", exc_info=True)
|
|
return ""
|
|
logger.info("检索结果总结完成", query=query, hits_count=len(selected), summary_len=len(summary))
|
|
return summary.strip()
|
|
|
|
@staticmethod
|
|
def _build_context(hits: list[SearchHit]) -> str:
|
|
"""拼接命中结果为带编号的上下文"""
|
|
blocks: list[str] = []
|
|
for i, hit in enumerate(hits, start=1):
|
|
header_parts = [f"[{i}]"]
|
|
if hit.title:
|
|
header_parts.append(hit.title)
|
|
if hit.section_path:
|
|
header_parts.append(hit.section_path)
|
|
header = " / ".join(header_parts)
|
|
blocks.append(f"{header}\n{hit.text}")
|
|
return "\n\n---\n\n".join(blocks)
|
|
|
|
@staticmethod
|
|
def _build_prompt(query: str, context: str) -> str:
|
|
return (
|
|
"请根据以下检索结果,针对用户问题生成一段简洁的总结回答。\n"
|
|
"要求:\n"
|
|
"- 综合多条结果信息,不要简单逐条罗列;\n"
|
|
"- 只基于检索结果内容,不编造未提及的信息;\n"
|
|
"- 用中文回答,简洁明了。\n\n"
|
|
f"用户问题:{query}\n\n"
|
|
f"检索结果:\n{context}"
|
|
)
|