尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

AI应用工程化实战:从0到1搭建客服Agent的完整指南

AI应用工程化实战:从0到1搭建客服Agent的完整指南 之前和几位做 AI 应用的同行聊天大家都提到一个现象很多团队在模型效果上差距并不大真正拉开差距的往往是工程化能力。尤其当 AI 进入业务落地阶段如何设计 Agent、如何编排提示词、如何低成本部署模型、如何应对线上各种异常成为决定项目成败的关键。这也让我想到那些在 AI 赛道上持续发力的北大校友团队他们的技术路径各有侧重但底层都有一个共同点把算法、数据、工程三件事当作一个整体来推进。本文就从 AI 工程实践的角度完整拆解一个 AI 应用从 0 到 1 的搭建过程包括环境准备、Agent 核心逻辑、模型部署和线上排错适合刚接触 AI 开发、或者已经在做原型但想走向工程的读者。1. 背景与核心概念1.1 什么是 AI 应用开发AI 应用开发指的是在预训练大模型的基础上构建能够解决实际业务问题的软件系统。与传统的规则引擎或机器学习小模型不同今天的 AI 应用通常以 LLM大语言模型作为核心“大脑”通过提示词、检索增强RAG、工具调用Function Calling、多轮对话等机制让模型完成推理、生成、分析等任务。这里需要区分两个容易混淆的概念模型训练指用大规模数据调整模型参数需要 GPU 集群、数据管道和算法团队。模型应用指使用已经训练好的模型通过 API 或本地部署构建上层业务逻辑。大部分工程开发者真正需要掌握的是后者。北大校友在 AI 竞赛中的优势也恰恰体现在这里他们往往既有算法基础又愿意深入到工程细节中而工程能力正是从 Demo 到产品之间最难跨越的鸿沟。1.2 AI Agent 是什么AI Agent智能体可以理解为一个“会使用工具的助手”。它不只是回答用户问题还能根据问题自动决定调用哪些工具、如何拆分任务、如何校验结果。一个典型的 Agent 系统包含以下部分大模型负责理解意图和生成推理步骤。提示词模板定义 Agent 的角色、能力和限制。工具集例如搜索、计算、数据库查询、HTTP 请求等。执行循环模型输出动作指令系统执行并返回结果模型再继续推理。常见应用场景包括智能客服、数据分析助手、自动报告生成、个性化推荐解释、企业知识库问答等。在实际项目中Agent 的可靠性往往取决于工具设计的清晰度和失败处理策略而不是模型本身。1.3 为什么需要关注工程实践很多初学者把大模型 API 调用当成 AI 应用的全部但真实业务中还要考虑响应延迟、成本、上下文长度、错误恢复、安全合规、并发控制等问题。这也是为什么“AI 工程实践”和“AI 模型部署”逐渐成为团队能力建设的重点。本文后面会围绕一个具体的客服问答 Agent 项目展示这些工程问题的解决思路。2. 环境准备与版本说明2.1 基础环境本文示例以 Python 3.10 以上版本为参考操作系统推荐 Linux 或 macOSWindows 也可以运行但部分命令行操作略有差异。你需要提前安装Python 3.10pipvirtualenv 或 condaGit版本需要根据你的项目实际情况调整。如果你使用的是较新的 Python 3.12需要注意部分依赖库的兼容性。建议先创建独立虚拟环境避免污染系统 Python。# 创建一个 Python 3.10 虚拟环境 conda create -n ai-agent python3.10 -y conda activate ai-agent在开始写代码之前先确定你的大模型访问方式。本文示例使用 OpenAI 兼容接口你可以替换成任意支持 compatible 模式的国内模型或本地部署服务。如果你使用本地模型需要额外准备对应推理框架和显卡资源。2.2 项目依赖我们需要安装以下核心依赖openai用于调用大模型接口兼容 OpenAI 格式。fastapi和uvicorn用于构建并启动 Web 服务。requests用于 Agent 调用外部工具。python-dotenv管理环境变量。pip install openai fastapi uvicorn requests python-dotenv如果你后续要接入 LangChain 或 LlamaIndex可以再按需安装。但本文刻意避免过度依赖框架因为只有理解了底层逻辑使用框架时才不会迷失在抽象概念里。2.3 项目结构我们用一个简单的项目结构来组织代码ai-agent-demo/ ├── agent.py # Agent 核心逻辑 ├── tools.py # 工具函数集合 ├── app.py # FastAPI Web 服务 ├── .env # 环境变量不入库 └── requirements.txt # 依赖清单这样的结构适合小型项目。当业务复杂后你可以按功能模块拆分成更细的包。3. 核心语法、配置与原理拆解3.1 大模型调用基础在 Agent 系统中大模型扮演“决策者”的角色。它接收用户请求生成两种结果一种是直接回答另一种是“调用工具的指令”。为了让模型输出可解析的指令通常会使用 Function Calling 能力。以 OpenAI 兼容接口为例一次最简单的调用如下from openai import OpenAI client OpenAI( api_keyyour-api-key, base_urlhttps://api.example.com/v1 ) resp client.chat.completions.create( modelgpt-4o-mini, messages[ {role: system, content: 你是一个 AI 助手。}, {role: user, content: 你好} ] ) print(resp.choices[0].message.content)这里的base_url可以替换为任何兼容 OpenAI 协议的服务。关键参数model模型名称不同服务商略有差异。messages对话消息列表包含 system、user、assistant 三种角色。temperature控制随机性0 到 2 之间。用于工具调用时建议调低比如 0.1避免指令不稳定。3.2 Function Calling 原理Function Calling 的本质是你在请求中声明一组函数模型根据用户问题决定是否需要调用函数并返回结构化的 JSON 参数。系统再使用这个 JSON 参数实际执行函数把结果回传给模型生成最终答案。一个最小声明如下tools [ { type: function, function: { name: get_datetime, description: 获取当前日期时间, parameters: { type: object, properties: {}, required: [] } } } ]当用户问“现在几点”模型会返回一个 tool_calls 结果而不是直接回答。开发者的任务就是解析这个结果、执行函数、再次请求模型。3.3 提示词设计的基本思路提示词是 Agent 的行为说明书。好的提示词需要做到三点明确角色和目标。给出限制条件。给出处理失败时的兜底策略。例如你是企业客服助手。你可以使用以下工具查询订单、查找物流和提供退换货说明。 如果用户的问题与业务无关请礼貌拒绝回答。 如果工具返回结果为空请如实告知用户“暂时无法查询”不要编造信息。“不要编造信息”这句话很关键因为大模型有时会产生“幻觉”也就是生成看似合理但实际错误的答案。通过提示词约束可以降低幻觉概率但不能完全消除因此后续需要用工具结果约束模型输出。3.4 工具函数的设计原则工具函数是 Agent 和外部世界的桥梁。工具设计得越清晰模型就越容易正确调用。推荐每个工具只做一件事并给出详细的 description。比如query_order_status(order_id)根据订单号查询订单状态。calculate_delivery_days(city, date)计算预计送达天数。send_refund_request(order_id, reason)提交退换货申请。工具参数命名要直观类型要明确。否则模型可能为了迎合工具格式而编造参数。4. 完整实战案例下面我们构建一个“客服问答 Agent”它支持两个工具查询订单状态、计算配送时间。整体流程是用户输入问题。Agent 调用模型判断是否需要工具。如果需要执行工具并回传结果。模型结合工具结果生成最终回答。通过 FastAPI 暴露 HTTP 接口。4.1 定义工具函数文件路径tools.pyimport json import random from datetime import datetime, timedelta # 模拟订单数据实际场景建议从数据库或第三方接口读取 ORDER_DATA { ORD20240101: { status: 已发货, city: 北京, ship_date: 2024-06-01, product: 无线鼠标 }, ORD20240102: { status: 待支付, city: 上海, ship_date: None, product: 机械键盘 }, ORD20240103: { status: 已签收, city: 广州, ship_date: 2024-05-28, product: 显示器 } } def query_order_status(order_id: str) - str: 根据订单号查询订单状态 order_id order_id.strip().upper() if order_id in ORDER_DATA: info ORDER_DATA[order_id] if info[status] 已发货: return json.dumps( { order_id: order_id, status: info[status], city: info[city], ship_date: info[ship_date], product: info[product], }, ensure_asciiFalse, ) return json.dumps( {order_id: order_id, status: info[status], product: info[product]}, ensure_asciiFalse, ) return json.dumps({error: order not found}, ensure_asciiFalse) def calculate_delivery_days(city: str) - str: 根据目的城市模拟计算配送天数 city city.strip() base_days { 北京: 2, 上海: 3, 广州: 4, 深圳: 3, 成都: 5, 杭州: 3, } days base_days.get(city, 7) eta datetime.now() timedelta(daysdays) return json.dumps( {city: city, delivery_days: days, estimated_arrival: eta.strftime(%Y-%m-%d)}, ensure_asciiFalse, )这里使用了random和datetime但实际并没有用到 random可以去掉。为了保持简单我在这里没有使用随机数而是按城市固定天数。你可以根据业务扩展。注意工具函数返回值是 JSON 字符串这是为了与模型输入保持一致也可以直接返回 dict但字符串解析更通用。4.2 编写 Agent 核心逻辑文件路径agent.pyimport json from openai import OpenAI from tools import query_order_status, calculate_delivery_days class CustomerServiceAgent: def __init__(self, model_name: str gpt-4o-mini, base_url: str None, api_key: str None): self.client OpenAI(api_keyapi_key, base_urlbase_url) self.model model_name self.tools [ { type: function, function: { name: query_order_status, description: 根据订单号查询订单状态订单号格式类似 ORD20240101, parameters: { type: object, properties: { order_id: { type: string, description: 用户的订单号 } }, required: [order_id] } } }, { type: function, function: { name: calculate_delivery_days, description: 根据目的城市计算预计配送天数城市为中文名, parameters: { type: object, properties: { city: { type: string, description: 目的城市 } }, required: [city] } } } ] def run(self, user_input: str, max_steps: int 5) - str: messages [ { role: system, content: ( 你是企业客服助手。你可以使用工具查询订单状态和计算配送时间。 如果用户问题与业务无关请礼貌拒绝回答。 如果工具返回‘order not found’请告诉用户订单号不存在。 不要编造订单信息。回答尽量简洁自然。 ), }, {role: user, content: user_input}, ] for step in range(max_steps): resp self.client.chat.completions.create( modelself.model, messagesmessages, toolsself.tools, tool_choiceauto, temperature0.1, ) msg resp.choices[0].message messages.append(msg) if msg.tool_calls: for tool_call in msg.tool_calls: func_name tool_call.function.name args json.loads(tool_call.function.arguments or {}) if func_name query_order_status: result query_order_status(args[order_id]) elif func_name calculate_delivery_days: result calculate_delivery_days(args[city]) else: result json.dumps({error: funknown tool {func_name}}) messages.append({ role: tool, tool_call_id: tool_call.id, content: result, }) continue return msg.content or return 处理超时请稍后再试。核心逻辑在run方法中第一次请求包含用户输入和工具定义。如果模型返回tool_calls循环执行工具并追加tool消息。如果模型没有返回tool_calls说明已经生成最终答案直接返回。设置max_steps防止无限循环。注意不同的 API 服务对tool_choice的支持略有差别。如果你的服务不支持可以去掉这个参数。4.3 创建环境变量文件文件路径.envOPENAI_API_KEYsk-your-key OPENAI_BASE_URLhttps://api.example.com/v1 OPENAI_MODEL_NAMEgpt-4o-mini建议不要将真实密钥提交到 Git 仓库。在本地测试时用python-dotenv自动加载。4.4 编写 FastAPI 服务文件路径app.pyimport os from dotenv import load_dotenv from fastapi import FastAPI from pydantic import BaseModel from agent import CustomerServiceAgent load_dotenv() app FastAPI(titleAI 客服助手) agent CustomerServiceAgent( model_nameos.getenv(OPENAI_MODEL_NAME, gpt-4o-mini), base_urlos.getenv(OPENAI_BASE_URL), api_keyos.getenv(OPENAI_API_KEY), ) class ChatRequest(BaseModel): message: str class ChatResponse(BaseModel): reply: str app.post(/chat, response_modelChatResponse) async def chat(req: ChatRequest): reply agent.run(req.message) return ChatResponse(replyreply) app.get(/health) async def health(): return {status: ok}这里需要注意agent是全局对象可以复用连接池。由于 Agent 内部调用的是阻塞式 API所以chat接口用async def但内部没有真正异步生产环境建议配合线程池或异步客户端使用。为了演示方便这里省略了请求日志、错误处理和接口限流生产环境必须补充。4.5 运行与验证在项目根目录执行uvicorn app:app --host 0.0.0.0 --port 8000服务启动后打开另一个终端用curl测试curl -X POST http://localhost:8000/chat \ -H Content-Type: application/json \ -d {message: 我的订单 ORD20240101 到哪了}预期返回结果类似{ reply: 您好您的订单 ORD20240101 已经发货商品是无线鼠标发货日期为 2024 年 6 月 1 日。请问还有什么可以帮您 }再测试一个需要连续使用工具的场景curl -X POST http://localhost:8000/chat \ -H Content-Type: application/json \ -d {message: 我的订单是 ORD20240103发货到杭州要几天}这个任务需要先查询订单信息再计算配送时间。Agent 会自动执行两步工具调用最后给出答案。你可以看到循环中messages的长度不断增加这就是多步推理的过程。5. 常见问题与排查思路在实际开发中最容易卡住的往往不是业务逻辑而是模型和工具之间的协作异常。这里整理几个高频问题。5.1 模型返回了不存在的函数名现象Agent 运行时抛出unknown tool或json.loads解析失败。原因模型根据工具描述生成了错误的函数名或者参数格式不符合预期。排查步骤打印tool_call.function.name确认模型输出。检查工具描述是否明确避免相似函数名。在代码中增加兜底处理返回错误信息给模型。解决方案在异常情况下把{error: 调用失败}返回给模型让模型自行调整。不要直接让程序崩溃。5.2 上下文长度超限现象多轮对话后请求报错提示maximum context length。原因每次工具调用的结果都追加到 messages导致上下文超过模型上限。解决方案对工具返回内容做截断例如只保留 500 字符对较长的多轮对话做摘要或丢弃早期消息。生产系统还需要设计上下文压缩策略。5.3 AI 幻觉导致编造订单信息现象用户问一个不存在的订单号模型却生成了“订单已发货”之类的回答。原因模型在训练时没有见过你的订单数据它只能依赖提示词和工具结果。如果工具没有返回有效数据模型可能会“补全”一个答案。解决方案在提示词中明确说明“工具返回空或错误时必须告知用户查询失败”同时在工具返回中带上明确的error字段。更严格的方案是在模型回答后增加一层校验逻辑例如使用正则检查订单号是否出现在工具结果中如果没出现则强制替换答案。5.4 API 请求超时现象外部模型接口响应慢或偶尔超时。原因网络波动、模型后端负载高、请求带上了过长的上下文。解决方案在客户端设置超时时间例如timeout30使用重试策略但注意避免重试导致业务重复。生产环境可以引入请求队列和缓存机制。5.5 工具调用循环无法结束现象Agent 反复调用同一个工具始终不输出最终答案。原因模型对工具返回结果不满意试图再次调用获取更符合预期的内容。解决方案设置max_steps例如 5 步后强制返回最后一次模型输出或超时提示。同时可以在一轮工具调用后加入“系统强制结束”的提示词不要让模型无限制尝试。6. 最佳实践与工程建议6.1 成本控制大模型按 token 计费Agent 多轮工具调用会显著增加 token 消耗。上线前必须评估限制每轮对话的最大步骤数。对长工具结果进行截断或摘要。对高频问题做缓存命中缓存直接返回结果。可以通过分类模型先判断问题类型减少不必要的工具调用。6.2 安全与权限边界让 Agent 调用工具时要遵循最小权限原则。例如客服 Agent 只需要订单查询权限不要给它连接内部数据库的高权限账号。涉及用户隐私时还要做敏感信息脱敏。如果你部署本地模型更要关注模型输出内容的安全过滤避免产生不当内容。6.3 日志与可观测性Agent 的推理过程很难预测因此必须记录完整消息链路。推荐为每个请求分配一个request_id并记录用户输入。每次模型返回的 token 数。工具调用名称和参数。最终回答。这样出现问题时可以快速复现和定位。日志中不要记录完整 API Key不要记录用户敏感信息。6.4 模型版本与接口变更大模型接口更新频繁模型名称和参数可能随时调整。建议把模型名、base_url 放到配置中心或环境变量中避免改代码。如果服务比较稳定可以考虑将模型客户端封装成独立模块方便将来替换供应商。6.5 性能优化Agent 的核心瓶颈在网络 IO。生产环境建议将模型客户端配置为连接池复用。对 Web 服务增加并发控制防止突发请求打满后端。使用消息队列削峰异步处理非实时任务。如果使用本地模型部署推荐使用 vLLM 或 TGI 等推理加速框架它们支持连续批处理和 PagedAttention可以有效提升吞吐。6.6 测试策略AI Agent 的输出具有随机性不能只靠传统单元测试。可以先做“确定性测试”固定模型温度为 0对已知输入断言工具调用参数再做“场景回归测试”每次更新提示词后跑一遍典型业务场景人工或自动比较回答质量。建议把测试用例沉淀到仓库中形成回归集。7. 总结与学习路线这篇教程从一个客服问答 Agent 入手串起了 AI 工程实践中最核心的几个能力模型接口调用、Function Calling、工具编排、Web 服务封装和故障排查。掌握这些之后你可以再往三个方向深入学习检索增强生成RAG把企业知识库接入 Agent。多 Agent 协作框架例如让多个 Agent 分别承担信息检索、分析和回复生成。模型部署与推理优化包括量化、微调、以及 vLLM 等推理框架的使用。如果你正在参与 AI 项目建议优先关注线上稳定性不要只沉迷于“模型效果”。一个能在生产环境稳定跑 99% 请求的简单 Agent远好过一个演示惊艳但频繁超时的复杂系统。动手跑一遍上面这个项目再结合自己的业务场景扩展工具函数你会对 AI 应用开发有更实在的体感。遇到问题时回到日志和请求链路里找答案这比盲目调提示词更高效。收藏这篇教程也欢迎在评论区分享你遇到的 AI Agent 工程问题我会抽时间一起讨论。
返回列表