上一篇 下一篇 分享链接 返回 返回顶部

把 AI 搜索成本打下来:从检索、缓存到本地部署的完整实操指南

发布人:慈云数据-客服中心 发布时间:19小时前 阅读量:4

AI搜索 如何降低成本|附完整命令

在企业落地 AI 搜索、知识库问答、RAG 检索增强生成系统时,很多团队一开始最关注的是“效果”:能不能搜得准、答得好、引用是否可靠。但真正上线后,大家很快会遇到另一个更现实的问题:成本太高

AI 搜索的成本并不只来自大模型调用。一次完整的 AI 搜索请求,可能涉及文档解析、文本切分、向量化、向量数据库检索、关键词检索、重排序、上下文拼接、大模型生成、日志存储、监控告警等多个环节。任何一个环节设计不当,都会导致成本迅速上升。

本文将系统拆解 AI 搜索的成本来源,并给出一套可落地的降本方案。文末附完整命令,帮助你快速搭建一套本地低成本 AI 搜索原型。


一、AI搜索的成本主要花在哪里?

一个典型的 AI 搜索系统通常包括以下流程:

用户问题
  ↓
问题改写 / 意图识别
  ↓
向量检索 / 关键词检索
  ↓
结果重排序
  ↓
上下文拼接
  ↓
大模型生成答案
  ↓
返回答案与引用来源

其中主要成本来自以下几个方面。


二、成本来源一:Embedding 向量化成本

Embedding 是 AI 搜索的基础。无论是文档入库,还是用户提问时进行相似度检索,通常都需要将文本转换成向量。

1. 文档入库时的向量化成本

如果企业有大量 PDF、Word、网页、知识库文档,每次入库都需要调用 embedding 模型。例如:

  • 10 万段文本;
  • 每段 500 tokens;
  • 总计 5000 万 tokens;
  • 如果使用云端 embedding API,就会产生持续费用。

2. 查询时的向量化成本

每个用户问题都要进行一次 query embedding。单次成本不高,但高并发下会明显增加。

降本方法

方法一:使用本地 embedding 模型

例如使用:

  • bge-small-zh-v1.5
  • bge-base-zh-v1.5
  • bge-m3
  • multilingual-e5-small
  • gte-small

这些模型可以部署在本地或私有云中,用 CPU 也可以运行,成本主要是机器成本。

方法二:文档只向量化一次

文档入库后,如果内容没有变化,不要重复向量化。可以为文档生成 hash:

文档内容 → hash → 判断是否变化 → 未变化则跳过向量化

方法三:合理控制切分粒度

切分太细,会产生更多 chunk,向量化成本更高;切分太粗,检索效果下降。

一般建议:

中文知识库:每段 300~800 字
英文知识库:每段 300~700 tokens
chunk overlap:50~100 字

三、成本来源二:向量数据库存储与检索成本

向量数据库用于存储 embedding,并支持相似度搜索。常见方案包括:

  • Milvus
  • Qdrant
  • Weaviate
  • Elasticsearch Vector
  • PostgreSQL + pgvector
  • Redis Vector
  • FAISS

如果数据规模很大,向量维度很高,存储成本会很快增加。

降本方法

方法一:选择合适的向量维度

很多团队一开始就使用 1536、3072 维的 embedding,但并不是所有业务都需要这么高的维度。

例如:

场景 推荐维度
小型企业知识库 384~768
中文客服问答 512~1024
多语言搜索 768~1024
高精度法律 / 医疗场景 1024 以上

维度越高,存储成本和计算成本越高。

方法二:冷热数据分层

不是所有文档都需要常驻高性能向量库。

可以分为:

热数据:最近常用文档,放在向量库
温数据:偶尔访问,放在低成本存储
冷数据:归档数据,只在需要时重新索引或异步检索

方法三:定期清理无效向量

很多系统上线后会不断上传新文档,但不会删除旧向量。结果是数据库越来越大,成本越来越高。

