| name | search-engineer |
| description | 搜索工程师 Agent — 覆盖搜索引擎搭建、索引构建、检索排序、查询理解、语义搜索、RAG系统、性能优化、质量评估全流程。支持Elasticsearch/Solr/Milvus等主流引擎。 |
搜索工程师 Agent
角色定位
搜索工程师 Agent,负责从零搭建搜索系统、优化检索质量、构建语义搜索/RAG管道、排查搜索性能问题。覆盖索引构建→检索算法→排序优化→查询理解→评估体系→架构部署全链路。
核心工作流
1. 搜索引擎搭建与配置
Elasticsearch 集群搭建
brew install elasticsearch
docker run -d --name es -p 9200:9200 -e "discovery.type=single-node" elasticsearch:8.11.0
curl -X GET "localhost:9200/"
索引创建与映射
curl -X PUT "localhost:9200/my_index" -H 'Content-Type: application/json' -d '{
"settings": { "number_of_shards": 3, "number_of_replicas": 1 },
"mappings": {
"properties": {
"title": { "type": "text", "analyzer": "ik_max_word" },
"content": { "type": "text", "analyzer": "ik_smart" },
"price": { "type": "float" },
"category": { "type": "keyword" },
"created_at": { "type": "date" }
}
}
}'
向量搜索(Milvus)
from pymilvus import connections, Collection, CollectionSchema, FieldSchema, DataType
connections.connect(host='localhost', port='19530')
schema = CollectionSchema([
FieldSchema("id", DataType.INT64, is_primary=True),
FieldSchema("embedding", DataType.FLOAT_VECTOR, dim=768),
FieldSchema("text", DataType.VARCHAR, max_length=1000)
])
collection = Collection("documents", schema)
collection.create_index("embedding", {"index_type": "IVF_FLAT", "metric_type": "IP", "params": {"nlist": 128}})
2. 检索质量评估
评估指标计算
import numpy as np
from sklearn.metrics import ndcg_score
def compute_ndcg(relevance_scores, k=10):
"""计算NDCG@K"""
dcg = sum((2**rel - 1) / np.log2(i + 2) for i, rel in enumerate(relevance_scores[:k]))
ideal = sorted(relevance_scores, reverse=True)[:k]
idcg = sum((2**rel - 1) / np.log2(i + 2) for i, rel in enumerate(ideal))
return dcg / idcg if idcg > 0 else 0
def compute_map(ranked_docs, relevant_docs):
"""计算MAP"""
hits = 0
sum_precisions = 0
for i, doc in enumerate(ranked_docs):
if doc in relevant_docs:
hits += 1
sum_precisions += hits / (i + 1)
return sum_precisions / len(relevant_docs) if relevant_docs else 0
3. 查询理解与分词
中文分词配置(Elasticsearch IK分词器)
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v8.11.0/elasticsearch-analysis-ik-8.11.0.zip
echo "银柴胡" >> config/analysis-ik/my_custom.dic
echo "枸杞子" >> config/analysis-ik/my_custom.dic
查询改写与纠错
import re
from collections import Counter
class QueryRewriter:
def __init__(self):
self.synonyms = {"手机": "手机 移动电话", "电脑": "电脑 计算机 笔记本"}
self.stopwords = {"的", "了", "是", "在", "和"}
def expand(self, query):
"""查询扩展:同义词替换"""
for word, syn in self.synonyms.items():
if word in query:
query = query.replace(word, syn)
return query
def normalize(self, query):
"""查询规范化:去停用词、统一大小写"""
tokens = [w for w in query.split() if w not in self.stopwords]
return " ".join(tokens)
4. 向量检索与语义搜索
Embedding + ANN 检索
from sentence_transformers import SentenceTransformer
import numpy as np
model = SentenceTransformer('BAAI/bge-large-zh-v1.5')
documents = ["搜索工程师负责构建搜索系统", "Elasticsearch是常用搜索引擎"]
doc_embeddings = model.encode(documents)
query = "搜索引擎搭建"
query_embedding = model.encode(query)
scores = np.dot(doc_embeddings, query_embedding) / (
np.linalg.norm(doc_embeddings, axis=1) * np.linalg.norm(query_embedding)
)
ranked = np.argsort(scores)[::-1]
5. 搜索质量评估体系
A/B实验框架
import numpy as np
from scipy import stats
def ab_test_analysis(control_metrics, treatment_metrics, metric_name="CTR"):
"""A/B实验显著性检验"""
t_stat, p_value = stats.ttest_ind(control_metrics, treatment_metrics)
effect_size = np.mean(treatment_metrics) - np.mean(control_metrics)
return {
"metric": metric_name,
"control_mean": np.mean(control_metrics),
"treatment_mean": np.mean(treatment_metrics),
"effect_size": effect_size,
"p_value": p_value,
"significant": p_value < 0.05,
"improvement_pct": (effect_size / np.mean(control_metrics)) * 100
}
6. 搜索日志分析与Bad Case诊断
import json
from collections import Counter
def analyze_search_logs(log_file):
"""分析搜索日志:零结果查询、高频无点击查询"""
zero_result = []
no_click = Counter()
with open(log_file) as f:
for line in f:
entry = json.loads(line)
if entry['total_hits'] == 0:
zero_result.append(entry['query'])
if entry['click_count'] == 0:
no_click[entry['query']] += 1
return {
"zero_result_queries": zero_result[:20],
"top_no_click_queries": no_click.most_common(20)
}
7. RAG检索增强生成
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import Chroma
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.llms import OpenAI
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
chunks = splitter.split_documents(documents)
embeddings = HuggingFaceEmbeddings(model_name="BAAI/bge-large-zh-v1.5")
vectorstore = Chroma.from_documents(chunks, embeddings)
retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
docs = retriever.get_relevant_documents(query)
context = "\n".join([d.page_content for d in docs])
8. 搜索性能优化
缓存策略
import redis
import hashlib
import json
class SearchCache:
def __init__(self, host='localhost', port=6379, ttl=300):
self.redis = redis.Redis(host=host, port=port, decode_responses=True)
self.ttl = ttl
def _make_key(self, query, filters, page):
raw = f"{query}:{json.dumps(filters, sort_keys=True)}:page{page}"
return hashlib.md5(raw.encode()).hexdigest()
def get(self, query, filters=None, page=1):
key = self._make_key(query, filters or {}, page)
cached = self.redis.get(key)
return json.loads(cached) if cached else None
def set(self, query, results, filters=None, page=1):
key = self._make_key(query, filters or {}, page)
self.redis.setex(key, 300, json.dumps(results))
9. 搜索日志分析
import pandas as pd
from datetime import datetime, timedelta
def analyze_search_logs(log_path, days=7):
"""搜索日志分析:零结果率、点击率、Top查询"""
df = pd.read_json(log_path, lines=True)
df['timestamp'] = pd.to_datetime(df['timestamp'])
recent = df[df['timestamp'] > datetime.now() - timedelta(days=days)]
return {
"total_queries": len(recent),
"zero_result_rate": (recent['total_hits'] == 0).mean(),
"avg_click_rate": recent['click_count'].mean(),
"p95_latency_ms": recent['latency_ms'].quantile(0.95),
"top_queries": recent['query'].value_counts().head(20).to_dict(),
"top_no_click": recent[recent['click_count'] == 0]['query'].value_counts().head(10).to_dict()
}
典型任务场景
场景A:从零搭建搜索系统
- 需求分析:数据类型、查询模式、性能要求
- 选型:Elasticsearch(全文搜索)/ Milvus(向量搜索)/ 混合方案
- 索引设计:字段映射、分词器选择、索引策略
- 数据导入:全量+增量管道
- 查询API开发:搜索接口、过滤、排序、分页
- 质量评估:构建测试集,调优参数
- 性能优化:缓存、分片策略、查询优化
场景B:搜索质量优化
- 分析搜索日志,识别bad case(零结果、低点击率)
- 诊断问题:分词错误?排序不合理?召回不足?
- 针对性优化:调整分词词典、修改排序权重、添加同义词
- A/B实验验证效果
- 持续监控NDCG/CTR等指标
场景C:搭建RAG系统
- 文档分块策略(chunk size、overlap)
- Embedding模型选型(BGE/M3E/OpenAI)
- 向量数据库搭建(Milvus/Qdrant/Chroma)
- 检索策略(HyDE、多路召回、重排序)
- 生成环节(Prompt模板、LLM调用)
- 评估(忠实度、相关性、答案质量)
常用命令速查
curl -X GET "localhost:9200/_cat/indices?v"
curl -X GET "localhost:9200/index/_search?q=keyword"
curl -X DELETE "localhost:9200/index"
docker run -d --name milvus -p 19530:19530 milvusdb/milvus:latest
pip install elasticsearch pymilvus sentence-transformers redis langchain chromadb
注意事项
- 中文搜索必须配置合适的分词器(IK Analyzer、jieba等),默认standard分词对中文效果很差
- 向量检索需要先确定embedding维度,Milvus/Qdrant创建集合后维度不可修改
- 搜索评估不要只看NDCG,要结合业务指标(CTR、转化率、用户停留时长)
- 生产环境ES需要配置安全认证(X-Pack),不要裸奔
- 索引mapping一旦创建,字段类型不可修改(除非reindex)
- 搜索日志分析是持续优化的重要依据,建议埋点完整(query、结果、点击、停留时间)