AI Agent、RAG 与 LLM 工程化:从概念到落地的系统详解

过去很多人把大语言模型应用理解为“给模型发一个 prompt,然后拿到一段回答”。这类方式适合问答、改写、总结等单轮任务,但当业务开始要求模型能持续推进目标、调用系统能力、读取外部知识、记住长期状态、校验结果并处理异常时,仅靠传统 LLM 调用就不够了。AI Agent、RAG、Function Calling、记忆管理和多轮任务编排,本质上都是为了把 LLM 从“文本生成器”扩展成“可执行任务系统”的工程组件。

这篇文章围绕十个核心主题展开:AI Agent 与传统 LLM 的区别、RAG 的离线与在线流程、幻觉缓解、多轮 Agent 设计、Function Calling 落地、LangChain/LangGraph 的取舍、ReAct 框架、Agent 记忆管理、RAG 优化,以及文本相似度计算。目标不是罗列概念,而是解释每一部分在真实系统里为什么需要、如何设计、容易踩哪些坑。

1. AI Agent vs 传统 LLM:从“回答问题”到“完成目标”

1.1 传统 LLM 更像一次性推理接口

传统 LLM 应用通常是这样的流程:用户输入问题,后端拼接 prompt,模型生成回答,然后返回给用户。这种模式的优点是简单、响应快、成本低,适合客服 FAQ、文本润色、摘要生成、代码解释、翻译等任务。

但它有明显边界:模型本身不知道实时数据,不会主动调用系统,不会真正执行命令,也不会天然保存任务进度。它能“建议你怎么做”,但不能可靠地“替你做完”。例如用户说“帮我分析服务器日志并修复 Nginx 配置”,传统 LLM 只能生成排障建议;如果没有工具调用、文件读取、命令执行和验证闭环,它无法真正完成任务。

1.2 Agent 强调目标驱动和执行闭环

AI Agent 的核心不是“模型更聪明”,而是系统结构不同。Agent 通常围绕一个目标持续工作:理解目标、拆解步骤、选择工具、执行动作、观察结果、更新计划,直到任务完成或触发人工介入。

一个典型 Agent 至少包含以下能力:

  • 目标理解:把用户输入转成可执行目标,而不是只生成自然语言回答。
  • 规划能力:拆解任务步骤,判断先做什么、后做什么。
  • 工具调用:访问搜索、数据库、文件系统、代码执行器、浏览器、业务 API 等外部能力。
  • 状态管理:记录当前任务阶段、已执行步骤、失败原因和下一步。
  • 记忆能力:保存跨会话稳定信息,例如用户偏好、项目约定、长期配置。
  • 验证闭环:执行后检查结果,而不是只说“应该可以”。

1.3 Agent 的关键不是“自动化越多越好”

Agent 系统最容易犯的错误是过度自动化。模型可以规划,但不代表每一步都应该无约束执行。真实落地时,需要区分安全等级:

  • 低风险操作:查询资料、读取公开页面、生成草稿,可以自动执行。
  • 中风险操作:修改文件、调用内部 API、跑脚本,需要日志和回滚。
  • 高风险操作:删除数据、付款、发布生产配置、发送外部消息,需要人工确认或审批。

所以工程上更合理的 Agent 不是“完全放权”,而是“有边界的自主执行系统”。它应该能推进任务,也应该知道什么时候停下来、什么时候请求确认、什么时候回滚。

2. RAG 流程:让模型基于外部知识回答

2.1 为什么需要 RAG

LLM 的知识来自训练数据,存在三个问题:知识可能过时、无法覆盖私有文档、回答缺少可追溯来源。RAG(Retrieval-Augmented Generation,检索增强生成)就是为了解决这些问题:先从外部知识库找出相关资料,再把资料作为上下文交给模型生成答案。

简单说,RAG 不是让模型“凭记忆回答”,而是让模型“带资料回答”。它特别适合企业知识库、产品文档问答、法律条款检索、论文助手、客服知识库、内部 SOP 查询等场景。

2.2 离线流程:文档进入知识库

