feat: complete RAG pipeline integration (ingest + query + Memory)
Parser Service: - Add /ocr/ingest endpoint (PARSER → RAG in one call) - Add RAG_BASE_URL and RAG_TIMEOUT to config - Add OcrIngestResponse schema - Create file_converter utility for PDF/image → PNG bytes - Endpoint accepts file, dao_id, doc_id, user_id - Automatically parses with dots.ocr and sends to RAG Service Router Integration: - Add _handle_rag_query() method in RouterApp - Combines Memory + RAG → LLM pipeline - Get Memory context (facts, events, summaries) - Query RAG Service for documents - Build prompt with Memory + RAG documents - Call LLM provider with combined context - Return answer with citations Clients: - Create rag_client.py for Router (query RAG Service) - Create memory_client.py for Router (get Memory context) E2E Tests: - Create e2e_rag_pipeline.sh script for full pipeline test - Test ingest → query → router query flow - Add E2E_RAG_README.md with usage examples Docker: - Add RAG_SERVICE_URL and MEMORY_SERVICE_URL to router environment
This commit is contained in:
125
tests/E2E_RAG_README.md
Normal file
125
tests/E2E_RAG_README.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# E2E RAG Pipeline Test
|
||||
|
||||
End-to-end тест для повного пайплайну: PARSER → RAG → Router (Memory + RAG).
|
||||
|
||||
## Підготовка
|
||||
|
||||
1. Запустити всі сервіси:
|
||||
```bash
|
||||
docker-compose up -d parser-service rag-service router memory-service city-db
|
||||
```
|
||||
|
||||
2. Перевірити, що сервіси працюють:
|
||||
```bash
|
||||
curl http://localhost:9400/health # PARSER
|
||||
curl http://localhost:9500/health # RAG
|
||||
curl http://localhost:9102/health # Router
|
||||
curl http://localhost:8000/health # Memory
|
||||
```
|
||||
|
||||
## Тест 1: Ingest Document
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:9400/ocr/ingest \
|
||||
-F "file=@tests/fixtures/parsed_json_example.json" \
|
||||
-F "dao_id=daarion" \
|
||||
-F "doc_id=microdao-tokenomics-2025-11"
|
||||
```
|
||||
|
||||
**Очікуваний результат:**
|
||||
```json
|
||||
{
|
||||
"dao_id": "daarion",
|
||||
"doc_id": "microdao-tokenomics-2025-11",
|
||||
"pages_processed": 2,
|
||||
"rag_ingested": true,
|
||||
"raw_json": { ... }
|
||||
}
|
||||
```
|
||||
|
||||
## Тест 2: Query RAG Service Directly
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:9500/query \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"dao_id": "daarion",
|
||||
"question": "Поясни токеноміку microDAO і роль стейкінгу"
|
||||
}'
|
||||
```
|
||||
|
||||
**Очікуваний результат:**
|
||||
```json
|
||||
{
|
||||
"answer": "MicroDAO використовує токен μGOV...",
|
||||
"citations": [
|
||||
{
|
||||
"doc_id": "microdao-tokenomics-2025-11",
|
||||
"page": 1,
|
||||
"section": "Токеноміка MicroDAO",
|
||||
"excerpt": "..."
|
||||
}
|
||||
],
|
||||
"documents": [...]
|
||||
}
|
||||
```
|
||||
|
||||
## Тест 3: Query via Router (Memory + RAG)
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:9102/route \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"mode": "rag_query",
|
||||
"dao_id": "daarion",
|
||||
"user_id": "test-user",
|
||||
"payload": {
|
||||
"question": "Поясни токеноміку microDAO і роль стейкінгу"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
**Очікуваний результат:**
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"provider_id": "llm_local_qwen3_8b",
|
||||
"data": {
|
||||
"text": "Відповідь з урахуванням Memory + RAG...",
|
||||
"citations": [...]
|
||||
},
|
||||
"metadata": {
|
||||
"memory_used": true,
|
||||
"rag_used": true,
|
||||
"documents_retrieved": 5,
|
||||
"citations_count": 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Автоматичний E2E тест
|
||||
|
||||
Запустити скрипт:
|
||||
```bash
|
||||
./tests/e2e_rag_pipeline.sh
|
||||
```
|
||||
|
||||
Скрипт перевіряє всі три кроки автоматично.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### RAG Service не знаходить документи
|
||||
- Перевірити, що документ був успішно індексований: `rag_ingested: true`
|
||||
- Перевірити логі RAG Service: `docker-compose logs rag-service`
|
||||
- Перевірити, що `dao_id` збігається в ingest та query
|
||||
|
||||
### Router повертає помилку
|
||||
- Перевірити, що `mode="rag_query"` правильно обробляється
|
||||
- Перевірити логі Router: `docker-compose logs router`
|
||||
- Перевірити, що RAG та Memory сервіси доступні з Router
|
||||
|
||||
### Memory context порожній
|
||||
- Перевірити, що Memory Service працює
|
||||
- Перевірити, що `user_id` та `dao_id` правильні
|
||||
- Memory може бути порожнім для нового користувача (це нормально)
|
||||
|
||||
101
tests/e2e_rag_pipeline.sh
Executable file
101
tests/e2e_rag_pipeline.sh
Executable file
@@ -0,0 +1,101 @@
|
||||
#!/bin/bash
|
||||
# E2E test script for RAG pipeline: ingest → query
|
||||
|
||||
set -e
|
||||
|
||||
PARSER_URL="${PARSER_URL:-http://localhost:9400}"
|
||||
RAG_URL="${RAG_URL:-http://localhost:9500}"
|
||||
ROUTER_URL="${ROUTER_URL:-http://localhost:9102}"
|
||||
|
||||
echo "=== E2E RAG Pipeline Test ==="
|
||||
echo ""
|
||||
|
||||
# Step 1: Ingest document
|
||||
echo "Step 1: Ingesting document via /ocr/ingest..."
|
||||
INGEST_RESPONSE=$(curl -s -X POST "${PARSER_URL}/ocr/ingest" \
|
||||
-F "file=@tests/fixtures/parsed_json_example.json" \
|
||||
-F "dao_id=daarion" \
|
||||
-F "doc_id=microdao-tokenomics-2025-11")
|
||||
|
||||
echo "Ingest response:"
|
||||
echo "$INGEST_RESPONSE" | jq '.'
|
||||
echo ""
|
||||
|
||||
DOC_ID=$(echo "$INGEST_RESPONSE" | jq -r '.doc_id')
|
||||
RAG_INGESTED=$(echo "$INGEST_RESPONSE" | jq -r '.rag_ingested')
|
||||
|
||||
if [ "$RAG_INGESTED" != "true" ]; then
|
||||
echo "ERROR: Document was not ingested into RAG"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✓ Document ingested: doc_id=${DOC_ID}"
|
||||
echo ""
|
||||
|
||||
# Step 2: Query via RAG Service directly
|
||||
echo "Step 2: Querying RAG Service directly..."
|
||||
RAG_QUERY_RESPONSE=$(curl -s -X POST "${RAG_URL}/query" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"dao_id": "daarion",
|
||||
"question": "Поясни токеноміку microDAO і роль стейкінгу"
|
||||
}')
|
||||
|
||||
echo "RAG query response:"
|
||||
echo "$RAG_QUERY_RESPONSE" | jq '.'
|
||||
echo ""
|
||||
|
||||
ANSWER=$(echo "$RAG_QUERY_RESPONSE" | jq -r '.answer')
|
||||
CITATIONS_COUNT=$(echo "$RAG_QUERY_RESPONSE" | jq '.citations | length')
|
||||
|
||||
if [ -z "$ANSWER" ] || [ "$ANSWER" == "null" ]; then
|
||||
echo "ERROR: Empty answer from RAG Service"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$CITATIONS_COUNT" -eq 0 ]; then
|
||||
echo "WARNING: No citations returned"
|
||||
fi
|
||||
|
||||
echo "✓ RAG query successful: answer length=${#ANSWER}, citations=${CITATIONS_COUNT}"
|
||||
echo ""
|
||||
|
||||
# Step 3: Query via Router (mode="rag_query")
|
||||
echo "Step 3: Querying via Router (mode=rag_query)..."
|
||||
ROUTER_QUERY_RESPONSE=$(curl -s -X POST "${ROUTER_URL}/route" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"mode": "rag_query",
|
||||
"dao_id": "daarion",
|
||||
"user_id": "test-user",
|
||||
"payload": {
|
||||
"question": "Поясни токеноміку microDAO і роль стейкінгу"
|
||||
}
|
||||
}')
|
||||
|
||||
echo "Router query response:"
|
||||
echo "$ROUTER_QUERY_RESPONSE" | jq '.'
|
||||
echo ""
|
||||
|
||||
ROUTER_OK=$(echo "$ROUTER_QUERY_RESPONSE" | jq -r '.ok')
|
||||
ROUTER_TEXT=$(echo "$ROUTER_QUERY_RESPONSE" | jq -r '.data.text // .data.answer // ""')
|
||||
ROUTER_CITATIONS=$(echo "$ROUTER_QUERY_RESPONSE" | jq '.data.citations // .metadata.citations // []')
|
||||
|
||||
if [ "$ROUTER_OK" != "true" ]; then
|
||||
echo "ERROR: Router query failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$ROUTER_TEXT" ] || [ "$ROUTER_TEXT" == "null" ]; then
|
||||
echo "ERROR: Empty answer from Router"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ROUTER_CITATIONS_COUNT=$(echo "$ROUTER_CITATIONS" | jq 'length')
|
||||
|
||||
echo "✓ Router query successful: answer length=${#ROUTER_TEXT}, citations=${ROUTER_CITATIONS_COUNT}"
|
||||
echo ""
|
||||
|
||||
echo "=== E2E Test Complete ==="
|
||||
echo "All steps passed successfully!"
|
||||
|
||||
Reference in New Issue
Block a user