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

0 评论 301 浏览 1 收藏 24 分钟

当AI代码生成遇上国内LLM API,一场真实的生产级RAG实验给出了答案。从Claude Code生成的440行方案文档出发,到集成通义千问API、修复14个隐蔽Bug,最终仅花费100元人民币就搭建起包含混合检索、状态机管道和企业级前端的全栈系统。本文将揭秘架构选型、核心数据样例与上线前自查清单,为评估AI代码生成+国内大模型落地的团队提供实战参考。

本文记录一次完整实验:先用 Claude Code 生成约 440 行的实现方案文档,再据此逐模块生成 Monorepo 代码,运行时调用阿里百炼通义千问(对话 qwen3.6-plus、向量 text-embedding-3-large),全链路 API 花费约 100 元人民币。系统包含多格式文档入库、Milvus 混合检索、LangGraph 十节点状态机、评测面板与企业级前端,共修复 14 个 Bug——其中多数表现为「静默失败」而非明确报错。

若你正在评估「AI 生成代码 + 国内 LLM API」路线是否可行,本文重点提供:架构选型逻辑、核心数据样例、判定与阈值规则、四条典型场景演练,以及上线前自查清单,便于对照自家环境与预算做决策。

 

一、问题背景:为什么要把「成本」和「踩坑」写清楚

企业内部文档问答、客服知识库、合规手册检索——场景不同,技术路径却高度相似:解析文档、切块、向量化、检索、生成、带来源引用。立项时,业务方常问三个问题:

  1. 要花多少钱? Embedding 批量写入、多轮对话测试、Rerank 调用,Token 消耗不透明。
  2. 要多久能上线? 若依赖海外模型与默认 SDK 示例,国内 API 兼容、向量维度、相似度阈值等细节会拖慢进度。
  3. AI 写代码靠不靠谱? 若只有 Demo 级能力,缺少评测、可观测性与工程化,仍无法称为「生产级」。

本次实验的目标因此很明确:不是做一个能跑通的 Demo,而是实测从零完成一套带评测与可观测性的 RAG 平台,究竟消耗多少 Token、会遇到哪些典型故障。开发方式采用「先写规格、再生成代码」:Claude Code 产出施工蓝图 hashed-gliding-metcalfe.md,再据此生成 Monorepo、Docker、前后端与 LangGraph 流水线;模型侧统一走阿里百炼 OpenAI 兼容接口。

二、交付边界:这个项目到底交付了什么

产品定位:生产级 RAG 平台——用户上传 PDF、Word、Excel、HTML、Markdown,系统自动解析、分块、向量嵌入、索引存储,通过对话界面进行基于文档内容的智能问答,并附带引用来源。

不在本期范围(或后续优化)

  • MinHash+LSH 高级去重(因 minhash 包弃用,暂用内容哈希替代)
  • 生产环境 Nginx 与完整 CI/CD(文档侧重本地构建与调试路径)

核心交付物

  • 方案文档:hashed-gliding-metcalfe.md(约 440 行),含架构、目录树、LangGraph 节点、API 与数据模型
  • 后端:Node.js + Fastify 5 + LangGraph 十节点 DAG + SSE 流式响应
  • 前端:Vite + React 19 + TailwindCSS 4,四面板(对话、文档、评估、配置)
  • 基础设施:Milvus 2.5.x(稠密+BM25 稀疏)、PostgreSQL 16、Redis 7、Attu 管理界面
  • 可观测与评测:命中率、MRR、忠实度、相关性等指标面板

三、系统底盘:「从 Markdown 编译出代码」的两段式开发

传统开发是边想边写;本次实验采用 规格驱动 + AI 生成

第一段:生成施工蓝图

在创建任何代码文件之前,Claude Code 先输出 hashed-gliding-metcalfe.md,内容包括:

  • 生产级 RAG 架构与 Monorepo 目录职责
  • LangGraph 十节点状态机(查询分类、HyDE、混合检索、Rerank、自纠正等)
  • 入库流水线(多格式解析 → 语义分块 → Milvus 混合索引)
  • API 路由与共享类型定义

