Files
maskanx_cm_backend/tests/live_aom_test.py
T

217 lines
7.9 KiB
Python
Raw Normal View History

2026-08-01 10:28:22 +05:30
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Live AOM test with real LLM (aliyun-intl qwen3.5-plus).
Run: python tests/live_aom_test.py
"""
import asyncio
import json
import os
import sys
import time
import tempfile
from pathlib import Path
import httpx
# Add src to path
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
from adclaw.memory_agent.store import MemoryStore
from adclaw.memory_agent.embeddings import FakeEmbeddingPipeline
from adclaw.memory_agent.ingest import IngestAgent
from adclaw.memory_agent.consolidate import ConsolidationEngine
from adclaw.memory_agent.query import QueryAgent
from adclaw.memory_agent.models import AOMConfig
# --- Real LLM caller via OpenAI-compatible API ---
API_KEY = os.environ.get("QWEN_API_KEY", "")
API_URL = os.environ.get("QWEN_API_URL", "https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions")
MODEL = os.environ.get("QWEN_MODEL", "qwen-plus")
async def real_llm_caller(prompt: str) -> str:
"""Call qwen3.5-plus via OpenAI-compatible API."""
async with httpx.AsyncClient(timeout=60) as client:
resp = await client.post(
API_URL,
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
},
json={
"model": MODEL,
"messages": [{"role": "user", "content": prompt}],
"temperature": 0.3,
"max_tokens": 500,
},
)
resp.raise_for_status()
data = resp.json()
content = data["choices"][0]["message"]["content"]
# Strip thinking tags if present (qwen3.5 sometimes uses them)
if "<think>" in content and "</think>" in content:
think_end = content.index("</think>") + len("</think>")
content = content[think_end:].strip()
return content
def print_header(text):
print(f"\n{'='*60}")
print(f" {text}")
print(f"{'='*60}")
def print_ok(text):
print(f" [OK] {text}")
def print_fail(text):
print(f" [FAIL] {text}")
async def main():
print_header("AOM Live Test — Real LLM (qwen3.5-plus)")
# --- 1. Test LLM connectivity ---
print_header("1. LLM Connectivity")
t0 = time.time()
try:
resp = await real_llm_caller("Say 'hello' in one word.")
print_ok(f"LLM responded in {time.time()-t0:.1f}s: {resp[:100]}")
except Exception as e:
print_fail(f"LLM unreachable: {e}")
return
# --- 2. Initialize components ---
print_header("2. Initialize AOM Components")
with tempfile.TemporaryDirectory() as tmpdir:
db_path = Path(tmpdir) / "aom_live_test.db"
store = MemoryStore(db_path, dimensions=32)
await store.initialize()
print_ok(f"MemoryStore initialized: {db_path}")
embedder = FakeEmbeddingPipeline(dimensions=32)
print_ok("FakeEmbeddingPipeline ready (32 dims)")
config = AOMConfig(
enabled=True,
embedding_dimensions=32,
importance_threshold=0.2,
)
ingest = IngestAgent(store, embedder, real_llm_caller, config)
print_ok("IngestAgent ready")
# --- 3. Ingest with REAL LLM extraction ---
print_header("3. Ingest — Real LLM Entity/Topic Extraction")
test_data = [
{
"content": '{"keyword": "buy running shoes online", "search_volume": 14800, "cpc": "$2.30", "competition": "high"}',
"source_type": "mcp_tool",
"source_id": "ahrefs_keywords",
},
{
"content": "Competitor analysis: Nike.com ranks #1 for 'running shoes' with Domain Authority 95. Their top landing page has 2,340 backlinks from 890 referring domains.",
"source_type": "mcp_tool",
"source_id": "ahrefs_backlinks",
},
{
"content": "Google Ads campaign 'Spring Running': CTR 3.8%, CPC $1.95, Conversions 127, ROAS 4.2x. Top performing ad group: 'trail running shoes' with 5.1% CTR.",
"source_type": "mcp_tool",
"source_id": "google_ads",
},
{
"content": "Email campaign 'March Newsletter': sent to 15,000 subscribers, open rate 24.3%, click rate 3.7%, 12 unsubscribes. Best subject line: 'Your spring running guide'.",
"source_type": "skill",
"source_id": "sendgrid_analytics",
},
{
"content": "Social media report: Instagram post about new trail shoes got 1,240 likes, 89 comments, 45 saves. Engagement rate 4.8% vs account average 2.1%.",
"source_type": "mcp_tool",
"source_id": "instagram_insights",
},
]
for i, item in enumerate(test_data):
t0 = time.time()
mem = await ingest.ingest(
content=item["content"],
source_type=item["source_type"],
source_id=item["source_id"],
)
elapsed = time.time() - t0
print_ok(
f"[{i+1}/{len(test_data)}] Ingested in {elapsed:.1f}s | "
f"entities={mem.entities[:3]} | topics={mem.topics[:3]} | "
f"importance={mem.importance:.2f}"
)
stats = await store.get_stats()
print(f"\n Store stats: {json.dumps(stats, indent=2)}")
# --- 4. Test deduplication ---
print_header("4. Deduplication Test")
dup_mem = await ingest.ingest(
content=test_data[0]["content"],
source_type="mcp_tool",
source_id="duplicate_test",
)
stats2 = await store.get_stats()
if stats2["total_memories"] == stats["total_memories"]:
print_ok(f"Dedup works: still {stats2['total_memories']} memories")
else:
print_fail(f"Dedup failed: {stats['total_memories']}{stats2['total_memories']}")
# --- 5. Consolidation with REAL LLM ---
print_header("5. Consolidation — Real LLM Insight Generation")
engine = ConsolidationEngine(store, embedder, real_llm_caller, config)
t0 = time.time()
insights = await engine.run_consolidation_cycle()
elapsed = time.time() - t0
print_ok(f"Generated {len(insights)} insights in {elapsed:.1f}s")
for ins in insights:
print(f"\n Insight: {ins.insight[:200]}")
print(f" Importance: {ins.importance}")
print(f" Based on {len(ins.memory_ids)} memories")
# --- 6. Query with REAL LLM synthesis ---
print_header("6. Query — Real LLM Hybrid Search + Synthesis")
questions = [
"What do we know about running shoes marketing performance?",
"What is our email campaign open rate?",
"How does our Instagram engagement compare to average?",
]
query_agent = QueryAgent(store, embedder, real_llm_caller, config)
for q in questions:
t0 = time.time()
result = await query_agent.query(q, max_results=5)
elapsed = time.time() - t0
print(f"\n Q: {q}")
print(f" A ({elapsed:.1f}s): {result.answer[:300]}")
print(f" Citations: {len(result.citations)}")
for c in result.citations[:3]:
print(f" - [{c.memory.source_type}/{c.memory.source_id}] score={c.score:.4f}")
# --- 7. List all memories ---
print_header("7. Final Memory Dump")
all_mems = await store.list_memories(limit=20)
for m in all_mems:
print(f"\n [{m.source_type}/{m.source_id}] imp={m.importance:.2f}")
print(f" entities: {m.entities}")
print(f" topics: {m.topics}")
print(f" content: {m.content[:100]}...")
# --- 8. Cleanup ---
await store.close()
print_header("DONE — All live tests completed!")
if __name__ == "__main__":
asyncio.run(main())