应定期清理:

  • 已删除文档对应的向量;
  • 重复文档;
  • 过期版本;
  • 低质量 chunk;
  • 无引用来源的数据。

四、成本来源三:大模型生成成本

AI 搜索中最贵的部分,通常不是检索,而是大模型生成答案。

一次 RAG 请求可能会把多个检索结果拼接进 prompt。上下文越长,消耗 tokens 越多,成本越高。

例如:

系统提示词:500 tokens
用户问题:50 tokens
检索上下文:6000 tokens
模型回答:800 tokens
总计:7350 tokens

如果每次请求都这样处理,在高并发场景下费用会非常可观。

降本方法

方法一:减少上下文长度

不要把 Top 20 的结果全部塞给大模型。更合理的方式是:

先召回 Top 20
再重排序 Top 5
最后只传 Top 3 给大模型

这样可以显著减少 prompt tokens。

方法二:使用小模型处理简单问题

不是所有问题都需要最强模型。

可以建立模型路由:

问题类型 推荐模型
简单 FAQ 小模型 / 规则匹配
普通知识问答 中等模型
复杂推理问题 高级模型
敏感或高价值问题 高级模型 + 审核

例如:

如果命中 FAQ,直接返回答案;
如果问题简单,使用本地小模型;
如果需要复杂推理,再调用云端大模型。

方法三:答案缓存

大量用户会重复问类似问题,例如:

  • “怎么重置密码?”
  • “发票怎么开?”
  • “怎么申请退款?”
  • “接口限流是多少?”

可以对问题归一化后缓存答案。

缓存策略:

问题 → 标准化 → embedding → 相似问题匹配 → 命中缓存则直接返回

这样可以避免重复调用大模型。


五、成本来源四:重排序模型成本

为了提高准确率,很多 AI 搜索系统会使用 reranker 模型,例如:

  • bge-reranker-base
  • bge-reranker-large
  • Cohere Rerank
  • Jina Reranker
  • 云厂商 rerank API

重排序效果很好,但如果每次对大量候选结果进行 rerank,成本也会增加。

降本方法

1. 控制候选数量

推荐:

向量召回 Top 20~50
关键词召回 Top 20~50
合并去重后最多 rerank 20 条
最终取 Top 3~5

不要对 Top 100、Top 200 全量重排序。

2. 只在必要时 rerank

以下场景可以跳过 rerank:

  • 关键词精准命中标题;
  • FAQ 完全匹配;
  • 向量相似度明显高于其他结果;
  • 用户只是查询固定字段。

3. 使用本地 reranker

本地部署 bge-reranker-base,在访问量稳定时,通常比持续调用 API 更低成本。


六、推荐的低成本 AI 搜索架构

一个比较适合中小团队的降本架构如下:

                   ┌──────────────┐
                   │   用户问题    │
                   └──────┬───────┘
                          ↓
                   ┌──────────────┐
                   │  问题标准化   │
                   └──────┬───────┘
                          ↓
        ┌─────────────────────────────────┐
        │      缓存 / FAQ / 规则匹配       │
        └──────────────┬──────────────────┘
                       │ 未命中
                       ↓
        ┌─────────────────────────────────┐
        │  Hybrid Search:向量 + 关键词    │
        └──────────────┬──────────────────┘
                       ↓
        ┌─────────────────────────────────┐
        │        轻量 rerank Top N         │
        └──────────────┬──────────────────┘
                       ↓
        ┌─────────────────────────────────┐
        │   拼接少量上下文,调用模型生成    │
        └──────────────┬──────────────────┘
                       ↓
        ┌─────────────────────────────────┐
        │       返回答案 + 引用来源        │
        └─────────────────────────────────┘

这个架构的核心思想是:

能不用大模型就不用大模型,能用小模型就不用大模型,能少传上下文就少传上下文,能缓存就缓存。


七、具体降本策略清单

