Add verbose flag to ask
This commit is contained in:
parent
2dfb1882dd
commit
49eac86259
6 changed files with 91 additions and 8 deletions
|
|
@ -43,6 +43,9 @@ haiku-rag ask "Who is the author of haiku.rag?" --cite
|
|||
# Deep QA (multi-agent question decomposition)
|
||||
haiku-rag ask "Who is the author of haiku.rag?" --deep --cite
|
||||
|
||||
# Deep QA with verbose output
|
||||
haiku-rag ask "Who is the author of haiku.rag?" --deep --verbose
|
||||
|
||||
# Multi‑agent research (iterative plan/search/evaluate)
|
||||
haiku-rag research \
|
||||
"What are the main drivers and trends of global temperature anomalies since 1990?" \
|
||||
|
|
|
|||
|
|
@ -97,7 +97,12 @@ Use deep QA for complex questions (multi-agent decomposition):
|
|||
haiku-rag ask "What are the main features and architecture of haiku.rag?" --deep --cite
|
||||
```
|
||||
|
||||
The QA agent will search your documents for relevant information and provide a comprehensive answer. With `--cite`, responses include citations showing which documents were used. With `--deep`, the question is decomposed into sub-questions that are answered in parallel before synthesizing a final answer.
|
||||
Show verbose output with deep QA:
|
||||
```bash
|
||||
haiku-rag ask "What are the main features and architecture of haiku.rag?" --deep --verbose
|
||||
```
|
||||
|
||||
The QA agent will search your documents for relevant information and provide a comprehensive answer. With `--cite`, responses include citations showing which documents were used. With `--deep`, the question is decomposed into sub-questions that are answered in parallel before synthesizing a final answer. With `--verbose` (only with `--deep`), you'll see the planning, searching, evaluation, and synthesis steps as they happen.
|
||||
When available, citations use the document title; otherwise they fall back to the URI.
|
||||
|
||||
## Research
|
||||
|
|
|
|||
|
|
@ -194,10 +194,18 @@ class HaikuRAGApp:
|
|||
for chunk, score in results:
|
||||
self._rich_print_search_result(chunk, score)
|
||||
|
||||
async def ask(self, question: str, cite: bool = False, deep: bool = False):
|
||||
async def ask(
|
||||
self,
|
||||
question: str,
|
||||
cite: bool = False,
|
||||
deep: bool = False,
|
||||
verbose: bool = False,
|
||||
):
|
||||
async with HaikuRAG(db_path=self.db_path) as self.client:
|
||||
try:
|
||||
if deep:
|
||||
from rich.console import Console
|
||||
|
||||
from haiku.rag.qa.deep.dependencies import DeepQAContext
|
||||
from haiku.rag.qa.deep.graph import build_deep_qa_graph
|
||||
from haiku.rag.qa.deep.nodes import DeepPlanNode
|
||||
|
|
@ -208,7 +216,9 @@ class HaikuRAGApp:
|
|||
original_question=question, use_citations=cite
|
||||
)
|
||||
state = DeepQAState(context=context)
|
||||
deps = DeepQADeps(client=self.client)
|
||||
deps = DeepQADeps(
|
||||
client=self.client, console=Console() if verbose else None
|
||||
)
|
||||
|
||||
start_node = DeepPlanNode(
|
||||
provider=Config.QA_PROVIDER,
|
||||
|
|
|
|||
|
|
@ -304,11 +304,16 @@ def ask(
|
|||
"--deep",
|
||||
help="Use deep multi-agent QA for complex questions",
|
||||
),
|
||||
verbose: bool = typer.Option(
|
||||
False,
|
||||
"--verbose",
|
||||
help="Show verbose progress output (only with --deep)",
|
||||
),
|
||||
):
|
||||
from haiku.rag.app import HaikuRAGApp
|
||||
|
||||
app = HaikuRAGApp(db_path=db)
|
||||
asyncio.run(app.ask(question=question, cite=cite, deep=deep))
|
||||
asyncio.run(app.ask(question=question, cite=cite, deep=deep, verbose=verbose))
|
||||
|
||||
|
||||
@cli.command("research", help="Run multi-agent research and output a concise report")
|
||||
|
|
|
|||
|
|
@ -248,6 +248,23 @@ async def test_ask_with_cite(app: HaikuRAGApp, monkeypatch):
|
|||
mock_client.ask.assert_called_once_with("test question", cite=True)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_ask_with_verbose(app: HaikuRAGApp, monkeypatch):
|
||||
"""Test asking a question with verbose (should be ignored for non-deep)."""
|
||||
mock_answer = "Test answer"
|
||||
mock_client = AsyncMock()
|
||||
mock_client.ask.return_value = mock_answer
|
||||
mock_client.__aenter__.return_value = mock_client
|
||||
|
||||
mock_print = MagicMock()
|
||||
monkeypatch.setattr(app.console, "print", mock_print)
|
||||
|
||||
with patch("haiku.rag.app.HaikuRAG", return_value=mock_client):
|
||||
await app.ask("test question", verbose=True)
|
||||
|
||||
mock_client.ask.assert_called_once_with("test question", cite=False)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_ask_with_deep(app: HaikuRAGApp, monkeypatch):
|
||||
"""Test asking a question with deep QA."""
|
||||
|
|
@ -308,3 +325,32 @@ async def test_ask_with_deep_and_cite(app: HaikuRAGApp, monkeypatch):
|
|||
call_kwargs = mock_graph.run.call_args[1]
|
||||
assert call_kwargs["state"].context.original_question == "test question"
|
||||
assert call_kwargs["state"].context.use_citations is True
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_ask_with_deep_and_verbose(app: HaikuRAGApp, monkeypatch):
|
||||
"""Test asking a question with deep QA and verbose output."""
|
||||
from haiku.rag.qa.deep.models import DeepAnswer
|
||||
|
||||
mock_output = DeepAnswer(answer="Deep QA answer", sources=["test.md"])
|
||||
mock_result = MagicMock()
|
||||
mock_result.output = mock_output
|
||||
|
||||
mock_graph = AsyncMock()
|
||||
mock_graph.run.return_value = mock_result
|
||||
|
||||
mock_client = AsyncMock()
|
||||
mock_client.__aenter__.return_value = mock_client
|
||||
|
||||
mock_print = MagicMock()
|
||||
monkeypatch.setattr(app.console, "print", mock_print)
|
||||
|
||||
with patch("haiku.rag.app.HaikuRAG", return_value=mock_client):
|
||||
with patch(
|
||||
"haiku.rag.qa.deep.graph.build_deep_qa_graph", return_value=mock_graph
|
||||
):
|
||||
await app.ask("test question", deep=True, verbose=True)
|
||||
|
||||
mock_graph.run.assert_called_once()
|
||||
call_kwargs = mock_graph.run.call_args[1]
|
||||
assert call_kwargs["deps"].console is not None
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ def test_ask():
|
|||
|
||||
assert result.exit_code == 0
|
||||
mock_app_instance.ask.assert_called_once_with(
|
||||
question="What is Python?", cite=False, deep=False
|
||||
question="What is Python?", cite=False, deep=False, verbose=False
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -221,7 +221,7 @@ def test_ask_with_cite():
|
|||
|
||||
assert result.exit_code == 0
|
||||
mock_app_instance.ask.assert_called_once_with(
|
||||
question="What is Python?", cite=True, deep=False
|
||||
question="What is Python?", cite=True, deep=False, verbose=False
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -235,7 +235,7 @@ def test_ask_with_deep():
|
|||
|
||||
assert result.exit_code == 0
|
||||
mock_app_instance.ask.assert_called_once_with(
|
||||
question="What is Python?", cite=False, deep=True
|
||||
question="What is Python?", cite=False, deep=True, verbose=False
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -249,7 +249,21 @@ def test_ask_with_deep_and_cite():
|
|||
|
||||
assert result.exit_code == 0
|
||||
mock_app_instance.ask.assert_called_once_with(
|
||||
question="What is Python?", cite=True, deep=True
|
||||
question="What is Python?", cite=True, deep=True, verbose=False
|
||||
)
|
||||
|
||||
|
||||
def test_ask_with_deep_and_verbose():
|
||||
with patch("haiku.rag.app.HaikuRAGApp") as mock_app:
|
||||
mock_app_instance = MagicMock()
|
||||
mock_app_instance.ask = AsyncMock()
|
||||
mock_app.return_value = mock_app_instance
|
||||
|
||||
result = runner.invoke(cli, ["ask", "What is Python?", "--deep", "--verbose"])
|
||||
|
||||
assert result.exit_code == 0
|
||||
mock_app_instance.ask.assert_called_once_with(
|
||||
question="What is Python?", cite=False, deep=True, verbose=True
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue