From ab38e93516de38d6282e0602576ef5d737acfe5c Mon Sep 17 00:00:00 2001 From: nogueiraguh Date: Wed, 11 Mar 2026 10:31:24 -0300 Subject: [PATCH] feat: dedicated consult prompt and enriched document content extraction - Add CONSULT_SYSTEM_PROMPT (concise data viewer, not compliance assistant) - Add _enrich_doc_content to extract text from metadata.text when TEXT column is short - Enriches context with recommendation number, chapter, tenancy, section - Improves RAG context quality for all vector search flows --- backend/app.py | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/backend/app.py b/backend/app.py index 850f5f2..bf86885 100644 --- a/backend/app.py +++ b/backend/app.py @@ -2120,6 +2120,16 @@ RAG_DEFAULT_SYSTEM_PROMPT = """Você é um assistente RAG especializado em Oracl - CIS_REPORT: - CIS_RECOMMENDATIONS: (se usado)""" +CONSULT_SYSTEM_PROMPT = """Você é um consultor de dados vetorizados. Sua função é responder perguntas com base nos documentos recuperados do banco vetorial. + +### Regras +- Responda **somente** com informações presentes nos documentos fornecidos. +- Se não encontrar informação relevante, diga claramente. +- Seja direto e objetivo. Apresente os dados de forma organizada. +- Use markdown para formatação (negrito, listas, tabelas quando apropriado). +- Cite de qual tabela/fonte veio cada informação. +- Não invente dados que não estejam nos documentos.""" + TF_DEFAULT_SYSTEM_PROMPT = """Você gera somente Terraform HCL para Oracle Cloud Infrastructure (OCI) usando o provider oracle/oci. Se pedirem AWS, Azure, GCP ou outro provider, recuse educadamente. @@ -2518,6 +2528,37 @@ def _vector_search(cfg: dict, query_embedding: list, top_k: int = 5, table_name: finally: conn.close() +def _enrich_doc_content(doc: dict) -> str: + """Extract the best text content from a document, checking metadata.text as fallback.""" + content = doc.get("content", "") + meta = doc.get("metadata", "") + if isinstance(meta, str) and meta: + try: + meta = json.loads(meta) + except Exception: + meta = {} + if isinstance(meta, dict): + # If TEXT column is short/empty, use metadata.text instead + meta_text = meta.get("text", "") + if meta_text and len(meta_text) > len(content): + header_parts = [] + if meta.get("recommendationNumber"): + header_parts.append(f"Recommendation: {meta['recommendationNumber']}") + if meta.get("chapter"): + header_parts.append(f"Chapter: {meta['chapter']}") + if meta.get("header"): + header_parts.append(meta["header"]) + header = " | ".join(header_parts) + content = (header + "\n" + meta_text) if header else meta_text + # Also enrich with section/tenancy info if available + elif meta.get("section") or meta.get("tenancy"): + extra = [] + if meta.get("tenancy"): extra.append(f"Tenancy: {meta['tenancy']}") + if meta.get("section"): extra.append(f"Section: {meta['section']}") + if extra: + content = " | ".join(extra) + "\n" + content + return content + def _build_rag_context(documents: list) -> str: """Format retrieved documents into a context string for the LLM prompt.""" if not documents: @@ -2525,7 +2566,7 @@ def _build_rag_context(documents: list) -> str: parts = [] for i, doc in enumerate(documents, 1): source = doc.get("source", "unknown") - content = doc.get("content", "") + content = _enrich_doc_content(doc) if len(content) > 2000: content = content[:2000] + "..." parts.append(f"[Document {i} | Source: {source}]\n{content}") @@ -3428,7 +3469,7 @@ async def consult_embeddings(req: ConsultQuery, u=Depends(current_user)): parts.append(f"**Documento {i}** — `{d.get('source', '?')}` (distância: {d.get('distance', 0):.4f})\n\n{content}") return {"answer": "\n\n---\n\n".join(parts), "documents": doc_list, "total": len(all_docs)} try: - gc["system_prompt"] = RAG_DEFAULT_SYSTEM_PROMPT + gc["system_prompt"] = CONSULT_SYSTEM_PROMPT answer, _, _ = _call_genai(gc, augmented) except Exception as e: log.error(f"Consult GenAI error: {e}")