公司动态
从零构建RAG应用:AI转型中技术人员的工程实践
我像是给自己挖了坟墓——这是 AI 转型时期很多一线工作者说过的一句真实感慨。对技术人员来说这种焦虑更多来自工作内容的变化AI 编程助手能快速生成样板代码、写单元测试、解释陌生报错大模型 API 开始承担客服、审核、数据分析等原本需要人反复处理的环节。问题已经不是要不要接受 AI而是技术人员该用什么方式参与这场转型让 AI 成为可被自己理解和控制的工程工具而不是反过来替代自己。这篇文章围绕一条完整的技术主线展开先从机制上分析 AI 转型对技术工作的影响然后搭好一套可用于学习和实验的开发环境再从零实现一个最小可运行的 RAG 问答应用把“文档加载、文本切分、向量检索、大模型生成”这条链路真正跑通最后给出运行验证、效果评估、问题排查和长期学习路线。完成这个闭环后你至少能从“会用 AI 工具”推进到“能做 AI 应用”并在实际项目中具备独立排查问题的能力。1. 先理解 AI 转型为什么让一线工作者焦虑1.1 被替代的是任务不一定是整个岗位“我像是给自己挖了坟墓”这句话在一些场景里是成立的但它描述的并不是“AI 取代了整个职业”而是“一个人把自己长期固定在了一类可以被自动化的任务上”。举个例子。一个后端开发者的日常工作可以拆成理解需求、设计接口、编写增删改查代码、写单元测试、调试线上问题、做代码评审、配置部署。AI 编程工具目前最擅长的是中间这一段也就是生成样板代码、补测试用例、解释报错信息。如果一个人每天的主要产出恰好集中在这类任务上同时缺乏对业务的判断能力那么 AI 对他的替代性确实很高。反过来如果一个开发者用 AI 快速完成样板代码把节省下来的时间用于梳理业务边界、排查索引和事务问题、优化接口性能他的位置就不容易被替代。被替代的不是岗位本身而是岗位里那些可以标准化、模板化的部分。1.2 技术人员的价值在向两侧迁移从工程实践看AI 转型后技术人员的价值正在向两端集中。第一端是“定义问题”。包括把模糊的业务需求拆解成可执行的技术方案明确评价标准设计提示词和评估集判断模型输出是否符合预期。第二端是“系统集成与兜底”。包括数据质量、权限控制、稳定性、成本、日志审计、回滚方案。中间层的机械编码工作正在被压缩。这也就是为什么越来越多招聘要求里出现“AI 工程实践”“模型部署”“Agent 开发”这类关键词。模型本身是外部能力技术人员的差异体现在能不能把模型安全、稳定、可评估地接入业务系统。1.3 技术人员转型的四个常见方向AI 转型不是只有“算法工程师”一条路大多数后端、测试、运维、产品背景的人可以往四个方向走。方向核心工作典型技能准备常见岗位映射AI 应用开发用大模型 API、RAG、Agent 做业务功能Python 或 Java、LangChain/Spring AI、向量数据库后端开发、全栈工程师AI 模型部署与平台模型服务化、推理优化、资源管理Docker、Kubernetes、vLLM、GPU 环境平台工程师、AI 运维AI 产品与体验需求定义、提示词设计、效果评估数据分析、评估体系、用户场景拆解AI 产品经理、解决方案AI 质量与治理输出审计、成本控制、合规检查日志、监控、测试、审计测试开发、质量工程无论选择哪个方向都需要一条共同的技术底座环境搭建、模型调用、检索增强、部署运行、效果评估。下面从环境开始把这套底座完整搭建起来。2. 搭建一套能支撑学习和实验的 AI 开发环境2.1 Python 与依赖环境AI 生态里绝大多数框架、模型 SDK 和示例代码都优先支持 Python学习阶段直接用 Python 可以避免很多兼容性问题。Java 团队可以关注 Spring AI但在入门阶段Python 的迭代速度更快调试成本更低。推荐使用 Python 3.10 或 3.11。隔离环境用虚拟环境完成不要直接往系统 Python 里装依赖。python --version python -m venv .venv source .venv/bin/activate pip install --upgrade pipWindows 下激活命令是.venv\Scripts\activate。虚拟环境的作用是让项目之间的依赖互不干扰尤其是 AI 框架更新很快不同项目很可能需要不同版本的库。项目先建立一个requirements.txt内容可以按下面的参考版本锁定langchain0.2.14 langchain-community0.2.12 langchain-openai0.1.23 langchain-text-splitters0.2.4 chromadb0.5.5 openai1.40.3 python-dotenv1.0.1需要注意LangChain 的 API 变化较快新版本很可能调整方法名。上面的版本号只作为参考落地前要结合自己的 Python 版本确认兼容性。2.2 模型能力来源API 与本地模型如何取舍开发 AI 应用的第一步是确定模型从哪来。云模型 API 和本地部署模型各有利弊不是越贵的方案越好。维度云模型 API本地部署模型硬件要求低按调用量付费需要 GPU 或较高内存数据安全数据会发送到服务商需要评估数据留在自有环境延迟依赖网络状态本地推理延迟更可控运维成本服务商负责升级和稳定性自己处理部署、监控、扩容学习成本低适合入门高适合生产优化入门阶段建议先使用云模型 API把精力放在应用逻辑上。等到需要控制成本、满足数据合规要求时再考虑用 Ollama 做本地实验用 vLLM 这类推理框架做生产部署。2.3 开发框架与日常 AI 编程工具应用层框架的选择决定了代码组织方式。LangChain 生态最全文档加载、切分、向量存储、模型调用都有封装但 API 变动频繁。Spring AI 适合 Java 团队能够与 Spring Boot 项目自然整合。如果业务逻辑简单也可以直接用模型厂商的 SDK不引入额外框架。日常开发中Cursor、IDEA AI Assistant、VS Code Copilot 这类 AI 编程工具能显著加快编码速度。但要注意工具会生成代码却不会替你理解代码。使用 AI 编程工具时每一步都要能解释清楚“它为什么这样写边界条件是什么”。如果之后要把服务发布出去可以准备一台云主机。云主机按需购买即可初期不需要高配重点是学会把 Python 服务用 systemd、Docker 或反向代理跑起来。这些都是工程化必经环节。3. 从零实现一个最小 RAG 问答应用3.1 为什么第一个项目选择 RAGRAG 全称是 Retrieval-Augmented Generation检索增强生成。核心思路是从私有文档库中检索出与问题相关的片段再把这些片段作为上下文交给大模型生成答案。选择 RAG 作为第一个项目有三个原因。第一它解决的是真实问题大模型训练数据是公开的不知道企业内部文档内容直接问会“一本正经地胡说八道”。第二它覆盖了完整工程链路数据清洗、文本切分、向量化、检索、模型生成、效果评估。第三它是当前企业 AI 应用里落地最多的形态做这个项目积累的经验可以平移到客服、内部知识库、文档问答等场景。3.2 项目结构与数据准备项目目录保持最小化只保留必要文件。rag_demo/ ├── .env ├── requirements.txt ├── data/ │ └── ops_manual.md └── rag_app.pydata/ops_manual.md是一份模拟的内部运维手册内容要简单但能验证检索逻辑# 值班系统操作手册 ## 1. 登录说明 值班系统使用工号加动态口令登录。连续输错 5 次会锁定账号 30 分钟。 ## 2. 告警处理 收到磁盘使用率超过 85% 的告警时先检查磁盘分布再清理超过 90 天的日志文件。 ## 3. 数据备份 数据库每天凌晨 2 点执行全量备份备份文件保留 14 天。这样一份文档足以验证后续的三个核心能力能否根据问题检索到正确片段能否用检索片段生成答案以及超出知识库范围时模型是否拒绝回答。3.3 核心实现代码rag_app.py包含两个部分构建索引和回答问题。构建索引时读取文档、切分、向量化并写入 Chroma回答问题时先检索相关片段再交给大模型生成。import os import sys from dotenv import load_dotenv from langchain_community.document_loaders import TextLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_openai import OpenAIEmbeddings, ChatOpenAI from langchain_community.vectorstores import Chroma from langchain.prompts import ChatPromptTemplate load_dotenv() PERSIST_DIR ./chroma_db DOC_PATH ./data/ops_manual.md def build_index(): loader TextLoader(DOC_PATH, encodingutf-8) docs loader.load() splitter RecursiveCharacterTextSplitter( chunk_size500, chunk_overlap50, separators[\n\n, \n, 。, , , ], ) chunks splitter.split_documents(docs) embedding OpenAIEmbeddings( modelos.getenv(EMBEDDING_MODEL, text-embedding-3-small) ) vectorstore Chroma.from_documents( documentschunks, embeddingembedding, persist_directoryPERSIST_DIR, ) vectorstore.persist() print(findex built, chunks: {len(chunks)}) def ask(question: str): embedding OpenAIEmbeddings( modelos.getenv(EMBEDDING_MODEL, text-embedding-3-small) ) vectorstore Chroma( persist_directoryPERSIST_DIR, embedding_functionembedding, ) retriever vectorstore.as_retriever(search_kwargs{k: 3}) context_docs retriever.invoke(question) context \n\n.join([d.page_content for d in context_docs]) prompt ChatPromptTemplate.from_messages([ ( system, 你是企业内部知识库助手。只能根据上下文中已有的内容回答问题 如果上下文中没有答案明确回答“知识库中未找到相关说明”不要编造。, ), (human, 上下文\n{context}\n\n问题{question}), ]) llm ChatOpenAI( modelos.getenv(LLM_MODEL, gpt-4o-mini), temperature0.1, ) chain prompt | llm answer chain.invoke({context: context, question: question}).content return answer, context_docs if __name__ __main__: if len(sys.argv) 1 and sys.argv[1] build: build_index() else: q input(请输入问题) answer, docs ask(q) print(\n答案) print(answer) print(\n检索来源) for i, d in enumerate(docs, 1): print(f{i}. {d.page_content[:80]}).env文件保存 API 配置不要提交到代码仓库OPENAI_API_KEYsk-xxxx OPENAI_BASE_URLhttps://api.example.com/v1 LLM_MODELgpt-4o-mini EMBEDDING_MODELtext-embedding-3-small只要模型服务商提供 OpenAI 兼容接口就可以通过OPENAI_BASE_URL切换到不同模型。使用国内模型时把 base_url 和 model 名称改成对应的值即可。3.4 启动与运行pip install -r requirements.txt python rag_app.py build python rag_app.pybuild会把文档切分并写入本地 Chroma 持久化目录。第二次运行问答时不再需要重建索引直接读取向量库即可。输入“磁盘告警怎么处理”预期输出会引用手册中的 85% 阈值和日志清理策略。如果改成“工资怎么计算”模型应回答“知识库中未找到相关说明”而不是自己编一个答案。4. 关键机制与参数取舍详解4.1 文档切分检索质量的第一道门文本切分决定了检索的基本单位。切分太大一个块里塞进多个主题检索时命中的内容可能包含大量无关信息切分太小单个块缺少上下文模型无法理解完整语义。参数含义常见值设置错误的表现chunk_size单个文本块的最大字符数300 到 800太大则检索噪声多太小则语义不完整chunk_overlap相邻文本块之间的重叠字符数50 到 100为 0 时段落边界信息容易丢失separators切分时的分隔符优先级按结构从大到小缺少中文标点时句子会被硬切代码里把 “。” “” “” 加进 separators是为了让中文文本尽量在句子边界切断避免一个完整句子被劈成两半。对于带标题的 Markdown 或结构化文档生产环境需要按标题层级做父子块切分而不是只按字符数硬切。4.2 向量检索语义匹配怎么做切分完成后每个文本块通过 Embedding 模型转换成向量。查询问题时问题文本也被转换成向量向量库用余弦相似度找到最接近的文本块。search_kwargs{k: 3}表示返回最相似的 3 个块。k 值太小关键信息可能漏掉k 值太大不相关内容会混进上下文影响生成质量。事实问答场景3 到 5 是比较常用的区间。向量检索适合语义匹配但并不是所有检索场景都该用它。企业实践中常见做法是“关键词检索 向量检索”的混合模式先召回再统一排序。对于编号、报错码、设备型号这类精确信息关键词检索往往比向量检索更可靠。4.3 生成阶段提示词与生成参数检索到上下文后生成阶段是否可控取决于提示词和采样参数。系统提示词必须明确约束模型的行为。上面代码里的规则是“只能根据上下文回答上下文没有就说不存在”。这是压制幻觉最基础的一层防护。temperature控制生成的随机性。事实问答中建议设置在 0 到 0.3 之间越大越容易发散甚至编造内容。max_tokens控制输出长度设置太小答案会被截断太大则单次调用成本增加。参数含义推荐值错误表现temperature生成随机性事实问答 0 到 0.3过高导致答案偏离上下文top_k检索上下文条数3 到 5太小漏信息太大引入噪声max_tokens最大输出长度500 到 1000太小答案被截断system 提示词约束回答范围明确“只依据上下文”缺少约束时模型容易编造生产环境的提示词应单独管理并针对不同业务场景写多个模板不建议把提示词硬编码在业务代码里。4.4 数据质量决定系统的上限RAG 系统的质量上限由知识库文档决定。模型再强也无法从错误、过时、重复的文档中生成正确答案。使用知识库前要确认几点文档是否有明确版本是否有人负责更新是否有重复或矛盾的说明敏感信息是否做了权限分层文档格式是否统一能否稳定解析。很多 RAG 项目上线后发现效果不行问题并不在模型而在知识库本身。5. 运行验证与效果评估5.1 功能验证三个必须测的场景项目跑通不等于功能正确。最少要验证三个场景第一个是命中场景。问一个答案明确在文档里的问题确认答案引用了正确内容并且检索来源里出现了对应片段。第二个是越界场景。问一个知识库不存在的敏感话题确认模型拒绝回答而不是把训练数据里的东西拿出来拼凑。第三个是边界场景。问“账号被锁怎么办”确认模型能回答出“输错 5 次、锁定 30 分钟”这两个关键约束。示例输出答案 收到磁盘使用率超过 85% 的告警时先检查磁盘分布再清理超过 90 天的日志文件。 检索来源 1. 收到磁盘使用率超过 85% 的告警时先检查磁盘分布再清理...验证时一定要把检索来源打印出来。如果答案对了但检索来源里没有对应内容说明大模型可能在凭记忆作答这是另一种形式的幻觉。5.2 效果评估不要只凭感觉评估需要一套固定的测试问题集。从知识库中整理 20 到 50 个问答对覆盖正常问题、边界问题、越界问题然后建立三个简单指标。上下文命中率衡量检索阶段是否把正确答案片段带回来了。答案正确率衡量最终回答是否准确。幻觉率衡量回答中有多少信息不在检索上下文里。每次修改切分参数、提示词或模型后都用同一套问题集重跑对比指标变化。这样就不需要靠“感觉好像变好了”来决策。自动化评估可以借助 RAGAS、DeepEval 这类开源框架也可以先用表格手工记录结果。对个人项目来说先建立一套固定问题集比盲目引入评估框架更有价值。5.3 学习环境与生产环境的差异个人电脑上能跑通的脚本距离生产服务还有一段工程距离。维度学习 Demo生产环境配置管理本地 .env配置中心或密钥管理系统日志print 输出结构化日志与请求链路追踪模型调用失败重试即可超时、限流、降级、熔断数据权限不校验文档级权限控制成本调用量小预算告警、缓存、token 统计部署命令行运行Docker、Kubernetes、CI/CD知识库更新手动重建索引版本化、异步更新、灰度发布生产环境的 RAG 服务除了写业务代码还需要考虑知识库如何增量更新、检索接口如何限流、敏感文档如何控制权限、模型调用如何监控成本。这些内容越早接触越好。6. 常见问题排查路径6.1 依赖冲突与框架版本变化现象pip install报错运行时出现 pydantic 兼容问题或者 LangChain 某个类找不到。原因LangChain 等 AI 框架迭代快版本之间 API 变动很大Python 生态中 pydantic 版本冲突也非常常见。检查方式查看完整报错堆栈用pip list确认当前环境中的版本到框架官方变更日志里确认方法名是否调整。处理建议创建独立虚拟环境按参考版本锁定依赖升级框架时先跑一遍测试问题集。不要把项目直接安装在系统 Python 里。6.2 检索结果为空或答非所问现象文档里明明有答案模型却说找不到或者返回的内容和问题完全无关。原因文本切分粒度不合理中文标点没有加入分隔符Embedding 模型不匹配文档实际没被加载旧的向量索引没有随文档更新。检查方式先打印构建索引时的chunks数量确认文档确实被切分再打印检索返回的片段确认检索阶段是否命中最后检查向量库持久化目录是否对应最新数据。处理建议调整chunk_size到 300 到 800 之间加入中文分隔符修改文档后必须重新执行python rag_app.py build重建索引。排查顺序是“数据有没有进来 - 切片是否合理 - 检索是否命中 - 再考虑生成”。6.3 API 超时、限流与费用问题现象请求等待很久后报超时返回 429 限流错误月底发现模型调用费用超出预期。原因没有设置重试和超时并发调用过高相同问题重复请求没有做缓存也没有预算告警。检查方式查看接口返回的 HTTP 状态码和错误体到服务商控制台查看 token 用量和调用次数结合日志确认哪些接口消耗最大。处理建议调用模型 SDK 时启用指数退避重试对相似问题做缓存减少重复调用在服务商控制台设置每月预算告警控制max_tokens避免生成超长无效内容。6.4 幻觉问题现象模型给出的内容在知识库中完全不存在或者把多个文档的内容拼接成错误结论。原因检索阶段没有带回关键内容模型只能凭训练记忆作答系统提示词约束不够temperature设置过高。检查方式打印context_docs确认生成答案依据的上下文是否包含正确信息。如果上下文里根本没有该信息问题在检索如果上下文有信息但答案仍然错误问题在提示词或生成参数。处理建议强化系统提示词明确要求只能依据上下文回答并要求模型引用来源片段把temperature调到 0.1 或更低用固定问题集记录幻觉率每次改动后对比。问题现象常见原因检查方式处理建议依赖安装报错版本冲突看完整堆栈、pip list锁定版本、独立虚拟环境检索结果为空切分不合理或索引过期打印 chunks 和检索片段调参后重建索引429 限流并发过高、无重试看状态码和用量记录指数退避、加缓存、预算告警答案编造内容检索漏召回或提示词不严打印检索来源修检索、约束提示词、降低温度7. 面向长期转型的实践建议与学习路线7.1 每周可执行的转型清单转型不是学完一门课就完成的建议把它拆成每周可执行的动作。每周用模型 API 实现一个可运行的小功能比如文档摘要、文本分类、关键词抽取。选一个开源 RAG 或 Agent 项目读一条完整调用链弄清楚数据从进入到生成经历了哪些步骤。记录每次提示词和参数变化后的效果差异逐渐建立自己的评估问题集。学习 Docker 和云主机部署把自己写的服务发布出去再补上日志和监控。每次调用记录 token 消耗建立成本意识。每季度复盘一次你的工作中哪些任务已经被 AI 自动化你在这些任务上的附加价值到底在哪里。7.2 五个阶段的学习路线第一阶段是模型 API 基础。掌握 chat、completion、embedding 三种核心接口的区别理解 token 的含义和计费方式。第二阶段是提示词工程。掌握 system prompt、few-shot、输出格式约束知道哪些问题该调提示词哪些问题该改流程。第三阶段是 RAG 工程。沿本文的例子继续深入学习文档结构解析、父子切分、混合检索、重排序。第四阶段是 Agent 基础。学习 function calling、工具调用、任务拆解了解 LangChain Agent 和 Spring AI 的实现差异。第五阶段是部署与质量。学习 Docker、vLLM、监控告警掌握评测集、成本控制、权限管理。这五个阶段对应了文首说的“AI 工程实践”和“AI 模型部署”这两类核心能力。7.3 三个容易踩的坑第一个坑是只复制不验证。网上代码片段可能来自不同版本直接复制大概率报错。每段代码都要运行、理解、测试边界条件才能变成自己的工程能力。第二个坑是用 AI 加速但放弃理解。一直让 AI 生成代码却不阅读时间一长系统出了问题无法定位需求变化无法评估影响。这正是“给自己挖坟墓”的技术版本你不是被 AI 替代的是被只会复制粘贴的自己替代的。第三个坑是跳过评估直接上线。没有固定问题集没有指标基线任何修改都靠“看起来不错”来判断。结果就是系统越改越不可控。先建评估再做迭代这是 RAG 项目最值得投入的一步。回到开头那句感慨。AI 转型期真正危险的不是模型变得更强而是技术人员把自己的工作停留在“可以被自动化的任务层”。如果你能理解 RAG 链路里每一步为什么存在能定位一次错误是来自切分、检索、提示词还是模型调用能在数据质量、成本、权限这些工程问题上做出判断你的位置就不是模型能轻易替代的。先跑通最小闭环再迭代评估这是 AI 转型里最有价值的第一步。