AI Agent开发实战⑲|生成优化与Prompt工程:让LLM准确输出你想要的答案
检索到了正确的信息,但LLM生成时跑题了、漏掉了关键细节、或者把检索结果当成了噪音。问题不在检索,而在生成阶段的Prompt设计。本文讲透RAG场景下的Prompt工程技巧。
一、RAG生成的三大问题
问题1:跑题 检索内容:研发投入占比8.3% LLM输出:公司研发投入逐年增长,创新能力不断提升... 问题:检索内容只说了占比,LLM自己脑补了"逐年增长"、"创新能力" 问题2:遗漏 检索内容:收入15.6亿,利润2.1亿,员工12700人 LLM输出:公司收入15.6亿,利润2.1亿。 问题:漏掉了员工数 问题3:幻觉 检索内容:公司成立于2010年 LLM输出:公司成立于2008年,经过多年发展... 问题:LLM无视检索内容,输出了错误信息二、Prompt工程核心原则
2.1 明确约束
# ❌ 差PromptBAD_PROMPT=""" 根据以下信息回答问题: {context} 问题:{question} """# ✅ 好PromptGOOD_PROMPT=""" 你是一个专业的知识助手。请根据提供的参考资料回答问题。 【重要约束】 1. 只使用参考资料中的信息,不要添加任何外部知识 2. 如果参考资料中没有相关信息,请直接说明"参考资料中未提及" 3. 引用具体信息时,用[编号]标注来源,如[1]、[2] 【参考资料】 {context} 【问题】 {question} 【回答】 """2.2 结构化指令
STRUCTURED_PROMPT=""" 请按以下结构回答问题: 1. 直接回答(1-2句话概括核心答案) 2. 详细说明(基于参考资料展开) 3. 数据引用(列出所有相关数字、名称) 4. 补充信息(如有) 5. 免责声明(如果信息不完整或不确定) 【参考资料】 {context} 【问题】 {question} """2.3 示例驱动
FEW_SHOT_PROMPT=""" 请参考以下示例格式回答问题: 示例1: 问题:公司的营收是多少? 参考资料:[1] 公司2023年营收15.6亿元 回答: - 直接回答:公司2023年营收为15.6亿元[1] - 详细说明:根据财报数据,公司2023年实现营业收入15.6亿元 - 数据引用:营收15.6亿元 - 补充信息:无 - 免责声明:数据来源于参考资料[1],建议以官方财报为准 示例2: 问题:公司的竞争对手有哪些? 参考资料:[1] 公司在AI领域的竞争对手包括百度、阿里、腾讯 回答: - 直接回答:公司在AI领域的竞争对手包括百度、阿里、腾讯[1] - 详细说明:参考资料显示,公司在AI赛道的主要竞争对手是BAT三巨头 - 数据引用:百度、阿里、腾讯 - 补充信息:无 - 免责声明:该信息可能不完整,建议进一步调研 现在请回答: 问题:{question} 参考资料:{context} """三、自我检验机制
让LLM在输出前自我检查。
3.1 输出前检验
SELF_CHECK_PROMPT=""" 请先回答问题,然后自我检验。 【回答问题】 {question} 【参考资料】 {context} 【你的回答】 (在这里写回答) 【自我检验】 请检查你的回答: 1. 是否所有信息都来自参考资料?(是/否) 2. 是否有遗漏的重要信息?(有/无) 3. 是否添加了参考资料中没有的内容?(有/无) 4. 引用的数字是否准确?(是/否) 如果检验发现问题,请修正后输出最终答案。 """classSelfCheckingGenerator:"""带自我检验的生成器"""def__init__(self,llm):self.llm=llmdefgenerate(self,query:str,context:str)->str:"""生成并检验"""# 第一轮:生成初始回答prompt=SELF_CHECK_PROMPT.format(question=query,context=context)response=self.llm.invoke(prompt)# 第二轮:检验并修正check_prompt=f""" 你的回答:{response.content}请检验: 1. 是否所有信息都来自参考资料? 2. 是否有遗漏? 3. 是否有添加的内容? 如果有问题,请输出修正后的最终答案。 如果没有问题,请输出"答案验证通过"。 """check_result=self.llm.invoke(check_prompt)if"验证通过"incheck_result.content:returnresponse.contentelse:returncheck_result.content3.2 CoT推理
让LLM显式推理过程。
COT_PROMPT=""" 请按以下步骤思考和回答: 步骤1:理解问题 - 问题在问什么? - 需要哪些信息才能回答? 步骤2:查找信息 - 在参考资料中查找相关信息 - 标注每条信息的来源[编号] 步骤3:整合信息 - 将相关信息按逻辑组织 - 检查是否有遗漏 步骤4:生成答案 - 用清晰的语言回答 - 引用所有数据和来源 【参考资料】 {context} 【问题】 {question} 请开始: """四、处理特殊场景
4.1 信息冲突
多文档信息矛盾时如何处理?
CONFLICT_HANDLING_PROMPT=""" 【重要】如果参考资料中有相互矛盾的信息,请: 1. 列出所有矛盾的信息点 2. 标注各自来源 3. 说明无法确定哪个正确 4. 建议用户核实 示例: 问题:公司成立时间? 参考资料: [1] 公司成立于2010年 [2] 公司创立于2008年 回答: 参考资料中存在矛盾信息: - [1] 显示成立于2010年 - [2] 显示创立于2008年 由于信息不一致,无法确定准确成立时间,建议以公司官网或工商登记信息为准。 【参考资料】 {context} 【问题】 {question} """4.2 信息不完整
INCOMPLETE_INFO_PROMPT=""" 【重要】如果参考资料信息不完整,请: 1. 回答已知部分 2. 明确指出哪些信息缺失 3. 不要猜测或脑补 示例: 问题:公司的营收、利润、员工数分别是多少? 参考资料:[1] 公司营收15.6亿元,利润2.1亿元 回答: 根据参考资料[1]: - 营收:15.6亿元 - 利润:2.1亿元 - 员工数:参考资料中未提及 建议查询公司年报或官网获取完整信息。 """4.3 跨文档整合
CROSS_DOC_PROMPT=""" 请从多个参考资料中整合信息回答问题。 要求: 1. 如果信息来自不同文档,请分别标注来源 2. 如果需要计算或推理,请展示过程 3. 最后汇总成一个完整的答案 示例: 问题:公司研发投入占营收的比例是多少? 参考资料: [1] 公司研发投入1.2亿元 [2] 公司营收15.6亿元 回答: 根据参考资料: - 研发投入:1.2亿元[1] - 营收:15.6亿元[2] 计算:研发投入占营收比例 = 1.2 / 15.6 = 7.7% 【参考资料】 {context} 【问题】 {question} """五、生成质量控制
5.1 输出格式控制
FORMAT_CONTROL_PROMPT=""" 请严格按照以下JSON格式输出: { "answer": "直接答案(1-2句话)", "confidence": "high/medium/low", "sources": [ {"id": 1, "content": "相关内容摘要"}, {"id": 2, "content": "相关内容摘要"} ], "caveats": ["注意事项1", "注意事项2"], "missing_info": ["缺失的信息"] } 【参考资料】 {context} 【问题】 {question} 只输出JSON,不要其他内容。 """5.2 答案验证
classAnswerValidator:"""答案验证器"""def__init__(self,llm):self.llm=llmdefvalidate(self,answer:str,context:str,question:str)->dict:"""验证答案质量"""prompt=f""" 请验证以下答案的质量: 问题:{question}参考资料:{context}答案:{answer}请从以下维度打分(0-10分): 1. 相关性:答案是否回答了问题? 2. 准确性:答案是否与参考资料一致? 3. 完整性:答案是否包含了所有相关信息? 4. 简洁性:答案是否简洁明了? 输出JSON格式: {{ "relevance": 0-10, "accuracy": 0-10, "completeness": 0-10, "conciseness": 0-10, "overall": 0-10, "issues": ["问题列表"] }} """response=self.llm.invoke(prompt)returnjson.loads(extract_json(response.content))defshould_regenerate(self,validation:dict)->bool:"""判断是否需要重新生成"""returnvalidation["overall"]<7六、完整生成流程
classRAGGenerator:"""完整的RAG生成器"""def__init__(self,llm):self.llm=llm self.validator=AnswerValidator(llm)defgenerate(self,query:str,context:str,max_attempts:int=2)->dict:"""生成答案"""forattemptinrange(max_attempts):# 生成answer=self._generate_once(query,context)# 验证validation=self.validator.validate(answer,context,query)ifvalidation["overall"]>=7:return{"answer":answer,"validation":validation,"attempts":attempt+1}# 质量不达标,重新生成context=self._enhance_context(query,context,validation["issues"])return{"answer":answer,"validation":validation,"attempts":max_attempts,"note":"答案质量未达标,建议人工审核"}def_generate_once(self,query:str,context:str)->str:"""单次生成"""prompt=GOOD_PROMPT.format(context=context,question=query)response=self.llm.invoke(prompt)returnresponse.contentdef_enhance_context(self,query:str,context:str,issues:list)->str:"""根据问题增强上下文"""# 添加提示hints=[]if"准确性"instr(issues):hints.append("注意:请确保所有信息都来自参考资料")if"完整性"instr(issues):hints.append("注意:请检查是否遗漏了重要信息")enhanced=context+"\n\n【生成提示】\n"+"\n".join(hints)returnenhanced七、总结
| Prompt技巧 | 效果 | 适用场景 |
|---|---|---|
| 明确约束 | 减少幻觉 | 所有场景 |
| 结构化指令 | 提升完整性 | 复杂问题 |
| 示例驱动 | 稳定格式 | 格式要求高 |
| 自我检验 | 提升准确性 | 高质量要求 |
| CoT推理 | 提升逻辑性 | 推理类问题 |
Prompt工程是低成本高回报的优化手段,值得投入时间打磨。
下篇预告:「RAG系统整体优化:从Pipeline到端到端」——各模块优化完了,如何整合成一个完整的RAG系统?
需要完整Prompt模板的同学,可以看我主页的付费资源专栏。
有问题欢迎评论区留言,大家一起讨论!