用 AI 写规格、国内大模型做推理:一百块能否搭出生产级 RAG?

从 Claude Code 生成 440 行方案文档出发,到集成通义千问 API、修复 14 个隐蔽 Bug,最终仅花费 100 元人民币就搭建起包含混合检索、状态机管道和企业级前端的全栈 RAG 系统。

基本信息

核心观点

  1. 成本验证:100 元即可搭建生产级 RAG

    • 全链路 API 花费约 100 元人民币(含 Embedding 批量写入 + 多轮对话测试 + Rerank 调用)
    • 对话模型:qwen3.6-plus,向量模型:text-embedding-3-large(实际输出 1024 维)
    • 证明”AI 代码生成 + 国内 LLM API”路线在预算层面可行
  2. 规格驱动开发有效:先写 440 行方案再生成代码

    • 采用”两段式开发”:Claude Code 先输出 hashed-gliding-metcalfe.md 施工蓝图(包含架构、目录树、LangGraph 节点、API 与数据模型)
    • 再据此逐模块生成 Monorepo 代码(packages/backend、packages/frontend、packages/shared)
    • 避免”边想边写”导致的架构漂移,第一天就明确 Monorepo 结构和 API 边界
  3. 真正的敌人是静默失败:14 个 Bug 中最耗时的不报错

    • 修复 14 个 Bug,类型分布:SDK 参数不兼容(3 个)、参数不匹配(3 个)、配置/路径问题(3 个)、逻辑 Bug(3 个)、环境问题(2 个)
    • 最危险的是”静默型”故障:检索 0 条、向量维度不一致、API 地址被忽略、阈值过滤全部丢弃——无报错不代表正常
    • 例如:Milvus Schema 定义 3072 维但实际 API 返回 1024 维,检索可能仍能插入但静默返回 0 条
  4. 国内大模型接入需要实测验证,不能照搬海外经验

    • 向量维度:必须实测 Embedding 模型输出维度,通义 text-embedding-3-large 实际输出 1024 维,不是 OpenAI 的 3072 维
    • 相似度阈值:通义 v3 的 COSINE 分数常在 0.2–0.45,不能照搬 OpenAI 经验值 0.7(会导致全部被过滤)
    • SDK 配置写法:LangChain 对国内 API 需用 configuration.baseURL,不是 baseUrl,否则请求打到 api.openai.com 导致超时
  5. 完整交付物:不只是 Demo,而是带评测与可观测性的平台

    • 后端:Node.js + Fastify 5 + LangGraph 十节点 DAG + SSE 流式响应
    • 前端:Vite + React 19 + TailwindCSS 4,四面板(对话、文档、评估、配置)
    • 基础设施:Milvus 2.5.x(稠密 + BM25 稀疏混合检索)、PostgreSQL 16、Redis 7、Attu 管理界面
    • 评测指标:命中率、MRR、忠实度、相关性等面板,支持上线前对比调参效果

实操内容保留

LangGraph 十节点状态机管道

查询进入后先 classify

  • 事实类/比较类 → decompose 子问题 → retrieve
  • 通用类/其他 → rewrite,可选 HyDE(生成假设文档),再 retrieve

retrieve 后统一流程:

retrieve → rerank → compress → generate → evaluate

evaluate 结果判定

  • pass / ambiguous → format → END
  • fail 且未超重试次数 → rewrite → 回到检索链路

关键约束:节点名不得与 RAGState 字段同名(如 grade 节点需改名为 evaluate)

环境配置样例

# .env 配置(必须在 Monorepo 根目录,不是 packages/backend/.env)
LLM_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
LLM_MODEL=qwen3.6-plus
EMBEDDING_MODEL=text-embedding-v3
EMBEDDING_DIMENSION=1024  # 必须与实际输出一致
DATABASE_URL=postgresql://...  # PostgreSQL 连接串

验证点:Monorepo 中 dotenv 默认在 process.cwd() 查找 .env,子包启动时 cwd 往往是 packages/backend/,必须在代码中显式指定根目录 .env 路径,否则 Zod 校验会报全部环境变量 undefined。

Milvus 集合字段配置

# 集合名:rag_chunks
# 字段结构
{
  "id": "VarChar (主键)",
  "document_id": "VarChar (分区键)",
  "content": "VarChar",
  "dense_vector": "FloatVector, dim=1024",  # 必须与 Embedding 实际输出一致
  "sparse_vector": "SparseFloatVector (BM25)",
  "chunk_index": "Int64",
  "metadata": "JSON (含 headerPath、section_title 等)",
  "doc_type": "VarChar",
  "source": "VarChar",
  "author": "VarChar"
}
 
# 索引配置
{
  "index_type": "IVF_FLAT",
  "metric_type": "COSINE",
  "params": { "nlist": 1024 }  # 必须传对象,不能 JSON.stringify
}

验证点:若 Schema 按 OpenAI 默认写成 3072 维,而实际 API 返回 1024 维,Milvus 可能仍能插入但检索静默返回 0 条——这是本次实验中最耗时的隐蔽故障之一。

LangChain 国内 API 配置写法

// ✅ 正确:configuration.baseURL
new OpenAIEmbeddings({
  model: 'text-embedding-v3',
  apiKey: 'sk-…',
  configuration: { baseURL: 'https://dashscope.aliyuncs.com/compatible-mode/v1' },
  dimensions: 1024,
});
 
