"""Manual check of the knowledge base on synthetic questions. python -m app.llm.rag "через сколько начинают действовать антидепрессанты" python -m app.llm.rag --audience doctor "синдром отмены антидепрессантов" python -m app.llm.rag --search "ДПДГ при ПТСР" # raw retrieval: chunks, scores, passages python -m app.llm.rag --stats # corpus summary The question always goes through `privacy.scrub()` first; the CLI never bypasses it. """ import argparse import asyncio from collections import Counter from app.core import privacy from app.llm.gateway import get_gateway from app.llm.rag.index import get_index from app.llm.rag.qa import answer, fallback_text def main(argv: list[str] | None = None) -> int: parser = argparse.ArgumentParser(prog="python -m app.llm.rag") parser.add_argument("question", nargs="?") parser.add_argument("--audience", choices=["patient", "doctor", "team"], default="patient") parser.add_argument("--search", action="store_true", help="show retrieved chunks instead of an answer") parser.add_argument("--top", type=int, default=5) parser.add_argument("--stats", action="store_true") args = parser.parse_args(argv) index = get_index() if args.stats: by_doc = Counter(c.doc.short for c in index.chunks) print(f"chunks={len(index.chunks)}", ", ".join(f"{d}: {n}" for d, n in by_doc.items())) return 0 if not args.question: parser.error("question is required") question = privacy.scrub(args.question) if args.search: for hit in index.search(question, audience=args.audience, top_k=args.top, min_score=0): print(f"{hit.score:6.1f} (bm25 {hit.bm25:5.1f}) {hit.chunk.citation} {hit.chunk.section}") print(f" > {hit.passage[:300]}") return 0 print(f"provider={get_gateway().provider_name} audience={args.audience}\n") reply = asyncio.run(answer(question, audience=args.audience, index=index)) print(reply.text if reply else fallback_text(args.audience)) return 0 if __name__ == "__main__": raise SystemExit(main())