ai-agent-book 精选快照(<2MB 代码与文档,来自 github.com/bojieli/ai-agent-book)
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s

This commit is contained in:
2026-08-20 13:12:50 +00:00
commit b119135836
10275 changed files with 3284984 additions and 0 deletions
@@ -0,0 +1,200 @@
#!/usr/bin/env python3
"""Test script for the retrieval pipeline with external doc_id support."""
import httpx
import asyncio
import json
import logging
from datetime import datetime
# Set up logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# Service URLs
DENSE_URL = "http://localhost:4240"
SPARSE_URL = "http://localhost:4241"
PIPELINE_URL = "http://localhost:4242"
async def test_sparse_service():
"""Test the sparse service directly to ensure it handles external doc_ids."""
logger.info("Testing sparse service with external doc_id...")
async with httpx.AsyncClient(timeout=10.0) as client:
# Test indexing with external doc_id
test_doc = {
"text": "Python is a high-level programming language known for its simplicity and readability.",
"doc_id": "test_python_doc_001",
"metadata": {"category": "programming", "language": "Python"}
}
try:
response = await client.post(f"{SPARSE_URL}/index", json=test_doc)
response.raise_for_status()
result = response.json()
logger.info(f"Sparse indexing result: {json.dumps(result, indent=2)}")
# Verify the doc_id matches what we sent
if result.get("doc_id") == "test_python_doc_001":
logger.info("✅ Sparse service correctly preserved external doc_id")
else:
logger.error(f"❌ Sparse service returned different doc_id: {result.get('doc_id')}")
# Test search
search_query = {"query": "Python programming", "top_k": 5}
response = await client.post(f"{SPARSE_URL}/search", json=search_query)
response.raise_for_status()
search_results = response.json()
if search_results:
logger.info(f"✅ Sparse search returned {len(search_results)} results")
first_result = search_results[0]
logger.info(f"First result doc_id: {first_result.get('doc_id')}")
if first_result.get('doc_id') == "test_python_doc_001":
logger.info("✅ Search correctly returned our document with external doc_id")
return True
except Exception as e:
logger.error(f"❌ Sparse service test failed: {e}")
return False
async def test_pipeline():
"""Test the complete retrieval pipeline."""
logger.info("Testing retrieval pipeline...")
async with httpx.AsyncClient(timeout=30.0) as client:
try:
# First, clear the pipeline
logger.info("Clearing pipeline...")
response = await client.delete(f"{PIPELINE_URL}/clear")
logger.info(f"Clear response: {response.json()}")
# Test documents
test_documents = [
{
"text": "Python is renowned for its clean syntax and readability, making it ideal for beginners and experts alike.",
"doc_id": "prog_python",
"metadata": {"category": "programming", "subcategory": "languages"}
},
{
"text": "Machine learning with Python involves libraries like scikit-learn, TensorFlow, and PyTorch for building AI models.",
"doc_id": "ml_python",
"metadata": {"category": "machine_learning", "subcategory": "tools"}
},
{
"text": "JavaScript is the language of the web, enabling dynamic and interactive user interfaces in browsers.",
"doc_id": "prog_javascript",
"metadata": {"category": "programming", "subcategory": "web"}
}
]
# Index documents
for doc in test_documents:
logger.info(f"Indexing document: {doc['doc_id']}")
response = await client.post(f"{PIPELINE_URL}/index", json=doc)
response.raise_for_status()
result = response.json()
# Check both services succeeded
dense_success = result.get("dense", {}).get("success", False)
sparse_success = result.get("sparse", {}).get("success", False)
if dense_success and sparse_success:
logger.info(f"✅ Document {doc['doc_id']} indexed successfully in both services")
else:
logger.error(f"❌ Indexing failed for {doc['doc_id']}")
logger.error(f" Dense: {result.get('dense')}")
logger.error(f" Sparse: {result.get('sparse')}")
# Wait a moment for indexing to complete
await asyncio.sleep(1)
# Test search in different modes
search_query = "Python programming language"
logger.info(f"\nTesting search with query: '{search_query}'")
for mode in ["dense", "sparse", "hybrid"]:
logger.info(f"\n--- Testing {mode} search ---")
search_request = {
"query": search_query,
"mode": mode,
"top_k": 10,
"rerank_top_k": 5,
"skip_reranking": False if mode == "hybrid" else True
}
response = await client.post(f"{PIPELINE_URL}/search", json=search_request)
response.raise_for_status()
results = response.json()
# Log results summary
if mode == "dense":
dense_results = results.get("dense_results", [])
if dense_results:
logger.info(f"✅ Dense search returned {len(dense_results)} results")
logger.info(f" Top result: {dense_results[0]['doc_id']} (score: {dense_results[0]['score']:.4f})")
else:
logger.error("❌ No dense results returned")
elif mode == "sparse":
sparse_results = results.get("sparse_results", [])
if sparse_results:
logger.info(f"✅ Sparse search returned {len(sparse_results)} results")
logger.info(f" Top result: {sparse_results[0]['doc_id']} (score: {sparse_results[0]['score']:.4f})")
else:
logger.error("❌ No sparse results returned")
elif mode == "hybrid":
dense_results = results.get("dense_results", [])
sparse_results = results.get("sparse_results", [])
reranked_results = results.get("reranked_results", [])
logger.info(f"✅ Hybrid search results:")
logger.info(f" Dense: {len(dense_results)} results")
logger.info(f" Sparse: {len(sparse_results)} results")
logger.info(f" Reranked: {len(reranked_results)} results")
if reranked_results:
logger.info(f" Top reranked result: {reranked_results[0]['doc_id']} (score: {reranked_results[0]['rerank_score']:.4f})")
# Check statistics
stats = results.get("statistics", {})
if stats:
logger.info(f" Overlap: {stats.get('overlap_count', 0)} documents ({stats.get('overlap_percentage', 0):.1f}%)")
logger.info("\n✅ All pipeline tests completed successfully!")
return True
except Exception as e:
logger.error(f"❌ Pipeline test failed: {e}")
import traceback
logger.error(traceback.format_exc())
return False
async def main():
"""Run all tests."""
logger.info("Starting retrieval pipeline tests...")
logger.info("Make sure all three services are running:")
logger.info(" - Dense service on port 4240")
logger.info(" - Sparse service on port 4241")
logger.info(" - Pipeline service on port 4242")
logger.info("")
# Test sparse service first
sparse_ok = await test_sparse_service()
if sparse_ok:
logger.info("\n" + "="*50 + "\n")
# Test full pipeline
pipeline_ok = await test_pipeline()
if pipeline_ok:
logger.info("\n🎉 All tests passed successfully!")
else:
logger.info("\n⚠️ Some pipeline tests failed")
else:
logger.error("\n⚠️ Sparse service test failed - skipping pipeline tests")
if __name__ == "__main__":
asyncio.run(main())