Agent Tool Use实战:让AI真正操作业务系统(完整代码+12个工具案例)
8/30/2026

文章链接:https://blog.csdn.net/qq_43201350/article/details/163399083


一、AgentTool Use 是什么?

通俗解释:用户用自然语言说"查一下我上个月的工单",AI 不是生成一段文字建议你去哪里查,而是 自己动手查数据库,然后把结果用自然语言告诉你

技术上的核心是一个循环:

这个循环里最关键的不是 AI 能力,而是中间层的 工具注册、权限控制、参数校验 ——三个纯工程化问题。


二、工具注册:12 个业务工具的元数据管理

先定义每个工具的描述,让 AI 知道什么时候该调哪个:

interface ToolDefinition {
  name: string
  description: string  // AI 靠这段文字理解工具用途
  parameters: {
    type: 'object'
    properties: Record<string, { type: string; description: string }>
    required: string[]
  }
  type: 'read' | 'write'  // 读操作 / 写操作
  roles: string[]          // 哪些角色可以调用
}
 
const tools: ToolDefinition[] = [
  {
    name: 'queryWorkOrder',
    description: '根据房号查询该户主的所有维修工单。返回工单列表,包括工单号、状态、创建时间',
    parameters: {
      type: 'object',
      properties: {
        houseId: { type: 'string', description: '房号,如 3-501' }
      },
      required: ['houseId']
    },
    type: 'read',
    roles: ['finance', 'customer_service', 'manager', 'supervisor']
  },
  {
    name: 'createWorkOrder',
    description: '创建一个新的维修工单。需要提供房号、工单类型和问题描述',
    parameters: {
      type: 'object',
      properties: {
        houseId: { type: 'string', description: '房号' },
        type: { type: 'string', description: '工单类型:water/electric/carpentry/gas/other' },
        description: { type: 'string', description: '问题描述' }
      },
      required: ['houseId', 'type', 'description']
    },
    type: 'write',
    roles: ['customer_service', 'manager']
  },
  // ... 其余 10 个工具类似定义
]

12 个工具覆盖了完整业务:

  • 查询类(6个) :工单查询、工单列表、财务账单、缴费记录、住户信息、投诉进度

  • 操作类(6个) :创建工单、催缴通知、派发工单、修改排班、系统配置、数据导出

为什么要区分"读"和"写"?

这是整个系统安全的最后防线。读到脏数据可以重试,写到错误数据可能造成生产事故。所以设计规则就是:

读操作 → 自动执行 → 直接返回结果
写操作 → 生成预览 → 用户确认 → 执行

三、Agent 循环:完整代码实现

async function agentLoop(
  message: string,
  role: string,
  history: Message[]
): Promise<AgentResponse> {
  // 1. 获取该角色可用的工具白名单
  const availableTools = tools.filter(t => t.roles.includes(role))
 
  // 2. 构建请求,带上工具定义
  const response = await aiClient.chat({
    messages: [
      { role: 'system', content: getSystemPrompt(role) },
      ...history,
      { role: 'user', content: message }
    ],
    tools: availableTools,
    tool_choice: 'auto'  // AI 自己判断是否需要调工具
  })
 
  // 3. 判断 AI 是否要调工具
  const toolCalls = response.tool_calls || []
  if (toolCalls.length === 0) {
    // 纯文本回复,直接返回
    return { type: 'text', content: response.content }
  }
 
  // 4. 处理工具调用
  const results: ToolResult[] = []
  for (const toolCall of toolCalls) {
    // 4a. 权限二次校验(防止 AI 绕过角色限制)
    const toolDef = tools.find(t => t.name === toolCall.name)
    if (!toolDef || !toolDef.roles.includes(role)) {
      results.push({
        tool_call_id: toolCall.id,
        error: '你没有权限执行此操作'
      })
      continue
    }
 
    // 4b. 参数校验
    const validationError = validateParams(toolCall.params, toolDef.parameters)
    if (validationError) {
      results.push({
        tool_call_id: toolCall.id,
        error: `参数错误: ${validationError}`
      })
      continue
    }
 
    // 4c. 写操作需要用户确认
    if (toolDef.type === 'write') {
      return {
        type: 'confirm',
        tool_name: toolCall.name,
        params: toolCall.params,
        message: `即将执行【${toolDef.name}】操作,请确认参数:\n${
          JSON.stringify(toolCall.params, null, 2)
        }`
      }
    }
 
    // 4d. 读操作自动执行
    const data = await executeTool(toolCall.name, toolCall.params)
    results.push({
      tool_call_id: toolCall.id,
      output: JSON.stringify(data)
    })
  }
 
  // 5. 把工具执行结果喂回 AI,让它生成最终回答
  const finalResponse = await aiClient.chat({
    messages: [
      ...response.messages,
      { role: 'tool', content: results }
    ],
    tools: []  // 第二轮不允许再调工具,防止死循环
  })
 
  // 6. 判断是否需要渲染数据卡片
  const card = buildCard(finalResponse.content, results)
  return {
    type: card ? 'card' : 'text',
    content: finalResponse.content,
    card: card
  }
}