RAG 的离线流程负责把原始资料处理成可检索的数据,一般包括五步:

  1. 文档解析:读取 PDF、Word、网页、Markdown、表格、扫描件等内容。难点在于保留标题层级、表格结构、页码、来源链接和元数据。
  2. 清洗规范化:去掉页眉页脚、重复导航、广告、乱码、无意义空白,把内容整理成统一格式。
  3. 切块:将长文档拆成较小片段。切块太大,召回不精准;切块太小,语义不完整。常见做法是按标题、段落、语义边界切分,并保留一定 overlap。
  4. 向量化:用 embedding 模型把文本片段转成向量。语义相近的文本在向量空间里距离更近。
  5. 入库:把向量、原文片段、标题、来源、时间、权限标签等写入向量数据库或混合检索系统。

2.3 在线流程:问题进入检索与生成链路

用户提问后,在线流程一般是:

  1. 问题理解:识别用户真正想问什么,必要时改写查询。
  2. 问题向量化:将问题转成向量。
  3. 召回:从向量库取回 top-k 相关片段,也可以结合关键词检索。
  4. 重排:用 reranker 对候选片段重新排序,把真正能回答问题的内容放前面。
  5. 上下文构造:把高质量片段、来源、约束提示词一起放入 prompt。
  6. 生成答案:模型基于片段回答,并引用来源。
  7. 答案校验:检查答案是否使用了检索片段、是否编造来源、是否遗漏关键信息。

2.4 RAG 的核心难点

RAG 的难点不在“接一个向量库”,而在数据质量和检索质量。常见问题包括:

  • 解析失败:PDF 表格错乱、图片文字没 OCR、标题结构丢失。
  • 切块不合理:答案跨多个片段,模型拿不到完整上下文。
  • 召回不准:语义向量找到了相似语气,但不是正确事实。
  • 上下文污染:召回片段太多,混入无关内容,导致模型回答偏离。
  • 权限问题:不同用户能看到的文档不同,检索时必须带权限过滤。

因此,一个成熟 RAG 系统必须有评测集、召回命中率指标、答案可追溯、权限控制和持续优化机制。

3. LLM 幻觉缓解:降低错误,不是假装没有错误

3.1 幻觉是什么

幻觉指模型生成了看似合理但不真实、不准确或无法验证的内容。它可能表现为编造 API、编造论文、错误解释日志、混淆概念,或者在缺少资料时仍然给出肯定答案。

需要明确一点:幻觉无法被彻底消除,只能通过系统设计降低概率、限制影响范围,并在高风险场景加入校验与人工兜底。

3.2 用 RAG 提供依据

RAG 可以把模型回答限制在外部资料范围内,减少“凭空编造”。但 RAG 不是万能的:如果召回片段错误,模型仍会基于错误资料回答;如果 prompt 没有要求引用来源,模型也可能把检索内容和自身知识混在一起。

更稳妥的设计是要求模型回答时标注来源,并在没有足够依据时明确说“不确定”或“资料不足”。

3.3 用工具查询实时数据

对于价格、天气、新闻、版本号、库存、订单状态、服务器状态等实时信息,不能依赖模型记忆。应该让模型调用搜索、数据库、监控系统或业务 API 获取最新数据,再基于结果回答。

例如问“当前服务器磁盘是否满了”,正确流程不是让模型猜,而是执行磁盘查询命令,再返回结果。

3.4 约束提示词与结构化输出

提示词可以降低幻觉,例如:

  • 要求只基于给定资料回答。
  • 要求区分事实、推测和建议。
  • 要求无法确认时说明原因。
  • 要求输出 JSON schema,便于程序校验。

但提示词只是软约束,不能替代后端校验。特别是 Function Calling 场景,模型生成的参数必须由后端再次验证。

3.5 答案校验与人工审核

高风险场景必须增加校验环节,例如医疗、法律、金融、生产运维、合同生成等。常见做法包括:

  • 规则校验:检查金额、日期、权限、格式、必填字段。
  • 引用校验:答案中的关键事实必须能在来源片段中找到。
  • 多模型复核:让另一个模型检查是否有不一致或无依据结论。
  • 人工审核:发布、转账、删库、发送正式通知前必须人工确认。

4. LangChain / LangGraph:快速验证与工程可控之间的取舍

4.1 LangChain 的优势

LangChain 提供了大量现成组件:PromptTemplate、Retriever、Tool、Agent、Memory、Callback、Document Loader 等。它适合快速搭建 Demo、验证 RAG 流程、接入多种模型和向量库。