下面是一份可以直接用于项目评审的降本清单。

1. 文档处理阶段

  • 删除重复文档;
  • 对文档内容计算 hash;
  • 未变化文档不重新入库;
  • 过滤页眉、页脚、目录、版权声明等低价值内容;
  • 控制 chunk 大小;
  • 避免过大的 overlap;
  • 图片 OCR 按需执行,不要默认全量 OCR。

2. 向量化阶段

  • 优先使用本地 embedding;
  • 批量处理 embedding;
  • 降低向量维度;
  • 对失败任务重试,但避免无限重试;
  • 文档版本变更时只处理变化部分。

3. 检索阶段

  • 使用 hybrid search;
  • 先粗召回,再精排;
  • 控制 Top K;
  • 设置最低相似度阈值;
  • 无关结果不要传给大模型;
  • 高频问题走缓存。

4. 生成阶段

  • 控制 prompt 模板长度;
  • 控制上下文数量;
  • 控制最大输出 tokens;
  • 简单问题使用小模型;
  • 复杂问题再调用强模型;
  • 流式输出提升体验,但不要放任无限生成。

5. 监控阶段

必须记录以下指标:

每次请求的输入 tokens
每次请求的输出 tokens
检索耗时
rerank 耗时
模型生成耗时
缓存命中率
平均单次请求成本
每日总成本
用户满意度
无答案率

没有监控,就无法持续降本。


八、本地低成本 AI 搜索方案

下面给出一套本地可运行的示例方案:

  • 向量数据库:Qdrant
  • 本地大模型:Ollama
  • 本地 embedding:Ollama embedding 模型
  • 后端:Python
  • 检索框架:LangChain
  • 文档格式:Markdown / TXT / PDF

这套方案适合:

  • 内部知识库;
  • 小型客服系统;
  • 产品文档搜索;
  • 研发文档问答;
  • 本地验证 RAG 流程。

九、完整命令:搭建本地 AI 搜索环境

以下命令以 macOS / Linux 为例。


1. 创建项目目录

mkdir low-cost-ai-search
cd low-cost-ai-search

2. 创建 Python 虚拟环境

python3 -m venv .venv
source .venv/bin/activate

如果是 Windows PowerShell:

python -m venv .venv
.\.venv\Scripts\Activate.ps1

3. 安装依赖

pip install -U pip
pip install langchain langchain-community langchain-qdrant qdrant-client ollama pypdf fastapi uvicorn python-dotenv

4. 启动 Qdrant 向量数据库

如果你已经安装 Docker,可以执行:

docker run -d \
  --name qdrant \
  -p 6333:6333 \
  -p 6334:6334 \
  -v "$(pwd)/qdrant_storage:/qdrant/storage" \
  qdrant/qdrant

检查 Qdrant 是否启动:

curl http://localhost:6333

如果返回类似下面内容,说明启动成功:

{"title":"qdrant - vector search engine","version":"x.x.x"}

5. 安装 Ollama

macOS 可以使用:

brew install ollama

Linux 可以使用:

curl -fsSL https://ollama.com/install.sh | sh

启动 Ollama:

ollama serve

如果提示端口已占用,说明 Ollama 可能已经在后台运行。


6. 下载本地模型

下载一个生成模型:

ollama pull qwen2.5:7b

下载一个 embedding 模型:

ollama pull nomic-embed-text

如果机器配置较低,可以使用更小的模型:

ollama pull qwen2.5:3b

查看已安装模型:

ollama list

十、创建示例文档

创建文档目录:

mkdir docs

创建一个示例知识库文件:

cat > docs/company_policy.md <<'EOF'
# 公司报销制度

员工因公产生的交通费、住宿费、餐饮费可以申请报销。

## 报销时间

员工应在费用发生后的30天内提交报销申请。

## 报销材料

报销时需要提供合法有效的发票、费用说明、审批记录。

## 审批流程

员工提交报销申请后,由直属主管审批。金额超过5000元的,需要部门负责人二次审批。

