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
@@ -36,11 +36,20 @@ async def check_document_with_controls(
doc_title: str,
db_url: str = "",
max_controls: int = 0, # 0 = no limit, check ALL
use_agent: bool = False, # Use LLM agent for intelligent evaluation
) -> list[dict]:
"""Check document against ALL doc_check_controls for this doc_type.
Deterministic: same text + same MCs = same result. No LLM involved.
Two modes:
- use_agent=False (default): Deterministic keyword matching. Fast, reproducible.
- use_agent=True: LLM agent with tool calling. Intelligent, contextual.
"""
if use_agent:
try:
from compliance.services.compliance_agent import run_compliance_check
return await run_compliance_check(text, doc_type, doc_title)
except Exception as e:
logger.warning("Agent mode failed, falling back to regex: %s", e)
if not text or len(text) < 100:
return []