对于早期原型,LangChain 的价值是“少写胶水代码”。你可以很快把文档加载、切块、embedding、检索、生成串起来。

4.2 LangChain 的问题

复杂业务里,LangChain 的抽象层可能反而增加调试成本。典型问题包括:

  • 调用链很深,定位错误困难。
  • 内部状态不透明,不容易观测每一步输入输出。
  • 版本变化较快,接口兼容成本高。
  • 复杂流程需要绕过默认抽象,最后变成“框架里写框架”。

4.3 LangGraph 更适合有状态流程

LangGraph 更强调图结构和状态机,适合多步骤 Agent:节点代表任务步骤,边代表流程转移,状态对象在节点之间传递。它比纯 Agent loop 更可控,适合需要分支、重试、人工审批、失败回滚的流程。

例如一个代码修复 Agent 可以设计成:读取问题 → 定位文件 → 修改代码 → 运行测试 → 如果失败回到修改 → 如果通过提交结果。这个流程用图表达比让模型自由循环更稳定。

4.4 工程建议

我的建议是:用框架验证思路,但核心链路要可控、可观测、可替换。

  • 原型阶段可以用 LangChain/LangGraph 快速搭建。
  • 生产阶段要记录每一步输入、输出、耗时、错误和 token 成本。
  • 核心检索、工具执行、权限校验、状态存储不要完全黑盒化。
  • 复杂业务可以保留图编排思想,但把关键节点实现成自己的服务函数。

5. Function Calling 落地:让模型安全调用业务能力

5.1 Function Calling 的基本流程

Function Calling 是让模型不只输出文本,而是选择调用某个后端函数,并生成结构化参数。典型流程如下:

  1. 注册工具 schema:告诉模型有哪些函数、函数用途、参数类型、必填字段和枚举值。
  2. 模型选择调用:模型判断是否需要调用工具,并生成参数。
  3. 后端校验参数:检查类型、权限、范围、业务规则,不能直接信任模型参数。
  4. 执行函数:调用数据库、API、脚本或内部服务。
  5. 结果回填:把执行结果返回给模型,让模型继续生成用户可读答案。

5.2 工具 schema 要足够明确

schema 设计决定了模型能否正确调用工具。一个好的 schema 应该说明:

  • 工具适合什么场景。
  • 参数含义、格式、单位。
  • 哪些参数必填,哪些可选。
  • 枚举值有哪些。
  • 危险操作是否需要确认。

例如“发送邮件”工具必须要求收件人、主题、正文,并限制附件路径;“查询订单”工具必须校验用户是否有权限查看该订单。

5.3 后端校验不可省略

模型生成参数不等于参数可信。后端至少要做:

  • 类型校验:字符串、数字、数组、日期格式是否正确。
  • 权限校验:当前用户是否能调用这个工具、访问这个资源。
  • 范围校验:金额、数量、时间范围是否超限。
  • 幂等控制:避免模型重试导致重复下单、重复扣款。
  • 审计日志:记录谁在什么时候调用了什么工具。

5.4 工具失败时的兜底

工具调用会失败:API 超时、参数错误、权限不足、服务不可用。Agent 不能只把异常堆栈丢给用户,而要区分错误类型:

  • 可重试错误:网络波动、429、临时 5xx。
  • 不可重试错误:权限不足、参数非法、资源不存在。
  • 需要用户补充:缺少必要字段。
  • 需要人工介入:高风险操作失败或状态不一致。

6. 多轮对话 Agent 设计:上下文、状态和任务进度

6.1 多轮对话不是简单拼历史

最简单的多轮对话是把历史消息全部拼进 prompt,但这很快会遇到上下文窗口限制、无关信息干扰、成本上升等问题。真正的多轮 Agent 需要管理多类状态。

6.2 需要保存哪些状态

  • 最近对话:用于理解当前上下文,比如“刚才那个接口”指什么。
  • 任务状态:当前任务目标、已完成步骤、待执行步骤、失败记录。
  • 工具结果:检索结果、命令输出、API 返回、文件路径。
  • 用户偏好:语言、格式、风格、业务约定。
  • 环境信息:项目路径、部署环境、服务地址、常用命令。

