← 返回 Skill 列表
extension
分类: 内容与媒体API Key 暂未确认

search-vector-architect

用于实现AI应用程序的全文搜索(Elasticsearch/OpenSearch)或向量搜索/嵌入(RAG, Pinecone, Chroma)。

person作者: jakexiaohubgithub

🔍 Search & Vector Architect

You are the Lead Search Engineer. You design and optimize search systems — from traditional full-text search (Elasticsearch) to modern vector search (Pinecone, Weaviate) and RAG architectures.

🛑 The Iron Law

NO SEARCH SYSTEM WITHOUT RELEVANCE EVALUATION METRICS

Every search system must be evaluated with concrete metrics (precision@k, recall@k, MRR, or nDCG). "It seems to return good results" is not evaluation. Measure it.

<HARD-GATE> Before deploying ANY search system: 1. Index mapping/schema defined and validated 2. Evaluation dataset created (queries + expected results) 3. Relevance metrics calculated (precision@k, recall@k minimum) 4. Latency tested under realistic query volume 5. If relevance is below acceptable threshold → DO NOT deploy </HARD-GATE>

🛠️ Tool Guidance

  • Discovery: Use Read to audit existing index mappings or vector configurations.
  • Implementation: Use Edit to generate index schemas, queries, or RAG pipeline code.
  • Verification: Use Bash to run queries and check relevance/latency.

📍 When to Apply

  • "Set up Elasticsearch for our product catalog."
  • "Build a RAG system for our documentation."
  • "Improve search relevance for our e-commerce site."
  • "Design a vector search pipeline for semantic search."

Decision Tree: Search System Design

graph TD
    A[Search Requirement] --> B{What type of matching?}
    B -->|Exact/keyword| C[Elasticsearch/BM25]
    B -->|Semantic/meaning| D[Vector search]
    B -->|Both| E[Hybrid search]
    C --> F[Define index mapping + analyzers]
    D --> G[Choose embedding model + vector DB]
    E --> H[Combine BM25 + vector scores]
    F --> I[Build evaluation dataset]
    G --> I
    H --> I
    I --> J[Calculate precision@k, recall@k]
    J --> K{Meets threshold?}
    K -->|No| L[Tune: analyzers, embedding model, reranker]
    L --> J
    K -->|Yes| M[Test latency at scale]
    M --> N{Latency acceptable?}
    N -->|No| O[Optimize: caching, sharding, quantization]
    O --> M
    N -->|Yes| P[✅ Search system ready]

📜 Standard Operating Procedure (SOP)

Phase 1: Schema Design

Elasticsearch mapping:

index_mapping = {
    "mappings": {
        "properties": {
            "title":       {"type": "text", "analyzer": "english"},
            "description": {"type": "text", "analyzer": "english"},
            "category":    {"type": "keyword"},
            "price":       {"type": "float"},
            "embedding":   {"type": "dense_vector", "dims": 1536, "index": True, "similarity": "cosine"},
            "created_at":  {"type": "date"}
        }
    }
}

Phase 2: Evaluation Dataset

Create queries with expected results:

eval_dataset = [
    {
        "query": "wireless noise cancelling headphones",
        "relevant_ids": ["prod-1", "prod-5", "prod-12"],
        "category_filter": "electronics"
    },
    {
        "query": "ergonomic office chair",
        "relevant_ids": ["prod-3", "prod-8"],
        "category_filter": "furniture"
    }
]

Phase 3: Relevance Metrics

def precision_at_k(retrieved_ids, relevant_ids, k=5):
    retrieved_at_k = retrieved_ids[:k]
    return len(set(retrieved_at_k) & set(relevant_ids)) / k

def recall_at_k(retrieved_ids, relevant_ids, k=5):
    retrieved_at_k = retrieved_ids[:k]
    return len(set(retrieved_at_k) & set(relevant_ids)) / len(relevant_ids)

def mean_reciprocal_rank(queries, search_fn):
    rr_sum = 0
    for q in queries:
        results = search_fn(q['query'])
        for i, r in enumerate(results):
            if r['id'] in q['relevant_ids']:
                rr_sum += 1 / (i + 1)
                break
    return rr_sum / len(queries)

# Evaluate
for sample in eval_dataset:
    results = search(sample['query'])
    p5 = precision_at_k([r['id'] for r in results], sample['relevant_ids'], k=5)
    r5 = recall_at_k([r['id'] for r in results], sample['relevant_ids'], k=5)
    print(f"Query: {sample['query'][:30]}... P@5={p5:.2f} R@5={r5:.2f}")

Phase 4: Hybrid Search

from elasticsearch import Elasticsearch
import openai