// ❌ 错误:baseUrl 会被忽略,请求打到 api.openai.com,超时或异常
new OpenAIEmbeddings({ 
  baseUrl: 'https://dashscope.aliyuncs.com/…' 
});

验证点:@langchain/openai 对 baseUrl 与 configuration.baseURL 的处理不一致;ChatOpenAI 与 OpenAIEmbeddings 均需使用后者,否则表现为”日志显示成功、检索却无结果”。

本地构建链路

# 1. 启动基础设施
docker compose up -d  # Milvus、PostgreSQL、Redis、Attu
 
# 2. 安装依赖
npm install  # workspaces 依赖
 
# 3. 配置环境变量(根目录 .env)
LLM_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
LLM_MODEL=qwen3.6-plus
EMBEDDING_MODEL=text-embedding-v3
EMBEDDING_DIMENSION=1024
 
# 4. 启动开发服务器
npm run dev  # Turbo 并行启动后端:3000 与前端:5173
 
# 5. 使用流程
# 上传文档 → 入库流水线 → 对话问答 → 评测面板调参

多格式文档入库流程

采用解析器工厂模式

  • PDF:pdf-parse
  • DOCX:mammoth
  • Excel:xlsx 转 CSV 文本
  • HTML:cheerio + turndown
  • Markdown:保留标题元数据

分块策略可按文档类型路由:Markdown 按标题层级、语义边界、父子结构或固定大小。

单次文档入库日志样例

文件名:员工手册-2025.pdf
解析结果:5868 characters
分块数:8 chunks
Embedding:Generated 8 embeddings
索引:Indexed 8 chunks in Milvus
耗时:Ingestion completed in 789ms

验证点:路由层 ingest.ts 与服务层 ingestion.service.ts 若各调用一次 documentService.create(),列表会出现两条同名记录——入库链路应「路由创建 ID,服务层复用 ID」。

原文精彩摘录

关于静默失败的深刻洞察

“14 个 Bug 里,最耗时的不是 npm 404 或端口占用,而是检索 0 条、配置被忽略、维度 silently mismatch——它们共同特点是系统不报错。生产 RAG 的上限,往往由 Embedding 兼容性、向量库 Schema、阈值与评测闭环决定,而不是 Prompt 写得多漂亮。“

关于相似度阈值的经验教训

“不同 Embedding 模型的 COSINE 分数分布差异很大,不能照搬海外模型的阈值;上线前必须用独立脚本测自家模型的分数区间。”

“Milvus 直接 search Top5 分数:0.4522、0.3395、0.3032、0.2815、0.2654。错误阈值设定:0.7(参照 OpenAI 经验值)→ 全部被过滤,管道返回 0 条。修正后默认阈值:0.2,或由 Rerank / Grade 承担质量控制。“

关于规格驱动开发的价值

“传统开发是边想边写;本次实验采用规格驱动 + AI 生成:在创建任何代码文件之前,Claude Code 先输出 hashed-gliding-metcalfe.md,内容包括生产级 RAG 架构与 Monorepo 目录职责、LangGraph 十节点状态机、入库流水线、API 路由与共享类型定义。“

关于成本与可行性的结论

“这次实验给出的结论可以概括为三句话:第一,成本可控。在 Claude Code 生成方案与代码、通义千问提供推理与向量的组合下,完成一套带评测面板与混合检索的生产级 RAG,API 花费约 100 元——对立项预算有参考意义,但需叠加人力调试与基础设施成本。“

关于排查方法论

“当 RAG 管道「返回 0 条」时,建议按层自下而上隔离,而不是反复改 Prompt:

  1. 存储层:Milvus count、PostgreSQL documents/chunks 是否一致
  2. 向量层:sample vector length、索引是否存在、集合是否残缺
  3. API 层:独立脚本测 Embedding Base URL、延迟、维度
  4. 管道层:retrieve 日志中的条数与 score,阈值与 Rerank 是否误杀”

关于上线自查清单的价值

“若你计划走「AI 写规格 + 国内大模型 API」路线,建议把本文的数据示例、判定规则、场景演练与自查清单直接纳入你的上线 Checklist——比再做一个 Demo 更能降低返工与 Token 浪费。“

关键概念

  • RAG 知识库:检索增强生成,企业内部文档问答、客服知识库、合规手册检索的核心技术
  • Claude Code:Anthropic 官方 CLI 工具,本案例中用于生成方案文档和 Monorepo 代码
  • LangGraph:状态机管道编排框架,本案例构建了十节点 DAG(classify → rewrite/HyDE → retrieve → rerank → compress → generate → evaluate)
  • Milvus:向量数据库,本案例使用 2.5.x 版本实现稠密向量 + BM25 稀疏向量混合检索
  • 通义千问:阿里百炼提供的国内大模型,本案例使用 qwen3.6-plus 对话模型和 text-embedding-3-large 向量模型
  • 混合检索:稠密向量(语义)+ 稀疏向量(关键词 BM25)+ RRF 融合,生产 RAG 常见组合
  • Rerank:对 TopK 检索结果重排序,提升相关性,避免单一向量检索的局限
  • Monorepo:单一代码仓库管理多个项目(packages/backend、packages/frontend、packages/shared),便于共享类型定义和统一构建

相关页面