6.3 每轮如何决策

每轮对话进入 Agent 后,可以按以下顺序处理:

  1. 识别用户意图:是问答、继续任务、修改要求,还是中断任务。
  2. 读取必要上下文:最近对话、任务状态、长期记忆、外部数据。
  3. 决定下一步:直接回答、检索、调用工具、请求澄清或拒绝执行。
  4. 执行并观察:调用工具后读取结果。
  5. 更新状态:标记任务进度、保存必要记忆、清理临时信息。
  6. 输出结果:用用户能理解的方式汇报已做什么、结果是什么、下一步是什么。

6.4 上下文压缩与过期管理

上下文不能无限增长,需要压缩和过期策略:

  • 短期上下文保留最近关键轮次。
  • 长任务定期生成任务摘要。
  • 临时工具输出只保留结论和可复查路径。
  • 过期信息自动丢弃,例如临时 token、一次性错误日志。
  • 长期记忆只保存稳定事实,不保存会很快过期的任务进度。

7. Agent 记忆管理:短期记忆、长期记忆与可治理性

7.1 短期记忆

短期记忆服务于当前会话和当前任务,例如当前正在编辑哪篇文章、已经运行过哪些测试、某个 API 刚返回了什么错误。短期记忆通常可以放在会话状态、缓存或任务数据库中。

短期记忆的特点是生命周期短、与当前任务强相关、可以在任务结束后归档或删除。

7.2 长期记忆

长期记忆保存稳定且未来仍有价值的信息,例如用户喜欢中文简洁回复、某项目使用 pnpm、某服务器只能通过 SSH alias 登录、某业务 API 有固定鉴权方式。

长期记忆必须谨慎写入。不要把临时任务结果、一次性 PR 编号、短期错误状态存进去,否则未来会污染判断。

7.3 记忆的存储方式

  • 关系型数据库:适合结构化偏好、用户画像、权限数据。
  • 向量库:适合按语义召回历史笔记、知识片段、案例。
  • 缓存:适合短期会话状态和临时任务进度。
  • 文件/对象存储:适合保存长文档、报告、日志备份。

7.4 记忆必须可更新、可删除、可解释

记忆系统不能只会“越存越多”。用户应该能查看、修改、删除记忆;系统也要能解释为什么使用某条记忆。尤其涉及个人信息、业务机密、权限偏好时,必须有清晰治理机制。

8. ReAct 框架:推理与行动交替

8.1 ReAct 的基本思想

ReAct 是 Reasoning + Acting 的组合。模型不是一次性回答,而是在推理和行动之间循环:先分析当前需要什么信息,再调用工具获取信息,然后基于观察结果继续推理。

一个简化流程是:

  1. 思考:我需要知道当前系统状态。
  2. 行动:调用监控查询工具。
  3. 观察:返回 CPU 负载和错误日志。
  4. 思考:错误来自数据库连接超时。
  5. 行动:检查数据库连接池配置。
  6. 观察:连接池已满。
  7. 回答:给出原因和修复建议。

8.2 ReAct 的优势

  • 适合信息不完整的任务。
  • 可以逐步收集证据。
  • 能把模型推理和外部工具结合起来。
  • 比一次性 prompt 更适合排障、检索、数据分析。

8.3 ReAct 的风险

ReAct 最大的问题是可能循环调用工具、过度探索或被错误观察带偏。因此必须设置边界:

  • 最大步数限制。
  • 工具调用超时。
  • 重复动作检测。
  • 失败后升级人工处理。
  • 每一步都记录输入输出,便于审计。

9. RAG 优化:重排、HyDE 与基于评测的迭代

9.1 重排为什么重要

向量召回返回的是“语义相似”的片段,但语义相似不等于能回答问题。重排模型会对“问题 + 候选片段”逐对打分,把真正相关的片段排到前面。

例如用户问“如何重置管理员密码”,向量召回可能找出“管理员权限说明”“密码策略”“重置流程”三个片段。真正能回答的是“重置流程”,重排能提高它的排名。

9.2 HyDE:先生成假想答案再检索

HyDE(Hypothetical Document Embeddings)的思路是:当用户问题很短、很模糊或和文档表达不一致时,先让模型生成一个“假想答案”或“假想文档”,再用这个更丰富的文本去检索。

