欢迎光临
我们一直在努力

RAG与智能问答系统实战:从需求分析到Agent流程自动化完整落地

引言:从“对话机器人”到“AI 业务员”的演进

随着大语言模型(LLM)能力的爆发,单纯依赖模型内在知识已经无法满足企业级业务的需求。我们正面临着三大核心挑战:

  • 幻觉问题:LLM 容易捏造事实,无法确保回答严格基于企业内部数据。
  • 时效性问题:LLM 的训练数据存在截止日期,无法回答最新的业务动态。
  • 能力边界问题:LLM 只能“说”,无法“做”。例如,它无法查询库存、无法下单、无法调用外部业务系统。
  • 检索增强生成(RAG) 解决了前两个问题,而 AI Agent(智能体) 正是解决第三个问题的核心利器。本文将带领读者一步步从需求分析入手,完成一套包含 RAG 核心链路、Agent 动作编排、异步实时交互以及生产级部署运维的完整实战。


    一、 需求分析、技术选型与系统架构设计

    1.1 业务场景与痛点挖掘

    场景设定:某大型制造企业需要构建一个“内部知识专家 AI 助手”。这个助手需要解决三个层次的业务需求:

    • 基础层:回答员工关于公司制度、技术文档、产品手册的问题(基础 RAG)。
    • 动作层:当员工询问“我的项目审批进度如何了”时,AI 需要调用内部 OA 接口查询,并返回实时数据(Agent 工具调用)。
    • 分析层:当员工问“今年 Q1 的客户投诉数据有什么趋势”时,AI 需要跨多个知识库检索,进行逻辑推理并生成分析结论(Agent 任务拆解与上下文管理)。

    1.2 总体系统架构设计

    基于上述需求,我们采用前后端分离 + 编排层中间件的架构:

    • 前端层:基于 React / Vue 构建。
    • 网关层(BFF):负责身份认证、限流与 WebSocket/SSE 协议转换。
    • 编排层(Agent Orchestration):核心大脑,使用 LangChain / LangGraph 实现。
    • 向量检索与数据层:Pinecone / Milvus 向量数据库 + 关系型数据库(存储工单状态、用户权限等)。
    • 大模型层:通过 Azure OpenAI / DeepSeek / 自研大模型提供的 API 接口。
    • 工具与插件层:内部 OA 系统 API、汇率查询、天气预报、搜索引擎等。

    二、 核心 RAG 与 AI Agent 工作流编排实现

    2.1 基础 RAG 链路代码实战(Python + LangChain)

    我们首先实现标准的 RAG 链路:文档加载 -> 文本切分 -> 向量化存储 -> 检索 -> 上下文合成 -> 生成。

    # rag_core.py
    import os
    from langchain_community.embeddings import OpenAIEmbeddings
    from langchain_community.vectorstores import Chroma
    from langchain.text_splitter import RecursiveCharacterTextSplitter
    from langchain_community.document_loaders import PyPDFLoader, TextLoader
    from langchain_openai import ChatOpenAI
    from langchain_core.prompts import ChatPromptTemplate

    class RAGService:
    def __init__(self, persist_directory="./chroma_db"):
    self.embeddings = OpenAIEmbeddings()
    self.vectorstore = Chroma(persist_directory=persist_directory, embedding_function=self.embeddings)
    self.llm = ChatOpenAI(model="gpt-4-turbo", temperature=0.2)

    def load_and_index(self, file_paths):
    """在线构建知识库"""
    docs = []
    for path in file_paths:
    if path.endswith(".pdf"):
    loader = PyPDFLoader(path)
    else:
    loader = TextLoader(path, encoding='utf-8')
    docs.extend(loader.load())

    # 文本切分(Chunking),设定重叠区域保持上下文
    text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
    splits = text_splitter.split_documents(docs)

    # 存入向量数据库
    self.vectorstore.add_documents(splits)
    self.vectorstore.persist()
    return f"成功存入 {len(splits)} 个片段。"

    def simple_rag_query(self, query):
    """基础检索增强生成"""
    # 1. 检索 Top-K 相关知识片段
    retriever = self.vectorstore.as_retriever(search_kwargs={"k": 4})
    context_docs = retriever.get_relevant_documents(query)
    context_text = "\\n\\n".join([doc.page_content for doc in context_docs])

    # 2. 构造 Prompt
    prompt_template = ChatPromptTemplate.from_template(
    "你是一个企业内部专家,请基于以下提供的资料,严谨地回答用户的问题。如果资料中没有相关内容,请回答“资料库中未找到相关信息”,不要捏造。\\n\\n"
    "【企业资料】:{context}\\n\\n"
    "【用户问题】:{question}\\n"
    )
    chain = prompt_template | self.llm

    # 3. 调用 LLM 生成回复
    return chain.invoke({"context": context_text, "question": query}).content

    2.2 升级为具有“行动力”的 AI Agent

    仅仅检索文档是远远不够的。接下来我们将 RAG 封装成一个工具(Tool),并利用 LangGraph 构建具备状态管理和工具调用能力的 Agent 工作流(对标 JD 第 3 条中的“Agent工作流编排”)。

    # agent_workflow.py
    import json
    import requests
    from typing import TypedDict, List
    from langgraph.graph import StateGraph, END
    from langchain_core.agents import AgentAction, AgentFinish
    from langchain_core.messages import BaseMessage, HumanMessage, SystemMessage, AIMessage
    from langgraph.prebuilt import ToolExecutor
    from langgraph.graph import StateGraph, END

    # 1. 定义 Agent 的状态(State)
    class AgentState(TypedDict):
    messages: List[BaseMessage]
    next_step: str

    # 2. 定义工具(Tools),将 RAG 包装为工具
    def rag_search_tool(query: str) > str:
    """查询企业内部资料库,获取知识信息"""
    # 这里复用前面的 RAGService
    rag = RAGService()
    return rag.simple_rag_query(query)

    def query_internal_api_tool(parameter: str) > str:
    """查询企业内部 OA 系统 API(例如审批状态)"""
    # 模拟调用内部 API
    print(f"正在调用内部 API,参数:{parameter}")
    # response = requests.get("https://internal.company.com/api/approve?flow_id=…")
    return json.dumps({"status": "已完成", "detail": "审批流已流转至最后节点"})

    # 3. 构建 Agent 节点(LLM 决策核心)
    from langchain_openai import ChatOpenAI
    from langgraph.prebuilt import ToolExecutor, ToolInvocation
    from langchain_core.tools import StructuredTool

    # 注册工具
    tools = [
    StructuredTool.from_function(rag_search_tool),
    StructuredTool.from_function(query_internal_api_tool)
    ]

    # 模型绑定工具
    model = ChatOpenAI(model="gpt-4-turbo", temperature=0).bind_tools(tools)

    def agent_node(state: AgentState):
    """Agent 节点:决定下一步是思考、调用工具、还是结束"""
    messages = state["messages"]
    response = model.invoke(messages)
    return {"messages": [response]}

    # 4. 执行工具节点
    def tool_node(state: AgentState):
    """执行工具调用的节点"""
    last_message = state["messages"][1]
    tool_calls = last_message.tool_calls
    if not tool_calls:
    return {"messages": []}

    tool_invocation = ToolInvocation(
    tool=tool_calls[0]["name"],
    tool_input=tool_calls[0]["args"],
    )

    tool_result = tools[0].invoke(tool_invocation) # 简化逻辑,实际需循环调用
    response = AIMessage(
    content=str(tool_result),
    name=tool_invocation.tool,
    additional_kwargs={"tool_call_id": tool_calls[0]["id"]}
    )
    return {"messages": [response]}

    # 5. 构建流程图与路由(Workflow)
    def should_continue(state: AgentState) > str:
    last_message = state["messages"][1]
    if last_message.tool_calls:
    return "tools"
    return END

    workflow = StateGraph(AgentState)
    workflow.add_node("agent", agent_node)
    workflow.add_node("tools", tool_node)

    workflow.set_entry_point("agent")
    workflow.add_conditional_edges("agent", should_continue, {"tools": "tools", END: END})
    workflow.add_edge("tools", "agent")

    # 编译为可运行的应用
    app = workflow.compile()

    # 测试调用
    inputs = {"messages": [HumanMessage(content="请帮我查询昨天发布的《Q2采购指南》文档内容,并查一下我的工单编号 'T-20260716' 的审批进度。")]}
    for event in app.stream(inputs):
    for key, value in event.items():
    print(f"节点 [{key}]: {value['messages'][1].content if value.get('messages') else ''}")

    架构洞察:通过 LangGraph 构建的循环逻辑,Agent 可以在一轮对话中主动分步执行(先搜资料,再调 API),并将两次返回结果汇总,结合上下文管理,最终给出高确定性的结论,这彻底打破了传统规则引擎的死板限制。


    三、 面向生产的前后端工程实践

    在实际生产环境中,AI 回复往往需要几秒甚至几十秒。如果直接使用 HTTP 阻塞式接口,前端会因为请求超时而报错。因此,我们需要引入 SSE(Server-Sent Events) 或 WebSocket 实现流式传输(Streaming)。

    3.1 后端异步流式接口设计(FastAPI + SSE)

    # api.py
    from fastapi import FastAPI, Request
    from fastapi.responses import StreamingResponse
    from sse_starlette.sse import EventSourceResponse
    import asyncio
    from agent_workflow import app as agent_app # 导入上文中构建的 Agent
    from langchain_core.messages import HumanMessage, AIMessageChunk

    app = FastAPI()

    async def stream_agent_response(query: str):
    """
    在 Agent 执行过程中,使用流式方式逐步返回 LLM 的 Token 和 工具执行状态
    """

    inputs = {"messages": [HumanMessage(content=query)]}

    try:
    # 使用异步流式执行 LangGraph Agent
    async for event in agent_app.astream(inputs):
    for key, value in event.items():
    msg = value.get('messages', [])
    if not msg:
    continue
    msg = msg[1]

    # 如果 Agent 正在执行工具
    if key == "tools":
    yield {
    "event": "tool_call",
    "data": f"【Action】正在调用工具: {msg.content}"
    }

    # 如果 Agent 正在进行LLM生成(核心需要流式输出 Token)
    elif key == "agent":
    if hasattr(msg, 'content') and msg.content:
    # 确保是逐步吐出的 Token
    yield {
    "event": "message",
    "data": msg.content # 在实际生产中,这里应处理 AIMessageChunk 的增量
    }
    # 流结束
    yield {"event": "end", "data": "[DONE]"}
    except Exception as e:
    yield {"event": "error", "data": f"系统异常: {str(e)}"}

    @app.get("/chat/stream")
    async def chat_stream(query: str):
    """SSE 流式接口"""
    return EventSourceResponse(stream_agent_response(query))

    3.2 前端工程化:基于 React 的流式交互体验

    前端需使用 EventSource 来解析 text/event-stream 响应,实现打字机效果的交互体验。

    // ChatBox.jsx (React伪代码)
    import React, { useState } from 'react';

    const ChatBox = () => {
    const [messages, setMessages] = useState([]);
    const [input, setInput] = useState('');
    const [isLoading, setIsLoading] = useState(false);

    const sendMessage = () => {
    if (!input.trim()) return;
    setMessages(prev => […prev, { role: 'user', content: input }]);
    setIsLoading(true);

    const currentInput = input;
    setInput('');

    // 构造 SSE 连接
    const eventSource = new EventSource(`/api/chat/stream?query=${encodeURIComponent(currentInput)}`);
    let aiMessageContent = "";

    // 添加一条空消息等待流式填充
    setMessages(prev => […prev, { role: 'assistant', content: '' }]);

    eventSource.onmessage = (event) => {
    const data = event.data;
    if (data === '[DONE]') {
    eventSource.close();
    setIsLoading(false);
    return;
    }

    // 流式拼接 Token
    aiMessageContent += data;
    setMessages(prev => {
    const newMsgs = […prev];
    newMsgs[newMsgs.length – 1].content = aiMessageContent;
    return newMsgs;
    });
    };

    eventSource.onerror = (err) => {
    console.error("SSE Error:", err);
    eventSource.close();
    setIsLoading(false);
    };
    };

    return (
    <div>
    <div className="chat-history">
    {messages.map((msg, idx) => <div key={idx}>{msg.content}</div>)}
    </div>
    <input value={input} onChange={(e) => setInput(e.target.value)} />
    <button onClick={sendMessage} disabled={isLoading}>发送</button>
    </div>
    );
    };

    关键设计点:这种 SSE 异步非阻塞 的交互方式,配合 React 的 useState 增量更新,完美解决了 LLM 响应慢导致的用户体验降级问题,同时缓解了后端的长连接资源占用。


    四、 工程化落地与部署运维

    企业级 AI 应用不能停留在本地代码,必须走完 CI/CD、容器化、监控告警 的全链路。

    4.1 容器化与 Docker 镜像构建

    我们需要将 Python 后端和 React 前端分别打包成镜像。

    # Dockerfile (Backend)
    FROM python:3.10-slim

    WORKDIR /app

    # 安装依赖
    COPY requirements.txt .
    RUN pip install –no-cache-dir -r requirements.txt

    # 复制代码
    COPY . .

    # 暴露端口
    EXPOSE 8000

    # 启动命令,使用 Gunicorn + Uvicorn 保证生产环境的高并发稳定性
    CMD ["gunicorn", "-w", "4", "-k", "uvicorn.workers.UvicornWorker", "api:app", "–bind", "0.0.0.0:8000"]

    • 运维关键点:生产环境绝对不建议使用 python api.py 这种简单的命令运行,必须使用类似 Gunicorn 或 Uvicorn 的多进程/异步Worker来并发处理SSE长连接,否则一旦并发数上升,服务器会瞬间过载。

    4.2 CI/CD 与 版本管理策略

    在 GitLab / GitHub Actions 中,我们可以配置如下流水线:

  • 代码提交(触发 Webhook)。
  • 单元测试:对 RAG 向量检索准确率、Agent工具调用逻辑做单测(Mock 外部 API)。
  • 镜像构建:根据提交的 Tag(如 v1.2.0)构建 Docker 镜像并推送到仓库。
  • 安全扫描:对镜像进行漏洞扫描(使用 Trivy 等工具)。
  • 蓝绿部署 / 金丝雀发布:在 Kubernetes 中更新 Deployment,确保 Zero Downtime(零停机)。
  • 4.3 监控告警与日志分析

    在生产环境,需要监控以下黄金指标:

    • LLM API 请求延迟与 Token 消耗(用于成本控制)。
    • 向量数据库 QPS 与 内存占用量。
    • Agent 各节点执行耗时(如果某一步骤超时,可及时告警)。
    • Linux 机器层面的监控:CPU、内存、磁盘 I/O、网络带宽(尤其是 SSE 长连接产生的流量)。
      使用 Prometheus + Grafana 搭建可视化仪表盘,结合 Elasticsearch + Filebeat + Kibana (EFK) 实现日志的集中管理和错误追踪。

    五、 生产级进阶优化策略

    从 Demo 走向 100万级 QPS 的高并发生产环境,还需要解决 3 大隐性技术问题:

    5.1 检索增强优化(HyDE 与 多查询机制)

    直接使用用户自然语言检索,有时无法命中精确关键词。

    • 多查询(Multi-Query):让 LLM 针对同一个问题,生成 3 个不同角度的问题描述,并分别进行检索,最后去重。
    • HyDE(假设性文档嵌入):让 LLM 先基于当前问题“假设”出一个完美答案,然后将这个“假设答案”作为检索的 Query,能大幅提高召回率。可以在代码中封装一个 rewrite_query(query) 预处理器。

    5.2 上下文管理与缓存机制

    • 长上下文管理:对历史对话记录进行 Summary 摘要,只将摘要传给 LLM,以节省 Token 消耗,同时保留记忆。
    • 多级缓存:对于高频重复的咨询问题(如“公司休假政策”),在前置缓存(Redis)中直接缓存完整响应,不再走完整的 RAG 链路,响应时间可从 5s 降低至 50ms。

    5.3 系统稳定性的兜底策略(容错与 Fallback)

    • 当外部大模型 API 服务降级或中断时,系统必须提供 Fallback 机制(例如降级到仅使用向量检索结果,不加生成,只展示原文)。
    • 优雅停机:在 Kubernetes Pod 停止时,确保当前的 SSE 连接已经处理完毕并关闭,避免客户端连接中断。

    结语:AI 应用落地的关键不是模型,而是工程

    通过本文从需求分析、RAG 链路代码编写、Agent 工作流编排、前后端流式交互,到最终的容器化部署与链路优化的完整实战,可以清晰地看到:在一线企业级 AIGC 开发中,AI 算法能力只占 20%,剩余 80% 都是后端架构的稳定度、前端交互的流畅度以及 DevSecOps 的工程化实力。

    作为全栈 AI 工程师(如招聘 JD 所要求),我们需要深度拥抱云原生技术(Docker/K8s),熟练通过优雅的代码模块(如 LangGraph)来封装业务逻辑,并时刻关注系统底层性能与稳定性。唯有“工程+算法”双向驱动,才能让 AI 智能体真正从实验室走入生产,释放降本增效的业务价值。

    赞(0)
    未经允许不得转载:171主机测评 » RAG与智能问答系统实战:从需求分析到Agent流程自动化完整落地
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址