ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

构建具备自我评估能力的智能问答系统:应对AI不确定性

构建具备自我评估能力的智能问答系统:应对AI不确定性 最近在项目开发中尝试使用 Deepseek 进行技术调研和代码生成发现了一个有趣且值得深思的现象当 Deepseek 模型在处理某些复杂、模糊或需要实时验证的问题时它有时会对自己生成的答案或引用的搜索结果表现出“不自信”甚至直接建议用户去外部验证。这背后其实涉及到大语言模型LLM的固有局限性、检索增强生成RAG的边界以及我们作为开发者如何更有效地利用这类工具。本文将深入探讨这一现象分析其背后的技术原理并通过一个完整的实战案例展示如何构建一个能自我评估、交叉验证的智能问答系统。无论你是正在探索 AI 应用落地的开发者还是希望提升使用 AI 工具效率的工程师都能从中获得启发和可直接复用的代码。1. 背景与核心概念为什么 AI 会“不自信”在深入技术细节之前我们首先要理解问题的本质。Deepseek 作为一个大型语言模型其核心能力是基于海量训练数据进行模式识别和概率生成。它并不具备“理解”事实或实时访问外部世界的能力。当遇到以下情况时模型的不确定性会显著增加事实性查询Factual Queries询问某个软件的最新版本号、某个 API 的确切参数、或者今天某只股票的价格。这些信息具有时效性和唯一正确答案但模型训练数据可能过时导致它无法给出确定回答。复杂推理与计算Complex Reasoning涉及多步骤逻辑推导、复杂数学计算或需要特定领域专业知识的问题。模型可能会在推理链条的某个环节出错从而对最终结论产生怀疑。模糊或矛盾的用户输入Ambiguous Input用户问题表述不清或者提供的上下文信息有限且可能存在矛盾。模型难以确定用户的真实意图。超出训练数据分布Out-of-Distribution问题涉及训练数据中极少出现或从未出现过的概念、事件或技术组合。当模型“感知”到这些不确定性时负责任的模型如 Deepseek通常会采取保守策略它可能会在回答中附加免责声明如“根据我的知识截止日期...”直接承认不知道或者建议用户去查阅官方文档、运行代码进行验证。这恰恰是 AI 辅助开发走向成熟和可靠的关键一步——承认不确定性比盲目自信更有价值。我们的目标不是消除这种不自信而是学会识别它并构建工具和方法来弥补它。2. 环境准备与版本说明为了演示如何构建一个具备自我评估能力的问答系统我们将使用 Python 作为主要语言并集成 Deepseek API 和一些辅助工具。请确保你的环境满足以下要求操作系统Windows 10/11, macOS, 或 Linux (Ubuntu 20.04 推荐)Python 版本3.8 或更高版本 (本文示例使用 Python 3.9)关键库openai(用于调用 Deepseek API因其兼容 OpenAI SDK)requests(用于网络请求和搜索)beautifulsoup4和lxml(用于网页内容解析可选)pydantic(用于数据验证和结构化)tenacity(用于重试逻辑提升鲁棒性)你可以通过以下命令快速创建虚拟环境并安装依赖# 创建并激活虚拟环境 (以 Linux/macOS 为例) python3 -m venv venv source venv/bin/activate # 安装核心依赖 pip install openai requests beautifulsoup4 lxml pydantic tenacity # 对于 Windows 用户激活命令为venv\Scripts\activate重要提示你需要一个有效的 Deepseek API Key。请访问 Deepseek 开放平台注册并获取。本文将使用环境变量来管理密钥确保安全。# 在终端中设置环境变量 (临时) export DEEPSEEK_API_KEYyour_api_key_here # Windows: set DEEPSEEK_API_KEYyour_api_key_here3. 核心原理拆解从 RAG 到自我评估链传统的检索增强生成RAG系统流程是“检索 - 生成”。我们在此基础上增加一个“评估”环节形成“检索 - 评估 - (可能再检索) - 生成”的闭环。3.1 检索增强生成RAG基础RAG 的核心思想是当模型遇到知识盲区时先去外部知识库如文档、数据库、网络查找相关信息然后将这些信息作为上下文提供给模型再生成最终答案。这大大提升了答案的准确性和时效性。3.2 置信度评估与不确定性量化模型的不自信本质上是对其生成内容置信度低的表现。我们可以通过一些技术手段来量化这种不确定性自我一致性Self-Consistency让模型对同一个问题生成多个答案如果答案高度一致则置信度高如果差异很大则置信度低。支持证据检索Supporting Evidence Retrieval要求模型在生成答案的同时指出答案所依据的原文片段或来源。如果找不到强有力的支持证据则置信度低。验证链Verification Chain将复杂问题分解为多个可验证的子问题。先回答子问题并验证每个子答案的正确性例如通过代码执行、调用计算器API等再综合成最终答案。概率输出Logprobs一些高级 API 可以提供模型生成每个 token 的概率。通过分析整个回答序列的概率可以估算整体置信度。注Deepseek API 目前对 logprobs 的支持情况需查阅最新文档。在我们的实战中我们将主要结合支持证据检索和验证链的思想。4. 完整实战案例构建一个自我验证的编程问答助手假设场景用户询问一个复杂的编程问题例如“如何在 Python 中高效地合并两个字典并处理键冲突” 我们的系统不仅要给出答案还要评估答案的可靠性并在不确定时主动提示。4.1 项目结构与核心模块设计我们创建以下项目结构self_verifying_qa/ ├── config.py # 配置文件存放API密钥等 ├── retriever.py # 检索模块从外部获取信息 ├── evaluator.py # 评估模块判断答案置信度 ├── generator.py # 生成模块调用Deepseek生成答案 ├── orchestrator.py # 编排模块控制整体流程 └── main.py # 主程序入口4.2 实现检索模块 (retriever.py)这个模块负责从预设的可靠来源如官方文档、Stack Overflow API获取信息。这里我们简化实现模拟从本地知识库和网络使用 requests获取信息。# retriever.py import requests from typing import List, Dict, Optional from tenacity import retry, stop_after_attempt, wait_exponential import json class KnowledgeRetriever: def __init__(self, local_kb_path: str data/local_kb.json): 初始化检索器可以加载本地知识库。 self.local_knowledge self._load_local_kb(local_kb_path) def _load_local_kb(self, path: str) - Dict: 加载本地JSON格式的知识库。 try: with open(path, r, encodingutf-8) as f: return json.load(f) except FileNotFoundError: print(f本地知识库文件 {path} 未找到将使用空知识库。) return {} retry(stopstop_after_attempt(3), waitwait_exponential(multiplier1, min4, max10)) def search_web(self, query: str, source: str duckduckgo) - List[Dict]: 模拟从网络搜索信息。 注意实际生产环境应使用正式的搜索API如Serper、Google Custom Search。 此处为演示我们模拟返回结构化数据。 # 这是一个模拟函数。实际应用中你需要替换为真正的搜索API调用。 print(f[Retriever] 正在从网络搜索: {query}) # 模拟根据查询返回一些“找到”的片段 simulated_results [ { title: Python官方文档 - dict.update(), snippet: dict.update([other]) 更新字典如果键存在则覆盖。, url: https://docs.python.org/3/library/stdtypes.html#dict.update, relevance_score: 0.9 }, { title: Stack Overflow - 合并字典的多种方法, snippet: 在Python 3.9中可以使用 z x | y。对于旧版本{**x, **y} 很常用。, url: https://stackoverflow.com/questions/38987, relevance_score: 0.85 }, { title: 某博客 - 高级合并技巧, snippet: 使用 collections.ChainMap 可以惰性合并但不直接解决冲突。, url: https://example.com/blog, relevance_score: 0.7 } ] # 简单过滤只返回高相关度的结果 return [r for r in simulated_results if r[relevance_score] 0.6] def retrieve(self, query: str) - Dict[str, List]: 主检索函数结合本地和网络检索。 返回格式{local: [...], web: [...]} all_context {local: [], web: []} # 1. 本地知识库检索 (简单关键词匹配) for key, content in self.local_knowledge.items(): if any(word in query.lower() for word in key.lower().split()): all_context[local].append({ source: local_kb, key: key, content: content }) # 2. 网络检索 web_results self.search_web(query) all_context[web] web_results return all_context if __name__ __main__: # 简单测试 retriever KnowledgeRetriever() context retriever.retrieve(Python merge dict) print(json.dumps(context, indent2, ensure_asciiFalse))4.3 实现评估模块 (evaluator.py)这是核心模块它调用 Deepseek 来评估检索到的上下文是否足以支撑一个高质量的回答并给出置信度分数和理由。# evaluator.py import os from openai import OpenAI from typing import List, Dict, Any from pydantic import BaseModel import json # 配置 Deepseek 客户端 client OpenAI( api_keyos.getenv(DEEPSEEK_API_KEY), base_urlhttps://api.deepseek.com # Deepseek API 端点 ) class ConfidenceAssessment(BaseModel): 用于结构化存储置信度评估结果 confidence_score: float # 0.0 到 1.0 reasoning: str # 评估理由 missing_info: List[str] # 缺失的关键信息 suggested_verification: List[str] # 建议的验证步骤 class AnswerEvaluator: def __init__(self, model: str deepseek-chat): self.model model def assess_confidence(self, query: str, retrieved_context: Dict[str, List]) - ConfidenceAssessment: 评估基于当前检索到的上下文回答问题的置信度。 # 构建评估提示词 context_str self._format_context(retrieved_context) system_prompt 你是一个严谨的技术评估助手。你的任务是根据提供的“用户问题”和“检索到的上下文”评估如果仅基于这些上下文生成答案其可信度和完整性如何。 请从以下几个维度思考 1. 上下文是否直接回答了问题的核心 2. 上下文来源是否可靠如官方文档、高赞Stack Overflow回答 3. 上下文信息是否足够具体和详细能指导用户操作 4. 是否有明显的矛盾或过时信息 5. 还缺少哪些关键信息才能给出完美答案 请输出一个JSON对象包含以下字段 - confidence_score: 一个0到1之间的浮点数表示整体置信度。 - reasoning: 一段文字解释你给出这个分数的理由。 - missing_info: 一个字符串列表列出缺失的关键信息。 - suggested_verification: 一个字符串列表建议用户或系统如何进一步验证答案例如“运行示例代码”、“查阅某官方文档的第X节”。 user_prompt f 用户问题{query} 检索到的上下文 {context_str} 请进行评估。 try: response client.chat.completions.create( modelself.model, messages[ {role: system, content: system_prompt}, {role: user, content: user_prompt} ], temperature0.1, # 低温度使输出更确定 response_format{type: json_object} # 要求返回JSON ) result_json json.loads(response.choices[0].message.content) assessment ConfidenceAssessment(**result_json) return assessment except Exception as e: print(f[Evaluator] 评估过程中发生错误: {e}) # 返回一个低置信度的默认评估 return ConfidenceAssessment( confidence_score0.3, reasoningf评估过程出错: {e}。无法可靠判断。, missing_info[评估服务暂时不可用], suggested_verification[请直接查阅官方文档或手动测试。] ) def _format_context(self, context: Dict[str, List]) - str: 将检索到的上下文格式化为字符串。 parts [] if context.get(local): parts.append(【本地知识库】) for item in context[local]: parts.append(f- 主题{item[key]}\n 内容{item[content][:200]}...) # 截断显示 if context.get(web): parts.append(【网络检索结果】) for idx, item in enumerate(context[web], 1): parts.append(f{idx}. {item[title]}\n 摘要{item[snippet]}\n 来源{item[url]}) return \n.join(parts) if parts else 未检索到相关上下文 if __name__ __main__: evaluator AnswerEvaluator() # 模拟检索结果 mock_context { web: [ {title: Test Doc, snippet: Snippet about Python dict., url: http://test.com, relevance_score: 0.8} ] } assessment evaluator.assess_confidence(How to merge dicts?, mock_context) print(f置信度分数: {assessment.confidence_score}) print(f评估理由: {assessment.reasoning})4.4 实现生成模块 (generator.py)这个模块在评估认为置信度足够高时被调用来生成最终答案。它同样使用 Deepseek但提示词侧重于生成友好、准确、带示例的答案。# generator.py import os from openai import OpenAI from typing import Dict, List from .evaluator import ConfidenceAssessment # 假设在同一包内 client OpenAI( api_keyos.getenv(DEEPSEEK_API_KEY), base_urlhttps://api.deepseek.com ) class AnswerGenerator: def __init__(self, model: str deepseek-chat): self.model model def generate_answer(self, query: str, retrieved_context: Dict[str, List], assessment: ConfidenceAssessment) - str: 基于查询、上下文和置信度评估生成最终答案。 如果置信度低会在答案前添加警告。 context_str self._format_context_for_generation(retrieved_context) system_prompt 你是一个乐于助人且严谨的技术专家。请根据提供的上下文信息清晰、准确地回答用户的问题。 你的回答应该 1. 直接解决问题。 2. 提供可运行的代码示例如果适用。 3. 解释关键步骤和原理。 4. 如果提供的信息有局限性或不确定性请诚实说明。 5. 最后可以给出进一步学习的建议或官方文档链接。 user_prompt_parts [f用户问题{query}] # 如果置信度评估认为信息不足在提示词中明确指出 if assessment.confidence_score 0.7: user_prompt_parts.append( f注意系统评估认为当前信息的置信度较低{assessment.confidence_score:.2f}。 f缺失的信息可能包括{, .join(assessment.missing_info[:3])}。 请在回答中体现出这种不确定性并引导用户进行验证。 ) user_prompt_parts.append(f可用的上下文信息\n{context_str}) user_prompt_parts.append(请基于以上信息生成回答。) user_prompt \n\n.join(user_prompt_parts) try: response client.chat.completions.create( modelself.model, messages[ {role: system, content: system_prompt}, {role: user, content: user_prompt} ], temperature0.7, # 稍高的温度使回答更自然 streamFalse ) final_answer response.choices[0].message.content return self._postprocess_answer(final_answer, assessment) except Exception as e: return f生成答案时出错{e}。请检查网络和API设置。 def _format_context_for_generation(self, context: Dict[str, List]) - str: 为生成阶段格式化上下文更简洁。 # 实现类似于评估模块的格式化但可以更精简 formatted [] for source, items in context.items(): if items: formatted.append(f【{source}】) for item in items[:3]: # 限制条数 if source web: formatted.append(f- {item[snippet]} (来源{item[url]})) else: formatted.append(f- {item.get(content, )[:150]}...) return \n.join(formatted) if formatted else 无额外上下文。 def _postprocess_answer(self, answer: str, assessment: ConfidenceAssessment) - str: 后处理答案例如添加置信度标签。 if assessment.confidence_score 0.5: disclaimer ( \n\n---\n **⚠️ 可靠性提示**\n f*系统评估置信度{assessment.confidence_score:.2f}/1.0*\n f*可能缺失{, .join(assessment.missing_info[:2])}*\n **建议**{assessment.suggested_verification[0] if assessment.suggested_verification else 请通过运行代码或查阅官方文档进行验证。} ) answer disclaimer elif assessment.confidence_score 0.8: note ( \n\n---\n ** 说明**\n f以上答案基于现有信息整合系统评估置信度为 {assessment.confidence_score:.2f}/1.0。 对于关键操作建议进行额外测试。 ) answer note # 高置信度答案可以不添加额外标记或添加一个正向标记 else: answer \n\n---\n**✅ 以上信息基于相对可靠的来源整合。** return answer4.5 实现编排模块 (orchestrator.py)这是系统的大脑它串联起检索、评估、生成以及可能的二次检索流程。# orchestrator.py from typing import Optional from .retriever import KnowledgeRetriever from .evaluator import AnswerEvaluator, ConfidenceAssessment from .generator import AnswerGenerator class QASystemOrchestrator: def __init__(self): self.retriever KnowledgeRetriever() self.evaluator AnswerEvaluator() self.generator AnswerGenerator() self.confidence_threshold_high 0.7 self.confidence_threshold_low 0.4 def answer_question(self, query: str, max_retrieval_rounds: int 2) - Dict[str, any]: 回答问题的核心流程。 返回一个包含答案和元数据的字典。 print(f[System] 开始处理问题: {query}) all_retrieved_context {local: [], web: []} final_assessment None for round_num in range(1, max_retrieval_rounds 1): print(f[System] 第 {round_num} 轮检索与评估...) # 1. 检索 new_context self.retriever.retrieve(query) # 合并上下文实际中可能需要去重 all_retrieved_context[local].extend(new_context[local]) all_retrieved_context[web].extend(new_context[web]) # 2. 评估 assessment self.evaluator.assess_confidence(query, all_retrieved_context) final_assessment assessment print(f[System] 本轮评估置信度: {assessment.confidence_score:.2f}) # 3. 决策 if assessment.confidence_score self.confidence_threshold_high: print([System] 置信度足够准备生成最终答案。) break # 跳出循环准备生成 elif assessment.confidence_score self.confidence_threshold_low and round_num max_retrieval_rounds: # 置信度太低尝试用缺失的信息重新构造查询进行下一轮检索 if assessment.missing_info: # 简化策略将缺失的关键信息加入查询 refined_query query .join(assessment.missing_info[:2]) print(f[System] 置信度过低尝试优化查询: {refined_query}) query refined_query # 更新查询进入下一轮循环 else: # 没有明确缺失信息直接跳出 break else: # 置信度中等不再继续检索直接生成但会附带说明 print([System] 置信度中等将生成带说明的答案。) break # 4. 生成最终答案 print([System] 正在生成最终答案...) final_answer self.generator.generate_answer(query, all_retrieved_context, final_assessment) return { question: query, answer: final_answer, confidence_score: final_assessment.confidence_score if final_assessment else 0.0, assessment_reasoning: final_assessment.reasoning if final_assessment else , retrieval_rounds: round_num, sources_used: len(all_retrieved_context[web]) len(all_retrieved_context[local]) }4.6 主程序入口 (main.py)最后我们创建一个简单的主程序来运行整个系统。# main.py import os from orchestrator import QASystemOrchestrator def main(): # 检查API密钥 if not os.getenv(DEEPSEEK_API_KEY): print(错误未设置 DEEPSEEK_API_KEY 环境变量。) print(请执行: export DEEPSEEK_API_KEYyour_key (Linux/macOS)) print(或: set DEEPSEEK_API_KEYyour_key (Windows)) return orchestrator QASystemOrchestrator() print( * 50) print(自我验证问答系统启动) print(输入 quit 或 exit 退出) print( * 50) while True: user_question input(\n请输入你的技术问题: ).strip() if user_question.lower() in [quit, exit, q]: print(再见) break if not user_question: continue print(\n *30 处理中 *30) result orchestrator.answer_question(user_question) print(\n *30 回答 *30) print(result[answer]) print(\n *30 元数据 *30) print(f最终置信度评分: {result[confidence_score]:.2f}) print(f检索轮次: {result[retrieval_rounds]}) print(f使用来源数量: {result[sources_used]}) print( * 68) if __name__ __main__: main()4.7 运行与验证确保已设置DEEPSEEK_API_KEY环境变量。在项目根目录下创建一个简单的本地知识库文件data/local_kb.json{ Python字典合并: 在Python中合并字典有多种方法包括update()方法、字典解包{**d1, **d2}Python 3.5和合并运算符|Python 3.9。键冲突时后出现的值会覆盖先出现的值。, 虚拟环境: Python虚拟环境用于隔离项目依赖常用工具为venv内置和virtualenv。 }运行主程序python main.py输入问题进行测试例如“Python 3.8 里怎么合并两个字典”“collections.ChainMap和dict.update有什么区别”“最新的 Django 版本是什么”这是一个典型的模型可能“不自信”的事实性问题预期结果对于信息充足的问题系统会给出高置信度的完整答案。对于模糊或信息不足的问题系统生成的答案会附带“可靠性提示”明确指出置信度较低并建议验证步骤。这模拟了 Deepseek “不自信”时的行为但将其系统化、透明化了。5. 常见问题与排查思路在实现和使用此类系统时你可能会遇到以下问题问题现象常见原因解决思路API 调用失败返回认证错误1. API Key 未设置或错误。2. 环境变量未正确加载。3. API 端点 (base_url) 不正确。1. 检查echo $DEEPSEEK_API_KEY(Linux/macOS) 或echo %DEEPSEEK_API_KEY%(Windows)。2. 在代码中直接打印os.getenv(DEEPSEEK_API_KEY)的前几位进行验证。3. 查阅 Deepseek 官方文档确认最新的 API 端点。评估模块始终返回低置信度1. 检索模块返回的上下文质量太差或无关。2. 评估提示词 (system_prompt) 过于苛刻。3. 模拟的网络检索结果太假模型能识别出来。1. 优化检索逻辑引入更精准的关键词匹配或向量相似度搜索。2. 调整评估提示词使其更符合实际场景。可以尝试让模型扮演“宽松的评审员”。3. 替换模拟检索为真实的搜索 API如 Serper Dev、Google Custom Search JSON API。系统响应速度很慢1. 网络检索是同步的且可能超时。2. 进行了多轮检索-评估循环。3. Deepseek API 本身有延迟。1. 为网络请求设置合理的超时时间并使用tenacity库实现重试和退避。2. 限制最大检索轮次 (max_retrieval_rounds)。对于简单问题一轮即可。3. 考虑使用异步编程 (asyncio,aiohttp) 来并行化独立的 I/O 操作。生成的答案依然包含明显错误1. 检索到的上下文本身有误。2. 模型在生成时“幻觉”了信息。3. 置信度阈值设置不合理低置信度答案也被直接输出了。1. 严格把关数据源优先使用官方文档、权威教程。2. 在生成提示词中加强约束如“严格基于上下文回答不要编造”。3. 当置信度低于某个阈值如0.5时不生成答案而是直接回复“信息不足建议您查阅以下链接[来源列表]”。“缺失信息”列表不准确评估模型可能无法精准识别到底缺什么。1. 尝试让评估模型以更结构化的方式思考缺失信息例如分为“概念定义缺失”、“代码示例缺失”、“版本信息缺失”等类别。2. 结合规则如果问题中包含“最新”、“当前”等词而上下文发布日期很旧则自动加入“缺失时效性信息”。6. 最佳实践与工程建议将 AI 的“不自信”转化为系统优势需要良好的工程实践。分层次置信度与应对策略高置信度 (0.8)直接提供完整答案可标注来源。中置信度 (0.5-0.8)提供答案但明确说明局限性“基于2023年的资料...”并给出验证建议。低置信度 (0.5)不提供肯定性答案。转而提供可能相关的信息片段、搜索关键词或引导用户到更权威的平台提问。这是避免传播错误信息的关键。多样化检索源与来源可信度加权不要只依赖单一来源。结合官方文档、高质量技术博客、Stack Overflow 高票答案、GitHub 源码等。为不同来源赋予不同的初始可信度权重如官方文档权重为1.0个人博客权重为0.6并在评估时考虑这个权重。实现事实核查与代码执行对于代码类问题最强的验证是实际执行。可以在沙箱环境中自动运行生成的代码片段检查是否有语法错误、运行时错误并验证输出是否符合预期。对于事实类问题版本号、API 参数可以尝试从官方文档的固定位置如版本发布页面、API 目录进行精准检索。设计人性化的不确定性表达避免生硬的“我不知道”。可以这样说“关于这个问题目前找到的信息可能不够全面。通常的做法是 A 或 B但建议您参考 [官方链接] 获取最准确的信息。”使用进度条、置信度图标等可视化元素在Web/GUI应用中来直观展示答案的可靠程度。持续迭代与评估构建一个测试集包含各种类型的问题清晰的、模糊的、过时的、复杂的。定期运行测试集监控系统答案的准确率和置信度评分的校准情况即置信度高的答案是否真的准确。根据评估结果不断优化检索策略、评估提示词和置信度阈值。安全与合规对于网络检索遵守目标网站的robots.txt协议控制请求频率避免被封禁。谨慎处理用户输入和生成的内容防止注入攻击或生成有害内容。明确告知用户系统的局限性答案仅供参考不构成专业建议。通过以上实践我们不再是被动地接受 AI 的“不自信”而是主动地管理这种不确定性构建出更可靠、更透明、也更值得用户信赖的 AI 辅助工具。这正是解决“当 Deepseek 不相信自己的搜索结果时”这一问题的终极思路——将人的智慧与机器的能力相结合在流程中嵌入验证与反思的环节。
返回列表