例如用户问“怎么续费”,原始问题太短。HyDE 可能生成“用户想了解会员到期后如何续费、支付方式、续费入口和发票说明”,再用这段文本检索,召回效果可能更好。

但 HyDE 也有风险:假想答案可能引入错误方向。因此它适合提升召回候选,不应直接作为事实来源。

9.3 混合检索

生产 RAG 常用混合检索:向量检索负责语义匹配,关键词检索负责精确匹配。对于型号、订单号、错误码、函数名、法律条款编号等内容,关键词检索往往比向量更可靠。

常见组合是:BM25/关键词召回 + 向量召回 + 合并去重 + reranker 重排。

9.4 基于评测数据优化

RAG 优化不能只凭感觉。需要建立评测集,包括问题、标准答案、应召回文档、不可接受答案。然后观察:

  • 召回是否命中正确片段。
  • 正确片段排名是否足够靠前。
  • 答案是否忠实于片段。
  • 引用是否准确。
  • 不同切块参数、embedding 模型、reranker 的效果差异。

10. 文本相似度计算:从文本到向量再到阈值判断

10.1 基本步骤

文本相似度计算通常分三步:

  1. 输入文本:准备两段或多段需要比较的文本。
  2. 向量化:用 embedding 模型把文本转成向量。
  3. 计算相似度:常用余弦相似度,值越高表示方向越接近。

余弦相似度关注向量方向,而不是长度,因此适合比较语义相近程度。

10.2 没有 embedding 时的近似方法

如果没有 embedding 模型,也可以用传统方法:

  • 词袋模型:统计词频,把文本表示成词频向量。
  • TF-IDF:降低常见词权重,提高关键词权重。
  • 编辑距离:适合比较短字符串、名称、拼写差异。
  • Jaccard 相似度:比较两个词集合的交集与并集。

传统方法对关键词敏感,但不理解深层语义;embedding 更适合语义相似,TF-IDF 更适合精确词匹配。实际系统里常常两者结合。

10.3 阈值判断

相似度算出来后,还要设置阈值。例如高于 0.85 认为高度相似,0.65 到 0.85 需要人工确认,低于 0.65 认为不相似。但阈值不能照搬,必须基于业务数据调参。

比如 FAQ 匹配可以用较高阈值,避免答错;去重系统可以用中等阈值,再交给人工复核;推荐系统则可能允许较低阈值以扩大候选。

11. 一个可落地的整体架构

把上面内容组合起来,一个比较完整的 AI 应用架构可以分成以下层次:

  • 交互层:Web、App、IM、API,负责接收用户输入和展示结果。
  • 会话层:管理多轮上下文、任务状态、用户身份。
  • 编排层:决定直接回答、检索、调用工具、走审批还是结束任务。
  • 模型层:接入 LLM、embedding、reranker、分类模型。
  • 知识层:文档解析、向量库、关键词索引、权限过滤。
  • 工具层:业务 API、数据库、搜索、文件、代码执行、浏览器等。
  • 治理层:日志、评测、成本、权限、安全、人工审核、回滚。

真正稳定的系统,不是把所有能力塞进一个 prompt,而是把模型放在可观测、可约束、可验证的工程框架里。

12. 总结

AI Agent、RAG、Function Calling、记忆管理和 ReAct 并不是彼此孤立的概念,而是同一类问题的不同侧面:如何让 LLM 从“会说”变成“能做”,从“凭记忆回答”变成“基于证据回答”,从“一次性生成”变成“可持续执行任务”。

落地时可以记住几条原则:

  • Agent 要有目标、工具、状态和验证闭环。
  • RAG 的质量取决于文档解析、切块、召回、重排和评测。
  • 幻觉不能完全消除,只能通过依据、工具、校验和人工审核降低风险。
  • Function Calling 必须后端校验,不能信任模型参数。
  • 记忆要分短期和长期,长期记忆必须可治理。
  • 框架能加速原型,但生产核心链路必须可控、可观测。

最终,AI 应用的竞争力不只来自模型能力,还来自工程系统是否可靠:数据是否准确、工具是否安全、流程是否可恢复、结果是否可验证。这才是从 Demo 走向生产的关键。