Add filter to simple qa agent
This commit is contained in:
parent
ecba8cfd38
commit
d7c755f454
6 changed files with 36 additions and 10 deletions
13
CHANGELOG.md
13
CHANGELOG.md
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue