feat: LLM-agnostic Compliance Agent with tool calling

New agent architecture for intelligent MC evaluation:

agent_tools.py (367 LOC):
- 5 tools in OpenAI function-calling format
- query_controls: async DB query for MCs by doc_type
- evaluate_controls_batch: deterministic keyword matching
- search_document: text search with context
- get_document_stats: word count, sections, language
- submit_results: finalize check results

compliance_agent.py (398 LOC):
- ComplianceAgent class with agent loop
- 3 LLM providers: Ollama, OpenAI-compatible (OVH), Anthropic
- Tool call dispatch + result collection
- System prompt for systematic compliance analysis
- run_compliance_check() convenience function

Hybrid mode:
- COMPLIANCE_USE_AGENT=false (default): deterministic regex
- COMPLIANCE_USE_AGENT=true: LLM agent with tool calling
- Agent fallback to regex if LLM unavailable

Works with Qwen 35B (Ollama), Qwen 120B (OVH vLLM), Claude.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-05-10 22:56:09 +02:00
parent bdbc30e47b
commit 58f370f4ff
4 changed files with 778 additions and 2 deletions
@@ -287,8 +287,10 @@ async def _check_single_document(entry: DocCheckEntry) -> list[DocCheckResult]:
# binary pass/fail criteria verified by LLM (Qwen)
try:
from compliance.services.rag_document_checker import check_document_with_controls
use_agent = os.getenv("COMPLIANCE_USE_AGENT", "false").lower() == "true"
mc_results = await check_document_with_controls(
doc_text, entry.doc_type, entry.label, max_controls=0,
doc_text, entry.doc_type, entry.label,
max_controls=0, use_agent=use_agent,
)
if mc_results:
# Add MC results as additional checks to the main result