AI Agent开发核心:提示词工程+工作流+RAG知识库构建
AI Agent开发宝典提示词工程工作流RAG知识库构建收藏级教程说实话这两年AI Agent相关的项目我做过不少从最早只会调大模型接口写个聊天机器人到现在能独立构建带知识库、多轮工具调用的完整Agent系统最深的感触就是很多人把Agent开发想得太简单以为“包装一下大模型接口”就叫Agent也有人想得太复杂一上来就上多智能体框架最后连日志都看不懂。如果你也卡在这个中间地带——已经会调用大模型API但不知道怎么把它做成一个真正能解决业务问题的Agent那么这篇教程就是写给你的。我会从提示词工程、工作流编排、RAG知识库构建三个核心模块展开最后用一个完整的模拟项目串联起来。这套方法论是我自己在多个实际项目中沉淀下来的每一步都可以直接动手复现没有空话。1. 整体设计思路Agent开发的核心不是模型而是工程化先聊一个关键认知当我们开发AI Agent时实际上在做什么表面上看Agent是“大模型记忆工具”的组合。但真正开工后你会发现模型能力只是下限真正的上限取决于三件事你给模型写的提示词是否约束住了它的行为边界你设计的工作流是否让它在正确的时机调用正确的工具你的知识库能否提供足够精准的上下文。这三者缺一不可而且它们之间有严格的配合关系。1.1 三个核心模块的分工与协同提示词工程负责“定义人设和行为准则”。它解决的是“Agent是什么、能做什么、不能做什么、以什么风格回答”的问题。很多时候Agent回答质量差不是模型不行而是提示词没有把任务边界说清楚。工作流负责“编排多步骤逻辑”。它解决的是“Agent在什么条件下做什么决策、按什么顺序执行什么操作”的问题。比如一个简单的客服Agent需要先调用用户信息查询工具再根据查询结果决定是否调用退款工具——这就是工作流。RAG知识库负责“注入领域知识”。它解决的是“模型不知道的私有知识从哪来”的问题。比如某公司内部的规章制度、产品文档、历史工单这些内容模型默认不知道需要通过检索增强的方式喂给模型。我曾经接手过一个模拟项目X需求是做一个“企业制度问答Agent”最初团队只写了一段提示词就上线了结果用户问“年假几天”这类需要查资料的问题时Agent经常一本正经地编数据。后来查了日志才发现模型在训练数据里见过很多类似的制度文本它不知道自己其实不具备该企业的具体制度信息——这就是典型的“不知道自己不知道”。1.2 为什么建议按模块化方式构建早期我倾向于把提示词、流程逻辑、知识检索全写在一个超大函数里调试时痛不欲生——改一个提示词可能影响检索逻辑调一下检索参数又可能让输出格式崩掉。后来我改成模块化设计效果立刻不一样把“Agent对用户说什么”和“Agent怎么查资料、怎么调工具”完全解耦之后每个模块都能独立测试、独立优化。你甚至可以先用一个最弱的模型跑通全流程再逐步替换成更强模型观察每个环节的效果变化。这种“积木式”构建方式是Agent项目能持续迭代的基础。注意模块化不是说要写一堆抽象类、接口而是强调职责边界清晰。哪怕只是一个脚本文件只要每个函数只做一件事就比耦合在一起的代码好维护得多。2. 提示词工程决定Agent行为边界的核心手法提示词工程是Agent开发里门槛最低但陷阱最多的一块。很多人以为提示词就是“你是一个助手请回答用户的问题”实际上在生产环境中一段合格的Agent提示词至少要包含角色设定、任务目标、输入输出格式约束、知识引用规范、兜底话术五个部分。2.1 一个可以直接套用的系统提示词模板这是我经过多轮迭代后沉淀下来的模板结构SYSTEM_PROMPT # 角色设定 你是一个{领域}专业助手你的名字是{名字}服务对象是{用户群体}。 # 能力边界 你能做的事情 1. {能力1例如查企业制度} 2. {能力2例如计算年假余额} 你不能做的事情 1. 不能回答与{领域}无关的问题 2. 不能编造知识库中不存在的制度条款 3. 不能提供医疗、法律等专业建议 # 任务目标 当用户提问时你的目标是 1. 理解用户真正想解决的问题 2. 优先从知识库检索相关信息 3. 如检索不到明确告知用户“该问题暂时无法回答”而非自行猜测 # 回答格式 - 使用Markdown格式 - 先给出直接答案再说明依据 - 在回答末尾标注信息来源如来源《考勤管理制度》第3章 - 如遇到需多轮处理的请求先说明你的处理计划再开始执行 # 知识引用规范 你已经通过RAG检索到以下资料片段可能在多轮对话中穿插提供请严格依据这些片段回答 1. 若多个片段互相矛盾以最新发布版本为准 2. 片段未覆盖的问题直接回复“资料库中暂无相关信息” 3. 禁止拼凑不同片段的内容来制造不存在的条款 # 兜底话术 当你无法回答时参考以下话术模板 抱歉这个问题我暂时无法准确回答。你可以尝试换个问法或者联系人工客服处理。 为什么每个部分都要写清楚以“能力边界”为例。没有明确“不能做什么”的Agent很容易被用户绕偏。我见过一个法律咨询Agent用户问“怎么起诉公司”它真能长篇大论给出法律建议——这在合规上是巨大风险。加一句“不能提供法律建议”并配置兜底话术直接从源头杜绝这类问题。“知识引用规范”同样关键它规定了模型在RAG场景下的行为准则是抑制幻觉的第一道防线。2.2 提示词三大冤案太过抽象、上下文污染、示例错位这里说三个我踩过多次的坑。坑一抽象的指令等于没写。“请确保回答准确”这句指令没有任何约束力。模型是概率生成它不区分“准确”指什么语境。真正有效的是具象化表达“如果知识库中无该答案请一字不差地回复资料库中暂无相关信息。”清晰具体可执行。坑二上下文污染导致角色“失忆”。用户在多轮对话中一旦说“帮我写首诗”Agent可能就忘记自己是“制度问答助手”了。对策是把系统提示词固定为system角色消息每轮用户输入都附带上文中用户最近3轮消息必要时在下一条用户消息开头重复注入关键约束“请记住你是制度问答助手仅回答制度相关问题。”坑三示例和实际任务错位。Few-shot示例要选与真实用户输入高相似的样本。举个例子你做的是“技术工单分类”示例里却给的是“客服退货问询”模型会被带偏。示例要覆盖边界情况如“用户问了一个知识库外的问题Agent应该如何回复”让模型学到正确的兜底行为。2.3 提示词迭代的量化方法不要靠感觉调提示词。把提示词当成代码来管理建立固定测试集至少30条覆盖不同难度的用户问题每条问题人工标注标准答案等级满分/部分分/零分修改提示词后跑一遍全量测试集计算得分变化用git管理提示词版本改了之后可回滚。我曾经靠这个办法把一个Agent的回答准确率从62%提升到91%。核心就是每次只改一处变量用数据说话。3. 工作流编排让Agent从“话痨”变成“办事员”大模型本身是没有“执行链”的——你让它干一件事它只会输出文本。要做成Agent必须有工作流来调度什么时候调用搜索、什么时候调用数据库、什么时候直接回答。这块最容易翻车的地方在于把逻辑直接写进提示词让模型决定而不是在代码层给定选择支。3.1 最实用的一种流程意图识别→查资料→生成回答开发一个Agent时第一版千万别追求复杂框架。推荐从下面这个基础流程开始# -*- coding: utf-8 -*- 核心Agent流程意图识别 - 工具调用 - 结果生成 只依赖一个LLM封装接口和一个检索模块 import json class SimpleAgent: def __init__(self, llm_fn, retriever, max_history6): self.llm_fn llm_fn # 大模型调用函数入参是prompt列表出参是字符串 self.retriever retriever # 知识库检索器 self.history max_history # 保留最近N轮对话历史 def _build_messages(self, user_input, retrieved_docs): system_prompt 你是一个{领域}助手请根据资料回答问题... context \n.join( f[{i1}]{doc[content]} for i, doc in enumerate(retrieved_docs) ) messages [ {role: system, content: system_prompt}, {role: user, content: f参考资料:\n{context}\n\n问题{user_input}} ] for m in self.history: messages.append(m) return messages def handle(self, user_input): # 1. 召回相关知识 docs self.retriever.search(user_input, top_k3) # 2. 组织messages并调用LLM messages self._build_messages(user_input, docs) answer self.llm_fn(messages) # 3. 更新历史简单截断方式 self.history.append({role: user, content: user_input}) self.history.append({role: assistant, content: answer}) self.history self.history[-max_history:] return answer这个例子里最核心的一点是工具调用时机和检索时机固定在代码层不交给模型自由发挥。模型自由发挥多了很容易失控。先固定流程跑通后再用带工具调用的方案逐步放开。3.2 工具调用函数定义要“窄而明确”当Agent需要连接外部系统时建议使用结构化工具定义。参考如下定义方式{ type: function, function: { name: query_leave_balance, description: 查询员工剩余年假天数。仅当用户明确提到‘年假’、‘休假余额’等关键词时使用。, parameters: { type: object, properties: { employee_id: { type: string, description: 员工工号从对话上下文中提取 }, year: { type: integer, description: 年份默认当前年份 } }, required: [employee_id] } } }函数描述里的“仅当用户明确提到……时才使用”这句话至关重要它直接影响模型的工具选择判断。描述写得太宽泛模型会乱调工具写得太窄模型该调的时候不调。这个度需要根据真实日志反复修正。3.3 多步任务的状态管理一旦Agent需要多步操作比如查余额→提交请假申请→通知主管就涉及状态管理。我的经验是不要指望模型记忆状态把状态存在外部变量里。pending_actions { user_123: {action: submit_leave, step: awaiting_reason, data: {...}} }每轮用户输入进入时先查pending_actions有未完成的流程就继续执行否则按新请求处理。这个模式既简单又能保证多轮对话不失控。状态存储用普通dict就行生产建议用Redis但思路一致。3.4 日志工作流排障的最强武器很多Agent项目排障困难核心原因是日志太弱。我建议从第一版就做好三件事每次LLM调用都记录完整输入含系统提示词和输出方便复盘上下文是否被污染。每次工具调用记录参数和返回结果方便判断工具定义是否有歧义。记录耗时和token数方便对比不同方案的成本与延迟。日志文件建议用JSON Lines格式每行一条记录同时落盘原始请求与响应。配合简单的统计分析脚本很容易定位“哪一步把链路搞崩的”。4. RAG知识库构建让Agent拥有私域知识RAG检索增强生成这几年几乎成了Agent开发的标配但很多人搭建知识库时只做“切块→向量化→存向量库”三步上线后才发现检索质量一塌糊涂。原因通常是文档解析不到位、切片不讲究、检索策略太单一。4.1 从源文档到知识切片三个容易被忽视的细节第一步格式解析。PDF、Word、Markdown、PPT的解析质量天差地别。PDF尤其需要先用版面分析工具提取标题层级和段落结构再考虑是否需要保留表格结构很多解析工具会把表格拆得四分五裂。我踩过最典型的坑某产品的规格参数表在PDF里是两列解析后变成纯文本流检索“工作温度”时召回的内容完全不可读。第二步切片策略。切片不能盲目按固定字符数切。理想情况是“按语义段落切”而非按500字硬切。一个自然段落就是最小的语义单元切完尽量保证含义完整如果段落太长超过模型上下文限制再在子标题或句号附近二次切割。第三步保留“元数据”。每个切片都建议带上来源文档名、章节路径、页码、最近更新时间。这些信息既能在回答中标注引用出处也是后续知识库更新、回溯的关键线索。4.2 向量化与混合检索关键词检索其实很关键选Embedding模型时中文场景下建议优先评估支持中文的向量模型参考MTEB中文榜单效果并根据向量模型的实际出参维度调整后继向量库逻辑。向量维度会影响存储规模和检索速度维度越大不一定越好够用即可。只做向量检索远远不够因为纯向量检索对精确匹配工号、产品型号、政策文件的特定术语经常失效。更好的方案是混合检索检索方法优势劣势向量检索理解语义能处理同义表达对精确数字、专名不敏感关键词检索BM25精确匹配强可指定字段无法理解语义混合检索兼顾语义与精确召回稳需额外设计权重与重排一段参考实现如下def hybrid_search(query, top_k5): # 向量检索 emb embed_model.encode(query) vec_result vector_store.query(emb, top_ktop_k * 2) # 关键词检索 keyword_result bm25_index.search(query, top_ktop_k * 2) # 融合RRFRanked Reciprocal Fusion简单有效 from collections import defaultdict scores defaultdict(float) for rank, docid in enumerate(vec_result): scores[docid] 1 / (60 rank 1) for rank, docid in enumerate(keyword_result): scores[docid] 1 / (60 rank 1) top_docs sorted(scores.items(), keylambda x: -x[1])[:top_k] return [doc_map[docid] for docid, _ in top_docs]RRF融合算法简单实用不需要调权重就能把两种检索引擎的结果合并。很多人一开始直接上Rerank模型但我建议先把混合检索做扎实再考虑重排模型。4.3 重排与上下文压缩检索质量最后的临门一脚混合检索召回的Top-K结果里很可能仍有不相关内容。直接塞进提示词既浪费token又干扰模型。此时加一个重排环节就能显著提升回答质量。两个思路轻量级“基于上下文相关性”的重新排序。可以用大模型做二分类打分给一小段查询和候选片段让模型判断“相关/不相关/部分相关”然后按分数重新排序、截断。引入专门的重排模型。如果对效果要求高且对延迟不敏感可以在召回并行阶段调用重排模型服务对候选文本与查询高度匹配后取Top-K送入提示词。上下文压缩同样要做不要直接堆原文片段。写一个compress_context函数对检索出的每个长段落先抽取与问题最相关的几行内容再拼接进prompt能显著降低token成本。4.4 知识库更新与一致性只增不改的陷阱知识库上线后一定会面临文档更新。最常见的问题是旧版本文档和新版本文档都存在于向量库中检索结果新旧混杂回答自相矛盾。我的做法是文档入库时为每个文档记录版本号和有效时间区间检索时过滤掉当前时间不可见的版本定期构建“索引刷新任务”删除过期版本对应的向量和键值更新频率不高的知识库建议直接重建该文档的所有切片向量避免漏删。提示判断RAG好坏不要只看准确率。请重点关注“拒答率”——也就是“不知道的时候能明确说不知道”的比例。敢说“不知道”比乱编更有价值。5. 实操过程从0到1构建完整Agent模拟项目X这部分我用一个模拟项目来串联前面全部内容场景是“企业制度问答与请假代办Agent”。避免涉及真实业务但流程是完整可复现的。5.1 项目目标与功能拆解模拟项目X实现四个核心功能制度问答RAG、年假余额查询工具调用、请假申请工作流状态机、转人工兜底。输入侧是文本输出侧也是文本不做语音和UI。拆解后得到下面的功能清单功能模块核心技术点依赖溶制度问答RAG知识库、混合检索文档切片、向量库年假余额查询结构化工具调用员工系统模拟接口请假申请多步工作流状态管理状态存储、通知模拟拒答兜底提示词限制话术模板系统提示词5.2 从零搭建的完整步骤记录第一步准备知识库。把文档集合考勤制度、报销规范、人事手册等解析成Markdown用一个脚本批量清洗去掉多余空行和页眉页脚。然后按自然段落切片每段上限800字超出就按句号拆分。生成如下格式的切片文件{doc_id: hr_001, title: 考勤管理制度, chapter: 年假规定, content: 员工累计工作满1年不满10年的年休假5天..., updated_at: 2025-01-15}第二步装向量库并入库。我直接用最熟悉的实用方案轻度数据量直接使用文件型向量索引如faiss生产数据量大则上向量数据库客户端。建索引时设置normalizeTrue开启余弦相似度计算。入库时把上面JSON的结构映射成“向量元数据”元数据保留原样。第三步写核心Agent类。参考第三节的代码骨架把它扩展为同时支持RAG检索、工具调用和状态机翻转。关键点是区分“检索类问题”和“操作类问题”用意图识别先判断调用哪个工具再决定是否查库。第四步搭评测集验证。准备50条测试问题其中40条来自真实文档、10条故意超出知识库范围。跑完一轮后统计准确率和拒答率发现问题再回到提示词和索引参数上调整。5.3 多轮对话与工具调用的状态机设计我实现的请假流程如下state idle 用户: 我想请3天年假 state - awaiting_employee_id Agent: 请提供你的工号 用户: E10023 state - checking_balance Agent: 查询中... 你剩余年假10天请输入请假事由 用户: 家中有事 state - awaiting_approval Agent: 已提交请假申请正在通知主管审批 state - done每一步都在代码层用状态机控制绝不靠模型输出文本格式来驱动流程。这个方式看似笨拙但稳定性极高用户在流程中乱说一句话比如突然问“今天天气怎么样”也不会把流程打断。设计一个局部意图分支处理即可流程中嵌入旁路问题识别核心流程保持线性收敛。5.4 效果评估与调优记录第一轮测试结果存档端到端准确率78%拒答率只有35%。部分原因是提示词里的“知识引用规范”约束不够硬模型在某些边界问题上“猜”答案调整提示词为“没有资料必须一字不差回复‘资料库中暂无相关信息’”后拒答率升到61%整体准确率升到85%整体更可靠了。接着调切片大小从固定500字改为按语义段落800字上限准确率再涨了4个百分点。最后加了一个简单的Rerank环节用大模型打分把最终准确率稳定在91%左右。延迟从1.8秒增加到2.3秒仍可接受知识库类查询的价值远大于延迟成本。6. 常见问题与排查技巧实录这一节整理我在Agent项目里反复碰到的现场问题特别适合刚入坑的开发者照方抓药。6.1 回答“一本正经地胡编”现象Agent引用了一个知识库中不存在的条款但语气特别笃定。排查链路先查日志——该问题实际检索到了哪些切片切片内容和回答一致吗若切片里根本没有那段内容确认提示词是否要求“仅依据资料回答”。没有的话加约束并在约束中同时给出“拒答模板”与“不拼凑”的双重规则参考2.1节模板。若切片里有但不完整检查切片是否切得太碎、跨段落拆开了关键逻辑。调大切片容量或做重叠切片。6.2 多轮对话中Agent“忘记”身份现象用户连续问了几轮制度问题后开始闲聊Agent就“放开聊”了。问题本质是身份约束只在system消息里随着对话历史增长削弱。对策保留最近N轮上下文截断旧历史每轮用户输入前把当前任务的关键约束重新注回消息列表对“与当前Agent目标无关”的问题在提示词的“能力边界”中写清并给出转移话术。6.3 检索结果大量不相关现象问“报销流程”召回的却是“年假规定”。先说最常见的原因Embedding模型对文档主题区分力不足或关键词检索权重过高把同词根的文档带进来了。排查与优化检查是否存在另一批相似语义的文档干扰如两个制度文档都有“申请流程”章节调低混合检索中BM25权重或对文档标题做加权匹配入库时不只写正文把title和chapter一起编码进向量文本例如向量化的文本格式为“标题考勤管理制度章节年假规定内容……”对主题区分帮助巨大最终手段是上重排模型重新按查询相关性精排。6.4 Token成本失控现象上去没有几天账单飞涨。排查很多情况下是“全局把整篇文档塞进上下文”或“多轮历史全量保留”导致的。优化三板斧检索答案从Top-10降到Top-3用compress_context压缩长段落多轮历史只保留最近2轮完整消息其余只保留总结片段。如果走完整预算评估还可以在检索环节用一个“快速意图分类器”可以是一个超小的模型先判断要不要走知识库再控制调用流程无关问题直接跳过检索每年能省不少费用。6.5 工具调用乱入现象用户没问相关业务Agent却触发某工具。对策工具描述收紧见3.2节在触发条件中加入“仅当用户明确提到关键操作词时调用”设置置信度门槛——如果模型返回的工具调用概率低代码层不执行工具直接走正常回复增加“工具调用确认机制”在执行前让用户确认一次。客服场景尤其实用。6.6 常见问题速查表把上述问题整理成了一张表直接复制到你的项目文档里也行症状直接原因风险等级优先排查手段回答编造知识外内容提示词约束不足 / 切片缺失高检查检索切片加固提示词拒答规则多轮跑偏历史过长 / 身份泄露高固定system角色重置最近N轮关键约束回注检索不相关向量粒度不当 / 元数据缺失中标题加权混合检索调权重排模型Token暴涨上下文体量大中Top-K降低摘要压缩清理历史工具误触发描述过宽 / 概率过低中定义窄描述加触发阈值落地确认机制这六类问题覆盖了我见过的大部分Agent事故场景。每一条背后都有真实的翻车经历按着表格排查大多数情况下能快速定位根因。实操收尾的三个体会文章内容到这里基本讲完了最后分享三点我个人实操下来最深的体会。第一Agent项目真正的门槛是工程而非模型。模型选择固然重要但同等模型条件下提示词是否约束得当、检索结果是否准确、工作流是否稳定才是决定体验的三根支柱。把基础模块做好比追逐热门框架有意义得多。第二评测集和日志系统要尽早建立。我见过太多Agent项目“开发一时爽调优火葬场”——没有对照组、没有日志、没有量化指标全靠人工感觉调参这是项目失控的第一步。哪怕花一天时间写评测脚本和日志埋点后面能省一周都不止。第三给自己留一个降级路径。不要把所有环节都押在“模型一定听话”上。在关键工具调用前加确认、在敏感任务上加兜底话术、在状态机设计上保持“线性可控”即使模型表现爆炸系统也不会跟着崩。这套“提示词工程工作流RAG”的组合拳反复使用下来确实很稳。如果你正准备开始Agent项目建议把文中代码和检查表直接存下来从最小闭环跑起一步一步加功能别一开始就搞大而全的架构。哪怕是简单架构能把基础三件套打磨到位就能做出体验非常扎实的Agent。祝顺利。