Add filter to simple qa agent

This commit is contained in:
Yiorgis Gozadinos 2025-12-11 15:28:41 +02:00
parent ecba8cfd38
commit d7c755f454
No known key found for this signature in database
6 changed files with 36 additions and 10 deletions

View file

@ -1,6 +1,19 @@
# Changelog
## [Unreleased]
### Added
- **Search Filter for Graphs**: Research and Deep QA graphs now support `search_filter` parameter to restrict searches to specific documents
- Set `state.search_filter` to a SQL WHERE clause (e.g., `"id IN ('doc1', 'doc2')"`) before running the graph
- Enables document-scoped research workflows
- CLI: `haiku-rag research "question" --filter "uri LIKE '%paper%'"`
- CLI: `haiku-rag ask "question" --filter "title = 'My Doc'"`
- Python: `client.ask(question, filter="...")` and `agent.answer(question, filter="...")`
- **AG-UI Research Example**: Added bidirectional state demonstration with document filter
- New `/api/documents` endpoint to list available documents
- Frontend document selector component with search and multi-select
- Demonstrates client-to-server state flow via AG-UI protocol
## [0.20.0] - 2025-12-10
### Added

View file

@ -149,9 +149,9 @@ Show verbose output with deep QA:
haiku-rag ask "What are the main features and architecture of haiku.rag?" --deep --verbose
```
Filter to specific documents with deep QA:
Filter to specific documents:
```bash
haiku-rag ask "What are the main findings?" --deep --filter "uri LIKE '%paper%'"
haiku-rag ask "What are the main findings?" --filter "uri LIKE '%paper%'"
```
The QA agent searches your documents for relevant information and provides a comprehensive answer. When available, citations use the document title; otherwise they fall back to the URI.
@ -161,7 +161,7 @@ Flags:
- `--cite`: Include citations showing which documents were used
- `--deep`: Decompose the question into sub-questions answered in parallel before synthesizing a final answer
- `--verbose`: Show planning, searching, evaluation, and synthesis steps (only with `--deep`)
- `--filter`: Restrict searches to documents matching the filter (only with `--deep`)
- `--filter`: Restrict searches to documents matching the filter (see [Filtering Search Results](python.md#filtering-search-results))
## Research

View file

@ -363,7 +363,7 @@ class HaikuRAGApp:
if cite:
citations = result.citations
else:
answer, citations = await self.client.ask(question)
answer, citations = await self.client.ask(question, filter=filter)
self.console.print(f"[bold blue]Question:[/bold blue] {question}")
self.console.print()

View file

@ -309,7 +309,7 @@ def ask(
None,
"--filter",
"-f",
help="SQL WHERE clause to filter documents (only with --deep)",
help="SQL WHERE clause to filter documents (e.g., \"uri LIKE '%arxiv%'\")",
),
):
app = create_app(db)

View file

@ -1229,13 +1229,17 @@ class HaikuRAG:
return final_results + passthrough
async def ask(
self, question: str, system_prompt: str | None = None
self,
question: str,
system_prompt: str | None = None,
filter: str | None = None,
) -> "tuple[str, list[Citation]]":
"""Ask a question using the configured QA agent.
Args:
question: The question to ask.
system_prompt: Optional custom system prompt for the QA agent.
filter: SQL WHERE clause to filter documents.
Returns:
Tuple of (answer text, list of resolved citations).
@ -1243,7 +1247,7 @@ class HaikuRAG:
from haiku.rag.qa import get_qa_agent
qa_agent = get_qa_agent(self, config=self._config, system_prompt=system_prompt)
return await qa_agent.answer(question)
return await qa_agent.answer(question, filter=filter)
async def visualize_chunk(self, chunk: Chunk) -> list:
"""Render page images with bounding box highlights for a chunk.

View file

@ -15,6 +15,7 @@ class Dependencies(BaseModel):
model_config = {"arbitrary_types_allowed": True}
client: HaikuRAG
search_results: list[SearchResult] = []
search_filter: str | None = None
class QuestionAnswerAgent:
@ -46,7 +47,9 @@ class QuestionAnswerAgent:
Returns results with chunk IDs and relevance scores.
Reference results by their chunk_id in cited_chunks.
"""
results = await ctx.deps.client.search(query, limit=limit)
results = await ctx.deps.client.search(
query, limit=limit, filter=ctx.deps.search_filter
)
results = await ctx.deps.client.expand_context(results)
# Store results for citation resolution
ctx.deps.search_results = results
@ -54,13 +57,19 @@ class QuestionAnswerAgent:
parts = [r.format_for_agent() for r in results]
return "\n\n".join(parts) if parts else "No results found."
async def answer(self, question: str) -> tuple[str, list[Citation]]:
async def answer(
self, question: str, filter: str | None = None
) -> tuple[str, list[Citation]]:
"""Answer a question using the RAG system.
Args:
question: The question to answer
filter: SQL WHERE clause to filter documents
Returns:
Tuple of (answer text, list of resolved citations)
"""
deps = Dependencies(client=self._client)
deps = Dependencies(client=self._client, search_filter=filter)
result = await self._agent.run(question, deps=deps)
citations = resolve_citations(result.output.cited_chunks, deps.search_results)
return result.output.answer, citations