feat(rag): Telegram /rag 指令 + /rag/optimize ivfflat 端點
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 14m9s
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 14m9s
- telegram_gateway: /rag <query> → KnowledgeRAGService.query() _handle_group_command 加 full_text 參數取得完整指令文字 /help 更新加入 /rag 說明 - rag.py: POST /rag/optimize → rag_repo.create_ivfflat_index() - rag_chunk_repository: create_ivfflat_index() — ivfflat with lists=100 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -94,6 +94,13 @@ async def rag_stats() -> dict:
|
||||
return await svc.get_stats()
|
||||
|
||||
|
||||
@router.post("/optimize", summary="建立 ivfflat 向量索引(需 >100 chunks)", include_in_schema=False)
|
||||
async def rag_optimize() -> dict:
|
||||
"""對 rag_chunks.embedding 建立 ivfflat 索引,加速向量搜尋"""
|
||||
import src.repositories.rag_chunk_repository as rag_repo
|
||||
return await rag_repo.create_ivfflat_index()
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Background helper
|
||||
# ============================================================
|
||||
|
||||
@@ -88,6 +88,29 @@ async def delete_by_source_id(source_id: str) -> None:
|
||||
logger.warning("rag_chunk_delete_failed", source_id=source_id, error=str(e))
|
||||
|
||||
|
||||
async def create_ivfflat_index() -> dict:
|
||||
"""建立 ivfflat 向量索引(需 >100 chunks,加速 KNN 搜尋)"""
|
||||
try:
|
||||
async with get_db_context() as db:
|
||||
await db.execute(
|
||||
text("""
|
||||
CREATE INDEX IF NOT EXISTS idx_rag_chunks_embedding
|
||||
ON rag_chunks
|
||||
USING ivfflat (embedding vector_cosine_ops)
|
||||
WITH (lists = 100)
|
||||
""")
|
||||
)
|
||||
rows = await db.execute(
|
||||
text("SELECT indexname FROM pg_indexes WHERE tablename = 'rag_chunks'")
|
||||
)
|
||||
indexes = [r[0] for r in rows]
|
||||
logger.info("rag_ivfflat_index_created", indexes=indexes)
|
||||
return {"status": "ok", "indexes": indexes}
|
||||
except Exception as e:
|
||||
logger.error("rag_ivfflat_index_failed", error=str(e))
|
||||
return {"status": "error", "error": str(e)}
|
||||
|
||||
|
||||
async def get_stats() -> dict:
|
||||
"""取得 chunk 數量與來源統計"""
|
||||
try:
|
||||
|
||||
@@ -3643,7 +3643,7 @@ class TelegramGateway:
|
||||
# ── 指令路由 (2026-04-03 ogt: 方案B slash commands) ──────────────────
|
||||
cmd = text.strip().split()[0].lower().split("@")[0] if text.strip() else ""
|
||||
if cmd.startswith("/"):
|
||||
await self._handle_group_command(cmd, chat_id, message_id)
|
||||
await self._handle_group_command(cmd, chat_id, message_id, full_text=text.strip())
|
||||
return
|
||||
|
||||
from src.services.chat_manager import get_chat_manager as _get_cm
|
||||
@@ -3729,7 +3729,7 @@ class TelegramGateway:
|
||||
|
||||
logger.info("group_message_handled", user_id=user_id, text=text[:50])
|
||||
|
||||
async def _handle_group_command(self, cmd: str, _chat_id: int, message_id: int | None) -> None:
|
||||
async def _handle_group_command(self, cmd: str, _chat_id: int, message_id: int | None, full_text: str = "") -> None:
|
||||
"""
|
||||
SRE 群組 Slash Commands (2026-04-03 ogt: 方案B)
|
||||
|
||||
@@ -3737,6 +3737,7 @@ class TelegramGateway:
|
||||
/incidents → 活躍告警列表
|
||||
/cost → 本月 AI 費用統計
|
||||
/pods → 異常 Pod 列表
|
||||
/rag → RAG 知識庫查詢 (ADR-067 Phase 33)
|
||||
/help → 指令說明
|
||||
"""
|
||||
from src.repositories.k8s_repository import get_k8s_repository
|
||||
@@ -3810,6 +3811,31 @@ class TelegramGateway:
|
||||
msg = f"<b>⚠️ 異常 Pod</b>\n⚠️ 無法取得: {e}"
|
||||
await self.send_as_openclaw(text=msg, reply_to_message_id=message_id)
|
||||
|
||||
elif cmd == "/rag":
|
||||
# /rag <查詢內容> — RAG 知識庫語義查詢 (ADR-067 Phase 33)
|
||||
# 2026-04-10 Claude Sonnet 4.6 Asia/Taipei
|
||||
parts = full_text.split(None, 1)
|
||||
if len(parts) < 2 or not parts[1].strip():
|
||||
await self.send_as_openclaw(
|
||||
text="<b>📚 RAG 知識庫查詢</b>\n用法: <code>/rag 你的問題</code>\n例如: <code>/rag 什麼是 ADR-067?</code>",
|
||||
reply_to_message_id=message_id,
|
||||
)
|
||||
return
|
||||
question = parts[1].strip()
|
||||
await self.send_as_openclaw(
|
||||
text=f"<b>📚 查詢知識庫中...</b>\n<code>{question[:80]}</code>",
|
||||
reply_to_message_id=message_id,
|
||||
)
|
||||
try:
|
||||
from src.services.knowledge_rag_service import get_knowledge_rag_service
|
||||
svc = get_knowledge_rag_service()
|
||||
answer = await svc.query(question, top_k=5)
|
||||
msg = f"<b>📚 RAG 知識庫</b>\n<i>Q: {question[:80]}</i>\n\n{answer}"
|
||||
except Exception as e:
|
||||
logger.warning("rag_telegram_query_failed", error=str(e))
|
||||
msg = f"<b>📚 RAG 查詢失敗</b>\n{e}"
|
||||
await self.send_as_openclaw(text=msg, reply_to_message_id=message_id)
|
||||
|
||||
elif cmd == "/help":
|
||||
msg = (
|
||||
"<b>🤖 SRE 戰情室指令</b>\n\n"
|
||||
@@ -3817,6 +3843,7 @@ class TelegramGateway:
|
||||
"/incidents — 列出活躍告警\n"
|
||||
"/cost — 查詢本月 AI 費用\n"
|
||||
"/pods — 列出異常 Pod\n"
|
||||
"/rag <問題> — 查詢 RAG 知識庫\n"
|
||||
"/help — 顯示此說明\n\n"
|
||||
"<b>對話方式:</b>\n"
|
||||
"• 直接輸入 → 小O + 小賀 同時回應\n"
|
||||
|
||||
Reference in New Issue
Block a user