第二段:按方案逐模块生成代码

以方案文档为唯一规格说明,生成 packages/backend、packages/frontend、packages/shared,并在本地运行报错时通过对话逐条修复。

本地构建链路(用户侧执行):

  1. docker compose up -d — 启动 Milvus、PostgreSQL、Redis、Attu
  2. npm install — 安装 workspaces 依赖
  3. 配置 .env — 填入通义千问 API Key 与模型名
  4. npm run dev — Turbo 并行启动后端 :3000 与前端 :5173
  5. 上传文档 → 入库流水线 → 对话问答 → 评测面板调参

技术栈分层

  • 前端(5173):Vite + React 19 + TypeScript + TailwindCSS 4,Zustand + React Query
  • 后端(3000):Fastify 5 + LangGraph,Zod 配置校验,SSE 流式
  • 存储与外部 API:Milvus 稠密 1024 维 + BM25 稀疏向量;PostgreSQL 存元数据;Redis 缓存与限流;阿里百炼提供 LLM 与 Embedding

四、关键能力拆解

4.1 多格式文档入库

采用解析器工厂模式:PDF(pdf-parse)、DOCX(mammoth)、Excel(xlsx 转 CSV 文本)、HTML(cheerio + turndown)、Markdown(保留标题元数据)。分块策略可按文档类型路由:Markdown 按标题层级、语义边界、父子结构或固定大小。

设计意图:企业文档格式混杂,统一工厂 + 策略路由避免为每种格式写死一条流水线,便于后续扩展。

4.2 Milvus 混合索引

集合字段包含:document_id(分区键)、content、dense_vector(1024 维)、sparse_vector(BM25)、chunk_index、metadata JSON,以及 doc_type、source、author 等过滤字段。

设计意图:稠密向量捕获语义,稀疏向量补强关键词匹配;混合检索 + RRF 融合是生产 RAG 的常见组合。

4.3 LangGraph 十节点 RAG 管道

查询进入后先 classify;事实类/比较类走 decompose → retrieve;通用类走 rewrite,可选 HyDE,再 retrieve → rerank → compress → generate → evaluate;评估不通过且未超重试次数则回退 rewrite 循环。

设计意图:单轮「检索 + 生成」在复杂问题上容易漏召回或幻觉;分类、HyDE、Rerank、自纠正与置信度评估构成可调优的闭环,而非一次性黑盒。

4.4 前端四面板

  • 对话:多会话、引用面板、置信度徽章、反馈按钮
  • 文档管理:统计卡片、拖拽上传、列表/网格双视图
  • 评估:命中率/MRR/忠实度/相关性、7 天趋势、系统状态
  • 配置:检索/模型/分块/高级 Tab,开关与滑块调参

五、衡量指标:成本、质量与工程代价

