prashflow 1.0.0__tar.gz
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.
- prashflow-1.0.0/PKG-INFO +665 -0
- prashflow-1.0.0/README.md +596 -0
- prashflow-1.0.0/pyproject.toml +69 -0
- prashflow-1.0.0/setup.cfg +4 -0
- prashflow-1.0.0/src/prashflow/__init__.py +25 -0
- prashflow-1.0.0/src/prashflow/__version__.py +1 -0
- prashflow-1.0.0/src/prashflow/agent.py +112 -0
- prashflow-1.0.0/src/prashflow/agentchat.py +5 -0
- prashflow-1.0.0/src/prashflow/chat.py +38 -0
- prashflow-1.0.0/src/prashflow/cli.py +43 -0
- prashflow-1.0.0/src/prashflow/config.py +26 -0
- prashflow-1.0.0/src/prashflow/display.py +14 -0
- prashflow-1.0.0/src/prashflow/errors.py +15 -0
- prashflow-1.0.0/src/prashflow/inmemory.py +87 -0
- prashflow-1.0.0/src/prashflow/llm.py +206 -0
- prashflow-1.0.0/src/prashflow/loaders.py +40 -0
- prashflow-1.0.0/src/prashflow/mcp.py +55 -0
- prashflow-1.0.0/src/prashflow/memory.py +11 -0
- prashflow-1.0.0/src/prashflow/multiagent.py +140 -0
- prashflow-1.0.0/src/prashflow/rag.py +227 -0
- prashflow-1.0.0/src/prashflow/rerank.py +30 -0
- prashflow-1.0.0/src/prashflow/retrieval.py +38 -0
- prashflow-1.0.0/src/prashflow/session.py +21 -0
- prashflow-1.0.0/src/prashflow/sql_ingest.py +70 -0
- prashflow-1.0.0/src/prashflow/tools.py +64 -0
- prashflow-1.0.0/src/prashflow/vectorstores.py +91 -0
- prashflow-1.0.0/src/prashflow.egg-info/PKG-INFO +665 -0
- prashflow-1.0.0/src/prashflow.egg-info/SOURCES.txt +31 -0
- prashflow-1.0.0/src/prashflow.egg-info/dependency_links.txt +1 -0
- prashflow-1.0.0/src/prashflow.egg-info/entry_points.txt +2 -0
- prashflow-1.0.0/src/prashflow.egg-info/requires.txt +72 -0
- prashflow-1.0.0/src/prashflow.egg-info/top_level.txt +1 -0
- prashflow-1.0.0/tests/test_core.py +8 -0
prashflow-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,665 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: prashflow
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: General-purpose AI application and agent runtime with chat, RAG, tools, MCP, memory, streaming and multi-provider LLM support.
|
|
5
|
+
Author: Prasanth
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.10
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: pydantic>=2.7
|
|
10
|
+
Requires-Dist: pydantic-settings>=2.5
|
|
11
|
+
Requires-Dist: rich>=13.7
|
|
12
|
+
Requires-Dist: typer>=0.12
|
|
13
|
+
Requires-Dist: pyyaml>=6.0
|
|
14
|
+
Requires-Dist: requests>=2.32
|
|
15
|
+
Requires-Dist: sqlalchemy>=2.0
|
|
16
|
+
Requires-Dist: langchain-core>=0.3
|
|
17
|
+
Requires-Dist: langchain-community>=0.3
|
|
18
|
+
Requires-Dist: langchain-text-splitters>=0.3
|
|
19
|
+
Requires-Dist: langchain-chroma>=0.2
|
|
20
|
+
Requires-Dist: langgraph>=0.2
|
|
21
|
+
Requires-Dist: langchain-ollama>=0.2
|
|
22
|
+
Requires-Dist: chromadb>=0.5
|
|
23
|
+
Requires-Dist: rank-bm25>=0.2.2
|
|
24
|
+
Requires-Dist: pypdf>=5.0
|
|
25
|
+
Requires-Dist: docx2txt>=0.8
|
|
26
|
+
Requires-Dist: beautifulsoup4>=4.12
|
|
27
|
+
Requires-Dist: numpy>=1.26
|
|
28
|
+
Provides-Extra: openai
|
|
29
|
+
Requires-Dist: langchain-openai>=0.3; extra == "openai"
|
|
30
|
+
Provides-Extra: web
|
|
31
|
+
Requires-Dist: ddgs>=9.0; extra == "web"
|
|
32
|
+
Provides-Extra: rerank
|
|
33
|
+
Requires-Dist: sentence-transformers>=3.0; extra == "rerank"
|
|
34
|
+
Provides-Extra: qdrant
|
|
35
|
+
Requires-Dist: qdrant-client>=1.12; extra == "qdrant"
|
|
36
|
+
Requires-Dist: langchain-qdrant>=0.2; extra == "qdrant"
|
|
37
|
+
Provides-Extra: faiss
|
|
38
|
+
Requires-Dist: faiss-cpu>=1.9; extra == "faiss"
|
|
39
|
+
Provides-Extra: pgvector
|
|
40
|
+
Requires-Dist: pgvector>=0.3; extra == "pgvector"
|
|
41
|
+
Requires-Dist: psycopg[binary]>=3.2; extra == "pgvector"
|
|
42
|
+
Requires-Dist: langchain-postgres>=0.0.12; extra == "pgvector"
|
|
43
|
+
Provides-Extra: mcp
|
|
44
|
+
Requires-Dist: mcp>=1.0; extra == "mcp"
|
|
45
|
+
Provides-Extra: litellm
|
|
46
|
+
Requires-Dist: litellm>=1.70; extra == "litellm"
|
|
47
|
+
Provides-Extra: mysql
|
|
48
|
+
Requires-Dist: pymysql>=1.1; extra == "mysql"
|
|
49
|
+
Provides-Extra: postgres
|
|
50
|
+
Requires-Dist: psycopg[binary]>=3.2; extra == "postgres"
|
|
51
|
+
Provides-Extra: all
|
|
52
|
+
Requires-Dist: langchain-openai>=0.3; extra == "all"
|
|
53
|
+
Requires-Dist: ddgs>=9.0; extra == "all"
|
|
54
|
+
Requires-Dist: sentence-transformers>=3.0; extra == "all"
|
|
55
|
+
Requires-Dist: qdrant-client>=1.12; extra == "all"
|
|
56
|
+
Requires-Dist: langchain-qdrant>=0.2; extra == "all"
|
|
57
|
+
Requires-Dist: faiss-cpu>=1.9; extra == "all"
|
|
58
|
+
Requires-Dist: pgvector>=0.3; extra == "all"
|
|
59
|
+
Requires-Dist: psycopg[binary]>=3.2; extra == "all"
|
|
60
|
+
Requires-Dist: langchain-postgres>=0.0.12; extra == "all"
|
|
61
|
+
Requires-Dist: mcp>=1.0; extra == "all"
|
|
62
|
+
Requires-Dist: pymysql>=1.1; extra == "all"
|
|
63
|
+
Requires-Dist: litellm>=1.70; extra == "all"
|
|
64
|
+
Provides-Extra: dev
|
|
65
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
66
|
+
Requires-Dist: ruff>=0.8; extra == "dev"
|
|
67
|
+
Requires-Dist: build>=1.2; extra == "dev"
|
|
68
|
+
Requires-Dist: twine>=6.0; extra == "dev"
|
|
69
|
+
|
|
70
|
+
# PrashFlow
|
|
71
|
+
|
|
72
|
+
**PrashFlow** is a general-purpose Python AI application and agent runtime designed to make Chat, RAG, agents, multi-agent systems, tools, MCP, memory, streaming, and multiple model providers available through a small Python API.
|
|
73
|
+
|
|
74
|
+
It is **not only a RAG library**.
|
|
75
|
+
|
|
76
|
+
## What you can build
|
|
77
|
+
|
|
78
|
+
- Local Ollama RAG applications
|
|
79
|
+
- Streaming chat with user sessions
|
|
80
|
+
- Semantic, BM25/keyword, hybrid, MMR and multi-query retrieval
|
|
81
|
+
- Chroma, Qdrant, FAISS, PGVector and in-memory vector stores
|
|
82
|
+
- PDF/DOCX/TXT/Markdown/CSV/web ingestion
|
|
83
|
+
- SQL database ingestion
|
|
84
|
+
- Single tool-using agents with LangGraph
|
|
85
|
+
- Agentic Ollama chat
|
|
86
|
+
- Supervisor, sequential and parallel multi-agent workflows
|
|
87
|
+
- Custom Python tools
|
|
88
|
+
- Optional web search
|
|
89
|
+
- MCP configuration/adapter boundary
|
|
90
|
+
- OpenAI and OpenAI-compatible models
|
|
91
|
+
- LiteLLM model gateway
|
|
92
|
+
- Environment-variable based YAML configuration
|
|
93
|
+
- Retries and clear validation errors
|
|
94
|
+
|
|
95
|
+
## Architecture
|
|
96
|
+
|
|
97
|
+
```text
|
|
98
|
+
PRASHFLOW
|
|
99
|
+
|
|
|
100
|
+
+---------------------+----------------------+
|
|
101
|
+
| | |
|
|
102
|
+
Chat RAG Agent
|
|
103
|
+
| | |
|
|
104
|
+
Streaming Ingestion/Retrieval Tools
|
|
105
|
+
Sessions | MCP
|
|
106
|
+
| +-------+-------+ |
|
|
107
|
+
| | | | |
|
|
108
|
+
| Semantic BM25 MMR |
|
|
109
|
+
| | | | |
|
|
110
|
+
| +-------+-------+ |
|
|
111
|
+
| | |
|
|
112
|
+
| RRF |
|
|
113
|
+
| | |
|
|
114
|
+
| Rerank |
|
|
115
|
+
| | |
|
|
116
|
+
+----------------------+---------------------+
|
|
117
|
+
|
|
|
118
|
+
Model Layer
|
|
119
|
+
|
|
|
120
|
+
+---------+---------+
|
|
121
|
+
| | |
|
|
122
|
+
Ollama OpenAI LiteLLM
|
|
123
|
+
|
|
|
124
|
+
MultiAgent
|
|
125
|
+
|
|
|
126
|
+
+------------+------------+
|
|
127
|
+
| | |
|
|
128
|
+
Supervisor Sequential Parallel
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Installation
|
|
132
|
+
|
|
133
|
+
Basic:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
pip install prashflow
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
All optional integrations:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
pip install "prashflow[all]"
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
For local Ollama + Chroma RAG, the `all` extra is convenient. You can also install only the extras you need.
|
|
146
|
+
|
|
147
|
+
## 1. Local Ollama RAG in a few lines
|
|
148
|
+
|
|
149
|
+
Put documents in `./knowledge`:
|
|
150
|
+
|
|
151
|
+
```text
|
|
152
|
+
my-app/
|
|
153
|
+
├── knowledge/
|
|
154
|
+
│ ├── deployment.pdf
|
|
155
|
+
│ ├── architecture.docx
|
|
156
|
+
│ ├── troubleshooting.txt
|
|
157
|
+
│ └── security.md
|
|
158
|
+
├── data/
|
|
159
|
+
└── app.py
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Pull local models:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
ollama pull qwen3:8b
|
|
166
|
+
ollama pull nomic-embed-text
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Python:
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
from prashflow import RAG
|
|
173
|
+
|
|
174
|
+
rag = RAG(
|
|
175
|
+
llm="ollama:qwen3:8b",
|
|
176
|
+
embeddings="ollama:nomic-embed-text",
|
|
177
|
+
vector_db="chroma:./data/chroma",
|
|
178
|
+
retrieval={
|
|
179
|
+
"type": "hybrid",
|
|
180
|
+
"top_k": 5,
|
|
181
|
+
"candidate_k": 20,
|
|
182
|
+
"semantic_weight": 0.6,
|
|
183
|
+
"keyword_weight": 0.4,
|
|
184
|
+
},
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
rag.ingest("./knowledge")
|
|
188
|
+
|
|
189
|
+
print(rag.ask("What is our production deployment process?"))
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
PrashFlow hides the LangChain, Chroma, loader and embedding implementation from the application code.
|
|
193
|
+
|
|
194
|
+
## 2. Search algorithms
|
|
195
|
+
|
|
196
|
+
Semantic:
|
|
197
|
+
|
|
198
|
+
```python
|
|
199
|
+
rag.search("production deployment", search_type="semantic")
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
BM25/keyword:
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
rag.search("JIRA-12345", search_type="keyword")
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
MMR:
|
|
209
|
+
|
|
210
|
+
```python
|
|
211
|
+
rag.search("deployment architecture", search_type="mmr")
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Hybrid:
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
rag.search("production deployment", search_type="hybrid")
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Multi-query:
|
|
221
|
+
|
|
222
|
+
```python
|
|
223
|
+
rag.search("How do we release an application?", search_type="multi_query")
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Hybrid combines semantic and keyword rankings with reciprocal-rank fusion. MMR adds diversity. An optional cross-encoder reranker can be enabled with the `rerank` extra.
|
|
227
|
+
|
|
228
|
+
## 3. Persistent Chroma
|
|
229
|
+
|
|
230
|
+
```python
|
|
231
|
+
rag = RAG(
|
|
232
|
+
llm="ollama:qwen3:8b",
|
|
233
|
+
embeddings="ollama:nomic-embed-text",
|
|
234
|
+
vector_db={
|
|
235
|
+
"provider": "chroma",
|
|
236
|
+
"path": "./data/chroma",
|
|
237
|
+
"collection": "company_docs",
|
|
238
|
+
},
|
|
239
|
+
)
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
The Chroma data remains on disk after the Python process exits.
|
|
243
|
+
|
|
244
|
+
### In-memory vector store
|
|
245
|
+
|
|
246
|
+
```python
|
|
247
|
+
rag = RAG(
|
|
248
|
+
llm="ollama:qwen3:8b",
|
|
249
|
+
embeddings="ollama:nomic-embed-text",
|
|
250
|
+
vector_db={"provider": "memory"},
|
|
251
|
+
)
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
This is intended for tests, demos and short-lived applications.
|
|
255
|
+
|
|
256
|
+
## 4. User session + streaming RAG chat
|
|
257
|
+
|
|
258
|
+
This is the recommended API for a local RAG chatbot:
|
|
259
|
+
|
|
260
|
+
```python
|
|
261
|
+
from prashflow import RAG
|
|
262
|
+
|
|
263
|
+
rag = RAG(
|
|
264
|
+
llm="ollama:qwen3:8b",
|
|
265
|
+
embeddings="ollama:nomic-embed-text",
|
|
266
|
+
vector_db="chroma:./data/chroma",
|
|
267
|
+
retrieval={"type": "hybrid", "top_k": 5},
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
rag.ingest("./knowledge")
|
|
271
|
+
|
|
272
|
+
session_id = "user-001"
|
|
273
|
+
|
|
274
|
+
while True:
|
|
275
|
+
question = input("You: ")
|
|
276
|
+
if question.lower() in {"exit", "quit"}:
|
|
277
|
+
break
|
|
278
|
+
|
|
279
|
+
print("AI: ", end="")
|
|
280
|
+
for token in rag.chat_stream(
|
|
281
|
+
session_id=session_id,
|
|
282
|
+
query=question,
|
|
283
|
+
search_type="hybrid",
|
|
284
|
+
):
|
|
285
|
+
print(token, end="", flush=True)
|
|
286
|
+
print()
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
The session stores conversation history independently for each `session_id`.
|
|
290
|
+
|
|
291
|
+
```text
|
|
292
|
+
user-001 -> conversation A
|
|
293
|
+
user-002 -> conversation B
|
|
294
|
+
user-003 -> conversation C
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
The default session backend is in-memory. A persistent Redis/PostgreSQL session backend can be added behind the same `SessionStore` abstraction.
|
|
298
|
+
|
|
299
|
+
## 5. Normal Chat
|
|
300
|
+
|
|
301
|
+
```python
|
|
302
|
+
from prashflow import Chat
|
|
303
|
+
|
|
304
|
+
chat = Chat(
|
|
305
|
+
llm="ollama:qwen3:8b",
|
|
306
|
+
session_id="user-001",
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
print(chat.chat("My name is Prash."))
|
|
310
|
+
print(chat.chat("What is my name?"))
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
Streaming:
|
|
314
|
+
|
|
315
|
+
```python
|
|
316
|
+
for token in chat.stream("Explain Kubernetes"):
|
|
317
|
+
print(token, end="", flush=True)
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## 6. Agentic Ollama Chat
|
|
321
|
+
|
|
322
|
+
Use `AgentChat` when the model should decide when to call tools.
|
|
323
|
+
|
|
324
|
+
```python
|
|
325
|
+
from prashflow import AgentChat
|
|
326
|
+
|
|
327
|
+
agent = AgentChat(
|
|
328
|
+
llm="ollama:qwen3:8b",
|
|
329
|
+
tools=["calculator"],
|
|
330
|
+
session_id="user-001",
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
for token in agent.stream("Calculate 25% of 8000"):
|
|
334
|
+
print(token, end="", flush=True)
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
PrashFlow uses LangGraph internally for the agent loop. The application does not need to build `StateGraph` or `ToolNode` itself.
|
|
338
|
+
|
|
339
|
+
## 7. Custom Python tools
|
|
340
|
+
|
|
341
|
+
```python
|
|
342
|
+
from prashflow import Agent
|
|
343
|
+
def get_server_status(server: str) -> str:
|
|
344
|
+
"""Get Linux server status."""
|
|
345
|
+
return f"{server}: UP"
|
|
346
|
+
agent = Agent(
|
|
347
|
+
llm={
|
|
348
|
+
"provider": "ollama",
|
|
349
|
+
"model": "qwen3:8b",
|
|
350
|
+
"base_url": "http://localhost:11434",
|
|
351
|
+
},
|
|
352
|
+
tools=[
|
|
353
|
+
"calculator",
|
|
354
|
+
get_server_status,
|
|
355
|
+
],
|
|
356
|
+
)
|
|
357
|
+
print(
|
|
358
|
+
agent.run(
|
|
359
|
+
"Check web01 status and calculate 20 percent of 500."
|
|
360
|
+
)
|
|
361
|
+
)
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
Tools can also require interactive approval:
|
|
365
|
+
|
|
366
|
+
```python
|
|
367
|
+
@tool(requires_approval=True, max_retries=2)
|
|
368
|
+
def restart_service(server: str, service: str) -> str:
|
|
369
|
+
"""Restart a Linux service."""
|
|
370
|
+
# implement the real operation here
|
|
371
|
+
return f"Restarted {service} on {server}"
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
## 8. Multi-agent
|
|
375
|
+
|
|
376
|
+
### Supervisor
|
|
377
|
+
|
|
378
|
+
```python
|
|
379
|
+
from prashflow import MultiAgent
|
|
380
|
+
|
|
381
|
+
team = MultiAgent(
|
|
382
|
+
model="ollama:qwen3:8b",
|
|
383
|
+
mode="supervisor",
|
|
384
|
+
agents=[
|
|
385
|
+
{
|
|
386
|
+
"name": "researcher",
|
|
387
|
+
"description": "Research technical information.",
|
|
388
|
+
"tools": ["web_search"],
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
"name": "calculator",
|
|
392
|
+
"description": "Perform arithmetic calculations.",
|
|
393
|
+
"tools": ["calculator"],
|
|
394
|
+
},
|
|
395
|
+
],
|
|
396
|
+
)
|
|
397
|
+
|
|
398
|
+
print(team.run("Calculate 20% of 8000"))
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
The supervisor chooses the specialist.
|
|
402
|
+
|
|
403
|
+
### Sequential
|
|
404
|
+
|
|
405
|
+
```python
|
|
406
|
+
team = MultiAgent(
|
|
407
|
+
model="ollama:qwen3:8b",
|
|
408
|
+
mode="sequential",
|
|
409
|
+
agents=[
|
|
410
|
+
{"name": "planner", "description": "Create a plan."},
|
|
411
|
+
{"name": "developer", "description": "Develop the solution."},
|
|
412
|
+
{"name": "reviewer", "description": "Review the solution."},
|
|
413
|
+
],
|
|
414
|
+
)
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
Flow:
|
|
418
|
+
|
|
419
|
+
```text
|
|
420
|
+
Planner -> Developer -> Reviewer -> Final
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### Parallel
|
|
424
|
+
|
|
425
|
+
```python
|
|
426
|
+
team = MultiAgent(
|
|
427
|
+
model="ollama:qwen3:8b",
|
|
428
|
+
mode="parallel",
|
|
429
|
+
agents=[
|
|
430
|
+
{"name": "security", "description": "Analyze security."},
|
|
431
|
+
{"name": "performance", "description": "Analyze performance."},
|
|
432
|
+
{"name": "architecture", "description": "Analyze architecture."},
|
|
433
|
+
],
|
|
434
|
+
)
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
The current reference implementation runs the specialist calls independently and synthesizes their results. An async concurrent implementation can be added for high-throughput production workloads.
|
|
438
|
+
|
|
439
|
+
### Streaming multi-agent
|
|
440
|
+
|
|
441
|
+
```python
|
|
442
|
+
for token in team.stream("Analyze this deployment"):
|
|
443
|
+
print(token, end="", flush=True)
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
### Per-agent models
|
|
447
|
+
|
|
448
|
+
```python
|
|
449
|
+
team = MultiAgent(
|
|
450
|
+
model="ollama:qwen3:8b",
|
|
451
|
+
agents=[
|
|
452
|
+
{
|
|
453
|
+
"name": "researcher",
|
|
454
|
+
"model": "ollama:qwen3:8b",
|
|
455
|
+
"description": "Research information.",
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
"name": "coder",
|
|
459
|
+
"model": "ollama:qwen2.5-coder:14b",
|
|
460
|
+
"description": "Write and review code.",
|
|
461
|
+
},
|
|
462
|
+
],
|
|
463
|
+
)
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
## 9. RAG + Agent
|
|
467
|
+
|
|
468
|
+
```python
|
|
469
|
+
from prashflow import AgentChat, RAG
|
|
470
|
+
|
|
471
|
+
rag = RAG(
|
|
472
|
+
llm="ollama:qwen3:8b",
|
|
473
|
+
embeddings="ollama:nomic-embed-text",
|
|
474
|
+
vector_db="chroma:./data/chroma",
|
|
475
|
+
retrieval={"type": "hybrid", "top_k": 5},
|
|
476
|
+
)
|
|
477
|
+
rag.ingest("./knowledge")
|
|
478
|
+
|
|
479
|
+
agent = AgentChat(
|
|
480
|
+
llm="ollama:qwen3:8b",
|
|
481
|
+
tools=[rag.as_tool(), "calculator"],
|
|
482
|
+
)
|
|
483
|
+
|
|
484
|
+
print(agent.run("Find our production deployment procedure."))
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
## 10. Multi-agent + RAG
|
|
488
|
+
|
|
489
|
+
```python
|
|
490
|
+
team = MultiAgent(
|
|
491
|
+
model="ollama:qwen3:8b",
|
|
492
|
+
mode="supervisor",
|
|
493
|
+
agents=[
|
|
494
|
+
{
|
|
495
|
+
"name": "company_knowledge",
|
|
496
|
+
"description": "Answer questions from company documents.",
|
|
497
|
+
"tools": [rag.as_tool()],
|
|
498
|
+
},
|
|
499
|
+
{
|
|
500
|
+
"name": "calculator",
|
|
501
|
+
"description": "Perform calculations.",
|
|
502
|
+
"tools": ["calculator"],
|
|
503
|
+
},
|
|
504
|
+
],
|
|
505
|
+
)
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
## 11. SQL ingestion
|
|
509
|
+
|
|
510
|
+
```python
|
|
511
|
+
rag.ingest_sql(
|
|
512
|
+
url="postgresql+psycopg://user:password@localhost:5432/company",
|
|
513
|
+
query="SELECT id, title, description FROM incidents",
|
|
514
|
+
content_columns=["title", "description"],
|
|
515
|
+
metadata_columns=["id"],
|
|
516
|
+
)
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
MySQL is supported through the SQLAlchemy connection URL when the MySQL extra is installed.
|
|
520
|
+
|
|
521
|
+
## 12. MCP
|
|
522
|
+
|
|
523
|
+
PrashFlow provides an MCP configuration boundary so MCP can be attached to agents without changing the agent API.
|
|
524
|
+
|
|
525
|
+
```python
|
|
526
|
+
agent = AgentChat(
|
|
527
|
+
llm="ollama:qwen3:8b",
|
|
528
|
+
mcp_servers=[
|
|
529
|
+
{
|
|
530
|
+
"name": "filesystem",
|
|
531
|
+
"transport": "stdio",
|
|
532
|
+
"command": "npx",
|
|
533
|
+
"args": ["-y", "@modelcontextprotocol/server-filesystem", "./workspace"],
|
|
534
|
+
}
|
|
535
|
+
],
|
|
536
|
+
)
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
The reference package validates MCP server configuration. For production MCP transport/session discovery, pin and implement against the MCP SDK version used by your organization; MCP SDK transport APIs can evolve.
|
|
540
|
+
|
|
541
|
+
## 13. LiteLLM
|
|
542
|
+
|
|
543
|
+
```python
|
|
544
|
+
from prashflow import Chat
|
|
545
|
+
|
|
546
|
+
chat = Chat(
|
|
547
|
+
llm={
|
|
548
|
+
"provider": "litellm",
|
|
549
|
+
"model": "openai/gpt-4.1",
|
|
550
|
+
}
|
|
551
|
+
)
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
The application API remains `chat.chat()` / `chat.stream()` while the provider is selected by LiteLLM.
|
|
555
|
+
|
|
556
|
+
## 14. OpenAI / OpenAI-compatible
|
|
557
|
+
|
|
558
|
+
```python
|
|
559
|
+
from prashflow import Chat
|
|
560
|
+
|
|
561
|
+
chat = Chat(
|
|
562
|
+
llm={
|
|
563
|
+
"provider": "openai-compatible",
|
|
564
|
+
"model": "my-model",
|
|
565
|
+
"base_url": "http://localhost:8000/v1",
|
|
566
|
+
"api_key": "dummy",
|
|
567
|
+
}
|
|
568
|
+
)
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
## 15. YAML configuration
|
|
572
|
+
|
|
573
|
+
`prashflow.yaml`:
|
|
574
|
+
|
|
575
|
+
```yaml
|
|
576
|
+
llm:
|
|
577
|
+
provider: ollama
|
|
578
|
+
model: qwen3:8b
|
|
579
|
+
base_url: http://localhost:11434
|
|
580
|
+
|
|
581
|
+
embeddings:
|
|
582
|
+
provider: ollama
|
|
583
|
+
model: nomic-embed-text
|
|
584
|
+
base_url: http://localhost:11434
|
|
585
|
+
|
|
586
|
+
vector_db:
|
|
587
|
+
provider: chroma
|
|
588
|
+
path: ./data/chroma
|
|
589
|
+
collection: company_docs
|
|
590
|
+
|
|
591
|
+
retrieval:
|
|
592
|
+
type: hybrid
|
|
593
|
+
top_k: 5
|
|
594
|
+
candidate_k: 20
|
|
595
|
+
semantic_weight: 0.6
|
|
596
|
+
keyword_weight: 0.4
|
|
597
|
+
|
|
598
|
+
chunking:
|
|
599
|
+
size: 1000
|
|
600
|
+
overlap: 200
|
|
601
|
+
|
|
602
|
+
reranker:
|
|
603
|
+
enabled: false
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
Load it:
|
|
607
|
+
|
|
608
|
+
```python
|
|
609
|
+
from prashflow import RAG
|
|
610
|
+
|
|
611
|
+
rag = RAG.from_config("prashflow.yaml")
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
Environment variables are supported:
|
|
615
|
+
|
|
616
|
+
```yaml
|
|
617
|
+
llm:
|
|
618
|
+
provider: openai
|
|
619
|
+
model: ${OPENAI_MODEL}
|
|
620
|
+
api_key: ${OPENAI_API_KEY}
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
## 16. Error handling
|
|
624
|
+
|
|
625
|
+
PrashFlow exposes typed exceptions:
|
|
626
|
+
|
|
627
|
+
```python
|
|
628
|
+
from prashflow import PrashFlowError
|
|
629
|
+
|
|
630
|
+
try:
|
|
631
|
+
print(rag.ask("What is our deployment process?"))
|
|
632
|
+
except PrashFlowError as exc:
|
|
633
|
+
print(f"PrashFlow error: {exc}")
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
Available categories include configuration, LLM, embedding, vector DB, document loading, retrieval, reranking, tool, agent and MCP errors.
|
|
637
|
+
|
|
638
|
+
|
|
639
|
+
## 17. Design philosophy
|
|
640
|
+
|
|
641
|
+
Application developers should write:
|
|
642
|
+
|
|
643
|
+
```python
|
|
644
|
+
from prashflow import RAG, AgentChat, MultiAgent
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
and should not need to directly assemble LangChain loaders, LangGraph state graphs, Chroma clients, BM25 indexes, tool nodes or model-provider adapters for common use cases.
|
|
648
|
+
|
|
649
|
+
Advanced developers can still customize the underlying components when needed.
|
|
650
|
+
|
|
651
|
+
## Roadmap
|
|
652
|
+
|
|
653
|
+
Planned production enhancements:
|
|
654
|
+
|
|
655
|
+
- true async/parallel specialist execution
|
|
656
|
+
- persistent Redis/PostgreSQL session backends
|
|
657
|
+
- complete MCP client/session discovery against a pinned SDK
|
|
658
|
+
- A2A support
|
|
659
|
+
- model fallback and cost routing
|
|
660
|
+
- observability/tracing
|
|
661
|
+
- structured output and Pydantic schemas
|
|
662
|
+
- FastAPI integration helpers
|
|
663
|
+
- ingestion manifests and changed-file detection
|
|
664
|
+
- background ingestion jobs
|
|
665
|
+
- citation objects with source/page metadata
|