三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

大数据转大模型:SQL 写得好,AI 项目反而先翻车

大数据转大模型:SQL 写得好,AI 项目反而先翻车

聊《一个大数据项目改成 AI 流程后,最难的部分完全变了》之前,先说一句实在的:别急着背概念,先看它在真实项目里到底解决什么问题。

摘要

大数据工程师转型大模型,大多数人以为卡点在学习 Python 或者调参,实际翻车的环节往往是权限校验、日志追踪、数据溯源这些"脏活"。本文结合一个真实项目复盘,讲清楚数据工程师做 RAG 和 Agent 时的真正门槛在哪,以及怎么补。

---

目录

  • 大数据与大模型的根本差异
  • 数据治理:从离线批处理到实时可溯源
  • 向量数据库:不是换个存数据的工具
  • RAG 数据管道:最容易低估的工程环节
  • 落地项目:权限和日志才是生产上线的生死线
  • 总结

---

大数据与大模型的根本差异

做大数据的人,第一反应是:"大模型不就是换个模型吗,数据该清洗还是清洗。"

这个思路在 Demo 阶段没问题,一上生产就露馅。

大数据的核心假设是数据稳定、结构清晰、写入一次反复读。Hive 表建好,ETL 跑通,调度配好,基本就稳了。大模型工程的核心假设恰恰相反:数据在变、答案在变、每次请求的上下文都不一样。

我带的第一个 AI 项目是给内部知识库做问答系统。数据组的同学花两周把文档全部向量化,RAG 流程也跑通了,Demo 演示效果很好。然后业务方提了一个问题:

> "不同部门的人问同一个文档,答案能不一样吗?比如销售能看客户信息,客服不能。"

这一下就把我们打懵了。传统大数据的权限体系是表级或行级的,静态的。而 RAG 系统的权限是在检索阶段动态过滤的,需要把权限元数据和向量一起存、一起查。

这才是大数据工程师转型时最容易被低估的地方:你不是在换技术栈,你是在换一套问题建模方式。

---

数据治理:从离线批处理到实时可溯源

大数据的数据治理,重点是质量、血缘、一致性。这些在大模型场景下依然存在,但增加了一个新的维度:来源可溯源。

传统 ETL 链路:

原始日志 → Kafka → Hive → 数仓ODS/DWD/ADS → 报表

血缘是线性的,出了问题可以追到某张表的某个字段。

RAG 链路:

原始文档 → 清洗 → 分块 → 向量化 → 向量库 → 检索 → LLM 生成

问题出在生成结果不对时,你需要知道:这条答案是从哪几段文档来的?每段文档的原始来源是什么?向量库里的数据是今天更新的还是上周的?

我在项目里搭了一套简单的溯源方案,核心思路是把元数据跟着向量一起存:

# 向量化时带上元数据 from langchain_community.vectorstores import Chroma from langchain_core.documents import Document def embed_with_metadata(texts, sources, permissions): docs = [] for text, source, perm in zip(texts, sources, permissions): docs.append(Document( page_content=text, metadata={ "source": source, "permission_level": perm, "updated_at": datetime.now().isoformat(), "chunk_id": f"{source}_{len(docs)}" } )) return docs # 检索时按权限过滤 def search_with_permission(query, user_level, top_k=5): results = vector_db.similarity_search_with_score(query, k=top_k * 2) filtered = [ (doc, score) for doc, score in results if doc.metadata["permission_level"] <= user_level ] return filtered[:top_k]

看起来简单,但有几个实际踩过的坑:

第一,元数据不能太大。 每条向量都带一堆 metadata,向量库查询性能会明显下降。我们最初把所有文档属性都塞进去,QPS 直接掉了一半,后来只保留 source、permissionlevel、chunkid 三个字段才恢复正常。

第二,权限模型要提前设计。 不是等做出来了再加权限,而是在设计文档入库流程时就定义好权限层级。我们最终采用了"文档级权限 + 字段级权限"的混合方案,前者控制能不能看,后者控制能看到多少。

第三,数据过期要处理。 大模型场景下,文档可能今天更新了,但向量库里还是旧版本。我们加了updated_at字段,配合定时任务做增量更新,同时记录每次更新的版本号,方便排查问题。

---

向量数据库:不是换个存数据的工具

很多大数据工程师第一次接触向量数据库,第一反应是:"这不就是个带索引的 NoSQL 吗?"

确实有点像,但关键区别在于查询语义完全不同。

传统数据库你按条件过滤,结果确定。向量数据库你按相似度检索,结果是概率性的。这意味着同样的查询,不同时间可能返回不同结果——因为模型embedding在更新、数据在增量写入。

我们项目里对比了三个方案:Chroma(本地开发用)、Milvus(生产部署)、PGVector(想用现成PostgreSQL基础设施时用)。

最终选了 Milvus,原因很实际:

  • Chroma 并发能力不够,压测 50 个并发就扛不住了
  • PGVector 查询延迟波动大,p99 能达到 2 秒
  • Milvus 在 QPS 和延迟上表现最稳定

但选型只是第一步,索引策略才是关键。Milvus 支持 IVFFLAT、HNSW、IVFSQ8 等多种索引,我们最初用默认的 IVF_FLAT,召回率 92%,但查询延迟 300ms。换成 HNSW 之后,延迟降到 80ms,召回率 89%。

取舍很明确:延迟优先还是召回率优先? 对于内部知识库场景,我们选择了后者——用户能接受 100ms 左右的延迟,但不能接受漏掉关键文档。