API 成本(实测)

  • 全链路 API 调用(Embedding 批量写入 + 多轮对话测试 + Rerank 等)合计约 100 元人民币
  • 对话模型:qwen3.6-plus
  • 向量模型:经百炼接口的 text-embedding-3-large(实际输出 1024 维

工程质量指标

  • 修复 Bug 数量:14 个
  • Bug 类型分布:
    • SDK 参数不兼容:3 个(如 baseUrl vs configuration.baseURL)
    • 参数不匹配:3 个(向量维度、相似度阈值)
    • 配置/路径问题:3 个(.env 路径、Tailwind 插件、端口占用)
    • 逻辑 Bug:3 个(重复建记录、节点名冲突、索引静默失败)
    • 环境问题:2 个(依赖包不存在或弃用)

评测面板指标

  • 命中率、MRR(Mean Reciprocal Rank)、忠实度、相关性
  • 支持上线前对比调参效果,避免「感觉能答」却无法量化

六、核心数据示例

以下样例从实际配置、Schema 与调试日志提炼,用于评估「自家环境能否复现」。

6.1 环境配置样例

  • 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 连接串(Monorepo 根目录 .env,非 packages/backend/.env)

业务验证点

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

6.2 Milvus 集合字段样例

  • 集合名:rag_chunks
  • 主键 id:VarChar
  • document_id:VarChar,分区键
  • dense_vector:FloatVector,dim = 1024(必须与 Embedding 实际输出一致)
  • sparse_vector:SparseFloatVector(BM25)
  • metadata:JSON(含 headerPath、section_title 等)

业务验证点

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

6.3 单次文档入库日志样例

  • 文件名:员工手册-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」。

6.4 检索分数样例(通义 embedding-v3)

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

业务验证点

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

6.5 LangChain 客户端配置样例

// ✅ 正确: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 均需使用后者,否则表现为「日志显示成功、检索却无结果」。

七、规则与判定逻辑

7.1 LangGraph 查询路由

  • classify 输出查询类型
  • factual / comparative → decompose 子问题 → retrieve
  • general / other → rewrite;若 HyDE 开启则生成假设文档再 retrieve,否则直接 retrieve
  • retrieve 后统一:rerank → compress → generate → evaluate
  • evaluate 结果
    • pass / ambiguous → format → END
    • fail 且未超重试次数 → rewrite → 回到检索链路
  • 约束:节点名不得与 RAGState 字段同名(如 grade 节点需改名为 evaluate)

7.2 相似度与质量控制

  • retrieve 阶段:实验结论为不宜硬编码过高阈值;通义 v3 分数常在 0.2–0.45
  • rerank 阶段:对 TopK 结果重排序,提升相关性
  • evaluate 阶段:对生成答案做质量评估,失败则触发重写

7.3 Milvus 索引创建规则

  • index_type:IVF_FLAT
  • metric_type:COSINE
  • params:必须传对象 { nlist: 1024 },不能 JSON.stringify 给 extra_params,否则 Go 后端反序列化失败,索引静默未建

7.4 故障表现分级(便于运维响应)

  • 阻断型:npm install 失败、Zod 环境变量缺失、端口占用、LangGraph 编译错误——启动即失败,易发现
  • 警告型:Tailwind 无样式、开发环境 multipart 400——功能受限但可绕过
  • 静默型(最危险):检索 0 条、向量维度不一致、API 地址被忽略、阈值过滤全部丢弃——无报错即不代表正常

八、场景演练

场景 A:Happy Path — 从方案到首次成功问答

  1. 角色:开发者 — Claude Code 生成 hashed-gliding-metcalfe.md,再生成 Monorepo 代码
  2. 角色:开发者 — docker compose up -d,npm install,根目录配置 .env
  3. 角色:开发者 — 修复 dotenv 路径、LangGraph 节点命名、Milvus params 格式、Tailwind v4 插件
  4. 角色:业务测试 — 上传 PDF,日志显示 8 chunks 入库
  5. 角色:业务测试 — 提问「文档中的某政策是什么?」,SSE 返回答案 + 引用片段 + 置信度
  6. 角色:产品/算法 — 在评估面板查看命中率与忠实度,调整 Rerank TopK 与分块策略

业务验证点

你的团队是否具备「方案文档 → 分模块实现 → 评测调参」的闭环?若只有对话 Demo 没有评估面板,上线后难以证明效果。

场景 B:静默失败 — 有数据但检索永远为空(向量维度)

  1. 上传成功,PostgreSQL 与 Milvus 均有 8 条 chunk
  2. 对话接口返回空引用,无异常堆栈
  3. 逐层隔离:Milvus count=8 ✓ → sample vector length=1024 ✓ → Schema 定义 DENSE_VECTOR_DIM=3072 ✗
  4. 处置:改 Schema 为 1024,dropCollection 后重建并重新入库
  5. 再次检索,Top5 分数 0.26–0.45,结果正常返回

业务验证点

上线检查清单第一项必须是:Embedding 模型输出维度 == Milvus Schema dim,且变更模型后必须重建集合。

场景 C:静默失败 — Embedding「成功」实则走错 API

  1. 日志:Generated 8 embeddings,Indexed 8 chunks — 表面正常
  2. 检索仍为 0;Embedding 单次调用耗时数十秒(正常应 1–2 秒)
  3. 独立脚本对比:baseUrl 超时 vs configuration.baseURL 238ms 成功
  4. 处置:统一修改 embeddings/openai.ts 与 llm/openai.ts 的配置写法
  5. 重新入库后,检索分数与延迟均恢复正常

业务验证点

国内 OpenAI 兼容接口接入 LangChain 时,务必用独立脚本验证实际请求的 Base URL,不能只看「有没有返回向量」。

场景 D:边界 — 相似度阈值照搬 OpenAI 经验

  1. Milvus 直接 search 可得 5 条,分数最高 0.45
  2. 代码中 similarityThreshold: 0.7,retrieve 节点过滤后 0 条
  3. 处置:默认阈值降至 0.2,并移除 retrieve 硬过滤,由 rerank + grade 控质
  4. 问答质量通过 Rerank 与评估节点保障,而非过早丢弃候选

业务验证点

阈值是「产品 + 算法」联合决策:过低噪声多,过高召回空。应基于自家模型 + 自家语料实测分布,而非文档默认值。

九、对照自查清单

  • Embedding 维度|要问:我们选用的向量模型实际输出几维?|系统需支持:Milvus Schema dim 与模型一致,变更后支持重建集合
  • API 兼容写法|要问:LangChain 版本下国内 Base URL 怎么传?|系统需支持:configuration.baseURL,并用独立脚本验证延迟与返回维度
  • 相似度阈值|要问:COSINE 分数在自家语料上的分布区间?|系统需支持:可配置阈值,retrieve 勿过早硬过滤
  • Milvus 索引|要问:索引参数格式是否与 SDK 版本匹配?|系统需支持:params 传对象;启动时检查索引是否存在
  • 环境变量路径|要问:Monorepo 子包从哪里读 .env?|系统需支持:显式 resolve 根目录路径,变量名与 Zod Schema 一致
  • 入库幂等|要问:上传一次会写几条文档记录?|系统需支持:路由创建 documentId,服务层只更新状态不重复 insert
  • LangGraph 命名|要问:节点名是否与 State 字段冲突?|系统需支持:编译期可报错,命名规范 review
  • 前端样式链|要问:Tailwind 大版本升级插件是否注册?|系统需支持:Vite 中 @tailwindcss/vite
  • 开发代理|要问:multipart 上传走不走 dev proxy?|系统需支持:生产直连后端;开发期可用 curl/Postman 绕过已知 proxy 问题
  • 进程管理|要问:热重载是否残留占用端口?|系统需支持:重启前释放 3000 端口,或文档化 kill 命令

十、排查方法论(可复用的四层策略)

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

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

对比测试:对可疑参数写 A/B 两个最小脚本(如 baseUrl vs configuration.baseURL),用耗时与输出维度一锤定音。

日志驱动:解析字符数 → chunks 数 → embeddings 数 → indexed 数 → retrieved 数,缺哪一步就查哪一步。

十一、系统运行图

十二、结语

这次实验给出的结论可以概括为三句话:

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

第二,规格驱动有效。 先有 hashed-gliding-metcalfe.md 再生成代码,使 Monorepo 结构、LangGraph 节点与 API 边界在第一天就清晰,减少「写到哪算哪」的架构漂移。

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

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

本文由 @天涯轩 原创发布于人人都是产品经理。未经作者许可,禁止转载

题图来自AI生成,由作者提供

更多精彩内容,请关注人人都是产品经理微信公众号或下载App
评论
评论请登录
  1. 目前还没评论,等你发挥!