## 注意事项

个人消费、非工作相关支出、无票据支出原则上不予报销。
EOF

再创建一个产品文档:

cat > docs/product_api.md <<'EOF'
# 产品 API 使用说明

本产品提供 REST API 服务,支持用户管理、订单查询和数据同步。

## 鉴权方式

所有 API 请求都需要在 Header 中携带 Authorization 字段。

格式如下:

Authorization: Bearer 

## 限流规则

默认情况下,每个账号每分钟最多请求600次。

如果超过限制,接口会返回 HTTP 429 状态码。

## 错误码

401 表示认证失败。
403 表示没有权限。
429 表示请求过于频繁。
500 表示服务器内部错误。
EOF

十一、编写入库脚本

创建 ingest.py

cat > ingest.py <<'EOF'
import os
from langchain_community.document_loaders import DirectoryLoader, TextLoader, PyPDFLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.embeddings import OllamaEmbeddings
from langchain_qdrant import QdrantVectorStore
from qdrant_client import QdrantClient

DOCS_DIR = "docs"
COLLECTION_NAME = "knowledge_base"
QDRANT_URL = "http://localhost:6333"

def load_documents():
    docs = []

    for root, _, files in os.walk(DOCS_DIR):
        for file in files:
            path = os.path.join(root, file)

            if file.endswith(".md") or file.endswith(".txt"):
                loader = TextLoader(path, encoding="utf-8")
                docs.extend(loader.load())

            elif file.endswith(".pdf"):
                loader = PyPDFLoader(path)
                docs.extend(loader.load())

    return docs

def main():
    documents = load_documents()

    splitter = RecursiveCharacterTextSplitter(
        chunk_size=500,
        chunk_overlap=80,
        separators=["\n\n", "\n", "。", "!", "?", ";", ",", " ", ""]
    )

    chunks = splitter.split_documents(documents)

    embeddings = OllamaEmbeddings(
        model="nomic-embed-text",
        base_url="http://localhost:11434"
    )

    client = QdrantClient(url=QDRANT_URL)

    QdrantVectorStore.from_documents(
        documents=chunks,
        embedding=embeddings,
        url=QDRANT_URL,
        collection_name=COLLECTION_NAME,
        force_recreate=True
    )

    print(f"入库完成,共写入 {len(chunks)} 个文本块。")

if __name__ == "__main__":
    main()
EOF

执行入库:

python ingest.py

十二、编写查询脚本

创建 query.py

cat > query.py <<'EOF'
from langchain_community.embeddings import OllamaEmbeddings
from langchain_qdrant import QdrantVectorStore
from langchain_community.llms import Ollama

COLLECTION_NAME = "knowledge_base"
QDRANT_URL = "http://localhost:6333"

PROMPT_TEMPLATE = """
你是一个严谨的企业知识库助手。
请只根据下面提供的上下文回答问题。
如果上下文中没有答案,请回答:根据现有资料无法确定。

上下文:
{context}

问题:
{question}

请用中文回答,并尽量简洁。
"""

def main():
    question = input("请输入问题:")

    embeddings = OllamaEmbeddings(
        model="nomic-embed-text",
        base_url="http://localhost:11434"
    )

    vectorstore = QdrantVectorStore.from_existing_collection(
        embedding=embeddings,
        url=QDRANT_URL,
        collection_name=COLLECTION_NAME
    )

    docs = vectorstore.similarity_search(
        question,
        k=3
    )

    context = "\n\n".join([
        f"来源:{doc.metadata.get('source', 'unknown')}\n内容:{doc.page_content}"
        for doc in docs
    ])

    llm = Ollama(
        model="qwen2.5:7b",
        base_url="http://localhost:11434",
        temperature=0.2
    )

    prompt = PROMPT_TEMPLATE.format(
        context=context,
        question=question
    )

    answer = llm.invoke(prompt)

    print("\n=== 检索到的上下文 ===")
    print(context)

    print("\n=== AI回答 ===")
    print(answer)

