79 lines
2.6 KiB
Python
79 lines
2.6 KiB
Python
from pydantic import BaseModel, Field
|
|
from pydantic_ai import Agent, RunContext
|
|
from pydantic_ai.models.openai import OpenAIModel
|
|
from pydantic_ai.providers.ollama import OllamaProvider
|
|
|
|
from haiku.rag.client import HaikuRAG
|
|
from haiku.rag.config import Config
|
|
from haiku.rag.qa.prompts import SYSTEM_PROMPT, SYSTEM_PROMPT_WITH_CITATIONS
|
|
|
|
|
|
class SearchResult(BaseModel):
|
|
content: str = Field(description="The document text content")
|
|
score: float = Field(description="Relevance score (higher is more relevant)")
|
|
document_uri: str = Field(description="Source URI/path of the document")
|
|
|
|
|
|
class Dependencies(BaseModel):
|
|
model_config = {"arbitrary_types_allowed": True}
|
|
client: HaikuRAG
|
|
|
|
|
|
class QuestionAnswerAgent:
|
|
def __init__(
|
|
self,
|
|
client: HaikuRAG,
|
|
provider: str,
|
|
model: str,
|
|
use_citations: bool = False,
|
|
q: float = 0.0,
|
|
):
|
|
self._client = client
|
|
|
|
system_prompt = SYSTEM_PROMPT_WITH_CITATIONS if use_citations else SYSTEM_PROMPT
|
|
model_obj = self._get_model(provider, model)
|
|
|
|
self._agent = Agent(
|
|
model=model_obj,
|
|
deps_type=Dependencies,
|
|
system_prompt=system_prompt,
|
|
)
|
|
|
|
@self._agent.tool
|
|
async def search_documents(
|
|
ctx: RunContext[Dependencies],
|
|
query: str,
|
|
limit: int = 3,
|
|
) -> list[SearchResult]:
|
|
"""Search the knowledge base for relevant documents."""
|
|
search_results = await ctx.deps.client.search(query, limit=limit)
|
|
expanded_results = await ctx.deps.client.expand_context(search_results)
|
|
|
|
return [
|
|
SearchResult(
|
|
content=chunk.content,
|
|
score=score,
|
|
document_uri=chunk.document_uri or "",
|
|
)
|
|
for chunk, score in expanded_results
|
|
]
|
|
|
|
def _get_model(self, provider: str, model: str):
|
|
"""Get the appropriate model object for the provider."""
|
|
if provider == "openai":
|
|
return f"openai:{model}"
|
|
elif provider == "anthropic":
|
|
return f"anthropic:{model}"
|
|
elif provider == "ollama":
|
|
return OpenAIModel(
|
|
model_name=model,
|
|
provider=OllamaProvider(base_url=f"{Config.OLLAMA_BASE_URL}/v1"),
|
|
)
|
|
else:
|
|
raise ValueError(f"Unsupported provider: {provider}")
|
|
|
|
async def answer(self, question: str) -> str:
|
|
"""Answer a question using the RAG system."""
|
|
deps = Dependencies(client=self._client)
|
|
result = await self._agent.run(question, deps=deps)
|
|
return result.output
|