用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/aiskillstore/marketplace --skill search-engineer命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
Maintain a portable task-state ledger for long, multi-step work. Use when a task spans many files, produces large logs, needs a reliable handoff, or requires traceable evidence without repeatedly loading full outputs. Creates concise state records and private evidence references with explicit limits, redaction checks, and retention guidance.
【收纳储物必看】装修前不会规划收纳,入住半年家变仓库?这个 Skill 内置装修课堂会员版「家居收纳储物方法」152篇原创知识库,专门讲收纳储物——收纳是家的骨架、柜子不是越多越好、收纳本质是把东西藏起来、收纳加勤快缺一不可。问玄关鞋柜怎么装、问厨房9个收纳位置、问衣柜衣帽间怎么做、问小户型怎么榨干每1平米、问收纳避坑和鸡肋神器,全部覆盖。适合正在装修、准备收纳规划、家里东西多总是乱、想做满墙柜/通顶柜/800库的业主。
【儿童房装修必看】家里有小孩、正准备要孩子、或想给儿童房做环保安全装修?这个 Skill 内置装修课堂知识库,专门讲"适童化"——儿童是最易受甲醛伤害的人群,儿童房必须实木/ENF/控总量。问儿童房怎么装环保、问儿童房墙面地面用什么、问儿童家具选实木还是人造板、问孩子学习/游戏专区怎么规划、问有娃家庭怎么防磕碰防污染,全部覆盖。适合家里有娃、备孕婚房、想装出健康儿童房的业主。
基于 SOC 职业分类
正在显示 SKILL.md
| name | search-engineer |
| description | 搜索工程师 Agent — 覆盖搜索引擎搭建、索引构建、检索排序、查询理解、语义搜索、RAG系统、性能优化、质量评估全流程。支持Elasticsearch/Solr/Milvus等主流引擎。 |
搜索工程师 Agent,负责从零搭建搜索系统、优化检索质量、构建语义搜索/RAG管道、排查搜索性能问题。覆盖索引构建→检索算法→排序优化→查询理解→评估体系→架构部署全链路。
Elasticsearch 集群搭建
# 安装(macOS)
brew install elasticsearch
# 或 Docker
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}})
评估指标计算
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
中文分词配置(Elasticsearch IK分词器)
# 安装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)
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]
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
}
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)
}
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])
缓存策略
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)) # 5分钟过期
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()
}
# Elasticsearch
curl -X GET "localhost:9200/_cat/indices?v" # 查看索引
curl -X GET "localhost:9200/index/_search?q=keyword" # 搜索
curl -X DELETE "localhost:9200/index" # 删除索引
# Milvus
docker run -d --name milvus -p 19530:19530 milvusdb/milvus:latest
# 安装Python依赖
pip install elasticsearch pymilvus sentence-transformers redis langchain chromadb