This commit is contained in:
Yiorgis Gozadinos 2026-01-30 22:43:56 +02:00
parent 57d5b1bde5
commit 42f2d0fd0e
No known key found for this signature in database
3 changed files with 24 additions and 26 deletions

View file

@ -1,6 +1,14 @@
# Changelog
## [Unreleased]
### Changed
- **Iterative Research Planning**: Research graph now uses an iterative feedback loop instead of batch question processing
- Planner proposes ONE question at a time, sees the answer, then decides whether to continue
- Removes `gather_context` tool — planner proposes questions directly
- Simpler flow: `plan_next``search_one` → loop back until complete → `synthesize`
- Consolidated `build_conversational_graph()` into `build_research_graph(output_mode="conversational")`
## [0.27.2] - 2026-01-29
### Added

View file

@ -163,44 +163,39 @@ Frontend clients should extract state from under this key. See the [Web Applicat
## Research Graph
The research workflow is implemented as a typed pydantic-graph. It plans, searches (in parallel batches), evaluates, and synthesizes into a final report.
The research workflow is implemented as a typed pydantic-graph. It uses an iterative feedback loop where the planner proposes one question at a time, sees the answer, then decides whether to continue or synthesize.
```mermaid
---
title: Research graph
---
stateDiagram-v2
[*] --> plan
plan --> get_batch
get_batch --> search_one: Has questions (map)
get_batch --> synthesize: No questions
search_one --> collect_answers
collect_answers --> decide
decide --> get_batch: Continue research
decide --> synthesize: Done researching
[*] --> plan_next
plan_next --> search_one: Has next question
plan_next --> synthesize: Complete or max iterations
search_one --> plan_next
synthesize --> [*]
```
**Key nodes:**
- **plan**: Builds up to 3 standalone sub-questions (uses an internal presearch tool)
- **get_batch**: Retrieves remaining sub-questions for the current iteration
- **search_one**: Answers a single sub-question using the KB (mapped in parallel)
- **collect_answers**: Aggregates search results from parallel executions
- **decide**: Evaluates confidence and determines whether to continue or synthesize
- **plan_next**: Evaluates gathered evidence and either proposes the next question to investigate or marks research as complete
- **search_one**: Answers a single question using the knowledge base
- **synthesize**: Generates a final structured research report
**Primary models:**
- `SearchAnswer` — one per sub-question (query, answer, confidence, citations)
- `EvaluationResult` — confidence score, new questions, sufficiency assessment
- `IterativePlanResult` — planning decision (is_complete, next_question, reasoning)
- `SearchAnswer` — answer to a single question (query, answer, confidence, citations)
- `ResearchReport` — final report (title, executive summary, findings, conclusions, …)
- `ConversationalAnswer` — alternative output for chat integration (answer, citations, confidence)
**Parallel execution:**
**Iterative flow:**
- The `search_one` node is mapped over all questions in a batch
- Parallelism is controlled via `max_concurrency`
- Decision nodes process results after each batch completes
- Each iteration: planner evaluates context → proposes one question → search answers it → loop back
- Planner can decompose complex questions (e.g., "benefits and drawbacks" → start with "benefits")
- Session context is used to resolve ambiguous references and inform planning
- Loop terminates when planner marks `is_complete=True` or `max_iterations` is reached
### CLI Usage

View file

@ -308,12 +308,7 @@ async def run_qa_benchmark(
async def answer_question(question: str) -> str:
context = ResearchContext(original_question=question)
state = ResearchState.from_config(
context=context,
config=config,
max_iterations=2,
confidence_threshold=0.0,
)
state = ResearchState.from_config(context=context, config=config)
deps = ResearchDeps(client=rag)
report = await graph.run(state=state, deps=deps)
return report.executive_summary if report else ""