有三个关键设计值得展开:

设计 1:权限二次校验

AI 模型可能绕过SystemPrompt的限制。比如财务角色 Prompt 里写了"不能创建工单",但 AI 有时候会"自作主张"。所以代码层面做二次校验:

if (!toolDef.roles.includes(role)) {
  // 不管 AI 怎么想,后端不允许就是不允许
}

这是大模型应用开发的黄金原则: 不要把业务安全寄托在 Prompt 上,代码层面的权限校验才是最后防线。

设计 2:读操作自动执行 vs 写操作确认

一个真实的交互场景:

用户:"帮我在 3-501 创建一个水路维修工单"
AI:返回 tool_call: createWorkOrder({ houseId: "3-501", type: "water" })
系统:→ 生成确认卡片
    ┌─────────────────────────────┐
    │ 确认创建工单                 │
    │ 房号:3-501                 │
    │ 类型:水路维修               │
    │ [确认创建]  [取消]           │
    └─────────────────────────────┘

而查询操作不需要这个步骤——“查我上个月的物业费”,直接出结果就行。

设计 3:防止死循环

第二轮调用时 tools: [] ——AI 不能再调用新工具了。防止这种无限循环:

用户:"你好" → AI调用工具A → 结果有问题 → AI调用工具B → 又出问题 → AI调用工具A ...

生产环境中可以放宽到最多 3 轮工具调用,但必须有上限。


四、前端渲染:卡片 vs 纯文本

工具调用返回的结构化数据,前端需要根据类型渲染不同组件:

function buildCard(toolResults: ToolResult[]): CardData | null {
  const lastResult = toolResults[toolResults.length - 1]
 
  // 工单查询 → 工单卡片
  if (lastResult.type === 'work_order') {
    return {
      component: 'WorkOrderCard',
      props: { orders: lastResult.data }
    }
  }
 
  // 财务查询 → 账单汇总卡片
  if (lastResult.type === 'bill') {
    return {
      component: 'BillSummaryCard',
      props: { bills: lastResult.data }
    }
  }
 
  return null  // 纯文本回复,不渲染卡片
}

比如查物业费的结果不是一串文字,而是一张带样式的账单卡片——这比纯文本回复的体验好太多。


五、与RAG互补的两个系统

做完整套 Agent 系统后,我意识到它和 RAG(检索增强生成)是互补关系:

Agent Tool UseRAG
解决的问题AI 操作业务系统AI 查询知识库
数据来源数据库实时查询文档库向量检索
典型场景“查我的工单”“创建报修”“物业管理规定是什么”“停车收费标准”
系统复杂度高(需要工具注册+权限+校验)中(需要文档处理+向量库)

一个完整的 AI 对话系统需要两者配合:用户问操作类问题走 Agent,问知识类问题走 RAG。


六、总结

AgentToolUse 把一个"会聊天的 AI"变成了"能干活的 AI"。三个核心工程问题:

  1. 工具注册 :用结构化元数据描述每个工具,让 AI 理解何时调用

  2. 安全控制 :角色白名单 + 读写分离 + 参数校验,三道防线

  3. 前端体验 :结构化数据渲染卡片,比纯文本回复更专业

如果你也在做 AI 业务落地,建议先从一个工具开始(比如"工单查询"),跑通整个循环后再扩展到更多工具。一口吃不成胖子,但"工单查询→自然语言回答"这条路跑通,你就理解了 Agent 的内核。