2ab8b56a01
此提交实现了完整的知识库管理系统: 1. 新增Vue3 + Antd Vue前端管理后台,包含登录、文档管理、检索、类目设置等完整页面 2. 重构后端LLM调用抽象层,支持Ollama与OpenAI兼容服务动态切换 3. 调整默认嵌入模型配置为本地bge-m3模式 4. 优化入库任务去重逻辑与缓存清理机制 5. 完善Docker镜像构建与docker-compose部署配置 6. 修复多项测试用例与兼容性问题 7. 新增运行时配置API,支持动态调整系统参数
70 lines
2.6 KiB
Python
70 lines
2.6 KiB
Python
"""检索结果 AI 总结
|
||
|
||
对检索返回的 chunk 命中结果,调用 LLM(Ollama 或 OpenAI 兼容服务,由
|
||
runtime_settings.models.query 决定)生成一段针对用户 query 的总结回答。
|
||
仅基于检索结果内容,不编造未提及的信息。
|
||
"""
|
||
|
||
import structlog
|
||
|
||
from app.config import settings
|
||
from app.models.search import SearchHit
|
||
from app.services.llm import LLMClient, create_llm_client
|
||
|
||
logger = structlog.get_logger()
|
||
|
||
|
||
class ResultSummarizer:
|
||
"""检索结果总结器"""
|
||
|
||
def __init__(self, ollama: LLMClient | None = None) -> None:
|
||
# 默认按 runtime_settings.models.query 选择 LLM 实现;
|
||
# 测试可通过 ollama 参数注入替身。
|
||
self.ollama = ollama or create_llm_client("query")
|
||
|
||
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}"
|
||
)
|