haiku.rag 0.9.3__py3-none-any.whl → 0.10.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of haiku.rag might be problematic. Click here for more details.
- haiku/rag/app.py +50 -13
- haiku/rag/cli.py +16 -4
- haiku/rag/reranking/mxbai.py +1 -1
- haiku/rag/research/__init__.py +10 -27
- haiku/rag/research/common.py +53 -0
- haiku/rag/research/dependencies.py +3 -25
- haiku/rag/research/graph.py +29 -0
- haiku/rag/research/models.py +70 -0
- haiku/rag/research/nodes/evaluate.py +80 -0
- haiku/rag/research/nodes/plan.py +63 -0
- haiku/rag/research/nodes/search.py +91 -0
- haiku/rag/research/nodes/synthesize.py +51 -0
- haiku/rag/research/prompts.py +97 -113
- haiku/rag/research/state.py +25 -0
- {haiku_rag-0.9.3.dist-info → haiku_rag-0.10.0.dist-info}/METADATA +37 -1
- {haiku_rag-0.9.3.dist-info → haiku_rag-0.10.0.dist-info}/RECORD +19 -17
- haiku/rag/research/base.py +0 -130
- haiku/rag/research/evaluation_agent.py +0 -85
- haiku/rag/research/orchestrator.py +0 -170
- haiku/rag/research/presearch_agent.py +0 -39
- haiku/rag/research/search_agent.py +0 -69
- haiku/rag/research/synthesis_agent.py +0 -60
- {haiku_rag-0.9.3.dist-info → haiku_rag-0.10.0.dist-info}/WHEEL +0 -0
- {haiku_rag-0.9.3.dist-info → haiku_rag-0.10.0.dist-info}/entry_points.txt +0 -0
- {haiku_rag-0.9.3.dist-info → haiku_rag-0.10.0.dist-info}/licenses/LICENSE +0 -0
haiku/rag/research/prompts.py
CHANGED
|
@@ -1,129 +1,113 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
- Each
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
SEARCH_AGENT_PROMPT = """You are a search and question
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
1. Search the knowledge base for relevant
|
|
24
|
-
2. Analyze
|
|
25
|
-
3. Provide an
|
|
26
|
-
|
|
27
|
-
Output format:
|
|
28
|
-
- You must return a SearchAnswer model with fields:
|
|
29
|
-
- query: the question being answered (echo the user query)
|
|
30
|
-
- answer: your final answer based only on the provided context
|
|
31
|
-
- context: list[str] of only the minimal set of verbatim snippet texts you
|
|
32
|
-
used to justify the answer (do not include unrelated text; do not invent)
|
|
33
|
-
- sources: list[str] of document_uri values corresponding to the snippets you
|
|
34
|
-
actually used in the answer (one URI per context snippet, order aligned)
|
|
1
|
+
PLAN_PROMPT = """You are the research orchestrator for a focused, iterative
|
|
2
|
+
workflow.
|
|
3
|
+
|
|
4
|
+
Responsibilities:
|
|
5
|
+
1. Understand and decompose the main question
|
|
6
|
+
2. Propose a minimal, high‑leverage plan
|
|
7
|
+
3. Coordinate specialized agents to gather evidence
|
|
8
|
+
4. Iterate based on gaps and new findings
|
|
9
|
+
|
|
10
|
+
Plan requirements:
|
|
11
|
+
- Produce at most 3 sub_questions that together cover the main question.
|
|
12
|
+
- Each sub_question must be a standalone, self‑contained query that can run
|
|
13
|
+
without extra context. Include concrete entities, scope, timeframe, and any
|
|
14
|
+
qualifiers. Avoid ambiguous pronouns (it/they/this/that).
|
|
15
|
+
- Prioritize the highest‑value aspects first; avoid redundancy and overlap.
|
|
16
|
+
- Prefer questions that are likely answerable from the current knowledge base;
|
|
17
|
+
if coverage is uncertain, make scopes narrower and specific.
|
|
18
|
+
- Order sub_questions by execution priority (most valuable first)."""
|
|
19
|
+
|
|
20
|
+
SEARCH_AGENT_PROMPT = """You are a search and question‑answering specialist.
|
|
21
|
+
|
|
22
|
+
Tasks:
|
|
23
|
+
1. Search the knowledge base for relevant evidence.
|
|
24
|
+
2. Analyze retrieved snippets.
|
|
25
|
+
3. Provide an answer strictly grounded in that evidence.
|
|
35
26
|
|
|
36
27
|
Tool usage:
|
|
37
|
-
- Always call
|
|
38
|
-
- The tool returns
|
|
39
|
-
|
|
40
|
-
`document_uri` it came from.
|
|
28
|
+
- Always call search_and_answer before drafting any answer.
|
|
29
|
+
- The tool returns snippets with verbatim `text`, a relevance `score`, and the
|
|
30
|
+
originating `document_uri`.
|
|
41
31
|
- You may call the tool multiple times to refine or broaden context, but do not
|
|
42
|
-
exceed 3 total
|
|
32
|
+
exceed 3 total calls. Favor precision over volume.
|
|
43
33
|
- Use scores to prioritize evidence, but include only the minimal subset of
|
|
44
|
-
snippet texts (verbatim) in SearchAnswer.context.
|
|
45
|
-
- Set SearchAnswer.sources to the
|
|
46
|
-
used (one URI per snippet
|
|
47
|
-
- If no relevant information is found, say so and return an empty
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
34
|
+
snippet texts (verbatim) in SearchAnswer.context (typically 1‑4).
|
|
35
|
+
- Set SearchAnswer.sources to the corresponding document_uris for the snippets
|
|
36
|
+
you used (one URI per snippet; same order as context). Context must be text‑only.
|
|
37
|
+
- If no relevant information is found, clearly say so and return an empty
|
|
38
|
+
context list and sources list.
|
|
39
|
+
|
|
40
|
+
Answering rules:
|
|
41
|
+
- Be direct and specific; avoid meta commentary about the process.
|
|
42
|
+
- Do not include any claims not supported by the provided snippets.
|
|
43
|
+
- Prefer concise phrasing; avoid copying long passages.
|
|
44
|
+
- When evidence is partial, state the limits explicitly in the answer."""
|
|
45
|
+
|
|
46
|
+
EVALUATION_AGENT_PROMPT = """You are an analysis and evaluation specialist for
|
|
47
|
+
the research workflow.
|
|
48
|
+
|
|
49
|
+
Inputs available:
|
|
50
|
+
- Original research question
|
|
51
|
+
- Question–answer pairs produced by search
|
|
52
|
+
- Raw search results and source metadata
|
|
59
53
|
- Previously identified insights
|
|
60
54
|
|
|
61
|
-
Your dual role is to:
|
|
62
|
-
|
|
63
55
|
ANALYSIS:
|
|
64
|
-
1. Extract
|
|
65
|
-
2. Identify patterns and
|
|
66
|
-
3.
|
|
67
|
-
4. Focus on the most important discoveries
|
|
56
|
+
1. Extract the most important, non‑obvious insights from the collected evidence.
|
|
57
|
+
2. Identify patterns, agreements, and disagreements across sources.
|
|
58
|
+
3. Note material uncertainties and assumptions.
|
|
68
59
|
|
|
69
60
|
EVALUATION:
|
|
70
|
-
1.
|
|
71
|
-
2.
|
|
72
|
-
- Coverage of the main question
|
|
73
|
-
- Quality and
|
|
74
|
-
- Depth of
|
|
75
|
-
3.
|
|
76
|
-
4.
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
-
|
|
86
|
-
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
-
|
|
109
|
-
-
|
|
110
|
-
-
|
|
111
|
-
|
|
112
|
-
Focus on creating a report that provides clear value to the reader by:
|
|
113
|
-
- Answering the original research question thoroughly
|
|
114
|
-
- Highlighting the most important findings
|
|
115
|
-
- Explaining the implications of the research
|
|
116
|
-
- Suggesting concrete next steps"""
|
|
61
|
+
1. Decide if we have sufficient information to answer the original question.
|
|
62
|
+
2. Provide a confidence_score in [0,1] considering:
|
|
63
|
+
- Coverage of the main question’s aspects
|
|
64
|
+
- Quality, consistency, and diversity of sources
|
|
65
|
+
- Depth and specificity of evidence
|
|
66
|
+
3. List concrete gaps that still need investigation.
|
|
67
|
+
4. Propose up to 3 new sub_questions that would close the highest‑value gaps.
|
|
68
|
+
|
|
69
|
+
Strictness:
|
|
70
|
+
- Only mark research as sufficient when all major aspects are addressed with
|
|
71
|
+
consistent, reliable evidence and no critical gaps remain.
|
|
72
|
+
|
|
73
|
+
New sub_questions must:
|
|
74
|
+
- Be genuinely new (not answered or duplicative; check qa_responses).
|
|
75
|
+
- Be standalone and specific (entities, scope, timeframe/region if relevant).
|
|
76
|
+
- Be actionable and scoped to the knowledge base (narrow if necessary).
|
|
77
|
+
- Be ordered by expected impact (most valuable first)."""
|
|
78
|
+
|
|
79
|
+
SYNTHESIS_AGENT_PROMPT = """You are a synthesis specialist producing the final
|
|
80
|
+
research report.
|
|
81
|
+
|
|
82
|
+
Goals:
|
|
83
|
+
1. Synthesize all gathered information into a coherent narrative.
|
|
84
|
+
2. Present findings clearly and concisely.
|
|
85
|
+
3. Draw evidence‑based conclusions and recommendations.
|
|
86
|
+
4. State limitations and uncertainties transparently.
|
|
87
|
+
|
|
88
|
+
Report guidelines (map to output fields):
|
|
89
|
+
- title: concise (5–12 words), informative.
|
|
90
|
+
- executive_summary: 3–5 sentences summarizing the overall answer.
|
|
91
|
+
- main_findings: 4–8 one‑sentence bullets; each reflects evidence from the
|
|
92
|
+
research (do not include inline citations or snippet text).
|
|
93
|
+
- conclusions: 2–4 bullets that follow logically from findings.
|
|
94
|
+
- recommendations: 2–5 actionable bullets tied to findings.
|
|
95
|
+
- limitations: 1–3 bullets describing key constraints or uncertainties.
|
|
96
|
+
- sources_summary: 2–4 sentences summarizing sources used and their reliability.
|
|
97
|
+
|
|
98
|
+
Style:
|
|
99
|
+
- Base all content solely on the collected evidence.
|
|
100
|
+
- Be professional, objective, and specific.
|
|
101
|
+
- Avoid meta commentary and refrain from speculation beyond the evidence."""
|
|
117
102
|
|
|
118
103
|
PRESEARCH_AGENT_PROMPT = """You are a rapid research surveyor.
|
|
119
104
|
|
|
120
105
|
Task:
|
|
121
|
-
- Call
|
|
122
|
-
|
|
123
|
-
- Read that context and produce a
|
|
124
|
-
|
|
106
|
+
- Call gather_context once on the main question to obtain relevant text from
|
|
107
|
+
the knowledge base (KB).
|
|
108
|
+
- Read that context and produce a short natural‑language summary of what the
|
|
109
|
+
KB appears to contain relative to the question.
|
|
125
110
|
|
|
126
111
|
Rules:
|
|
127
112
|
- Base the summary strictly on the provided text; do not invent.
|
|
128
|
-
- Output only the summary as plain text (one short paragraph).
|
|
129
|
-
"""
|
|
113
|
+
- Output only the summary as plain text (one short paragraph)."""
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
|
|
3
|
+
from rich.console import Console
|
|
4
|
+
|
|
5
|
+
from haiku.rag.client import HaikuRAG
|
|
6
|
+
from haiku.rag.research.dependencies import ResearchContext
|
|
7
|
+
from haiku.rag.research.models import EvaluationResult
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class ResearchDeps:
|
|
12
|
+
client: HaikuRAG
|
|
13
|
+
console: Console | None = None
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class ResearchState:
|
|
18
|
+
question: str
|
|
19
|
+
context: ResearchContext
|
|
20
|
+
sub_questions: list[str] = field(default_factory=list)
|
|
21
|
+
iterations: int = 0
|
|
22
|
+
max_iterations: int = 3
|
|
23
|
+
max_concurrency: int = 1
|
|
24
|
+
confidence_threshold: float = 0.8
|
|
25
|
+
last_eval: EvaluationResult | None = None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: haiku.rag
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.0
|
|
4
4
|
Summary: Agentic Retrieval Augmented Generation (RAG) with LanceDB
|
|
5
5
|
Author-email: Yiorgis Gozadinos <ggozadinos@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -23,6 +23,7 @@ Requires-Dist: fastmcp>=2.12.3
|
|
|
23
23
|
Requires-Dist: httpx>=0.28.1
|
|
24
24
|
Requires-Dist: lancedb>=0.25.0
|
|
25
25
|
Requires-Dist: pydantic-ai>=1.0.8
|
|
26
|
+
Requires-Dist: pydantic-graph>=1.0.8
|
|
26
27
|
Requires-Dist: pydantic>=2.11.9
|
|
27
28
|
Requires-Dist: python-dotenv>=1.1.1
|
|
28
29
|
Requires-Dist: rich>=14.1.0
|
|
@@ -48,6 +49,7 @@ Retrieval-Augmented Generation (RAG) library built on LanceDB.
|
|
|
48
49
|
- **Local LanceDB**: No external servers required, supports also LanceDB cloud storage, S3, Google Cloud & Azure
|
|
49
50
|
- **Multiple embedding providers**: Ollama, VoyageAI, OpenAI, vLLM
|
|
50
51
|
- **Multiple QA providers**: Any provider/model supported by Pydantic AI
|
|
52
|
+
- **Research graph (multi‑agent)**: Plan → Search → Evaluate → Synthesize with agentic AI
|
|
51
53
|
- **Native hybrid search**: Vector + full-text search with native LanceDB RRF reranking
|
|
52
54
|
- **Reranking**: Default search result reranking with MixedBread AI, Cohere, or vLLM
|
|
53
55
|
- **Question answering**: Built-in QA agents on your documents
|
|
@@ -75,6 +77,14 @@ haiku-rag ask "Who is the author of haiku.rag?"
|
|
|
75
77
|
# Ask questions with citations
|
|
76
78
|
haiku-rag ask "Who is the author of haiku.rag?" --cite
|
|
77
79
|
|
|
80
|
+
# Multi‑agent research (iterative plan/search/evaluate)
|
|
81
|
+
haiku-rag research \
|
|
82
|
+
"What are the main drivers and trends of global temperature anomalies since 1990?" \
|
|
83
|
+
--max-iterations 2 \
|
|
84
|
+
--confidence-threshold 0.8 \
|
|
85
|
+
--max-concurrency 3 \
|
|
86
|
+
--verbose
|
|
87
|
+
|
|
78
88
|
# Rebuild database (re-chunk and re-embed all documents)
|
|
79
89
|
haiku-rag rebuild
|
|
80
90
|
|
|
@@ -90,6 +100,13 @@ haiku-rag serve
|
|
|
90
100
|
|
|
91
101
|
```python
|
|
92
102
|
from haiku.rag.client import HaikuRAG
|
|
103
|
+
from haiku.rag.research import (
|
|
104
|
+
ResearchContext,
|
|
105
|
+
ResearchDeps,
|
|
106
|
+
ResearchState,
|
|
107
|
+
build_research_graph,
|
|
108
|
+
PlanNode,
|
|
109
|
+
)
|
|
93
110
|
|
|
94
111
|
async with HaikuRAG("database.lancedb") as client:
|
|
95
112
|
# Add document
|
|
@@ -107,6 +124,25 @@ async with HaikuRAG("database.lancedb") as client:
|
|
|
107
124
|
# Ask questions with citations
|
|
108
125
|
answer = await client.ask("Who is the author of haiku.rag?", cite=True)
|
|
109
126
|
print(answer)
|
|
127
|
+
|
|
128
|
+
# Multi‑agent research pipeline (Plan → Search → Evaluate → Synthesize)
|
|
129
|
+
graph = build_research_graph()
|
|
130
|
+
state = ResearchState(
|
|
131
|
+
question=(
|
|
132
|
+
"What are the main drivers and trends of global temperature "
|
|
133
|
+
"anomalies since 1990?"
|
|
134
|
+
),
|
|
135
|
+
context=ResearchContext(original_question="…"),
|
|
136
|
+
max_iterations=2,
|
|
137
|
+
confidence_threshold=0.8,
|
|
138
|
+
max_concurrency=3,
|
|
139
|
+
)
|
|
140
|
+
deps = ResearchDeps(client=client)
|
|
141
|
+
start = PlanNode(provider=None, model=None)
|
|
142
|
+
result = await graph.run(start, state=state, deps=deps)
|
|
143
|
+
report = result.output
|
|
144
|
+
print(report.title)
|
|
145
|
+
print(report.executive_summary)
|
|
110
146
|
```
|
|
111
147
|
|
|
112
148
|
## MCP Server
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
haiku/rag/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
haiku/rag/app.py,sha256=
|
|
2
|
+
haiku/rag/app.py,sha256=m5agkPrJhbzEbdC01CU_GR2Gj4voFuAGmxR7DS2K9is,12934
|
|
3
3
|
haiku/rag/chunker.py,sha256=PVe6ysv8UlacUd4Zb3_8RFWIaWDXnzBAy2VDJ4TaUsE,1555
|
|
4
|
-
haiku/rag/cli.py,sha256=
|
|
4
|
+
haiku/rag/cli.py,sha256=oXEQoRTlzrrJ9hC27_Dht9ElBb9q_wTEESnXdNy3eW8,10257
|
|
5
5
|
haiku/rag/client.py,sha256=QgJQu7g7JjAzWN6R10NeDqpFf89Dml_LiWce4QRHLHc,21177
|
|
6
6
|
haiku/rag/config.py,sha256=SPEIv2IElZmZh4Wsp8gk7ViRW5ZzD-UGmIqRAXscDdI,2134
|
|
7
7
|
haiku/rag/logging.py,sha256=dm65AwADpcQsH5OAPtRA-4hsw0w5DK-sGOvzYkj6jzw,1720
|
|
@@ -22,17 +22,19 @@ haiku/rag/qa/prompts.py,sha256=LhRfDtO8Pb06lpr4PpwEaKUYItZ5OiIkeqcCogcssHY,3347
|
|
|
22
22
|
haiku/rag/reranking/__init__.py,sha256=IRXHs4qPu6VbGJQpzSwhgtVWWumURH_vEoVFE-extlo,894
|
|
23
23
|
haiku/rag/reranking/base.py,sha256=LM9yUSSJ414UgBZhFTgxGprlRqzfTe4I1vgjricz2JY,405
|
|
24
24
|
haiku/rag/reranking/cohere.py,sha256=1iTdiaa8vvb6oHVB2qpWzUOVkyfUcimVSZp6Qr4aq4c,1049
|
|
25
|
-
haiku/rag/reranking/mxbai.py,sha256=
|
|
25
|
+
haiku/rag/reranking/mxbai.py,sha256=uveGFIdmNmepd2EQsvYr64wv0ra2_wB845hdSZXy5Cw,908
|
|
26
26
|
haiku/rag/reranking/vllm.py,sha256=xVGH9ss-ISWdJ5SKUUHUbTqBo7PIEmA_SQv0ScdJ6XA,1479
|
|
27
|
-
haiku/rag/research/__init__.py,sha256=
|
|
28
|
-
haiku/rag/research/
|
|
29
|
-
haiku/rag/research/dependencies.py,sha256=
|
|
30
|
-
haiku/rag/research/
|
|
31
|
-
haiku/rag/research/
|
|
32
|
-
haiku/rag/research/
|
|
33
|
-
haiku/rag/research/
|
|
34
|
-
haiku/rag/research/
|
|
35
|
-
haiku/rag/research/
|
|
27
|
+
haiku/rag/research/__init__.py,sha256=t4JAmIXcKaWqvpFGX5yaehsNrfblskEMn-4mDmdKn9c,502
|
|
28
|
+
haiku/rag/research/common.py,sha256=EUnsA6VZ3-WMweXESuUYezH1ALit8N38064bsZFqtBE,1688
|
|
29
|
+
haiku/rag/research/dependencies.py,sha256=ZiSQdV6jHti4DuUp4WCaJL73TqYDr5vC8ppB34M2cNg,1639
|
|
30
|
+
haiku/rag/research/graph.py,sha256=m3vDP1nPXWzfS7VeTQzmTOk-lFpoaTvKHvRIF2mbxvs,798
|
|
31
|
+
haiku/rag/research/models.py,sha256=klE2qGF5fom5gJRQzQUbnoGYaXusNKeJ9veeXoYDD5Q,2308
|
|
32
|
+
haiku/rag/research/prompts.py,sha256=v_DZNaKk88CDEF8qt9c-puO6QF-NyBQKnl_mO1pMauY,5013
|
|
33
|
+
haiku/rag/research/state.py,sha256=vFwO8c2JmwwfkELE5Mwjt9Oat-bHn5tayf31MIG2SRs,623
|
|
34
|
+
haiku/rag/research/nodes/evaluate.py,sha256=Cp2J-jXYZothiQV3zRZFaCsBLaUU0Tm_-ri-hlgQQII,2897
|
|
35
|
+
haiku/rag/research/nodes/plan.py,sha256=9AkTls01Q3zTLKGgIgSCX9X4VYC8IWjEWii8A_f77YQ,2439
|
|
36
|
+
haiku/rag/research/nodes/search.py,sha256=lHgDCCL7hQdpQeMK-HVzsF_hH_pIv44xxSIiv1JuvYo,3513
|
|
37
|
+
haiku/rag/research/nodes/synthesize.py,sha256=4acKduqWnE11ML7elUksKLozxzWJTkBLSJ2li_YMxgY,1736
|
|
36
38
|
haiku/rag/store/__init__.py,sha256=hq0W0DAC7ysqhWSP2M2uHX8cbG6kbr-sWHxhq6qQcY0,103
|
|
37
39
|
haiku/rag/store/engine.py,sha256=-3MZJYft2XTWaLuyKha8DKhWQeU5E5CBeskXXF5fXso,9555
|
|
38
40
|
haiku/rag/store/models/__init__.py,sha256=s0E72zneGlowvZrFWaNxHYjOAUjgWdLxzdYsnvNRVlY,88
|
|
@@ -44,8 +46,8 @@ haiku/rag/store/repositories/document.py,sha256=m11SamQoGYs5ODfmarJGU1yIcqtgmnba
|
|
|
44
46
|
haiku/rag/store/repositories/settings.py,sha256=7XMBMavU8zRgdBoQzQg0Obfa7UKjuVnBugidTC6sEW0,5548
|
|
45
47
|
haiku/rag/store/upgrades/__init__.py,sha256=gDOxiq3wdZPr3JoenjNYxx0cpgZJhbaFKNX2fzXRq1Q,1852
|
|
46
48
|
haiku/rag/store/upgrades/v0_9_3.py,sha256=NrjNilQSgDtFWRbL3ZUtzQzJ8tf9u0dDRJtnDFwwbdw,3322
|
|
47
|
-
haiku_rag-0.
|
|
48
|
-
haiku_rag-0.
|
|
49
|
-
haiku_rag-0.
|
|
50
|
-
haiku_rag-0.
|
|
51
|
-
haiku_rag-0.
|
|
49
|
+
haiku_rag-0.10.0.dist-info/METADATA,sha256=QLc8BBJ4WCNEvseyYpWNfkuUfmdxGywD6Jtn0OTsrc0,5879
|
|
50
|
+
haiku_rag-0.10.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
51
|
+
haiku_rag-0.10.0.dist-info/entry_points.txt,sha256=G1U3nAkNd5YDYd4v0tuYFbriz0i-JheCsFuT9kIoGCI,48
|
|
52
|
+
haiku_rag-0.10.0.dist-info/licenses/LICENSE,sha256=eXZrWjSk9PwYFNK9yUczl3oPl95Z4V9UXH7bPN46iPo,1065
|
|
53
|
+
haiku_rag-0.10.0.dist-info/RECORD,,
|
haiku/rag/research/base.py
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
from abc import ABC, abstractmethod
|
|
2
|
-
from typing import TYPE_CHECKING, Any
|
|
3
|
-
|
|
4
|
-
from pydantic import BaseModel, Field
|
|
5
|
-
from pydantic_ai import Agent
|
|
6
|
-
from pydantic_ai.models.openai import OpenAIChatModel
|
|
7
|
-
from pydantic_ai.output import ToolOutput
|
|
8
|
-
from pydantic_ai.providers.ollama import OllamaProvider
|
|
9
|
-
from pydantic_ai.providers.openai import OpenAIProvider
|
|
10
|
-
from pydantic_ai.run import AgentRunResult
|
|
11
|
-
|
|
12
|
-
from haiku.rag.config import Config
|
|
13
|
-
|
|
14
|
-
if TYPE_CHECKING:
|
|
15
|
-
from haiku.rag.research.dependencies import ResearchDependencies
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class BaseResearchAgent[T](ABC):
|
|
19
|
-
"""Base class for all research agents."""
|
|
20
|
-
|
|
21
|
-
def __init__(
|
|
22
|
-
self,
|
|
23
|
-
provider: str,
|
|
24
|
-
model: str,
|
|
25
|
-
output_type: type[T],
|
|
26
|
-
):
|
|
27
|
-
self.provider = provider
|
|
28
|
-
self.model = model
|
|
29
|
-
self.output_type = output_type
|
|
30
|
-
|
|
31
|
-
model_obj = self._get_model(provider, model)
|
|
32
|
-
|
|
33
|
-
# Import deps type lazily to avoid circular import during module load
|
|
34
|
-
from haiku.rag.research.dependencies import ResearchDependencies
|
|
35
|
-
|
|
36
|
-
# If the agent is expected to return plain text, pass `str` directly.
|
|
37
|
-
# Otherwise, wrap the model with ToolOutput for robust tool-handling retries.
|
|
38
|
-
agent_output_type: Any
|
|
39
|
-
if self.output_type is str: # plain text output
|
|
40
|
-
agent_output_type = str
|
|
41
|
-
else:
|
|
42
|
-
agent_output_type = ToolOutput(self.output_type, max_retries=3)
|
|
43
|
-
|
|
44
|
-
self._agent = Agent(
|
|
45
|
-
model=model_obj,
|
|
46
|
-
deps_type=ResearchDependencies,
|
|
47
|
-
output_type=agent_output_type,
|
|
48
|
-
instructions=self.get_system_prompt(),
|
|
49
|
-
retries=3,
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
# Register tools
|
|
53
|
-
self.register_tools()
|
|
54
|
-
|
|
55
|
-
def _get_model(self, provider: str, model: str):
|
|
56
|
-
"""Get the appropriate model object for the provider."""
|
|
57
|
-
if provider == "ollama":
|
|
58
|
-
return OpenAIChatModel(
|
|
59
|
-
model_name=model,
|
|
60
|
-
provider=OllamaProvider(base_url=f"{Config.OLLAMA_BASE_URL}/v1"),
|
|
61
|
-
)
|
|
62
|
-
elif provider == "vllm":
|
|
63
|
-
return OpenAIChatModel(
|
|
64
|
-
model_name=model,
|
|
65
|
-
provider=OpenAIProvider(
|
|
66
|
-
base_url=f"{Config.VLLM_RESEARCH_BASE_URL or Config.VLLM_QA_BASE_URL}/v1",
|
|
67
|
-
api_key="none",
|
|
68
|
-
),
|
|
69
|
-
)
|
|
70
|
-
else:
|
|
71
|
-
# For all other providers, use the provider:model format
|
|
72
|
-
return f"{provider}:{model}"
|
|
73
|
-
|
|
74
|
-
@abstractmethod
|
|
75
|
-
def get_system_prompt(self) -> str:
|
|
76
|
-
"""Return the system prompt for this agent."""
|
|
77
|
-
pass
|
|
78
|
-
|
|
79
|
-
def register_tools(self) -> None:
|
|
80
|
-
"""Register agent-specific tools."""
|
|
81
|
-
pass
|
|
82
|
-
|
|
83
|
-
async def run(
|
|
84
|
-
self, prompt: str, deps: "ResearchDependencies", **kwargs
|
|
85
|
-
) -> AgentRunResult[T]:
|
|
86
|
-
"""Execute the agent."""
|
|
87
|
-
return await self._agent.run(prompt, deps=deps, **kwargs)
|
|
88
|
-
|
|
89
|
-
@property
|
|
90
|
-
def agent(self) -> Agent[Any, T]:
|
|
91
|
-
"""Access the underlying Pydantic AI agent."""
|
|
92
|
-
return self._agent
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
class SearchResult(BaseModel):
|
|
96
|
-
"""Standard search result format."""
|
|
97
|
-
|
|
98
|
-
content: str
|
|
99
|
-
score: float
|
|
100
|
-
document_uri: str
|
|
101
|
-
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
class ResearchOutput(BaseModel):
|
|
105
|
-
"""Standard research output format."""
|
|
106
|
-
|
|
107
|
-
summary: str
|
|
108
|
-
detailed_findings: list[str]
|
|
109
|
-
sources: list[str]
|
|
110
|
-
confidence: float
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
class SearchAnswer(BaseModel):
|
|
114
|
-
"""Structured output for the SearchSpecialist agent."""
|
|
115
|
-
|
|
116
|
-
query: str = Field(description="The search query that was performed")
|
|
117
|
-
answer: str = Field(description="The answer generated based on the context")
|
|
118
|
-
context: list[str] = Field(
|
|
119
|
-
description=(
|
|
120
|
-
"Only the minimal set of relevant snippets (verbatim) that directly "
|
|
121
|
-
"support the answer"
|
|
122
|
-
)
|
|
123
|
-
)
|
|
124
|
-
sources: list[str] = Field(
|
|
125
|
-
description=(
|
|
126
|
-
"Document URIs corresponding to the snippets actually used in the"
|
|
127
|
-
" answer (one URI per snippet; omit if none)"
|
|
128
|
-
),
|
|
129
|
-
default_factory=list,
|
|
130
|
-
)
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
from pydantic import BaseModel, Field
|
|
2
|
-
from pydantic_ai.run import AgentRunResult
|
|
3
|
-
|
|
4
|
-
from haiku.rag.research.base import BaseResearchAgent
|
|
5
|
-
from haiku.rag.research.dependencies import (
|
|
6
|
-
ResearchDependencies,
|
|
7
|
-
_format_context_for_prompt,
|
|
8
|
-
)
|
|
9
|
-
from haiku.rag.research.prompts import EVALUATION_AGENT_PROMPT
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class EvaluationResult(BaseModel):
|
|
13
|
-
"""Result of analysis and evaluation."""
|
|
14
|
-
|
|
15
|
-
key_insights: list[str] = Field(
|
|
16
|
-
description="Main insights extracted from the research so far"
|
|
17
|
-
)
|
|
18
|
-
new_questions: list[str] = Field(
|
|
19
|
-
description="New sub-questions to add to the research (max 3)",
|
|
20
|
-
max_length=3,
|
|
21
|
-
default=[],
|
|
22
|
-
)
|
|
23
|
-
confidence_score: float = Field(
|
|
24
|
-
description="Confidence level in the completeness of research (0-1)",
|
|
25
|
-
ge=0.0,
|
|
26
|
-
le=1.0,
|
|
27
|
-
)
|
|
28
|
-
is_sufficient: bool = Field(
|
|
29
|
-
description="Whether the research is sufficient to answer the original question"
|
|
30
|
-
)
|
|
31
|
-
reasoning: str = Field(
|
|
32
|
-
description="Explanation of why the research is or isn't complete"
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
class AnalysisEvaluationAgent(BaseResearchAgent[EvaluationResult]):
|
|
37
|
-
"""Agent that analyzes findings and evaluates research completeness."""
|
|
38
|
-
|
|
39
|
-
def __init__(self, provider: str, model: str) -> None:
|
|
40
|
-
super().__init__(provider, model, output_type=EvaluationResult)
|
|
41
|
-
|
|
42
|
-
async def run(
|
|
43
|
-
self, prompt: str, deps: ResearchDependencies, **kwargs
|
|
44
|
-
) -> AgentRunResult[EvaluationResult]:
|
|
45
|
-
console = deps.console
|
|
46
|
-
if console:
|
|
47
|
-
console.print(
|
|
48
|
-
"\n[bold cyan]📊 Analyzing and evaluating research progress...[/bold cyan]"
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
# Format context for the evaluation agent
|
|
52
|
-
context_xml = _format_context_for_prompt(deps.context)
|
|
53
|
-
evaluation_prompt = f"""Analyze all gathered information and evaluate the completeness of research.
|
|
54
|
-
|
|
55
|
-
{context_xml}
|
|
56
|
-
|
|
57
|
-
Evaluate the research progress for the original question and identify any remaining gaps."""
|
|
58
|
-
|
|
59
|
-
result = await super().run(evaluation_prompt, deps, **kwargs)
|
|
60
|
-
output = result.output
|
|
61
|
-
|
|
62
|
-
# Store insights
|
|
63
|
-
for insight in output.key_insights:
|
|
64
|
-
deps.context.add_insight(insight)
|
|
65
|
-
|
|
66
|
-
# Add new questions to the sub-questions list
|
|
67
|
-
for new_q in output.new_questions:
|
|
68
|
-
if new_q not in deps.context.sub_questions:
|
|
69
|
-
deps.context.sub_questions.append(new_q)
|
|
70
|
-
|
|
71
|
-
if console:
|
|
72
|
-
if output.key_insights:
|
|
73
|
-
console.print(" [bold]Key insights:[/bold]")
|
|
74
|
-
for insight in output.key_insights:
|
|
75
|
-
console.print(f" • {insight}")
|
|
76
|
-
console.print(
|
|
77
|
-
f" Confidence: [yellow]{output.confidence_score:.1%}[/yellow]"
|
|
78
|
-
)
|
|
79
|
-
status = "[green]Yes[/green]" if output.is_sufficient else "[red]No[/red]"
|
|
80
|
-
console.print(f" Sufficient: {status}")
|
|
81
|
-
|
|
82
|
-
return result
|
|
83
|
-
|
|
84
|
-
def get_system_prompt(self) -> str:
|
|
85
|
-
return EVALUATION_AGENT_PROMPT
|