从零跑通第一条AI Agent工单:大模型+查询工具最小闭环实战
发布时间:2026/9/28 6:40:58 作者:尧图编辑部 阅读量:1,286

1. 从一条文字工单说起为什么先跑起来比什么都重要很多人一上来就想搭一个完整的 AI Agent规划得特别宏大——要接知识库、要接多轮对话、要接权限系统、要接工单状态机结果两周过去连第一条工单都没跑通。我自己也踩过这个坑。最开始做智能工单处理的时候光在架构设计上就耗了快一周画了一堆图最后发现真正卡住我的不是架构而是“大模型到底能不能稳定地调用一个查询工具把工单里的关键信息查出来”。所以这篇东西的核心就一件事用大模型加一个查询工具把一条文字工单从输入到输出完整跑通。不搞花活不接一堆中间件就是最小可运行闭环。它解决的是“从 0 到 1”的问题适合刚接触 AI Agent、Tool Calling、大模型应用开发的人也适合已经会调 API 但没真正让模型去调用过外部工具的人。你只要有一台能联网的电脑、一个能用的大模型 API、一个能查的数据库或表格就能跟着复现。这里的关键词是大模型、查询工具、文字工单、AI Agent、Tool Calling。文字工单就是用户提交的一段自然语言描述比如“帮我查一下上周北京地区退货订单里金额超过 500 的那几单”。查询工具可以是一个 MySQL 查询接口、一个 HTTP API甚至是一个本地 CSV 查询函数。大模型负责理解这句话决定要不要调工具、调哪个工具、传什么参数最后把查询结果整理成人能看懂的回答。Tool Calling 就是模型和工具之间的那根线。我先把结论放前面第一条工单能不能跑通取决于你有没有把工具描述写清楚、参数定义写死、返回结果控制住长度。这三件事做不好后面接再多东西都是白搭。下面我按实际搭建顺序拆开讲包括我自己的选型逻辑、参数怎么定、代码怎么写、报错怎么查。2. 整体设计与选型为什么是“大模型 单查询工具”这个最小组合2.1 为什么不先做多工具、多轮、多 Agent刚上手的人最容易犯的错是一开始就上多工具。比如同时给模型挂“查订单”“查用户”“查物流”“查退款”四个工具结果模型在第一步就懵了——它不知道当前这句话该用哪个于是开始瞎猜或者干脆不调工具直接编答案。我实测下来单工具场景下 Tool Calling 的成功率明显高于多工具因为决策空间小模型只需要判断“调”还是“不调”以及“参数填什么”。另一个原因是调试成本。单工具跑通之后你至少知道链路是通的模型能识别意图、能生成结构化参数、工具能执行、结果能回传、模型能总结。这时候再加第二个工具你只需要关注“模型会不会选错工具”而不用怀疑底层链路。这就像学开车先在空地上把油门刹车方向盘摸熟再上路而不是一上来就进早高峰。所以第一版的设计目标非常明确一条工单进来模型判断是否需要查询需要就调唯一那个查询工具拿到结果后组织语言回复不需要就直接回复。整个流程只有一次工具调用不做多轮不做记忆不做并发。2.2 大模型怎么选先看能不能稳定输出结构化参数选模型这件事我的建议是第一版不要纠结哪个模型最强先选一个你调用成本低、响应快、支持 Tool Calling 的。因为你要反复试几十次甚至上百次每次都在烧钱和时间。我自己的做法是先用一个中等规模的模型把流程跑通等提示词和工具描述稳定了再换更强的模型对比效果。判断一个模型能不能用于这个场景看三点。第一它是否支持函数调用或工具调用协议也就是你能不能把工具定义按它要求的格式传进去。第二它返回的工具参数是不是稳定的 JSON而不是夹在一堆解释文字里。第三它在参数缺失时会不会主动追问而不是瞎填一个默认值。第三点特别重要我见过模型把“上周”直接填成固定日期结果查出来完全不对。如果你用的是本地部署模型还要注意上下文长度。工单本身可能不长但工具定义、系统提示词、历史示例加起来很容易超过 4K token。我一般会把系统提示词压到 500 字以内工具描述控制在 200 字以内给模型留足空间。2.3 查询工具怎么选能返回结构化结果就行查询工具这块很多人以为必须上 MySQL。其实第一版完全可以用一个 Python 函数查 CSV或者查 SQLite。核心不是数据库多强而是工具能不能接收参数、执行查询、返回一个列表或字典。我最初就是用 pandas 读一个 CSV写了个query_orders(region, min_amount, date_range)函数跑通之后才换成 MySQL。如果你要用 MySQL注意两点。第一不要让模型直接生成 SQL 字符串去执行除非你做了严格的校验和只读权限控制。更稳的做法是模型只填参数SQL 由你在代码里拼或者用参数化查询。第二查询结果要限制条数比如LIMIT 20否则模型拿到几百行数据总结的时候会漏、会编、会超上下文。选型项第一版建议原因模型支持 Tool Calling 的中等模型成本低、迭代快工具数量1 个降低模型决策难度工具实现本地函数或只读查询接口易调试、风险低返回条数限制 20 条以内控制上下文长度参数来源模型填参代码拼 SQL避免注入和乱查2.4 文字工单的输入特点与预处理文字工单最大的特点是“口语化 信息不全”。用户不会写“region北京 AND amount500 AND date BETWEEN ...”他会写“帮我看看上周北京那边退货超过五百的”。这里面有三个信息地区、时间、金额但“上周”是模糊的“五百”是中文数字“退货”对应的是订单类型。我的做法是在系统提示词里明确告诉模型如果工单里缺少必要参数不要猜直接追问。同时在工具定义里把每个参数标成必填或可选。必填参数缺失时模型应该返回一个追问而不是调用工具。这一步能挡掉大量错误查询。另外中文数字和相对时间可以在提示词里给几个转换示例比如“上周 最近 7 天”“五百 500”模型基本能学会。3. 核心细节拆解工具描述、参数定义和提示词到底怎么写3.1 工具描述是给模型看的“说明书”工具描述写得好不好直接决定模型会不会用、用得对不对。我见过有人把工具描述写成“查询订单”结果模型根本不知道什么时候该调。好的描述应该包含三部分这个工具做什么、什么时候用、每个参数是什么意思。比如我第一版是这么写的query_orders根据地区、金额下限、时间范围查询退货订单。 当用户询问某个地区、某段时间内金额超过某个值的退货订单时使用。 参数 - region地区名称字符串必填例如“北京” - min_amount金额下限数字必填例如 500 - days最近多少天整数必填例如 7这段描述里“什么时候用”是关键。它把触发条件和用户表达对应起来了。模型看到“上周北京退货超过五百”就会匹配到“地区 时间 金额”这个模式然后去填参数。如果描述里只写“查询订单”模型可能会在用户问“订单状态”时也去调那就错了。注意工具描述不要写得太长超过 300 字模型反而容易忽略重点。把触发条件放在第一句参数说明用短句。3.2 参数定义要“窄”不要“宽”参数定义越宽模型越容易乱填。比如你把时间参数定义成“任意时间字符串”模型可能填“上周”“最近”“2024 年”各种格式你的工具根本处理不了。我的做法是把参数类型和格式写死并且在代码里做校验。以days为例我定义成整数单位是天。模型看到“上周”会填 7看到“最近三天”会填 3。如果用户说“上个月”模型可能填 30也可能填 31这没关系因为我的查询逻辑是“最近 N 天”30 和 31 差别不大。但如果你的业务对日期边界很敏感那就不要用天数直接用开始日期和结束日期两个参数让模型填YYYY-MM-DD格式。金额参数也一样。我定义成数字模型会把“五百”转成 500。但如果用户说“五百左右”模型可能填 500也可能填 450。这时候你要么在提示词里规定“左右按下限处理”要么在工具里做模糊匹配。我一般选择前者因为规则越明确模型越稳定。参数类型必填格式要求缺失时行为region字符串是城市名追问用户min_amount数字是整数或小数追问用户days整数是正整数默认 7 天并说明3.3 系统提示词要管住三件事系统提示词不需要写很长但必须管住三件事角色、工具使用规则、输出格式。我的第一版提示词大概是这样你是一个工单处理助手。你可以调用 query_orders 工具查询退货订单。 规则 1. 只有当用户明确提到地区、金额、时间三个信息时才调用工具。 2. 缺少任何一个必填参数先向用户追问不要调用工具。 3. 调用工具后根据返回结果用中文总结不要编造数据。 4. 如果查询结果为空直接告诉用户没有符合条件的订单。这四条规则里第一条和第二条是防止乱调第三条是防止幻觉第四条是处理空结果。我实测下来加上这四条之后模型瞎调工具的概率明显下降。尤其是第二条很多模型默认会“猜一个值”明确说“不要猜”之后会好很多。输出格式这块我建议第一版不要限制太死。你可以要求“用一段话总结”但不要要求“必须输出 JSON”因为工单处理的最终读者是人不是程序。等后面要接自动化流程了再改成结构化输出。3.4 工具返回结果怎么控制长度和结构工具返回给模型的结果直接影响到模型能不能总结好。如果你返回一个 100 行的表格模型大概率会漏掉大部分甚至开始编。我的做法是只返回必要字段并且限制条数。比如查询订单我返回的每条记录只包含订单号、地区、金额、日期、状态。不返回用户 ID、商品详情、物流信息这些无关字段。条数限制在 20 条以内如果超过 20 条我在返回结果里加一句“共查到 35 条以下展示前 20 条”。这样模型总结的时候会说“共 35 条其中前 20 条显示……”不会漏掉总数。返回格式我用 JSON因为模型对 JSON 的解析能力比较强。结构大概是{ total: 35, shown: 20, orders: [ {order_id: A001, region: 北京, amount: 620, date: 2024-06-01, status: 退货中} ] }提示返回结果里不要包含换行符和特殊符号否则模型在总结时容易断句错误。我一般会把所有字段值转成字符串去掉多余空格。4. 实操过程从零把第一条工单跑通4.1 环境准备与最小依赖第一版不需要复杂环境。我用的是 Python依赖就三个openai或对应的大模型 SDK、pandas或sqlite3、json。如果你用 MySQL再加一个pymysql。不需要 LangChain不需要向量数据库不需要前端。一个.py文件就能跑。安装命令很简单pip install openai pandas如果你用的是其他模型平台把 SDK 换成对应的就行。关键是这个 SDK 要支持工具调用也就是你能传tools参数并且能拿到tool_calls返回。环境变量里放 API Key不要写死在代码里。我一般用.env文件加python-dotenv但第一版直接export也行。跑通之后再考虑配置管理。4.2 定义查询工具函数工具函数本身很简单就是接收参数、查数据、返回结果。我用 pandas 读 CSV 举例import pandas as pd def query_orders(region: str, min_amount: float, days: int): df pd.read_csv(orders.csv) df[date] pd.to_datetime(df[date]) cutoff pd.Timestamp.now() - pd.Timedelta(daysdays) result df[ (df[region] region) (df[amount] min_amount) (df[date] cutoff) (df[status].str.contains(退货)) ] total len(result) shown result.head(20) return { total: total, shown: len(shown), orders: shown[[order_id, region, amount, date, status]].to_dict(records) }这个函数里days用来算截止日期region精确匹配min_amount用大于等于。实际业务里地区可能有“北京市”“北京”两种写法第一版先不做模糊匹配等跑通了再加。4.3 把工具定义传给模型工具定义要按模型平台要求的格式写。以常见的函数调用格式为例tools [ { type: function, function: { name: query_orders, description: 根据地区、金额下限、时间范围查询退货订单。当用户询问某地区某时间段内金额超过某值的退货订单时使用。, parameters: { type: object, properties: { region: {type: string, description: 地区名称例如北京}, min_amount: {type: number, description: 金额下限例如500}, days: {type: integer, description: 最近多少天例如7} }, required: [region, min_amount, days] } } } ]这段定义里description和参数说明都是给模型看的。我特意在描述里写了“当用户询问……时使用”就是为了让模型把用户表达和工具触发条件对应起来。4.4 完整调用流程与代码骨架整个流程分四步发消息给模型、判断有没有工具调用、执行工具、把结果回传给模型。代码骨架如下import json from openai import OpenAI client OpenAI() def handle_ticket(ticket: str): messages [ {role: system, content: 你是一个工单处理助手。你可以调用 query_orders 工具查询退货订单。缺少必填参数时先追问不要猜。}, {role: user, content: ticket} ] response client.chat.completions.create( modelyour-model, messagesmessages, toolstools, tool_choiceauto ) msg response.choices[0].message if msg.tool_calls: tool_call msg.tool_calls[0] args json.loads(tool_call.function.arguments) result query_orders(**args) messages.append(msg) messages.append({ role: tool, tool_call_id: tool_call.id, content: json.dumps(result, ensure_asciiFalse) }) final client.chat.completions.create( modelyour-model, messagesmessages ) return final.choices[0].message.content return msg.content这段代码里tool_choiceauto表示让模型自己决定调不调。如果你希望第一版更可控可以设成强制调用但那样模型在参数不全时也会硬调所以我还是建议auto。4.5 第一次实测一条工单的完整记录我拿一条真实工单试了一下“帮我查一下最近 7 天北京地区退货金额超过 500 的订单。”模型返回的tool_calls参数是{region: 北京, min_amount: 500, days: 7}工具执行后返回{total: 3, shown: 3, orders: [{order_id: A001, region: 北京, amount: 620, date: 2024-06-01, status: 退货中}]}模型最终回复“最近 7 天北京地区退货金额超过 500 的订单共有 3 条其中一条是订单 A001金额 620 元状态为退货中。”这条链路跑通之后我做的第一件事不是加功能而是换不同的工单反复试。试了“上海最近三天退款超过一千的”“广州上周退货五百以上的”看模型能不能稳定填对参数。大概试了 20 条发现两个问题一是“上周”有时填 7 有时填 6二是有条工单没提地区模型自己填了“全国”。这两个问题后面都通过提示词解决了。5. 常见问题与排查技巧实录5.1 模型不调工具直接编答案这是最常见的问题。原因通常是工具描述没写清楚触发条件或者系统提示词没强调“必须调工具”。我的排查顺序是先看工具描述里有没有“当用户询问……时使用”再看系统提示词有没有说“不要编造数据”。如果都写了还不调就把tool_choice临时改成强制调用看模型能不能正确填参数。如果能填对说明是触发条件的问题如果填不对说明参数定义有问题。还有一种情况是模型觉得“这个问题不需要查”。比如用户问“退货流程是什么”这确实不需要查订单。这时候不调工具是对的。所以你要区分“该调没调”和“本来就不该调”。5.2 参数填错或缺失参数填错一般有三种格式错、值错、漏填。格式错比如days填了“一周”而不是 7这通常是参数类型没写清楚。值错比如地区填了“北京市”而数据库里是“北京”这需要你在工具里做兼容或者在提示词里规定用简称。漏填比如没提金额模型自己填了 0这要在提示词里明确“缺少必填参数时追问”。我一般会在代码里加一层校验如果args里缺少必填字段或者类型不对直接返回一个追问而不是执行查询。这样即使模型犯错也不会查出错误结果。问题可能原因排查方法解决不调工具描述不清看触发条件补“何时使用”参数格式错类型没写死看参数定义明确类型和示例参数值错没做兼容对比数据库加映射或提示词漏填参数没强调必填看 required提示词加追问规则结果太长没限制条数看返回加 LIMIT 和 total5.3 查询结果为空或报错空结果不是错误但模型有时会把空结果说成“查询失败”。我的做法是在工具返回里明确写total: 0并在提示词里说“如果 total 为 0直接告诉用户没有符合条件的订单”。这样模型就不会瞎猜。报错一般是数据库连接失败、字段名不对、日期格式不对。第一版我建议把所有异常都捕获返回一个error字段让模型告诉用户“查询暂时不可用”。不要让异常直接抛到模型那里否则模型会编一个奇怪的解释。5.4 模型总结时编造数据这个问题最危险。模型可能查到 3 条总结时说成 5 条或者把金额改了。防止的办法有三个一是返回结果里带total和shown让模型有明确数字可引用二是在提示词里强调“只根据返回结果总结不要添加未返回的信息”三是返回结果尽量短减少模型自由发挥的空间。我实测下来返回结果越结构化、字段越少模型编造的概率越低。如果你返回一大段文本模型很容易在里面“找”到不存在的信息。5.5 响应太慢或超时第一版链路里时间主要花在两次模型调用上。如果模型响应慢可以先换一个更快的模型或者把系统提示词缩短。工具查询本身通常很快除非数据量特别大。我一般会给查询加一个时间限制比如只查最近 90 天的数据避免全表扫描。另外如果你用的是流式输出注意工具调用和流式的配合。有些平台在流式模式下工具调用的返回格式不一样第一版建议先用非流式跑通再加流式。6. 跑通之后下一步可以往哪里扩展第一条工单跑通之后你手里就有了一个最小闭环输入文字、模型判断、工具查询、结果总结。这个闭环虽然简单但它是后面所有扩展的基础。我自己的扩展顺序是这样的先加第二个工具比如查物流再加多轮对话让用户能追问“那第二条呢”然后加工单状态回写让模型能改状态最后才考虑接知识库和权限。但我要提醒一句每加一个东西都要重新测一遍第一条工单。因为新工具、新提示词可能会影响模型对原有工具的判断。我见过加了查物流工具之后模型把“退货订单”也拿去查物流了。所以回归测试很重要哪怕只是手动跑几条。如果你现在还没跑通第一条不要急着看后面的扩展。先把工具描述改到模型能稳定调对把参数校验加到代码里把返回结果控制住长度。这三件事做完你才算真正“先跑起来”了。后面的事跑起来再说。