Files

98 lines
3.1 KiB
Python
Raw Permalink Normal View History

"""Provide service-layer logic for qa agent."""
from __future__ import annotations
2026-05-14 15:07:34 +08:00
from dataclasses import dataclass, field
from typing import Dict, Generator, List, Optional
2026-05-14 15:07:34 +08:00
from app.config.settings import settings
from app.shared.bootstrap import get_agent_conversation_service
# Keep service responsibilities explicit so downstream behavior stays predictable.
2026-05-14 15:07:34 +08:00
@dataclass
class AgentResponse:
"""Represent the Agent Response type."""
2026-05-14 15:07:34 +08:00
answer: str
sources: List[Dict] = field(default_factory=list)
model: str = ""
latency_ms: int = 0
retrieved_count: int = 0
context_tokens: int = 0
truncated: bool = False
error: Optional[str] = None
@property
def is_success(self) -> bool:
"""Return whether success for the Agent Response instance."""
2026-05-14 15:07:34 +08:00
return self.error is None
@dataclass
class AgentConfig:
"""Define configuration for agent config."""
llm_provider: str = settings.llm_provider
llm_model: str = settings.llm_model
top_k: int = settings.rag_top_k
min_score: float = 0.0
max_context_tokens: int = settings.rag_max_context_tokens
temperature: float = settings.llm_temperature
2026-05-14 15:07:34 +08:00
prompt_template: str = "compliance_qa"
include_metadata: bool = True
class QAAgent:
"""Represent the Q A Agent type."""
2026-05-14 15:07:34 +08:00
def __init__(self, config: Optional[AgentConfig] = None):
"""Initialize the Q A Agent instance."""
self.config = config or AgentConfig()
2026-05-14 15:07:34 +08:00
def ask(
self,
query: str,
filters: Optional[str] = None,
prompt_template: Optional[str] = None,
2026-05-14 15:07:34 +08:00
) -> AgentResponse:
"""Handle ask for the Q A Agent instance."""
_, result = get_agent_conversation_service().ask(
query=query,
filters=filters,
provider=self.config.llm_provider,
model=self.config.llm_model,
top_k=self.config.top_k,
prompt_template=prompt_template or self.config.prompt_template,
)
return AgentResponse(
answer=result.answer,
sources=[source.__dict__ for source in result.sources],
model=result.model,
latency_ms=result.latency_ms,
retrieved_count=result.retrieved_count,
context_tokens=result.context_tokens,
truncated=result.truncated,
error=result.error,
2026-05-14 15:07:34 +08:00
)
def ask_stream(self, query: str, filters: Optional[str] = None) -> Generator[dict, None, None]:
"""Handle ask stream for the Q A Agent instance."""
_, stream = get_agent_conversation_service().stream_chat(
query=query,
filters=filters,
provider=self.config.llm_provider,
model=self.config.llm_model,
top_k=self.config.top_k,
prompt_template=self.config.prompt_template,
)
for event in stream:
yield event
2026-05-14 15:07:34 +08:00
def close(self):
"""Release the resources held by this component."""
return None
2026-05-14 15:07:34 +08:00
def ask_compliance_question(query: str, top_k: int = 5) -> AgentResponse:
"""Handle ask compliance question."""
return QAAgent(AgentConfig(top_k=top_k)).ask(query)