if __name__ == "__main__":
    main()
EOF

执行查询:

python query.py

测试问题:

报销需要在多少天内提交?

或者:

API 每分钟最多请求多少次?

十三、继续降低成本的优化命令

1. 限制 Docker 容器资源

如果你不希望 Qdrant 占用过多资源,可以限制内存和 CPU:

docker rm -f qdrant
docker run -d \
  --name qdrant \
  --memory=1g \
  --cpus=1 \
  -p 6333:6333 \
  -p 6334:6334 \
  -v "$(pwd)/qdrant_storage:/qdrant/storage" \
  qdrant/qdrant

2. 使用更小的大模型

如果 7B 模型太慢,可以换成 3B:

ollama pull qwen2.5:3b

然后修改 query.py

sed -i.bak 's/qwen2.5:7b/qwen2.5:3b/g' query.py

重新运行:

python query.py

3. 减少检索数量

如果当前使用 k=3,可以改为 k=2

sed -i.bak 's/k=3/k=2/g' query.py

这样每次传给大模型的上下文更少,生成成本更低。


4. 减小 chunk 大小

如果文档内容较短,可以把 chunk 从 500 改为 400:

sed -i.bak 's/chunk_size=500/chunk_size=400/g' ingest.py

重新入库:

python ingest.py

5. 减少 chunk overlap

将 overlap 从 80 改为 40:

sed -i.bak 's/chunk_overlap=80/chunk_overlap=40/g' ingest.py

重新入库:

python ingest.py

十四、生产环境建议

本地方案适合验证,但生产环境还需要进一步增强。

1. 增加缓存层

可以使用 Redis 缓存高频问题答案:

用户问题 → 标准化 → hash → 查询 Redis → 命中直接返回

2. 增加权限控制

企业知识库通常需要按用户、部门、角色控制可见范围。检索时必须带上权限过滤条件。

3. 增加日志与成本统计

每次请求建议记录:

{
  "question": "用户问题",
  "retrieval_top_k": 3,
  "model": "qwen2.5:7b",
  "input_tokens": 1200,
  "output_tokens": 300,
  "cache_hit": false,
  "latency_ms": 1800
}

4. 增加无答案机制

不要让模型强行回答。Prompt 中必须明确:

如果资料中没有相关信息,请回答无法确定。

这不仅能减少幻觉,也能降低反复追问导致的额外成本。


十五、AI搜索降本的核心公式

AI 搜索成本可以简单理解为:

总成本 =
文档处理成本
+ 向量化成本
+ 向量库存储成本
+ 检索计算成本
+ rerank 成本
+ 大模型输入 tokens 成本
+ 大模型输出 tokens 成本
+ 服务器与运维成本

因此,降本不是单点优化,而是系统性优化。

最有效的策略通常是:

减少无效文档
减少重复向量化
减少无关召回
减少传入上下文
减少大模型调用
减少高级模型调用
提高缓存命中率

结语

AI 搜索想要真正降低成本,关键不是盲目换更便宜的模型,而是重新设计整个链路。

如果只关注模型单价,很容易忽略检索数量、上下文长度、重复问题、无效文档、向量维度和缓存命中率这些更关键的因素。对于大多数企业来说,最实用的降本路径是:

  1. 文档入库前先清洗和去重;
  2. 使用本地 embedding 降低长期成本;
  3. 检索时控制 Top K;
  4. 对结果做轻量重排序;
  5. 只把最相关内容传给大模型;
  6. 高频问题使用缓存;
  7. 简单问题使用小模型;
  8. 复杂问题才调用更强模型;
  9. 持续记录 tokens、耗时和命中率;
  10. 根据真实数据不断优化。

一句话总结:

AI 搜索降本的本质,是把大模型从“万能入口”变成“最后一步的高价值生成器”。

目录结构
全文