智能体+RAG+规划:构建AI节日助手的架构设计与工程实践
1. 项目概述一个AI驱动的节日助手诞生记最近我利用业余时间为我们的校园技术节“Pragyan NITT”捣鼓出了一个挺有意思的东西一个AI驱动的节日助手。这玩意儿不是简单的问答机器人而是一个集成了智能体Agents、检索增强生成RAG和任务规划Planning能力的“数字伙伴”。它的核心目标很简单让每一位参与Pragyan技术节的同学、访客和参赛者都能获得一个7x24小时在线的、无所不知的“百事通”和“小管家”。想象一下这个场景你是一名大一新生第一次参加Pragyan面对官网琳琅满目的活动、错综复杂的日程和一堆技术术语是不是有点懵这时候你打开手机向这个助手提问“嘿我对机器学习感兴趣明天下午有什么适合新手的活动吗”它不仅能立刻从海量活动手册、往届资料和实时更新中精准找出“机器学习入门工作坊”的信息告诉你具体时间、地点和主讲人还能顺带提醒你“这个工作坊需要提前在‘TechConnect’应用上预约席位哦目前还剩15个名额需要我帮你生成一个加入日历的提醒吗”——这就是我们构建的AI节日助手试图实现的效果。这个项目的核心是解决大型活动尤其是技术类活动中信息过载、查询路径复杂和个性化服务缺失的问题。传统的活动官网或手册是静态的信息查找依赖用户的关键词匹配能力而人工咨询台又受限于人力、时间和知识范围。我们的AI助手则试图扮演一个永不疲倦、知识渊博且能主动思考的“超级志愿者”。它背后的技术栈并不神秘主要围绕三个核心概念展开**智能体Agents**负责决策和行动**检索增强生成RAG确保回答基于准确、最新的知识库而任务规划Planning**则让助手能拆解复杂问题一步步引导用户达成目标。接下来我就把这几个月从构思、选型到踩坑、实现的全过程毫无保留地分享出来。2. 核心架构与设计思路拆解2.1 为什么是“智能体 RAG 规划”的组合在项目启动前我们评估过几种方案。最简单的当然是基于规则或意图分类的聊天机器人但Pragyan的活动信息动态变化如日程调整、名额更新规则难以维护。纯大语言模型LLM方案虽然灵活但容易“胡言乱语”幻觉比如把去年的活动时间说成今年的。因此我们决定采用一个混合架构。智能体Agents是整个系统的大脑。它不是一个单一的模型而是一个具备“思考-行动-观察”循环的框架。当用户提出一个问题时智能体的角色是判断“这是一个简单的事实查询还是一个需要多步骤完成的复杂任务”例如“Pragyan的吉祥物是什么”是简单查询而“我想组队参加黑客松但找不到队友该怎么办”就是一个复杂任务。智能体需要决定调用哪个工具Tool或者是否启动一个规划流程。检索增强生成RAG是系统的记忆库和事实核查员。我们将Pragyan所有的官方文档、往届资料、赞助商信息、活动规则PDF、常见问题FAQ等非结构化文本进行切片、向量化存入向量数据库。当智能体判断需要事实信息时RAG模块就会从向量库中检索出最相关的几段文本连同用户问题一起交给LLM生成答案。这确保了答案的根基是可靠的官方信息极大减少了幻觉。比如关于“注册截止日期”这种关键信息答案100%来自官方文档而不是LLM的“推测”。任务规划Planning是处理复杂交互的“项目经理”。对于“组队参加黑客松”这类问题智能体会启动一个规划器。规划器会将大目标分解为子任务1. 查询当前开放报名且允许组队的黑客松列表2. 检索“寻找队友”论坛或平台的使用方法3. 生成一个个性化的行动建议模板。规划器控制着执行顺序并能在子任务失败时比如某个活动已满员调整计划。这使得助手能引导用户完成一个多步骤的流程而不仅仅是给一个一次性答案。这个组合的优势在于RAG保证了准确性智能体赋予了决策能力规划实现了复杂交互。它们三者形成了一个闭环智能体根据问题类型调度资源RAG提供精准信息支撑规划管理多轮对话和任务流。2.2 技术栈选型背后的考量选型过程我们遵循了“成熟、可控、高效”的原则毕竟这是为一个实际活动服务稳定性优先级很高。1. LLM API与智能体框架我们选择了OpenAI的GPT-4 Turbo API作为核心LLM。原因很简单它在代码生成、逻辑推理和指令遵循方面表现稳定API也成熟可靠。虽然也有优秀的开源模型但考虑到部署、调试和响应速度的综合成本在项目初期使用成熟的云API是更务实的选择。对于智能体框架我们没有使用庞大的全功能框架而是基于LangChain的核心概念进行轻量级封装。LangChain提供了优秀的工具Tools定义和调用链Chain构建能力足够灵活又不会引入过多抽象层便于我们理解和调试。2. 向量数据库与嵌入模型这是RAG的核心。向量数据库我们选择了Pinecone。相比自建Chroma或MilvusPinecone作为托管服务省去了服务器运维、性能调优的麻烦其索引的快速检索能力对于实时问答场景至关重要。嵌入模型则使用了OpenAI的text-embedding-3-small。它的权衡点是性能、成本和效果。我们对比过更大的嵌入模型和开源模型如BGEtext-embedding-3-small在Pragyan知识库这种中等规模、领域特定的文本上检索准确度足够且速度和成本非常友好。3. 后端与规划引擎后端用FastAPI搭建轻快异步非常适合处理AI助手的并发请求。任务规划部分我们没有采用复杂的自动化规划算法如PDDL因为活动领域的任务逻辑相对结构化。我们实现了一个基于有向无环图DAG的轻量级规划器。每个复杂任务如“注册活动”都被预定义为一个DAG节点是子任务验证资格、填写表单、支付等边是执行顺序和条件逻辑。智能体根据用户输入匹配到对应的DAG然后按图索骥地引导用户。这种方式可控性强易于理解和调试。4. 前端与通信为了快速原型和部署前端采用了Streamlit。它允许我们用Python快速构建一个带有聊天界面的Web应用并且能方便地展示结构化信息如活动卡片、日程表格。前后端通过WebSocket进行通信以实现流畅的、低延迟的对话体验。注意技术选型没有银弹。我们的选择是基于“快速验证核心价值”的出发点。如果你的项目对数据隐私要求极高或者预算有限完全可以将OpenAI API替换为本地部署的Llama 3 Ollama将Pinecone替换为本地Chroma。架构的核心思想是通用的具体组件可以按需替换。3. 核心模块实现细节与实操要点3.1 知识库构建RAG的“原料”准备RAG的效果七八成取决于知识库的质量。我们花了大量时间在数据准备上。数据收集与清洗我们的数据源包括PDF版的活动手册、官网HTML页面、往届活动的照片描述文本通过图像识别生成、赞助商资料、组委会发布的新闻稿、以及一个庞大的FAQ文档。第一步是用pypdf和BeautifulSoup将这些内容统一提取为纯文本。这里的关键是保留结构信息。比如从PDF提取时我们不仅提取文字还尝试保留章节标题和层级关系这有助于后续的文本切片更符合语义。文本切片Chunking策略这是最容易踩坑的地方。简单的按固定字符数如500字切片可能会把一个活动描述从中间切断。我们采用了递归字符文本分割器并优先在段落、标题等自然边界进行分割。对于表格内容我们将其转换为Markdown格式的文本作为一个整体切片以保持其结构性。切片大小设置在300-600字符之间重叠部分设为50-100字符以确保上下文连贯。向量化与索引使用OpenAI的嵌入模型将每个文本切片转换为1536维的向量。在存入Pinecone时我们为每个向量存储了元数据这是后续精准过滤的关键。元数据包括source文档来源、page页码、activity_type活动类型如“工作坊”、“比赛”、date活动日期等。例如当用户问“明天有什么比赛”我们可以在检索时在向量相似度搜索的基础上增加一个元数据过滤器activity_type: “competition” AND date: “2024-03-XX”从而让结果无比精准。实操心得不要指望嵌入模型能理解一切。清晰的元数据是RAG系统的“导航仪”。在构建知识库时多花时间设计元数据 schema比后期调优嵌入模型往往更有效。我们甚至为一些关键实体如特定讲座的教授名字添加了专门的元数据标签。3.2 智能体决策逻辑的设计与实现我们的智能体本质是一个ReActReasoning Acting模式的循环。1. 工具Tools的定义智能体可以调用的工具是我们预先定义好的函数。核心工具包括search_knowledge_base(query, filters): 执行RAG检索返回相关文本片段。get_schedule(date, venue): 查询特定日期或地点的日程安排来自结构化数据库。check_registration_status(user_id, event_id): 检查用户的报名状态需要连接活动注册后端。submit_feedback(event_id, rating, comment): 提交反馈。plan_complex_task(task_goal): 触发任务规划器。每个工具都有清晰的描述这些描述会作为系统提示词的一部分告诉LLM。例如search_knowledge_base的描述是“在Pragyan的官方知识库中搜索与问题相关的信息。当用户询问具体活动详情、规则、历史或一般性事实时使用此工具。”2. 决策循环系统提示词会要求LLM以特定格式如JSON输出它的“思考”和“行动”。一个典型的循环如下用户输入“我想参加AI绘画工作坊但担心自己没基础。”智能体思考Reasoning“用户表达了参与意愿和担忧。我需要先提供AI绘画工作坊的详细信息然后针对‘无基础’的担忧从知识库中寻找该工作坊是否适合新手的信息或者提供相关准备建议。”智能体行动Acting调用search_knowledge_base查询词为“AI绘画工作坊 适合新手 前提条件”。系统观察Observation返回检索到的文本“‘AI绘画创意工坊’面向所有学生开放无需编程或美术基础现场提供所有工具和指导...”智能体思考“已找到相关信息可以回答用户了。同时我可以主动询问用户是否需要我帮他查询该工作坊的具体时间并设置提醒。”最终响应将整合后的信息工作坊介绍适合新手的说明以友好的语气回复给用户并附上一个追问“需要我帮你查看这个工作坊的举办时间并添加到你的日程提醒吗”这个循环的关键是让LLM“慢思考”。强制它输出推理过程不仅能让我们调试其逻辑也常常能提高最终行动的准确性。3.3 任务规划器的轻量级实现对于“注册活动”、“寻找队友”这类多步骤任务我们预定义了任务模板DAG。以“注册活动”为例任务注册活动 子任务节点 1. [条件节点] 确认用户身份是否已登录。 2. [信息节点] 展示用户可能感兴趣的活动列表基于历史或询问。 3. [交互节点] 用户选择目标活动。 4. [工具调用] 检查活动资格与名额check_event_availability。 5. [分支] 若名额充足进入下一步若不足提示用户并结束或加入等待列表。 6. [交互节点] 引导用户填写必要表单信息。 7. [工具调用] 提交注册信息submit_registration。 8. [确认节点] 向用户发送注册成功确认及后续步骤。规划器的工作就是维护用户在当前任务DAG中所处的节点状态。它根据智能体的指令启动一个任务然后在每轮用户交互后决定下一步该执行哪个节点并生成相应的提示如“请告诉我你想注册哪个活动”或调用工具。我们用一个简单的状态机State Machine在后台会话中跟踪每个用户的规划进度。这比让LLM在每次对话中都重新规划整个任务要稳定和高效得多。注意事项规划器的设计要避免过度复杂。初期只实现2-3个最常用、最标准的复杂任务流程。每个流程的DAG要经过充分测试确保所有分支成功、失败、用户中途取消都能被妥善处理。贪多嚼不烂一个稳定可靠的“注册活动”流程胜过十个半成品的高级功能。4. 系统集成与全流程实操记录4.1 后端服务搭建与核心API我们使用FastAPI构建了三个核心端点/chat(WebSocket)处理持续的对话流。它接收用户消息维护对话历史调用智能体主循环并流式返回助手的思考和回复。/ingest(POST)知识库更新入口。当组委会发布新通知或更新日程后我们可以将新文档通过此端点提交后端会自动完成文本处理、向量化并更新Pinecone索引。/task/status(GET)供前端查询用户当前正在进行的复杂任务状态用于在UI上显示进度条或向导。核心的聊天流程伪代码如下async def chat_endpoint(websocket: WebSocket): await websocket.accept() conversation_history [] current_task_graph None # 存储当前规划任务状态 while True: user_message await websocket.receive_text() conversation_history.append({role: user, content: user_message}) # 1. 判断是否处于某个规划任务中 if current_task_graph and not current_task_graph.is_finished(): next_step current_task_graph.get_next_step(conversation_history) if next_step.type prompt_user: response next_step.prompt elif next_step.type call_tool: result await execute_tool(next_step.tool_name, next_step.parameters) response result[summary] current_task_graph.update_with_result(result) else: # 2. 不在任务中进入智能体主循环 agent_response await call_agent_core(conversation_history) if agent_response.requires_planning: current_task_graph TaskGraphLoader.load(agent_response.task_type) response current_task_graph.get_initial_prompt() else: response agent_response.final_answer conversation_history.append({role: assistant, content: response}) await websocket.send_text(json.dumps({type: message, content: response}))4.2 前端交互界面与体验优化Streamlit界面主要分为三个区域左侧是聊天主窗口右侧上方是当前活动/任务的焦点信息卡片右侧下方是用户的个人日程速览。为了让对话更自然我们做了几处优化流式输出助手的回答是一个词一个词地“打”出来模拟真人打字的感觉这比等待完整响应再一次性显示体验好很多。结构化消息当助手检索到某个活动信息时我们不仅返回文本描述还会渲染一个美观的卡片包含活动名称、时间、地点、标签和一个“了解更多”的按钮。这通过在前端识别消息中的特定JSON结构来实现。进度指示器当用户进入一个规划任务如注册时界面顶部会显示一个步骤进度条明确告诉用户“当前是第2步填写联系信息”减少用户的迷茫感。4.3 部署与监控我们将后端部署在Railway上它对于Python应用的部署非常友好能自动处理环境变量和HTTPS。前端Streamlit应用则直接部署在Streamlit Community Cloud。两者通过环境变量配置API密钥和连接字符串。监控方面我们做了两件事日志记录详细记录每个用户会话的智能体思考过程、工具调用和最终响应。这用于分析助手在哪里犯了错或者用户常问哪些知识库中没有的问题。反馈机制在每条助手消息的末尾添加了“”和“”的按钮。用户点“”后会弹出一个简单的文本框让用户描述问题。这些反馈数据是我们迭代优化最重要的燃料。5. 遇到的挑战、解决方案与避坑指南5.1 幻觉与信息过时RAG的“阿喀琉斯之踵”即使有RAG幻觉依然存在。最常见的情况是当知识库中没有完全匹配的信息时LLM会基于其内部知识“捏造”一个听起来合理的答案。例如知识库中没有“今晚的嘉宾演讲是否提供晚餐”的信息LLM可能会根据“一般活动”的规律回答“通常不提供”但这可能与事实不符。解决方案强化系统提示词我们在给LLM的指令中非常强硬地写明“你只能使用提供的上下文信息来回答问题。如果上下文信息中没有明确答案你必须直接说‘根据Pragyan官方提供的信息我暂时无法确认这个问题建议您查看官方公告或联系咨询台。’严禁推断或编造信息。”设置置信度阈值在RAG检索环节我们计算检索到的文本片段与用户问题的向量相似度得分。如果最高得分低于一个阈值我们设为0.75则判定为“相关信息不足”直接触发上述“无法回答”的回复根本不将低质量检索结果送给LLM。建立快速更新通道对于演讲取消、地点变更等紧急信息我们除了更新知识库还设置了一个“优先级公告”内存区。智能体在回答任何与时间地点相关的问题前会先检查这个内存区是否有冲突信息。5.2 复杂任务中的用户“迷路”在规划任务执行中用户可能会突然问一个无关问题或者想中途取消。最初的版本中规划器会“死板”地继续推进原流程导致用户体验很糟。解决方案引入“中断检测”智能体在每轮都会分析用户输入。如果检测到强烈的“退出意图”如“算了”、“我先不弄了”、“换个话题”或完全无关的新问题规划器会将当前任务状态暂存并允许智能体先处理新的请求。之后可以通过“我们刚才说到哪了”来恢复。提供明确的出口在任务引导的每一步界面都提供一个清晰的“取消此任务”按钮让用户有掌控感。5.3 性能与成本优化最初的版本每次对话都调用GPT-4并检索大量上下文导致响应慢有时超过5秒且API成本上升很快。解决方案对话历史摘要我们不将完整的、可能很长的对话历史都发给LLM。而是维护一个独立的“对话摘要”每隔几轮对话就用LLM用更便宜的GPT-3.5-Turbo将之前的对话浓缩成一段摘要后续只发送摘要和最近几条消息。这大幅减少了token消耗。分级检索不是所有问题都需要“深挖”知识库。我们实现了一个简单的意图分类器基于少量提示词。对于“你好”、“谢谢”这类寒暄直接返回固定回复不调用RAG和复杂推理。对于明确的事实查询如“某活动在哪”才进行向量检索。对于开放性问题如“什么活动好玩”则结合检索结果和LLM的概括能力。缓存对常见问题Top 50的问答对进行缓存。当识别到高度相似的问题时直接返回缓存答案跳过LLM调用。5.4 评估与迭代如何知道助手在变好没有评估优化就是盲人摸象。我们建立了简单的评估体系自动化测试集编写了100个覆盖各类场景的测试问题事实类、流程类、闲聊类。每次代码更新后跑一遍测试集统计“回答正确率”和“幻觉率”。这保证了核心功能的稳定性不会因迭代而崩溃。人工抽查每天随机抽取20条真实对话记录由项目组成员进行标注回答是否准确、有用、自然。这帮助我们发现自动化测试覆盖不到的边缘情况。用户反馈分析定期分析“”反馈将问题归类如“信息错误”、“答非所问”、“流程卡住”并针对性地进行修复。这个项目从构想到在Pragyan技术节上实际服务数百名用户是一个不断踩坑、学习和调整的过程。最大的体会是构建一个有用的AI应用技术只占一半另一半是对问题域的深刻理解、对用户体验的细致打磨以及建立一个快速反馈和迭代的机制。我们并没有追求最前沿、最复杂的模型而是努力让现有的技术组件可靠地协同工作解决真实场景下的具体问题。看到有同学通过这个助手顺利找到了心仪的活动并完成了注册那种成就感远比单纯调高某个模型指标要实在得多。