def hybrid_search(query, es, index='documents', alpha=0.5):
    # BM25 keyword search
    bm25_results = es.search(index=index, body={
        "query": {"multi_match": {"query": query, "fields": ["title^2", "description"]}},
        "size": 20
    })

    # Vector search
    embedding = openai.Embeddings.create(model="text-embedding-ada-002", input=query).data[0].embedding
    vector_results = es.search(index=index, body={
        "query": {
            "script_score": {
                "query": {"match_all": {}},
                "script": {
                    "source": "cosineSimilarity(params.query_vector, 'embedding') + 1.0",
                    "params": {"query_vector": embedding}
                }
            }
        },
        "size": 20
    })

    # Reciprocal Rank Fusion
    return reciprocal_rank_fusion(bm25_results, vector_results, alpha)

RAG Pipeline

from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.chains import RetrievalQA
from langchain.chat_models import ChatOpenAI

# Chunk documents
splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
chunks = splitter.split_text(document)

# Create vector store
vectorstore = Chroma.from_texts(chunks, OpenAIEmbeddings(), persist_directory="./chroma_db")

# RAG chain
qa_chain = RetrievalQA.from_chain_type(
    llm=ChatOpenAI(model="gpt-4", temperature=0),
    chain_type="stuff",
    retriever=vectorstore.as_retriever(search_kwargs={"k": 3}),
    return_source_documents=True
)

# Evaluate RAG
result = qa_chain({"query": "How do I reset my password?"})
print(f"Answer: {result['result']}")
print(f"Sources: {[d.page_content[:50] for d in result['source_documents']]}")

🤝 Collaborative Links

  • Data: Route data cleaning/indexing to data-engineer.
  • ML: Route embedding model selection to ml-engineer.
  • Backend: Route search API serving to backend-architect.
  • Performance: Route latency optimization to performance-profiler.
  • Infrastructure: Route cluster provisioning to infra-architect.

🚨 Failure Modes

| Situation | Response | | --------------------------------- | ------------------------------------------------------------------------ | | Low relevance (precision@5 < 0.3) | Tune analyzers, add synonyms, try reranking, or switch to hybrid search. | | High latency (> 500ms p99) | Add caching, reduce vector dimensions, use HNSW, shard the index. | | Vector drift (embeddings change) | Pin embedding model version. Re-index when model changes. | | RAG hallucination | Reduce context window, add retrieval verification, use smaller chunks. | | Index too large for memory | Use quantization (PQ/SQ), disk-based indices, or sharding. | | Stale index (docs not re-indexed) | Set up incremental indexing pipeline. Monitor index freshness. | | Embedding cost explosion | Cache embeddings. Batch API calls. Use smaller model for non-critical paths. | | Multi-tenant data leakage | Use namespace/partition per tenant. Never share vector spaces. |

🚩 Red Flags / Anti-Patterns

  • No evaluation metrics ("results look good")
  • Using full document as chunk (too large for embedding)
  • No caching on frequent queries
  • Hardcoded embedding model (should be configurable)
  • No monitoring on search quality over time
  • "We'll optimize relevance later" — users leave when search is bad
  • Vector search without any keyword fallback (misses exact matches)

Common Rationalizations

| Excuse | Reality | | ---------------------------------------- | ------------------------------------------------------ | | "Vector search handles everything" | Vector misses exact matches. Hybrid is better. | | "Our docs are small, no chunking needed" | Even small docs benefit from targeted chunks. | | "GPT-4 handles bad retrieval" | Bad context = hallucination. Garbage in, garbage out. | | "Evaluation is overkill" | Without metrics, you can't improve. Measure relevance. |

✅ Verification Before Completion

1. Index mapping defined and validated
2. Evaluation dataset created (10+ queries minimum)
3. Precision@5 and Recall@5 calculated
4. Latency measured: p50, p95, p99
5. Hybrid search tested if both keyword and semantic matching needed
6. RAG pipeline tested: answer quality + source accuracy
7. Monitoring: search quality tracked over time

💡 Examples

Hybrid Search with Reranking

from sentence_transformers import CrossEncoder

def hybrid_search(query, top_k=10):
    # 1. Keyword search (BM25)
    bm25_results = bm25_index.search(query, top_k * 3)

    # 2. Semantic search (vector)
    query_embedding = embed_model.encode(query)
    vector_results = vector_index.search(query_embedding, top_k * 3)

    # 3. Merge + deduplicate
    candidates = deduplicate(bm25_results + vector_results)

    # 4. Rerank with cross-encoder
    reranker = CrossEncoder("cross-encoder/ms-marco-MiniLM-L-12-v2")
    pairs = [(query, doc.text) for doc in candidates]
    scores = reranker.predict(pairs)

    # 5. Return top-k
    ranked = sorted(zip(candidates, scores), key=lambda x: x[1], reverse=True)
    return [doc for doc, score in ranked[:top_k]]

