尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于RAG与工具调用的AI应用“开卷考”架构:解决幻觉,提升准确性

基于RAG与工具调用的AI应用“开卷考”架构:解决幻觉,提升准确性 这次我们来看一个解决 AI 幻觉问题的思路——“开卷考”。AI 幻觉简单说就是大模型一本正经地胡说八道生成看似合理但实际错误或虚构的信息。这在金融、医疗、法律等对准确性要求极高的领域是致命的。与其让模型在“闭卷”状态下凭空编造不如让它学会“开卷”即通过检索外部知识库或调用可信数据接口来获取答案。这不仅是当前智能体Agent和 MCPModel Context Protocol等框架的核心设计理念也是提升 AI 应用可靠性的关键路径。本文的核心是探讨如何通过“开卷考”机制为你的 AI 应用无论是智能体、聊天机器人还是自动化工具注入事实核查和知识引用的能力。我们将重点关注其实现原理、技术门槛、以及如何通过数据接口如金融、股票接口和 MCP 协议来构建一个可验证、可追溯的 AI 系统。无论你是想搭建一个能准确回答财经问题的智能体还是希望你的本地模型在生成内容时能自动引用来源这篇文章都将提供一套清晰的落地思路。1. 核心能力速览“开卷考”不是一个具体的软件包而是一种架构模式和实现方案。其核心在于将大语言模型的生成能力与外部可信数据源相结合。能力项说明核心目标解决 AI 幻觉提升生成内容的准确性和可信度。实现原理检索增强生成RAG工具调用Function Calling。模型在回答前先检索知识库或调用 API 获取实时/准确数据再基于这些信息生成回答。关键技术栈大语言模型本地/云端、向量数据库、MCP 协议、各类数据 API如金融、新闻、百科。硬件门槛灵活。纯 API 调用对本地硬件无要求若涉及本地模型嵌入和检索则需要 GPU/CPU 和内存支持具体取决于模型大小。启动与集成通常以代码库、框架插件或智能体平台如 Dify, Coze功能模块的形式提供需要集成到现有应用中。是否支持 API是。核心就是通过 API 调用来获取外部数据。是否支持批量任务是。可以构建流水线对批量查询进行“检索-生成”处理。适合场景问答系统、报告生成、数据分析、智能客服、任何需要事实准确性的 AI 应用场景。2. 适用场景与使用边界“开卷考”机制并非万能理解其适用边界能更好地发挥其价值。它最适合谁领域知识开发者需要构建金融、法律、医疗等专业领域 AI 应用的开发者。智能体Agent搭建者希望智能体能主动查询天气、股价、新闻等实时信息并据此行动。企业知识库管理者希望将内部文档、手册作为 AI 回答的依据避免模型胡编乱造公司政策。所有关心 AI 输出可靠性的用户即使是普通聊天引用来源也能大幅提升可信度。它能解决什么问题事实性错误让 AI 基于检索到的文档、数据回答问题而非依赖内部参数化记忆。信息过时通过接入实时 API如股票接口、新闻接口获取最新信息。领域深度不足用专业的领域知识库如医学文献、法律条文增强通用模型的专业能力。可解释性与溯源生成的答案可以附带引用来源方便用户核查。它不适合什么场景创意写作、诗歌生成这类任务本身不需要严格的事实依据过度约束反而会限制创造性。极度低延迟的简单对话检索步骤会增加响应时间对于“你好”这类问候直接生成更高效。完全封闭、无外部数据源的环境巧妇难为无米之炊。合规与安全边界数据授权确保接入的 API 或使用的知识库数据拥有合法授权遵守相关服务条款。隐私保护如果知识库包含用户隐私或敏感信息需做好数据脱敏和访问控制。内容审核即使引用了来源模型生成的内容仍需进行合规性审核避免产生有害信息。3. 环境准备与前置条件实施“开卷考”方案你需要准备以下几个层面的环境。1. 基础开发环境操作系统Windows / macOS / Linux 均可推荐 Linux 用于生产环境。Python3.8 及以上版本这是大多数 AI 框架和库的基础。包管理工具pip或conda。2. 核心组件选择根据方案二选一或组合方案A云端模型 向量检索经典 RAGLLM 服务OpenAI API、通义千问 API、DeepSeek API 等。或本地部署的模型服务如 Ollama, vLLM。嵌入模型用于将文本转换为向量例如text-embedding-ada-002,bge-large-zh。可以是云端 API 或本地模型。向量数据库用于存储和检索向量例如Chroma,Milvus,Qdrant,Weaviate。通常可本地部署或使用云服务。方案B智能体框架 工具调用MCP/Function Calling智能体框架LangChain, LlamaIndex, Dify, Coze 等。工具协议MCP (Model Context Protocol) 服务器或自定义 Function Calling 工具。数据接口你需要接入的具体 API如新浪财经股票接口、Wind 金融数据接口等。3. 硬件资源评估纯 API 调用只需网络和基础运行环境无特殊硬件要求。本地嵌入模型向量库需要一定内存和 CPU 算力。例如运行bge-base嵌入模型可能需要 1-2GB 内存。本地 LLM 全套流程需要满足所选本地大模型的硬件要求如 GPU 显存。这通常不是“开卷考”的瓶颈因为检索步骤可以独立于大模型运行。4. 安装部署与启动方式我们以一个典型的“本地知识库问答”场景为例演示如何搭建一个最简单的 RAG 系统。这里使用LangChain、Chroma向量数据库和Ollama本地运行大模型的组合。步骤1安装基础库# 创建虚拟环境可选 python -m venv rag_env source rag_env/bin/activate # Linux/macOS # rag_env\Scripts\activate # Windows # 安装核心库 pip install langchain langchain-community chromadb pypdf sentence-transformers # 安装 Ollama 的 LangChain 集成 pip install langchain-ollama步骤2准备知识库文档将你的 PDF、TXT、Word 等文档放入一个目录例如./knowledge_docs/。步骤3编写核心应用脚本创建一个名为rag_demo.py的文件import os from langchain_community.document_loaders import DirectoryLoader, PyPDFLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_community.vectorstores import Chroma from langchain_ollama import OllamaLLM from langchain.chains import RetrievalQA from langchain.prompts import PromptTemplate # 1. 加载文档 documents [] loader DirectoryLoader(./knowledge_docs/, glob**/*.pdf, loader_clsPyPDFLoader) documents.extend(loader.load()) # 可以添加其他格式的 loader如 TextLoader # 2. 分割文本 text_splitter RecursiveCharacterTextSplitter(chunk_size500, chunk_overlap50) texts text_splitter.split_documents(documents) # 3. 创建嵌入模型和向量库 # 使用本地嵌入模型无需GPU也能运行 embeddings HuggingFaceEmbeddings(model_nameBAAI/bge-small-zh-v1.5) # 持久化向量数据库到本地目录 vectorstore Chroma.from_documents(documentstexts, embeddingembeddings, persist_directory./chroma_db) vectorstore.persist() # 4. 连接本地大模型确保 Ollama 服务已启动并拉取了模型如 llama3.2 llm OllamaLLM(modelllama3.2, base_urlhttp://localhost:11434) # 5. 构建检索问答链 prompt_template 请根据以下上下文信息回答问题。如果上下文信息不足以回答问题请直接说“根据提供的信息无法回答”不要编造信息。 上下文 {context} 问题{question} 请给出准确、基于上下文的回答 PROMPT PromptTemplate(templateprompt_template, input_variables[context, question]) qa_chain RetrievalQA.from_chain_type( llmllm, chain_typestuff, retrievervectorstore.as_retriever(search_kwargs{k: 3}), # 检索最相关的3个片段 chain_type_kwargs{prompt: PROMPT}, return_source_documentsTrue # 返回来源文档 ) # 6. 提问 query 什么是AI幻觉 result qa_chain.invoke({query: query}) print(问题, query) print(回答, result[result]) print(\n--- 引用来源 ---) for i, doc in enumerate(result[source_documents]): print(f[{i1}] {doc.page_content[:200]}...) # 打印片段前200字符步骤4启动 Ollama 服务并拉取模型# 首先确保安装了 Ollama (https://ollama.com/) # 拉取一个模型例如 llama3.2 ollama pull llama3.2 # 启动 Ollama 服务通常拉取后会自动运行步骤5运行脚本python rag_demo.py首次运行会花费较长时间创建向量数据库。之后再次运行可以修改代码直接加载已有的向量库而无需重复处理文档。5. 功能测试与效果验证搭建好基础系统后我们需要从多个维度验证其“开卷”能力是否有效。5.1 基础事实问答测试测试目的验证系统能否从提供的知识库中准确找到答案而非依赖模型本身的记忆可能错误。输入知识库中明确记载的问题。例如如果你的知识库是一份产品手册可以问“产品A的最大支持用户数是多少”操作运行上述脚本传入问题。预期结果答案应精确匹配手册中的数字并在“引用来源”中显示包含该数字的原文片段。成功标准答案正确且来源可追溯。失败排查检查文档是否被正确加载和分割查看texts变量。检查向量检索是否返回了相关片段查看result[“source_documents”]。检查提示词Prompt是否明确要求模型基于上下文回答。5.2 “闭卷”幻觉对比测试测试目的直观展示“开卷”与“闭卷”的差异。操作A开卷使用上面的 RAG 系统提问一个知识库中不存在的信息例如“根据文档我们公司明年计划收购哪家公司”操作B闭卷直接向同一个大模型Ollama提问同样的问题不提供任何上下文。预期结果开卷系统应回答“根据提供的信息无法回答”或类似内容。纯模型可能会编造一个看似合理的公司名称和收购细节幻觉。成功标准开卷系统表现出对未知信息的克制而纯模型产生了幻觉。5.3 实时数据接口集成测试MCP/工具调用示例测试目的验证系统能否调用外部 API 获取实时信息。 这里以模拟一个查询天气的工具为例展示如何通过 LangChain 的Tool和Agent实现。from langchain.agents import initialize_agent, AgentType from langchain.tools import Tool from langchain_ollama import OllamaLLM import requests # 1. 定义一个获取天气的工具函数 def get_weather(city: str) - str: 通过模拟API获取城市天气。实际应替换为真实API调用。 # 模拟API响应 weather_data { 北京: 晴15-25°C, 上海: 多云18-28°C, 深圳: 阵雨22-30°C } return weather_data.get(city, f未找到{city}的天气信息) # 2. 将函数封装成 LangChain Tool weather_tool Tool( nameGetWeather, funcget_weather, description根据城市名称查询当前天气。输入应为城市名如‘北京’。 ) # 3. 初始化LLM和Agent llm OllamaLLM(modelllama3.2, base_urlhttp://localhost:11434) tools [weather_tool] agent initialize_agent(tools, llm, agentAgentType.ZERO_SHOT_REACT_DESCRIPTION, verboseTrue) # 4. 提问一个需要实时信息的问题 result agent.run(今天深圳的天气怎么样适合穿短袖吗) print(result)预期结果Agent 应识别出需要调用GetWeather工具获取“深圳”的天气信息阵雨22-30°C然后结合此信息判断是否适合穿短袖。成功标准最终答案包含了从工具获取的真实数据并且推理合理。6. 接口 API 与批量任务“开卷考”系统本身可以作为 API 服务提供也天然支持批量处理。6.1 构建 FastAPI 服务将上面的 RAG 问答链封装成 Web API方便其他系统调用。# file: rag_api.py from fastapi import FastAPI, HTTPException from pydantic import BaseModel from langchain_community.vectorstores import Chroma from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_ollama import OllamaLLM from langchain.chains import RetrievalQA from langchain.prompts import PromptTemplate app FastAPI() # 初始化组件启动时加载一次 embeddings HuggingFaceEmbeddings(model_nameBAAI/bge-small-zh-v1.5) vectorstore Chroma(persist_directory./chroma_db, embedding_functionembeddings) llm OllamaLLM(modelllama3.2) prompt_template ... # 同前的提示词 PROMPT PromptTemplate(templateprompt_template, input_variables[context, question]) qa_chain RetrievalQA.from_chain_type(llmllm, retrievervectorstore.as_retriever(), chain_type_kwargs{prompt: PROMPT}) class QueryRequest(BaseModel): question: str top_k: int 3 class QueryResponse(BaseModel): answer: str sources: list[str] app.post(/query, response_modelQueryResponse) async def query_knowledge_base(req: QueryRequest): try: result qa_chain.invoke({query: req.question}) sources [doc.page_content[:500] for doc in result.get(source_documents, [])] return QueryResponse(answerresult[result], sourcessources) except Exception as e: raise HTTPException(status_code500, detailstr(e)) if __name__ __main__: import uvicorn uvicorn.run(app, host0.0.0.0, port8000)启动服务python rag_api.py。即可通过http://localhost:8000/query进行 POST 查询。6.2 批量任务处理对于需要处理大量问题的场景可以构建批处理脚本。# file: batch_process.py import requests import json import time api_url http://localhost:8000/query questions [问题1, 问题2, 问题3, ...] # 从文件读取 results [] for q in questions: try: resp requests.post(api_url, json{question: q}, timeout30) if resp.status_code 200: results.append(resp.json()) else: results.append({question: q, error: resp.text}) except Exception as e: results.append({question: q, error: str(e)}) time.sleep(0.5) # 避免请求过快 # 保存结果 with open(batch_results.json, w, encodingutf-8) as f: json.dump(results, f, ensure_asciiFalse, indent2) print(f批量处理完成共处理 {len(questions)} 个问题。)6.3 集成真实数据接口示例模拟金融数据以接入一个模拟的股票查询接口为例展示如何为智能体增加“开卷”能力。# 扩展之前的工具列表 import yfinance as yf # 示例库需安装: pip install yfinance def get_stock_price(symbol: str) - str: 获取股票最新价格。 try: stock yf.Ticker(symbol) hist stock.history(period1d) if hist.empty: return f未找到股票代码 {symbol} 的数据。 latest_price hist[Close].iloc[-1] return f{symbol} 的最新收盘价为 {latest_price:.2f} 美元。 except Exception as e: return f查询股票{symbol}时出错{e} stock_tool Tool( nameGetStockPrice, funcget_stock_price, description根据股票代码如AAPL, 0700.HK查询最新收盘价。 ) # 将新工具加入Agent tools [weather_tool, stock_tool] agent initialize_agent(tools, llm, agentAgentType.ZERO_SHOT_REACT_DESCRIPTION, verboseTrue) print(agent.run(苹果公司AAPL和腾讯0700.HK的股价现在是多少哪个更高))这个 Agent 会自主决定调用两次GetStockPrice工具获取数据后进行对比分析。7. 资源占用与性能观察“开卷考”系统的性能开销主要来自两部分检索和生成。1. 检索阶段向量数据库查询CPU/内存向量相似度计算是计算密集型操作。对于千万级以下的向量在普通 CPU 上也能在毫秒到百毫秒内完成。内存占用主要取决于加载的向量索引大小。优化建议使用HNSW等近似最近邻算法在精度和速度间取得平衡。控制文本分块Chunk的大小和重叠度过小的块会增加检索次数过大的块会降低精度。将向量数据库部署在内存或高速 SSD 上。2. 生成阶段大模型推理资源消耗这是主要瓶颈。取决于所选大模型。本地模型消耗 GPU 显存或 CPU 内存。7B 参数模型在 4-bit 量化下可能需要 4-6GB 显存。云端 API无本地资源消耗但依赖网络且产生费用。延迟检索 生成的总时间。RAG 的提示词因为包含检索到的上下文通常会比纯对话更长因此生成时间也可能略长。观察方法本地模型使用nvidia-smi(GPU) 或任务管理器观察显存/内存占用。延迟监控在代码中记录每个环节检索、生成的耗时。3. 整体性能调优思路缓存对常见问题及其答案进行缓存避免重复检索和生成。异步处理对于批量任务使用异步请求来提高吞吐量。分级检索先使用简单的关键词匹配进行粗筛再用向量检索进行精排。精简上下文只将最相关的文本片段送入大模型避免提示词过长。8. 常见问题与排查方法在构建和运行“开卷考”系统时你可能会遇到以下典型问题。问题现象可能原因排查方式解决方案向量数据库检索不到相关内容1. 文档未正确加载或分割。2. 嵌入模型不匹配或质量差。3. 检索参数k设置过小。1. 检查texts变量确认文档内容已分割。2. 尝试用不同嵌入模型。3. 检查检索到的source_documents内容。1. 确保文档格式被支持调整分割参数chunk_size,chunk_overlap。2. 换用更强大的嵌入模型如bge-large。3. 增大k值或使用MMR等多样性检索方法。模型回答依然出现幻觉无视上下文1. 提示词Prompt未强制要求基于上下文。2. 上下文相关性太低模型“看不到”答案。3. 模型本身能力或微调问题。1. 检查传递给模型的最终提示词是否包含了检索到的上下文。2. 查看模型接收到的完整输入。1. 强化提示词例如“必须严格依据以下上下文...”。2. 提升检索质量确保返回的片段包含答案。3. 尝试指令跟随能力更强的模型。接入外部 API 失败或返回错误1. 网络问题。2. API 密钥无效或配额用尽。3. 请求参数格式错误。4. API 服务方限制。1. 使用curl或requests单独测试 API。2. 查看 API 返回的错误码和消息。1. 检查网络连接和代理设置。2. 复核 API 密钥和请求参数。3. 在代码中添加重试机制和错误处理。系统响应速度慢1. 嵌入模型推理慢本地。2. 向量数据库查询慢。3. 大模型生成慢。4. 网络延迟云端 API。1. 分阶段计时定位瓶颈。2. 监控系统资源CPU/GPU/内存。1. 使用量化后的嵌入模型。2. 优化向量数据库索引。3. 对大模型进行量化或使用更小模型。4. 考虑使用 CDN 或更近的 API 端点。智能体不调用工具1. 工具描述description不清晰模型无法理解何时调用。2. 模型Agent类型选择不当。3. 提示词未激发工具使用。1. 查看 Agent 的思考过程verboseTrue。2. 测试一个明确需要工具的问题。1. 优化工具描述明确输入输出格式和适用场景。2. 尝试ReAct或OpenAI Functions类型的 Agent。3. 在系统提示词中鼓励模型使用工具。9. 最佳实践与使用建议要让“开卷考”系统稳定、可靠地运行遵循以下实践至关重要。1. 数据源质量优先准确性确保知识库文档和接入的 API 数据源本身是准确、权威的。垃圾进垃圾出。时效性建立数据更新机制。过时的知识库同样会导致“幻觉”输出过时信息。结构化尽量使用结构化或半结构化数据如 Markdown、JSON便于解析和检索。2. 提示词工程是关键明确指令在提示词中清晰、强硬地要求模型“基于给定上下文回答”。提供格式示例对于需要特定格式如列表、表格的回答在上下文中提供例子。设置拒绝回答的边界明确告知模型当上下文不足时应回答“不知道”。3. 实施多层验证答案一致性检查对于关键问题可以用不同检索参数或模型多次生成答案进行交叉验证。来源可信度评估如果可能对检索到的文档来源进行可信度打分优先使用高可信度来源。人工审核流水线在正式发布前对系统输出进行抽样人工审核。4. 工程化与监控日志记录详细记录每次请求的查询、检索到的文档、生成的答案、耗时和模型用量。性能监控监控 API 响应时间、错误率、Token 消耗等指标。版本控制对知识库、模型版本、提示词模板进行版本管理便于回滚和对比实验。5. 合规与伦理数据版权仅使用你有权使用的数据和文档。用户告知当 AI 的回答基于特定数据源时应向用户明确说明。避免滥用防止系统被用于生成虚假信息或进行欺诈。设置内容安全过滤器。10. 总结与下一步“解决 AI 幻觉开卷考是当前最务实、最有效的工程化方案。” 它不追求创造一个全知全能的模型而是通过架构设计让模型学会“查阅资料”和“使用工具”。本文从概念到实践演示了如何通过 RAG 和智能体工具调用来构建这样一个系统。最值得尝试的第一步选择一个你熟悉的领域比如你的个人笔记、产品文档用 LangChain Chroma 本地模型如 Ollama搭建一个最小可用的知识库问答系统。亲自体验从“幻觉频出”到“有据可查”的转变。最容易踩的坑提示词太弱模型会忽略上下文。务必强化指令。检索质量差分块不合理或嵌入模型不合适导致找不到答案。多调试检索部分。工具描述模糊智能体无法理解何时该调用工具。把工具描述写得像给新手看的说明书。后续扩展方向多模态“开卷”不仅处理文本还能检索图片、表格中的信息来回答问题。复杂推理链让模型进行多步检索和推理解决更复杂的问题。自我修正让模型对初步答案进行事实核查调用搜索工具验证自己的回答。与 MCP 生态集成探索将你的数据源或工具封装成标准的 MCP 服务器使其能够被 Claude Desktop、Cursor 等更多智能体平台直接调用。将 AI 从“天才的臆想者”转变为“严谨的研究助理”开卷考是必经之路。这套方法论和工具链已经相当成熟投入实践的门槛并不高但其对应用可靠性的提升是立竿见影的。建议收藏本文在构建下一个需要准确性的 AI 功能时随时回来参考。
返回列表