另一个容易被忽视的点:批量写入 vs 实时写入。我们最初每条文档来了就写入向量库,结果写入延迟越来越高,因为每次写入都会触发索引重建。后来改成批量写入,每小时一次,延迟问题消失,但引入了一个新的权衡:数据延迟最多 1 小时。这个权衡是否可接受,需要根据业务场景判断。

---

RAG 数据管道:最容易低估的工程环节

RAG pipeline 看起来很简单:

用户问题 → 检索相关文档 → 拼接上下文 → 调用LLM → 返回答案

但生产环境里,每个环节都有大量工程问题要解决。

检索环节:我们最初直接用相似度检索,结果发现一个问题——文档里有些章节明显更相关,但向量相似度打分把它们和无关章节混在一起了。后来加了重排序(rerank)步骤,用 Cross-Encoder 模型对初步检索结果重新打分,效果明显提升。

拼接环节:上下文长度是个硬约束。我们最初把所有检索结果全塞进去,结果经常超出 token 限制。后来做了两段式处理:先粗筛取 top 20,再用 LLM 做摘要压缩到 top 5 的核心段落。

调用环节:这是最容易被忽视的。一个 RAG 系统不是单次调用,而是多次调用的组合——检索一次、rerank 一次、生成一次。任何一步超时或失败,整个流程都要有兜底。

from opentelemetry import trace from opentelemetry.trace import SpanKind import time tracer = trace.get_tracer(__name__) def rag_pipeline(query, user_id): with tracer.start_as_current_span("rag_pipeline") as span: span.set_attribute("user_id", user_id) span.set_attribute("query", query[:100]) start = time.time() # 检索 docs = search_with_permission(query, get_user_level(user_id)) span.add_event("search_done", {"count": len(docs), "latency_ms": (time.time()-start)*1000}) if not docs: return {"answer": "未找到相关文档", "sources": []} # 重排序 start = time.time() reranked = rerank(query, docs, top_k=5) span.add_event("rerank_done", {"latency_ms": (time.time()-start)*1000}) # 生成 start = time.time() context = build_context(reranked) answer = call_llm(query, context) span.add_event("generate_done", { "latency_ms": (time.time()-start)*1000, "tokens_used": len(answer) }) return {"answer": answer, "sources": [d.metadata["source"] for d in reranked]}

这套链路里,可观测性不是锦上添花,是必须的。没有 trace,你不知道慢在哪一步;没有日志,你无法复现问题;没有指标,你不知道系统是否健康。

我们后来接入了 Prometheus + Grafana,监控的关键指标就几个:

  • 端到端延迟(p50/p95/p99)
  • 各阶段延迟占比
  • 检索召回率(通过人工抽样评估)
  • LLM 调用失败率
  • 单位成本(每次查询的 token 消耗)

---

落地项目:权限和日志才是生产上线的生死线

这个项目做了三个月,前两个月都在做 Demo,看起来一切顺利。第三个月接入生产,才真正发现问题。

第一个问题:权限绕过。 我们以为做了向量级权限过滤就万事大吉,结果发现有用户通过拼接多个问题的方式,绕过了权限限制。比如用户 A 不能看文档 X,但他可以问"文档 X 里关于 Y 的内容是什么",系统检索到 X 的片段后,虽然没有直接返回原文,但通过 LLM 的重新组织,还是把敏感信息泄露了。

解决方案:在 LLM 输出端加了一道内容过滤,检测是否包含敏感关键词,同时限制单次查询的上下文长度,减少信息泄露的可能。

第二个问题:日志缺失。 我们最初只记录了查询和结果,没有记录中间过程。有一天用户反馈答案不对,我们查日志发现检索到了正确的文档,但 LLM 没有引用。因为没有记录 rerank 的结果和 LLM 的完整输入,我们花了半天时间才定位到是 rerank 模型把正确结果排到了后面。

解决方案:记录完整的链路日志,包括每次检索的结果、rerank 的打分、LLM 的输入输出。虽然日志量变大了,但排查问题的效率提升了几个数量级。

第三个问题:成本失控。 我们最初没有监控 token 消耗,结果一个月下来 LLM 调用费用超出预算三倍。排查发现,很多查询是重复的,但没有做缓存。

解决方案:加了一层结果缓存,相同问题的查询直接返回缓存结果。同时设置了单次查询的 token 上限和每日调用上限。

---

总结

大数据工程师转型大模型,最大的误区是以为技术栈切换就够了。实际上,真正的门槛在工程化能力:权限设计、日志追踪、成本管控、可观测性。这些在大数据领域你可能接触不多,但在大模型生产环境里,它们是决定项目能不能上线的关键因素。

建议的学习顺序:

1. 先搞懂 RAG 的基本原理和常见陷阱
2. 动手做一个完整的 RAG 项目,包括检索、重排序、生成
3. 给项目加上权限控制和日志追踪
4. 压测,看延迟、召回率、成本的平衡点在哪
5. 复盘:如果这个系统要服务 1000 个并发用户,哪里会先崩

Demo 能跑只是开始,权限、日志、可观测性才是真正的分水岭。

资料展示

下面是我整理的AI大模型学习资料和工具包预览,适合收藏后按主题逐步学习。

如果你想看完整资料目录,可以在评论区留言「资料」;也欢迎告诉我你更关注AI大模型里的哪类内容。

← 返回列表