从提示词工程到ReAct智能体:大模型应用开发实战指南
在实际项目里引入 AI 大模型很多开发者会直接陷入两个极端要么觉得 API 调用几行代码就能搞定没什么可学的要么被层出不穷的框架、概念和“幻觉”问题吓退感觉无从下手。真正阻碍项目落地的往往不是模型本身而是如何把模型能力稳定、可靠、低成本地集成到现有业务流中并让模型“听懂”你的意图。这篇文章面向已经具备基础编程能力希望将大模型能力应用到实际项目中的开发者。我们将从最核心的“提示词工程”和“智能体Agent”原理入手逐步构建一个可运行的 ReAct 模式智能体项目。整个过程会涉及多个主流框架的选型与集成并重点解释每一步背后的设计逻辑和常见陷阱目标是让你不仅能跑通 Demo更能理解在真实生产环境中如何设计、调试和部署一个 AI 智能体。1. 理解大模型应用开发的核心从提示词到智能体在开始写代码之前必须厘清几个核心概念及其关系。很多项目失败是因为开发者混淆了不同层次的技术栈。1.1 大模型基础能力与边界当前主流的大语言模型如 GPT、Claude、国内各大厂商的模型本质上是一个基于海量文本训练的概率预测器。它接收一段文本提示词并基于统计规律生成最可能的下文。这意味着模型没有真正的“理解”它不进行逻辑推理而是进行模式匹配。你给它的提示词就是在激活它训练数据中相关的模式。能力是内嵌的不是外挂的模型的知识截止于其训练数据。它无法直接访问训练数据之外的信息如实时数据、你的私有数据库除非你通过提示词或外部工具提供。输出具有随机性即使输入相同每次生成也可能略有不同这是由采样策略如 temperature 参数决定的。因此大模型应用开发的第一原则是不要期望模型“天生”知道一切而是要设计好“输入”和“上下文”引导它产生你期望的“输出”。1.2 提示词工程与模型沟通的“编程语言”如果把调用大模型 API 看作一次函数调用那么提示词Prompt就是传递给这个函数的“参数”。但这是一个极其灵活且强大的参数。提示词工程的核心目标是构建一段能清晰、无歧义地传达任务指令和背景信息的文本。一个结构化的提示词通常包含以下部分角色Role设定模型的角色如“你是一个资深的 Java 架构师”。任务Task清晰、具体地描述需要模型完成的工作。上下文Context提供完成任务所需的所有背景信息如数据、规则、格式要求。输出格式Output Format明确指定模型返回数据的结构如 JSON、Markdown、纯文本段落。你是一个智能客服助手。请根据以下用户问题和知识库片段生成一段友好、专业的回复。 【用户问题】 我的订单号是 20240315001为什么还没有发货 【知识库片段】 - 订单状态“待发货”表示商品正在仓库拣货打包。 - 订单号 20240315001 当前状态为“待发货”预计今天下午 18:00 前处理完毕。 - 发货后系统会自动发送短信通知。 【输出要求】 请用中文回复先安抚用户情绪然后告知订单状态和预计时间最后提醒用户注意查收短信。不要提及“知识库”这个词。为什么需要提示词工程因为模型的输出质量与输入提示的质量强相关。模糊的提示会导致无关、错误或格式混乱的回答即所谓的“幻觉”Hallucination。通过精心设计提示词可以显著抑制幻觉提升输出的准确性和可用性。1.3 智能体Agent赋予模型“行动”的能力如果提示词是与模型沟通的语言那么智能体就是让模型具备“感知-思考-行动”循环的大脑。一个基础的智能体框架通常包含以下核心组件规划Planning分析用户目标将其分解为可执行的子任务或步骤。工具Tools智能体可以调用的外部能力如计算器、搜索引擎、数据库查询、代码执行器。记忆Memory存储对话历史、工具执行结果为后续决策提供上下文。执行Action根据规划选择并调用合适的工具。观察Observation获取工具执行的结果。智能体与大模型的关系大模型是智能体的“核心决策引擎”。智能体框架负责组织对话、管理工具、维护状态并在关键时刻将当前状态规划、记忆、观察组织成提示词调用大模型来做出“下一步做什么”的决策。目前主流的两类智能体范式是ReAct和Plan-and-Execute。ReAct (Reason Act)模型在每一步都进行“思考”Reason然后决定“行动”Act。这是一个紧密交织的循环模型可以基于上一步行动的观察结果动态调整后续计划。灵活性高适合复杂、探索性任务。Plan-and-Execute模型先制定一个完整的计划Plan然后严格按计划执行Execute。计划阶段不涉及具体工具调用。结构清晰适合步骤明确、可预测的任务。本文将重点实现ReAct模式因为它更能体现智能体与环境和工具交互的动态特性。2. 环境准备与框架选型在开始编码前需要搭建开发环境并选择适合的框架。框架能帮助我们处理智能体循环、工具集成、状态管理等通用问题让我们更专注于业务逻辑。2.1 环境与依赖你需要准备Python 3.9目前大多数 AI 框架的首选语言。pipPython 包管理工具。一个可用的 AI 大模型 API例如 OpenAI GPT、智谱 AI、DeepSeek 等。本文示例将使用 OpenAI 兼容的 API包括许多国内厂商提供的兼容接口你需要准备相应的 API Key。首先创建一个干净的虚拟环境并安装基础依赖# 创建并激活虚拟环境以 conda 为例 conda create -n ai-agent python3.10 conda activate ai-agent # 安装核心框架。这里我们选择 LangChain它是一个功能全面、生态丰富的框架。 pip install langchain langchain-community langchain-openai # 安装用于网页内容提取的工具库后续示例会用到 pip install beautifulsoup4 requests2.2 框架选型分析市面上框架众多选型需结合项目需求。以下是一个快速对比框架名称核心特点适用场景学习曲线LangChain功能模块化生态丰富社区活跃文档齐全。提供了从提示词模板、链Chain到智能体Agent的全套工具。快速原型开发、研究、教育以及需要集成多种工具和数据源的复杂应用。中等。概念较多但结构清晰。LlamaIndex专注于数据索引和检索在构建 RAG检索增强生成应用方面非常强大。需要将私有数据文档、数据库与大模型结合的应用。中等。与 LangChain 可结合使用。Semantic Kernel微软出品强调“规划”和“插件”概念与 .NET 生态结合紧密。.NET 技术栈的项目或强调规划式智能体的场景。中等。AutoGen专注于多智能体对话和协作由微软研究院开发。需要多个智能体相互对话、协作完成复杂任务的场景。较陡峭。对于入门和大多数实战项目LangChain是一个平衡性很好的选择。它抽象了通用模式同时保持了足够的灵活性。本文后续将基于 LangChain 进行演示。注意框架版本迭代很快本文基于 LangChain 0.1.x 版本编写。安装时请注意版本兼容性遇到 API 变更可查阅官方文档。3. 构建第一个 ReAct 智能体联网查询助手我们将构建一个能理解用户问题、自主决定是否联网搜索、并整合信息给出回答的智能体。这个例子涵盖了 ReAct 的核心循环思考、行动、观察。3.1 项目结构与初始化创建项目目录如下react_agent_demo/ ├── config.py # 配置文件存放 API Key 等敏感信息 ├── tools/ # 自定义工具目录 │ └── web_search_tool.py ├── agent.py # 智能体核心逻辑 └── main.py # 程序入口首先在config.py中配置你的模型# config.py import os from dotenv import load_dotenv load_dotenv() # 从 .env 文件加载环境变量 # 配置模型。这里以 OpenAI 兼容接口为例。 # 如果你使用智谱、月之暗面等通常只需修改 base_url 和 api_key。 MODEL_CONFIG { base_url: https://api.openai.com/v1, # 或替换为国内厂商的 endpoint api_key: os.getenv(OPENAI_API_KEY), # 建议从环境变量读取 model: gpt-3.5-turbo, # 或 gpt-4, claude-3-haiku 等 temperature: 0.1, # 降低随机性使输出更稳定 }在项目根目录创建.env文件切勿提交到版本控制OPENAI_API_KEYyour_api_key_here3.2 创建自定义工具网页搜索智能体的能力来源于工具。我们创建一个简单的网页搜索工具它接收一个查询词返回搜索到的网页摘要。# tools/web_search_tool.py import requests from bs4 import BeautifulSoup from langchain.tools import BaseTool from pydantic import Field class WebSearchTool(BaseTool): 一个简单的网页搜索工具。给定一个查询词返回相关网页的摘要。 name: str web_search description: str ( 当用户的问题涉及最新事件、实时信息或你不知道的知识时使用此工具进行搜索。 输入应该是一个明确的搜索查询词。 ) max_results: int Field(default3, description返回的最大结果数) def _run(self, query: str) - str: 执行工具的主逻辑。 # 注意这是一个模拟的简化搜索。生产环境应使用 SerpAPI、Google Search API 等。 print(f[工具调用] 正在搜索: {query}) # 这里我们模拟返回一些固定结果。实际项目中请替换为真正的搜索API调用。 # 例如使用 requests 调用 DuckDuckGo 或 Bing 的简易接口。 simulated_results [ f关于 {query} 的搜索结果1: 这是根据网络信息模拟的摘要内容A。, f关于 {query} 的搜索结果2: 这是根据网络信息模拟的摘要内容B。, f关于 {query} 的搜索结果3: 这是根据网络信息模拟的摘要内容C。, ] return \n---\n.join(simulated_results[:self.max_results]) async def _arun(self, query: str): 异步版本可选。 raise NotImplementedError(此工具不支持异步调用)关键点解释BaseTool是 LangChain 中所有工具的基类。name和description至关重要。智能体会根据description来决定在什么情况下使用这个工具。描述必须清晰、具体。_run方法是工具的核心包含实际的业务逻辑。这里我们做了简化真实项目需要集成搜索引擎 API。3.3 组装 ReAct 智能体现在我们将模型、工具和 ReAct 逻辑组装起来。# agent.py from langchain.agents import AgentExecutor, create_react_agent from langchain.prompts import PromptTemplate from langchain_openai import ChatOpenAI from tools.web_search_tool import WebSearchTool from config import MODEL_CONFIG def create_react_agent_executor(): 创建并返回一个配置好的 ReAct 智能体执行器。 # 1. 初始化大语言模型 llm ChatOpenAI( base_urlMODEL_CONFIG[base_url], api_keyMODEL_CONFIG[api_key], modelMODEL_CONFIG[model], temperatureMODEL_CONFIG[temperature], ) # 2. 准备工具列表 tools [WebSearchTool()] # 3. 定义 ReAct 提示词模板 # 这是 LangChain 内置的 ReAct 模板它指导模型进行“思考-行动-观察”的循环。 react_prompt PromptTemplate.from_template( 请回答以下问题。你可以使用以下工具 {tools} 请严格按照以下格式回应 思考你需要先思考当前情况决定是否需要使用工具以及使用哪个工具。 行动你选择的工具名称必须是以下之一[{tool_names}] 行动输入你选择工具的输入内容 观察工具返回的结果 ... (这个 思考/行动/行动输入/观察 循环可以重复多次) 当你确信已经获得足够信息来回答问题时或者不需要使用工具时请使用以下格式 思考我已经获得足够信息可以给出最终答案。 最终答案你的最终回答应清晰、完整。 开始 问题{input} {agent_scratchpad} ) # 4. 创建智能体 agent create_react_agent(llmllm, toolstools, promptreact_prompt) # 5. 创建智能体执行器它负责运行循环、处理解析、管理中间状态。 agent_executor AgentExecutor( agentagent, toolstools, verboseTrue, # 设为 True 可以看到详细的思考过程调试时非常有用 handle_parsing_errorsTrue, # 处理模型输出格式解析错误 max_iterations5, # 限制最大循环次数防止无限循环 early_stopping_methodgenerate, # 当模型输出“最终答案”时停止 ) return agent_executor代码解析ChatOpenAILangChain 对 OpenAI 兼容接口的封装。通过base_url可以轻松切换不同厂商的模型。tools将我们自定义的WebSearchTool实例放入列表。一个智能体可以拥有多个工具。react_prompt这是 ReAct 模式的核心。它明确规定了模型的输出格式思考/行动/观察引导模型进行结构化推理。{agent_scratchpad}是一个占位符执行器会自动将之前的循环历史填充进去。create_react_agentLangChain 提供的工厂函数将模型、工具和提示词模板绑定在一起形成一个智能体对象。AgentExecutor智能体的“发动机”。它驱动整个循环将当前状态用户问题历史记录格式化为提示词 - 调用模型 - 解析模型输出 - 执行工具 - 将结果作为“观察”加入历史 - 进入下一轮循环直到模型输出“最终答案”或达到最大迭代次数。verboseTrue会打印出所有中间步骤是调试智能体逻辑的利器。3.4 运行与验证创建一个主程序来测试我们的智能体。# main.py from agent import create_react_agent_executor def main(): print(初始化 ReAct 智能体...) agent_executor create_react_agent_executor() # 测试用例 test_questions [ 今天的天气怎么样, # 需要联网查询 请用中文介绍一下你自己。, # 不需要工具模型自身知识可回答 2026年世界杯在哪里举行, # 需要查询未来事件模型知识可能过期 ] for question in test_questions: print(f\n{*50}) print(f用户问题: {question}) print(f{*50}) try: response agent_executor.invoke({input: question}) print(f\n智能体最终答案: {response[output]}) except Exception as e: print(f执行过程中出现错误: {e}) if __name__ __main__: main()运行程序python main.py预期输出部分verboseTrue时初始化 ReAct 智能体... 用户问题: 今天的天气怎么样 思考用户询问今天的天气这是一个需要实时信息的问题我无法直接回答需要使用搜索工具。 行动web_search 行动输入今天天气 [工具调用] 正在搜索: 今天天气 观察关于 今天天气 的搜索结果1: 这是根据网络信息模拟的摘要内容A。 --- 关于 今天天气 的搜索结果2: 这是根据网络信息模拟的摘要内容B。 --- 关于 今天天气 的搜索结果3: 这是根据网络信息模拟的摘要内容C。 思考我已经从搜索结果中获得了关于今天天气的信息可以整合成答案。 最终答案根据网络信息今天天气情况大致为...此处整合模拟内容 智能体最终答案根据网络信息今天天气情况大致为...此处整合模拟内容你会看到智能体完整的推理过程它先“思考”需要搜索然后“行动”调用web_search工具接着“观察”工具返回的结果最后再次“思考”并给出“最终答案”。对于“介绍自己”这种问题它可能直接思考后给出最终答案不会调用工具。4. 深入核心提示词模板、工具描述与解析逻辑仅仅跑通 Demo 是不够的。要构建可靠的智能体必须理解其内部运作的三个关键点。4.1 设计有效的工具描述工具的描述 (description) 是智能体能否正确使用工具的决定性因素。糟糕的描述会导致工具被误用或忽略。错误示例description: str 一个搜索工具。 # 太模糊智能体不知道何时该用它。优秀示例description: str ( 当问题涉及非公开的、实时的、或训练数据截止日期之后的信息时使用此工具。 例如今日新闻、股价、体育比赛结果、特定公司的近期动态。 输入应为一个简洁的关键词或短语。 )描述应该明确界定工具的使用场景和输入格式。4.2 理解并定制 ReAct 提示词模板LangChain 内置的模板是个很好的起点但在复杂场景下可能需要定制。模板中的{agent_scratchpad}变量会被自动替换成如下格式的历史记录思考上一次的思考内容 行动上一次的行动 行动输入上一次的输入 观察上一次工具返回的结果 然后重复你可以修改模板来强化规则例如要求模型在不确定时优先询问用户或者限制工具的使用顺序。4.3 处理解析错误与循环失控智能体执行中最常见的两个问题是解析错误模型没有严格按照“思考/行动/最终答案”的格式输出导致AgentExecutor无法解析。无限循环模型陷入“思考-行动-观察”的死循环无法得出最终答案。解决方案设置handle_parsing_errorsTrue这会让执行器在解析失败时尝试将错误信息反馈给模型让它重新输出。严格限制max_iterations通常设置为 5-10 次防止资源耗尽。优化提示词在模板开头加入强约束如“你必须严格遵守输出格式否则任务将失败。”增加验证逻辑在工具的_run方法中对输入进行校验返回结构化的、易于模型理解的观察结果。5. 生产环境进阶多工具、记忆与复杂 Agent一个实用的智能体往往需要多个工具和记忆能力。5.1 集成多个工具计算与搜索让我们增加一个计算器工具并观察智能体如何选择。# tools/calculator_tool.py from langchain.tools import BaseTool from pydantic import Field import re class CalculatorTool(BaseTool): 一个用于数学表达式计算的计算器工具。 name: str calculator description: str ( 当用户的问题包含明确的数学计算、算术表达式或需要数值求解时使用此工具。 输入应该是一个可计算的数学表达式例如3 5 * 2 或 sqrt(16)。 支持加减乘除(-*/)、乘方(**)和括号。 ) def _run(self, expression: str) - str: 计算数学表达式。注意使用 eval 有安全风险此处仅用于演示。 print(f[工具调用] 正在计算: {expression}) # 安全警告在生产环境中绝对不要直接使用 eval 处理用户输入 # 应使用 ast.literal_eval 或专门的数学表达式解析库如 numexpr。 try: # 简单的安全过滤不完善仅演示 if not re.match(r^[\d\s\\-\*\/\(\)\.\*\*]$, expression): return 错误表达式包含不安全字符。 # 将 ** 替换为 pow 函数并执行计算 # 再次强调此方法不安全仅用于演示。 result eval(expression.replace(**, pow)) return f计算结果: {result} except Exception as e: return f计算错误: {e} async def _arun(self, expression: str): raise NotImplementedError(此工具不支持异步调用)修改agent.py中的工具列表from tools.calculator_tool import CalculatorTool # ... 其他导入 ... tools [WebSearchTool(), CalculatorTool()] # 添加计算器工具现在当你问“珠穆朗玛峰的高度加上 1000 米是多少”智能体可能会先搜索“珠穆朗玛峰高度”得到“8848.86米”然后调用计算器计算“8848.86 1000”。5.2 为智能体添加记忆会话历史默认的AgentExecutor是“无状态”的每次调用互不影响。为了让智能体拥有上下文记忆如引用之前的对话需要使用ConversationBufferMemory。# agent_with_memory.py from langchain.memory import ConversationBufferMemory from langchain.agents import AgentExecutor, create_react_agent # ... 其他导入 ... def create_react_agent_with_memory(): llm ... # 初始化模型同上 tools ... # 初始化工具同上 react_prompt ... # 提示词模板同上 # 创建记忆体 memory ConversationBufferMemory(memory_keychat_history, return_messagesTrue) # 创建智能体注意create_react_agent 本身不直接处理记忆 # 我们需要将记忆作为上下文变量的一部分传入提示词。 # 一种常见做法是修改提示词模板加入 {chat_history} 占位符。 prompt_with_memory PromptTemplate.from_template( 你是一个有帮助的助手。以下是之前的对话历史 {chat_history} 现在请回答新问题。你可以使用以下工具 {tools} 请严格按照以下格式回应 思考... 行动... 行动输入... 观察... ... (循环) 当你确信已经获得足够信息来回答问题时请使用以下格式 思考我已经获得足够信息可以给出最终答案。 最终答案你的最终回答。 新问题{input} {agent_scratchpad} ) agent create_react_agent(llmllm, toolstools, promptprompt_with_memory) # 创建执行器时传入记忆 agent_executor AgentExecutor( agentagent, toolstools, verboseTrue, memorymemory, # 关键传入 memory 对象 max_iterations5, ) return agent_executor在调用时执行器会自动管理chat_history的存储和读取。5.3 使用 LangChain Expression Language (LCEL) 构建更灵活的链对于更复杂的流程如先检索后生成或多个智能体协作可以使用 LCEL。它提供了声明式、可组合的方式来构建链。from langchain.prompts import ChatPromptTemplate from langchain.schema.output_parser import StrOutputParser from langchain.schema.runnable import RunnablePassthrough # 1. 定义一个简单的提示词链 prompt ChatPromptTemplate.from_messages([ (system, 你是一个翻译助手将中文翻译成英文。), (user, {text}) ]) model ChatOpenAI(...) # 初始化模型 translation_chain prompt | model | StrOutputParser() # 2. 运行链 result translation_chain.invoke({text: 你好世界}) print(result) # 输出: Hello, world # 3. 组合链先搜索再总结 from langchain.schema import Document def fake_retriever(query: str): # 模拟一个检索器返回文档列表 return [Document(page_contentf关于{query}的文档内容...)] retrieval_chain ( {context: fake_retriever, question: RunnablePassthrough()} | ChatPromptTemplate.from_template(基于以下上下文\n{context}\n\n回答问题{question}) | model | StrOutputParser() )LCEL 让复杂的工作流变得清晰可维护是构建生产级应用推荐的方式。6. 常见问题排查与调试指南开发智能体时你一定会遇到各种问题。以下是系统性的排查路径。6.1 智能体不调用工具现象可能原因检查与解决模型直接回答忽略工具。1. 工具描述 (description) 不清晰模型无法匹配。2. 提示词模板未强调必须使用工具。3. 任务过于简单模型认为自身知识足够。1.检查工具描述确保描述明确指出了使用场景。用不同的任务测试。2.强化提示词在模板开头加入“你必须优先考虑使用提供的工具来获取最新或精确信息”。3.测试复杂任务询问一个模型知识截止日期之后的事件如“昨天某支股票收盘价”。6.2 智能体陷入无限循环现象可能原因检查与解决反复调用同一个工具或在不同工具间无效切换。1. 工具返回的“观察”结果质量差模型无法理解。2. 模型无法从观察中提炼出回答问题所需的信息。3.max_iterations设置过高。1.检查工具输出确保工具返回的是清晰、简洁、相关的文本。避免返回 HTML 或杂乱 JSON。2.优化工具设计让工具的输出更结构化。例如搜索工具返回“摘要... 来源...”。3.降低max_iterations设为 3-5强制早停然后分析日志看卡在哪一步。4.查看详细日志 (verboseTrue)分析模型的“思考”内容看它是否误解了任务或工具能力。6.3 解析错误Parsing Error现象可能原因检查与解决控制台报错OutputParserException。1. 模型未按指定格式思考/行动/最终答案输出。2. 工具名称拼写错误或与tool_names不匹配。3. 模型输出包含多余的解释或标记。1.设置handle_parsing_errorsTrue让执行器尝试自动修复。2.核对工具名称确保name字段与提示词模板中的[{tool_names}]列表一致。3.简化提示词移除模板中可能引起混淆的额外说明格式指令要极其醒目。4.使用更强的模型GPT-3.5 有时格式遵循能力较弱可尝试 GPT-4 或类似能力的模型。6.4 API 调用失败或超时现象可能原因检查与解决网络错误、超时、鉴权失败。1. API Key 错误或过期。2.base_url配置错误。3. 网络代理问题。4. 模型服务方限流或故障。1.验证 API Key在命令行用curl或简单脚本测试 API 连通性。2.检查base_url确保末尾没有多余斜杠路径正确。3.配置网络在代码中设置http_client参数或检查系统代理。4.添加重试机制使用tenacity库为 LLM 调用添加指数退避重试。7. 生产环境最佳实践将智能体从 Demo 推向生产需要考虑更多。配置管理API Key、模型参数、服务端点等必须通过环境变量或配置中心管理绝不能硬编码。错误处理与降级智能体流程中的每一步都可能出错模型调用、工具调用、解析。必须有完善的 try-catch并设计降级方案如返回默认答案、转人工。日志与监控记录完整的交互历史用户输入、模型思考、工具调用、最终输出用于后续分析和模型优化。监控耗时、费用和错误率。成本控制智能体的多次迭代会显著增加 Token 消耗。设置预算、监控用量并对非必要场景使用更小、更便宜的模型。安全与合规工具安全像计算器示例中的eval是极度危险的。任何执行代码、访问数据库、调用外部 API 的工具都必须进行严格的输入验证和权限控制。输出审查对模型的最终输出进行内容安全过滤防止生成有害、偏见或不合规的内容。数据隐私确保用户数据在通过工具和模型 API 时不泄露。性能优化缓存对频繁且结果不变的模型调用或工具调用如某些查询进行缓存。异步如果工具调用是 I/O 密集型如网络请求使用异步版本 (_arun) 提升并发性能。流式输出对于长文本生成使用流式接口提升用户体验。从提示词工程到 ReAct 智能体核心思想始终是将大模型视为一个具有强大文本理解和生成能力的“核”而我们需要通过精巧的工程手段提示词、工具、流程控制来引导、约束和扩展这个“核”使其能够可靠地完成特定任务。下一步你可以尝试集成真实的搜索引擎 API、数据库工具或者探索多智能体协作如 AutoGen将单个智能体的能力组合成更强大的工作流。