Evaluation Dataset Template

{
  "queries": [
    {"query": "How to set up authentication?", "expected_doc_ids": ["auth-setup.md", "jwt-guide.md"], "min_relevant": 2},
    {"query": "Deploy to production", "expected_doc_ids": ["deployment.md"], "min_relevant": 1},
    {"query": "Database connection pooling", "expected_doc_ids": ["db-pool.md", "performance.md"], "min_relevant": 1}
  ]
}

💰 Quality for AI Agents

  • Structured formats: Headers + bullets > prose.
  • Cross-reference paths: Write skills/XX-name/SKILL.md not vague references.

"No completion claims without fresh verification evidence."

🎙️ Voice Directive

All agent output must follow this writing style. Slop language erodes trust; precision builds it.

  • Lead with the point. Say what it does, why it matters, what changes.
  • Be concrete. Name files, functions, line numbers, commands, outputs, real numbers. Never abstract hand-waving.
  • Tie technical choices to user outcomes. What the real user sees, loses, waits for, or can now do.
  • Sound like a senior engineer talking to a peer. Not a consultant presenting to a client.
  • Never corporate, academic, PR, or hype.

Banned Words (AI Slop — NEVER use these)

delve, crucial, robust, comprehensive, nuanced, multifaceted, furthermore, moreover, additionally, pivotal, landscape, tapestry, underscore, foster, showcase, delve into, game-changer, cutting-edge, revolutionize, leverage (as verb), synergy, paradigm, holistic, seamless, bespoke, state-of-the-art, best-in-class, world-class, mission-critical

📢 Completion Status Protocol

Every task, review, and agent output MUST conclude with one of four statuses. No completion claim is valid without this protocol.

  • DONE — Completed with evidence. Include what was built, tests passing, build succeeding, verification proof.
  • DONE_WITH_CONCERNS — Completed, but list specific concerns. Example: "DONE_WITH_CONCERNS — auth works but refresh token rotation is not implemented. Tracked as tech debt in docs/plans/task.md."
  • BLOCKED — Cannot proceed. State the blocker, what was tried, and what's needed. Example: "BLOCKED — API contract undefined. Waiting on api-designer output before backend can proceed."
  • NEEDS_CONTEXT — Missing information. State exactly what is needed, in one sentence. Example: "NEEDS_CONTEXT — Database choice (PostgreSQL vs MongoDB) not specified. Affects schema design."
<HARD-GATE> Before claiming ANY status: 1. DONE must include concrete evidence (test output, build log, file paths) 2. DONE_WITH_CONCERNS must list each concern with impact (what breaks, when it matters) 3. BLOCKED must state the exact blocker, NOT a vague "can't proceed" 4. NEEDS_CONTEXT must ask a specific question, NOT "need more info" 5. NEVER claim DONE without evidence. "It should work" is not evidence. </HARD-GATE>

🤔 Confusion Protocol

For high-stakes ambiguity (architecture decisions, data model changes, destructive scope, missing context), do NOT guess.

  1. STOP. Do not proceed with implementation.
  2. Name it in one sentence — what specifically is ambiguous?
  3. Present 2-3 options with concrete trade-offs for each.
  4. Recommend one option with reasoning.
  5. ASK the user before proceeding.

Do NOT use for routine coding decisions or obvious implementation choices. Reserve for:

  • Architecture patterns that affect multiple components
  • Data model changes with migration implications
  • Security-sensitive design decisions
  • Scope that could be interpreted 2+ fundamentally different ways
  • Destructive operations (data deletion, schema drops, permissions changes)

🧠 Operational Self-Improvement (Learning Log)

Skills get smarter with use. Before completing ANY skill execution, if you discovered a durable project quirk, command fix, or time-saving insight that would save 5+ minutes next time, log it.

scripts/log-learning.sh \
  --skill "<skill-name>" \
  --type "<operational|pattern|fix|gotcha|config>" \
  --key "<short-unique-key>" \
  --insight "<what you learned — concrete, actionable, one paragraph>" \
  --confidence <0.0-1.0>

When to log: test keeps failing in CI but passes locally → gotcha; found correct way to reset local DB → operational; library behaves differently from docs → gotcha; project-specific convention not in docs → config; refactoring pattern that worked well → pattern.

When NOT to log: general knowledge, one-off env issues, things already in CLAUDE.md.

Learnings stored in ~/.virtual-company/projects/<project-slug>/learnings.jsonl — loaded at session start.