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

资讯详情

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

大模型应用开发实战:从Prompt工程到RAG、Agent与MCP的完整指南

大模型应用开发实战:从Prompt工程到RAG、Agent与MCP的完整指南 最近在尝试将大模型应用到实际业务中从简单的对话到复杂的系统集成踩了不少坑。我发现很多开发者包括我自己都卡在几个关键环节如何让模型理解更复杂的指令Prompt、如何让模型访问外部知识RAG、如何让模型自主完成任务Agent以及如何让模型与各种工具安全交互MCP。这些技术点看似独立实则环环相扣构成了现代LLM应用的核心骨架。本文旨在为你提供一份从入门到项目实战的完整指南。无论你是刚接触大模型的新手还是希望将LLM能力整合到现有系统的开发者都能从中找到清晰的路径。我们将从最基础的Prompt工程讲起逐步深入到RAG、Agent和MCP最后以视觉大模型微调作为综合实战案例。学完本教程你将有能力独立设计和实现一个具备知识检索、自主决策和工具调用能力的智能应用。1. 大模型应用开发核心概念解析在深入代码之前我们必须先理清几个核心概念。它们不仅是技术术语更是构建LLM应用的基石。1.1 Prompt工程与大模型沟通的艺术Prompt提示词是你与大模型对话的“指令集”。一个糟糕的Prompt可能得到无关或错误的回答而一个精心设计的Prompt则能激发模型最强的能力。它不仅仅是“问问题”更是一种结构化的编程。Prompt的核心要素角色Role 定义模型在对话中扮演的身份如“你是一位资深Java架构师”。任务Task 清晰、具体地说明你希望模型完成什么。上下文Context 提供完成任务所需的相关背景信息。格式Format 指定输出结果的格式如JSON、Markdown、代码块等。示例Few-shot 提供少量输入-输出示例让模型快速理解你的意图。一个进阶的Prompt示例你是一位经验丰富的技术文档撰写助手。请根据以下用户需求生成一份API接口文档。 【用户需求】 - 接口功能用户登录 - 方法POST - 路径/api/v1/auth/login - 请求参数username字符串必填password字符串必填 - 成功响应{“code”: 200, “message”: “success”, “data”: {“token”: “xxx”}} - 失败响应{“code”: 401, “message”: “invalid credentials”} 【输出要求】 请以Markdown格式输出必须包含“接口说明”、“请求示例”、“响应示例”和“错误码”四个章节。这个Prompt明确了角色、任务、上下文和格式能极大提高模型输出质量。1.2 RAG为模型装上“外部记忆”大模型的“知识”固化在其训练数据中存在时效性差、可能包含错误幻觉且无法访问私有数据的局限。检索增强生成Retrieval-Augmented Generation, RAG就是为了解决这些问题。RAG的核心工作流程索引Indexing 将你的私有文档如PDF、Word、数据库进行切片转化为向量Embedding并存入向量数据库如ChromaDB, Pinecone, Milvus。检索Retrieval 当用户提问时将问题也转化为向量在向量数据库中查找与之最相关的文本片段Top-K。增强Augmentation 将检索到的相关片段作为上下文与原始问题一起组合成新的Prompt发送给大模型。生成Generation 大模型基于这个“增强后”的Prompt生成最终答案。简单说RAG让模型在回答前先“查阅资料”从而给出更准确、更相关的回答。它是构建企业知识库、智能客服等场景的关键技术。1.3 Agent让模型学会“使用工具”如果说RAG扩展了模型的“知识”那么Agent智能体则扩展了模型的“能力”。一个Agent是一个能够感知环境、进行决策、执行动作通常通过调用工具以实现目标的系统。Agent的核心组件规划Planning 将复杂任务分解为可执行的子任务序列。工具使用Tool Use 调用外部工具如计算器、搜索引擎、数据库、API等。记忆Memory 保存对话历史、工具执行结果等用于后续决策。行动Action 根据规划和当前状态决定下一步调用哪个工具或直接生成回答。例如当用户问“北京今天天气怎么样适合穿什么衣服”一个简单的Agent可能的工作流是1. 调用“天气查询工具”获取北京今日天气2. 根据温度、湿度等信息内部规划“穿衣建议”子任务3. 调用“穿衣推荐模型”或直接生成建议。1.4 MCP模型上下文协议MCPModel Context Protocol是一个新兴的开放协议它定义了大模型客户端与工具、数据源服务器之间标准化的通信方式。你可以把它理解为LLM世界的“USB协议”。MCP解决了什么问题在没有MCP之前每个Agent框架如LangChain, LlamaIndex都需要为每个工具编写特定的适配器代码工作繁重且不通用。MCP提供了一套标准工具发现 服务器向客户端宣告自己提供了哪些工具函数。标准化调用 客户端通过统一的格式请求调用工具。资源管理 服务器可以主动向客户端推送数据如实时日志、数据库表结构。这使得工具开发者只需实现一次MCP服务端就能被所有支持MCP的LLM应用如Claude Desktop, Cursor使用。它极大地降低了工具生态的构建成本。1.5 视觉大模型超越文本的理解视觉大模型如GPT-4V, LLaVA, Qwen-VL能够同时理解和生成文本与图像。其微调是指使用特定领域的图像-文本对数据对预训练好的视觉大模型进行额外训练使其在该领域表现更专业。微调的核心价值领域适应 让通用模型精通特定领域如医疗影像分析、工业质检。风格控制 生成符合特定风格或要求的图像描述。任务定制 完成通用模型不擅长的特定视觉任务如图表数据提取。2. 环境准备与工具选型工欲善其事必先利其器。我们将搭建一个兼顾学习和项目开发的环境。2.1 基础开发环境操作系统 Windows 10/11, macOS, 或 Linux (Ubuntu 20.04)。本文命令以Linux/macOS为例Windows用户可使用WSL或Git Bash。Python 版本 3.9 或 3.10。这是大多数AI库兼容性最好的版本。包管理 强烈建议使用conda或venv创建独立的Python虚拟环境避免包冲突。代码编辑器 VS Code 或 PyCharm安装Python和Jupyter插件。2.2 核心库安装我们将使用pip安装一系列核心库。请在你的虚拟环境中执行以下命令# 基础AI与数据处理库 pip install openai1.12.0 # OpenAI SDK (如果使用GPT系列模型) pip install langchain0.1.0 # LLM应用开发框架 pip install langchain-community0.0.10 # LangChain社区集成 pip install langchain-openai0.0.5 # LangChain的OpenAI集成 pip install chromadb0.4.22 # 轻量级向量数据库 (用于RAG) pip install sentence-transformers2.2.2 # 用于生成文本向量的嵌入模型 pip install pypdf3.17.4 # 用于解析PDF文档 pip install python-dotenv1.0.0 # 管理环境变量 # 可选如果你使用其他模型或框架 # pip install anthropic # 用于Claude模型 # pip install transformers torch # 用于本地运行或微调Hugging Face模型 # pip install llama-index # 另一个流行的LLM应用框架版本说明 AI领域库更新频繁以上版本在撰写时稳定且相互兼容。如果你的项目遇到问题可尝试固定这些版本。生产环境请务必进行充分测试。2.3 API密钥与模型访问大部分高级模型如GPT-4, Claude 3需要通过API访问。你需要准备相应的API密钥。获取API KeyOpenAI 访问 platform.openai.com 注册并创建API Key。其他平台 如智谱AI、百度文心、通义千问等需前往各自官网申请。安全存储 切勿将API Key硬编码在代码中推荐使用.env文件。在项目根目录创建.env文件。在文件中添加OPENAI_API_KEY你的sk-xxx密钥在代码中使用python-dotenv加载。# config.py 或代码开头 from dotenv import load_dotenv import os load_dotenv() # 加载 .env 文件中的环境变量 openai_api_key os.getenv(OPENAI_API_KEY) if not openai_api_key: raise ValueError(请在 .env 文件中设置 OPENAI_API_KEY)3. Prompt工程实战从零编写高效提示词让我们通过一个完整的例子学习如何系统化地构建和优化Prompt。3.1 基础Prompt构造我们以“代码生成”任务为例看看Prompt如何一步步进化。第零版模糊请求效果差prompt “写一个排序函数。”问题 模型不知道用什么语言、排什么序、函数签名是什么输出随机。第一版明确基础要求prompt “”” 使用Python编写一个函数用于对整数列表进行快速排序。 函数名称为 quick_sort输入为一个整数列表 arr返回排序后的新列表。 “””改进 明确了语言、函数名、输入输出。但可能忽略边缘情况空列表、非整数。第二版增加角色和细节约束prompt “”” 你是一位注重代码质量和健壮性的Python专家。请完成以下任务 任务实现一个快速排序函数。 要求 1. 函数签名def quick_sort(arr: List[int]) - List[int]: 2. 必须处理输入为空列表或None的情况直接返回原输入。 3. 使用递归实现并添加清晰的注释说明分区(partition)过程。 4. 代码风格需符合PEP 8规范。 请只输出最终的Python代码不需要任何解释。 “””改进 定义了角色提出了具体、可验证的要求异常处理、注释、风格并指定了输出格式。3.2 使用LangChain规范化PromptTemplate在项目中我们通常需要复用和动态生成Prompt。LangChain的PromptTemplate非常有用。from langchain.prompts import PromptTemplate # 1. 定义一个模板 code_review_template PromptTemplate( input_variables[“language”, “code_snippet”, “concern”], template“”” 你是一位资深的{language}开发工程师。请审查以下代码片段{code_snippet}审查者主要关心{concern} 请从代码风格、性能、潜在bug、安全性四个方面给出具体的审查意见和改进建议。 你的输出请遵循以下格式 ## 审查总结 [一句话总结] ## 详细意见 1. **代码风格**: ... 2. **性能**: ... 3. **潜在Bug**: ... 4. **安全性**: ... ## 改进后的代码片段可选[如果需要在这里给出修改后的代码]“”” ) # 2. 使用模板生成具体的Prompt prompt code_review_template.format( language“Python”, code_snippet“def add(a, b):\n return a b”, concern“函数缺少类型注解和错误处理” ) print(prompt)通过模板我们可以将变量部分抽离便于管理和批量生成使Prompt工程更加模块化。3.3 高级技巧思维链与少样本学习思维链Chain-of-Thought, CoT 在Prompt中要求模型“逐步推理”能显著提升复杂逻辑问题的准确性。示例 “请一步步计算一个篮子里有12个苹果小明拿走了1/3小红又放入了拿走数量的一半。现在篮子里有多少苹果请先列出计算步骤。”少样本学习Few-Shot Learning 在Prompt中提供几个输入-输出的例子让模型通过类比来学习任务。prompt “”” 将中文情感词转换为英文情感词对。 示例1 输入 高兴 输出 happy 示例2 输入 悲伤 输出 sad 示例3 输入 愤怒 输出 angry 现在请转换 输入 惊讶 输出 “””4. RAG系统实战构建你的第一个智能知识库我们将构建一个基于本地PDF文档的问答系统。流程分为文档加载、文本分割、向量化、存储、检索和生成。4.1 项目结构与文档准备创建如下目录结构my_rag_project/ ├── data/ # 存放原始文档 │ └── your_document.pdf ├── vector_db/ # 向量数据库存储目录自动创建 ├── app.py # 主应用代码 ├── requirements.txt └── .env将你的PDF文档放入data/文件夹。4.2 实现完整的RAG流水线以下是app.py的完整代码包含了从文档处理到问答的所有步骤。# app.py import os from dotenv import load_dotenv from langchain_community.document_loaders import PyPDFLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_community.vectorstores import Chroma from langchain.chains import RetrievalQA from langchain_openai import ChatOpenAI # 1. 加载环境变量和API Key load_dotenv() openai_api_key os.getenv(“OPENAI_API_KEY”) # 2. 加载并分割文档 def load_and_split_documents(pdf_path): “””加载PDF并分割成小块””” loader PyPDFLoader(pdf_path) documents loader.load() # 使用递归字符分割器尽量保证语义完整性 text_splitter RecursiveCharacterTextSplitter( chunk_size500, # 每个块的最大字符数 chunk_overlap50, # 块之间的重叠字符数保持上下文 separators[“\n\n”, “\n”, “。”, “.”, “,”, “ “, “”] # 分割符优先级 ) splits text_splitter.split_documents(documents) print(f“已将文档分割成 {len(splits)} 个文本块。”) return splits # 3. 创建向量存储嵌入模型 向量数据库 def create_vector_store(splits, persist_directory“./vector_db”): “””将文本块转换为向量并存储到ChromaDB””” # 使用本地嵌入模型无需API调用适合离线或低成本场景 embeddings HuggingFaceEmbeddings( model_name“sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2” ) # 创建向量数据库并持久化到本地磁盘 vectordb Chroma.from_documents( documentssplits, embeddingembeddings, persist_directorypersist_directory ) vectordb.persist() # 保存到磁盘 print(f“向量数据库已创建并保存至 {persist_directory}”) return vectordb # 4. 构建RAG问答链 def create_rag_chain(vectordb): “””将检索器与大模型结合构建问答链””” # 初始化大模型这里使用GPT-3.5-turbo可根据需要更换 llm ChatOpenAI( model“gpt-3.5-turbo”, temperature0.1, # 较低的温度使输出更确定、更专注于检索到的内容 api_keyopenai_api_key ) # 创建检索器从向量库中获取最相关的2个文本块 retriever vectordb.as_retriever(search_kwargs{“k”: 2}) # 创建检索问答链 qa_chain RetrievalQA.from_chain_type( llmllm, chain_type“stuff”, # “stuff”将检索到的所有文档内容塞入Prompt简单有效 retrieverretriever, return_source_documentsTrue, # 返回源文档便于追溯 verboseTrue # 打印详细日志方便调试 ) return qa_chain # 5. 主函数首次运行创建索引后续直接加载 def main(): pdf_path “./data/your_document.pdf” # 替换为你的PDF路径 persist_dir “./vector_db” # 检查是否已存在向量数据库 if not os.path.exists(persist_dir) or not os.listdir(persist_dir): print(“未找到向量数据库开始创建…”) # 加载并分割文档 splits load_and_split_documents(pdf_path) # 创建向量存储 vectordb create_vector_store(splits, persist_dir) else: print(“加载已存在的向量数据库…”) embeddings HuggingFaceEmbeddings( model_name“sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2” ) vectordb Chroma(persist_directorypersist_dir, embedding_functionembeddings) # 创建问答链 qa_chain create_rag_chain(vectordb) # 开始交互式问答 print(“\n 智能知识库问答系统已就绪 ) print(“输入 ‘quit’ 或 ‘exit’ 退出程序。”) while True: query input(“\n请输入你的问题 “) if query.lower() in [“quit”, “exit”]: break if not query.strip(): continue # 执行查询 try: result qa_chain.invoke({“query”: query}) print(“\n【回答】:”, result[“result”]) print(“\n【参考来源】:”) for i, doc in enumerate(result[“source_documents”], 1): print(f” {i}. …{doc.page_content[:150]}…“) # 打印来源片段前150字符 except Exception as e: print(f“查询过程中出现错误 {e}”) if __name__ “__main__”: main()4.3 运行与测试将你的PDF文档如技术手册.pdf放入./data/目录并修改代码中pdf_path的变量值。在项目根目录下执行python app.py首次运行会进行文档分割和向量化稍等片刻。看到提示后即可输入关于文档内容的问题。例如如果文档是关于Docker的你可以问“Dockerfile中的FROM指令有什么用”系统会先在你的文档中查找相关信息再结合大模型的能力生成答案并附上答案的来源片段增强了可信度。5. Agent开发实战打造能调用工具的智能体我们将使用LangChain的Agent框架创建一个能查询天气和进行简单计算的智能体。5.1 定义工具Tools工具是Agent能力的延伸。我们先定义两个简单的工具。# agent_tools.py from langchain.tools import tool import requests import json tool def get_weather(city: str) - str: “””获取指定城市的当前天气信息。输入应为城市名如‘北京’。””” # 注意这里使用了一个模拟的天气API实际应用中请替换为真实的API如和风天气、OpenWeatherMap # 并且务必遵守相关API的使用条款处理鉴权和错误。 try: # 模拟API响应 mock_data { “北京”: {“city”: “北京”, “weather”: “晴”, “temperature”: “22°C”, “humidity”: “40%”}, “上海”: {“city”: “上海”, “weather”: “多云”, “temperature”: “25°C”, “humidity”: “65%”}, } if city in mock_data: return json.dumps(mock_data[city], ensure_asciiFalse) else: return json.dumps({“error”: f“未找到城市{city}的天气信息”}, ensure_asciiFalse) except Exception as e: return json.dumps({“error”: f“查询天气失败{str(e)}”}, ensure_asciiFalse) tool def calculate(expression: str) - str: “””计算一个数学表达式的结果。输入应为字符串形式的表达式如‘(3 5) * 2’。””” # 警告直接使用eval有安全风险仅用于示例。生产环境应使用更安全的计算库如numexpr或严格限制输入。 try: # 极其简单的安全过滤生产环境需要更严格的检查 allowed_chars set(“0123456789-*/(). “) if not all(c in allowed_chars for c in expression): return “错误表达式中包含非法字符。” result eval(expression) return str(result) except Exception as e: return f“计算错误{e}” # 工具列表 tools [get_weather, calculate]5.2 创建并运行Agent# agent_main.py import os from dotenv import load_dotenv from langchain_openai import ChatOpenAI from langchain.agents import initialize_agent, AgentType from langchain.memory import ConversationBufferMemory from agent_tools import tools # 导入上面定义的工具 load_dotenv() def main(): # 1. 初始化大模型 llm ChatOpenAI( model“gpt-3.5-turbo”, temperature0, api_keyos.getenv(“OPENAI_API_KEY”) ) # 2. 初始化记忆让Agent能记住对话历史 memory ConversationBufferMemory(memory_key“chat_history”, return_messagesTrue) # 3. 初始化Agent # 使用OPENAI_FUNCTIONS类型的Agent它擅长理解工具描述并决定何时调用。 agent initialize_agent( tools, llm, agentAgentType.OPENAI_FUNCTIONS, memorymemory, verboseTrue, # 打印详细的思考过程便于调试和学习 handle_parsing_errorsTrue # 优雅处理解析错误 ) # 4. 运行Agent print(“智能助手已启动。你可以让我查询天气或做数学计算。输入‘退出’结束。”) while True: user_input input(“\n你 “) if user_input.lower() in [“退出”, “exit”, “quit”]: print(“再见”) break try: response agent.run(user_input) print(f“助手 {response}”) except Exception as e: print(f“抱歉处理时出现错误{e}”) if __name__ “__main__”: main()5.3 运行示例运行python agent_main.py然后尝试以下对话你 “北京今天天气怎么样”助手思考后调用get_weather工具 “北京今天天气晴气温22°C湿度40%。”你 “那上海呢另外帮我算一下(2218)/2是多少。”助手思考后依次调用get_weather和calculate工具 “上海今天多云25°C湿度65%。你问的计算结果是20.0。”通过verboseTrue你可以在控制台看到Agent的完整思考链Reasoning Chain它是如何分析问题、选择工具、解析工具结果的。这是理解和调试Agent行为的关键。6. MCP初探标准化工具集成MCP协议目前主要由Anthropic推动用于Claude Desktop等客户端。其核心思想是工具提供者实现一个标准的MCP服务器任何兼容MCP的客户端都能自动发现并使用这些工具。6.1 MCP核心概念MCP Server 工具提供方。它向客户端宣告自己有哪些工具函数并在客户端调用时执行具体逻辑。MCP Client 工具使用方如Claude Desktop或我们自己的LLM应用。它发现服务器提供的工具并在需要时通过标准格式调用。Stdio Server 一种通过标准输入/输出stdio与客户端通信的服务器简单易用。6.2 一个简单的MCP服务器示例概念性以下是一个使用Pythonmcp库创建简单MCP服务器的概念性代码展示了其基本结构。# mcp_server_demo.py (概念示例) # 注意实际开发请参考官方MCP SDK (https://github.com/modelcontextprotocol/servers) import asyncio from mcp import Server, StdioServerTransport import json # 1. 创建MCP服务器实例 server Server(“my-tool-server”) # 2. 向服务器注册工具类似之前的tool装饰器 server.tool() async def search_web(query: str) - str: “””在互联网上搜索信息。请提供清晰的关键词。””” # 这里模拟搜索实际应调用搜索引擎API await asyncio.sleep(0.5) # 模拟网络延迟 return json.dumps({ “query”: query, “results”: [ {“title”: f“关于{query}的百科”, “url”: “https://example.com/1”}, {“title”: f“{query}的最新新闻”, “url”: “https://example.com/2”}, ] }, ensure_asciiFalse) server.tool() async def get_current_time(timezone: str “Asia/Shanghai”) - str: “””获取指定时区的当前时间。””” from datetime import datetime import pytz try: tz pytz.timezone(timezone) now datetime.now(tz) return now.strftime(“%Y-%m-%d %H:%M:%S %Z”) except pytz.exceptions.UnknownTimeZoneError: return f“错误未知时区 {timezone}” # 3. 定义服务器资源可选用于向客户端推送数据 server.resource(“config://app”) async def get_app_config() - str: “””获取应用程序的配置信息。””” return json.dumps({“version”: “1.0.0”, “author”: “MyTeam”}) # 4. 启动服务器使用Stdio传输 async def main(): async with StdioServerTransport() as transport: await server.run(transport) if __name__ “__main__”: asyncio.run(main())运行此服务器后支持MCP的客户端如配置好的Claude Desktop就能自动发现search_web和get_current_time这两个工具并在对话中调用它们。MCP的价值在于解耦工具开发者和LLM应用开发者无需为每个组合编写适配代码。7. 视觉大模型微调实战以LLaVA为例微调视觉大模型需要较强的计算资源GPU以下流程阐述了核心步骤和代码框架。7.1 环境与数据准备硬件 至少需要一张显存 16GB 的GPU如RTX 4090, A100。库安装pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 # 根据CUDA版本调整 pip install transformers accelerate peft datasets bitsandbytes pip install pillow数据准备 你需要一个“图像-文本对”数据集。例如自定义一个描述商品图片的数据集格式可以是JSONL{“image”: “path/to/image1.jpg”, “conversations”: [{“from”: “human”, “value”: “描述这张图片。”}, {“from”: “gpt”, “value”: “这是一件红色的连衣裙带有白色花纹款式修身。”}]} {“image”: “path/to/image2.jpg”, “conversations”: [{“from”: “human”, “value”: “图片里有什么”}, {“from”: “gpt”, “value”: “一个木制餐桌上摆放着一杯咖啡和一台笔记本电脑。”}]}7.2 微调脚本核心步骤以下是基于Hugging Facetransformers和peft参数高效微调库的微调核心代码框架。# finetune_llava.py (核心框架) import torch from transformers import LlavaForConditionalGeneration, LlavaProcessor, TrainingArguments from peft import LoraConfig, get_peft_model from datasets import load_dataset from trl import SFTTrainer import os def main(): # 1. 加载预训练模型和处理器 model_name “llava-hf/llava-1.5-7b-hf” # 选择一个LLaVA模型 processor LlavaProcessor.from_pretrained(model_name) model LlavaForConditionalGeneration.from_pretrained( model_name, torch_dtypetorch.float16, device_map“auto” ) # 2. 使用LoRA进行参数高效微调 lora_config LoraConfig( r16, # LoRA秩 lora_alpha32, target_modules[“q_proj”, “v_proj”], # 对注意力层的查询和值投影矩阵进行微调 lora_dropout0.1, bias“none”, task_type“CAUSAL_LM” ) model get_peft_model(model, lora_config) model.print_trainable_parameters() # 查看可训练参数量通常只有原模型的1% # 3. 加载和预处理数据集 dataset load_dataset(“json”, data_files{“train”: “your_dataset.jsonl”}) def preprocess_function(examples): # 预处理函数将图像路径加载为像素值并格式化对话 images [Image.open(img_path).convert(“RGB”) for img_path in examples[“image”]] texts [] for conv in examples[“conversations”]: # 将对话格式化为LLaVA要求的提示格式例如“USER: image\n{human_input} ASSISTANT:” # 这里需要根据具体模型的数据格式要求进行调整 prompt processor.tokenizer.apply_chat_template(conv, tokenizeFalse) texts.append(prompt) # 由processor统一处理图像和文本 inputs processor(texttexts, imagesimages, paddingTrue, return_tensors“pt”) inputs[“labels”] inputs[“input_ids”].clone() # 对于因果语言模型标签通常是输入ID的移位 return inputs tokenized_dataset dataset.map(preprocess_function, batchedTrue) # 4. 配置训练参数 training_args TrainingArguments( output_dir“./llava-finetuned”, num_train_epochs3, per_device_train_batch_size4, # 根据GPU显存调整 gradient_accumulation_steps4, warmup_steps100, logging_steps10, save_steps200, learning_rate2e-4, fp16True, # 混合精度训练节省显存 remove_unused_columnsFalse, push_to_hubFalse, # 可设置为True上传到Hugging Face Hub ) # 5. 创建Trainer并开始训练 trainer SFTTrainer( modelmodel, argstraining_args, train_datasettokenized_dataset[“train”], processing_classprocessor, max_seq_length2048, ) trainer.train() # 6. 保存微调后的模型 model.save_pretrained(“./my_finetuned_llava”) processor.save_pretrained(“./my_finetuned_llava”) print(“模型微调完成并已保存”) if __name__ “__main__”: main()7.3 微调后推理使用微调后的模型进行预测。# inference.py from PIL import Image from transformers import LlavaForConditionalGeneration, LlavaProcessor import torch # 加载微调后的模型和处理器 model_path “./my_finetuned_llava” processor LlavaProcessor.from_pretrained(model_path) model LlavaForConditionalGeneration.from_pretrained(model_path, device_map“auto”) # 准备输入 image Image.open(“test_image.jpg”).convert(“RGB”) prompt “USER: image\n请描述这张图片。\nASSISTANT:” # 格式需与训练时一致 inputs processor(textprompt, imagesimage, return_tensors“pt”).to(model.device) # 生成 with torch.no_grad(): output_ids model.generate(**inputs, max_new_tokens100) response processor.batch_decode(output_ids, skip_special_tokensTrue)[0] print(“模型回答”, response)8. 常见问题与排查思路在开发LLM应用过程中你会遇到各种问题。下表汇总了高频问题及其解决方法。问题现象可能原因排查思路与解决方案API调用失败提示无效密钥或超时1. API Key错误或过期。2. 网络连接问题。3. 账户余额不足或速率超限。1. 检查.env文件中的KEY是否正确或在平台重置KEY。2. 检查网络代理设置如需。3. 登录平台控制台检查额度和用量。RAG系统回答与文档无关幻觉1. 检索到的文本块不相关。2. 检索数量k值太少或太多。3. Prompt未强制模型基于上下文回答。1. 检查嵌入模型是否合适尝试更换text-embedding-ada-002或别的句子向量模型。2. 调整search_kwargs{“k”: n}尝试3-5。3. 在Prompt中明确加入“请严格依据以下上下文回答如果上下文未包含相关信息请说‘根据已知信息无法回答’。”Agent不调用工具或调用错误工具1. 工具描述不够清晰。2. 大模型如GPT-3.5能力不足。3. Agent类型选择不当。1. 完善工具的description和参数args_schema使其描述精准。2. 升级到更强的模型如GPT-4。3. 尝试不同的AgentType如ZERO_SHOT_REACT_DESCRIPTION,OPENAI_FUNCTIONS。向量数据库检索速度慢1. 文本块chunk太大或太多。2. 未使用索引或索引类型不当。3. 硬件资源不足。1. 优化chunk_size(如500-1000) 和chunk_overlap(50-100)。2. 对于大规模数据考虑使用带HNSW索引的向量库如Milvus, Weaviate。3. 确保有足够内存。微调视觉模型时GPU显存溢出1. 批次大小batch_size过大。2. 图像分辨率过高。3. 未使用梯度累积或混合精度训练。1. 减小per_device_train_batch_size。2. 在预处理中调整图像尺寸如224x224。3. 启用gradient_accumulation_steps和fp16True。使用bitsandbytes进行4/8-bit量化。提示词过长导致错误1. 模型有上下文长度限制如4K, 16K, 128K。2. RAG检索内容过多。1. 检查模型的最大上下文长度精简Prompt。2. 对长文档进行摘要或使用“Map-Reduce”等链式方法。ModuleNotFoundError或导入错误1. 依赖包未安装或版本冲突。2. 虚拟环境未激活。1. 使用pip list检查包是否存在。用requirements.txt严格管理版本。2. 确认终端处于正确的conda/venv环境中。9. 最佳实践与工程建议将LLM应用从原型推向生产需要关注以下工程化细节。9.1 提示词工程化模板化管理 不要将Prompt硬编码在业务逻辑中。使用配置文件如YAML、JSON或数据库存储和管理Prompt模板便于A/B测试和迭代。版本控制 对Prompt模板进行版本控制记录每次修改的内容和效果便于回滚和优化。结构化输出 尽可能要求模型输出结构化数据如JSON便于后续程序处理。可以使用LangChain的StructuredOutputParser或Pydantic来定义输出模式。9.2 RAG系统优化分块策略 根据文档类型选择分块方法。技术文档可用按标题分割普通文本用递归字符分割代码文件可按函数/类分割。多路检索与重排 不要只依赖向量检索。可以结合关键词检索BM25、元数据过滤如日期、作者等多种方式然后对结果进行重排Rerank提升召回率和准确率。来源追溯与评估 务必保留并展示答案的来源片段source_documents这不仅增加可信度也是评估RAG效果、发现检索问题的关键。缓存机制 对频繁查询的问题或嵌入向量进行缓存可以显著降低延迟和API成本。9.3 Agent设计原则工具设计原子化 每个工具应只做一件事并做好。避免设计功能过于复杂、耦合度高的“巨无霸”工具。完善的错误处理 工具内部必须有健壮的错误处理并向Agent返回结构化的错误信息让Agent能理解失败原因并决定下一步如重试、换工具、向用户求助。限制与超时 为Agent的执行步骤Step和总运行时间设置上限防止陷入死循环或长时间无响应。可观察性 记录Agent完整的思考链Chain-of-Thought和工具调用历史这是调试复杂Agent问题的唯一有效途径。9.4 安全与合规输入净化 对所有用户输入和来自外部的检索内容进行清洗和过滤防止Prompt注入攻击。权限最小化 Agent工具应遵循最小权限原则。例如一个文件读取工具不应有删除权限一个数据库查询工具应使用只读账户。内容审核 在最终答案返回给用户前可增加一层基于规则或模型的内容安全审核过滤不当内容。数据隐私 明确告知用户数据如何被使用、存储。涉及敏感数据的RAG考虑使用本地化模型和向量数据库。9.5 性能与成本异步处理 对于I/O密集型操作如调用多个API、检索多个向量库使用异步asyncio来提升吞吐量。模型选型 根据任务复杂度选择合适的模型。简单的分类任务可能用小模型如gpt-3.5-turbo就够了复杂的推理则需要大模型如GPT-4。混合使用可以优化成本。监控与告警 监控API调用延迟、失败率、Token消耗和费用。设置告警阈值及时发现异常。从理解Prompt的构造技巧到搭建一个能检索私有知识的RAG系统再到创建一个能自主调用工具的智能Agent最后探索了标准化工具协议MCP和视觉大模型微调。每一步都试图将概念与实践结合提供可运行的代码。LLM应用开发是一个快速迭代的领域核心在于理解这些基础组件的原理和交互方式然后根据实际业务需求进行组合与创新。建议你从最小的可运行示例开始亲手复现每一个步骤然后尝试修改参数、更换数据、增加功能在实验中加深理解。
返回列表