
摘要模型光会聊天不够得能查订单、查库存、算折扣。Tool把外部能力包装成模型可调用的函数Agent根据问题自动决定调哪个、怎么调。本文讲tool定义、多工具Agent、以及一个完整的电商客服Agent案例。一、为什么需要Tool用户问订单A1001什么状态模型不知道因为它没接订单系统。正确流程模型识别需要查订单→调用订单查询工具→拿到结果→回复用户。Tool就是把这个流程标准化把外部能力包装成模型可以调用的函数包括名称、参数说明、功能描述模型根据这些信息决定什么时候调用、传什么参数。二、Tool和普通函数的区别普通函数只管干活Tool多了模型需要的信息工具名称模型识别用参数类型知道传什么工具描述知道什么时候用返回值工具返回给模型的数据三、定义第一个Tool用tool装饰器把函数变成工具pythonfrom langchain.tools import tool tool def get_order_status(order_id: str) - str: 根据订单号查询订单状态支持A开头订单 status_map { A1001: 已发货预计后天送达, A1002: 已签收, A1003: 待支付 } return status_map.get(order_id, 未找到该订单)工具名称默认是函数名docstring自动变成工具描述类型注解告诉模型参数类型。查看工具信息pythonprint(f名称{get_order_status.name}) print(f描述{get_order_status.description}) print(f参数{get_order_status.args})四、手动调用Toolpythonresult get_order_status.invoke({order_id: A1001}) print(result) # 已发货预计后天送达先手动测通工具再交给Agent用排查问题时能分清是工具本身的问题还是Agent调度的问题。五、工具描述要写清楚模型完全靠名称和描述决定用不用工具。不推荐pythontool def calc(a: float, b: float) - float: 计算 return a * b推荐pythontool def calculate_discount(price: float, discount_rate: float) - float: 计算商品打折后的价格discount_rate是折扣率如0.8表示八折 return price * discount_rate名称用英文小写加下划线兼容性更好。六、多参数Toolpythonfrom langchain.tools import tool tool def get_inventory(product_id: str, warehouse: str 北京) - str: 查询商品库存product_id商品编号warehouse仓库名称 inventory { P1001: {北京: 100, 上海: 200}, P1002: {北京: 50, 上海: 30} } stock inventory.get(product_id, {}).get(warehouse, 0) return f商品{product_id}在{warehouse}仓库库存为{stock}件参数类型和默认值都会暴露给模型。七、用Pydantic描述参数参数多了以后用Pydantic让字段说明更清楚pythonfrom pydantic import BaseModel, Field class InventoryInput(BaseModel): product_id: str Field(description商品编号以P开头) warehouse: str Field(description仓库名称可选北京/上海/广州) tool(args_schemaInventoryInput) def get_inventory(product_id: str, warehouse: str 北京) - str: 查询商品库存 inventory {P1001: {北京: 100, 上海: 200}} stock inventory.get(product_id, {}).get(warehouse, 0) return f商品{product_id}在{warehouse}仓库库存为{stock}件Field(description...)让模型更清楚每个字段的含义。还可以加校验pythonclass InventoryInput(BaseModel): product_id: str Field(description商品编号以P开头) warehouse: str Field(description仓库名称, pattern^(北京|上海|广州)$)传郑州会直接报错。八、什么是AgentAgent会自己判断用户的问题要不要调用工具调哪个参数怎么填调完结果怎么回复普通Chain是固定流程Prompt→模型→Parser。Agent是动态循环模型判断→调工具→拿到结果→再判断→直到完成。Agent核心三件事感知接收问题、思考判断要不要调工具、调哪个、行动执行工具调用。九、Agent、Tool、Harness的关系Model是大脑只会思考决策不会自己动手。Harnesscreate_agent是管家负责调度循环把工具信息给模型、接收模型发起的工具调用、执行工具、把结果交回模型。Tool是具体干活的方法。Agent Model Harness。十、安装依赖bashpip install langchain langchain-openai python-dotenv十一、创建第一个Agentpythonfrom langchain.agents import create_agent from langchain.tools import tool from utils.model_factory import get_deepseek_model tool def get_current_time() - str: 获取当前日期和时间 from datetime import datetime return datetime.now().strftime(%Y-%m-%d %H:%M:%S) model get_deepseek_model(temperature0.1) agent create_agent(modelmodel, tools[get_current_time]) result agent.invoke({messages: [(user, 现在几点了)]}) print(result[messages][-1].content)create_agent把模型和工具组合在一起Agent会根据问题自动决定是否调用工具。查看完整消息流程pythonfor msg in result[messages]: print(f{msg.__class__.__name__}: {msg.content[:100]})能看到模型发起工具调用、工具返回结果、模型给出最终回答的完整循环。十二、多工具Agent多个工具传给Agent它会根据问题自动选择pythonfrom langchain.agents import create_agent from langchain.tools import tool tool def get_order_status(order_id: str) - str: 根据订单号查询订单状态 status_map {A1001: 已发货, A1002: 已签收} return status_map.get(order_id, 未找到订单) tool def get_inventory(product_id: str) - str: 查询商品库存 inventory {P1001: 100, P1002: 50} return f商品{product_id}库存{inventory.get(product_id, 0)}件 tool def calculate_discount(price: float, rate: float) - str: 计算折扣价rate为折扣率 return f折扣价{price * rate:.2f}元 model get_deepseek_model(temperature0.1) agent create_agent(modelmodel, tools[get_order_status, get_inventory, calculate_discount]) questions [ 订单A1001什么状态, P1002还有库存吗, 299元打八折是多少 ] for q in questions: result agent.invoke({messages: [(user, q)]}) print(f问题{q}) print(f回答{result[messages][-1].content}\n)Agent自动选工具不用人工判断。十三、企业案例电商客服Agent项目结构texttools.py # 业务工具 customer_agent.py # Agent创建 main.py # 终端交互tools.pypythonfrom langchain.tools import tool from datetime import datetime # 模拟数据 orders { A1001: {status: 已发货, 物流: 中通快递 123456, 时间: 2025-01-15}, A1002: {status: 已签收, 物流: 顺丰快递 789012, 时间: 2025-01-14}, A1003: {status: 待支付, 物流: 未发货, 时间: 2025-01-16} } inventory { P1001: 100, P1002: 0, P1003: 50 } refund_rules { 7天无理由: 签收后7天内可无理由退货, 质量问题: 15天内质量问题可退换, 已发货: 已发货订单需拒收后才能退款 } tool def query_order(order_id: str) - str: 查询订单状态参数为订单编号 order orders.get(order_id) if not order: return f未找到订单{order_id} return f订单{order_id}状态{order[status]}物流{order[物流]} tool def check_stock(product_id: str) - str: 查询商品库存参数为商品编号 stock inventory.get(product_id, -1) if stock -1: return f未找到商品{product_id} if stock 0: return f商品{product_id}已缺货 return f商品{product_id}剩余库存{stock}件 tool def get_refund_policy(order_id: str) - str: 查询退款政策参数为订单编号 order orders.get(order_id) if not order: return f未找到订单{order_id} status order[status] if status 已签收: return f订单{order_id}已签收适用规则{refund_rules[7天无理由]}{refund_rules[质量问题]} elif status 已发货: return f订单{order_id}已发货需拒收后申请退款 else: return f订单{order_id}未发货可直接取消订单 tool def calc_discount(amount: float, rate: float) - str: 计算优惠价格amount原价rate折扣率0-1之间 if not (0 rate 1): return 折扣率应在0到1之间 return f原价{amount}元折扣率{rate}优惠后{amount * rate:.2f}元customer_agent.pypythonfrom langchain.agents import create_agent from utils.model_factory import get_deepseek_model from tools import query_order, check_stock, get_refund_policy, calc_discount def create_customer_agent(): model get_deepseek_model(temperature0.1) tools [query_order, check_stock, get_refund_policy, calc_discount] return create_agent(modelmodel, toolstools)main.pypythonfrom customer_agent import create_customer_agent agent create_customer_agent() print(电商客服Agent已启动输入exit退出) while True: question input(\n用户).strip() if question.lower() exit: break if not question: continue result agent.invoke({messages: [(user, question)]}) answer result[messages][-1].content print(f客服{answer})测试用户订单A1001现在什么情况客服订单A1001状态已发货物流中通快递 123456用户P1002有货吗客服商品P1002已缺货用户订单A1001怎么退款客服订单A1001已发货需拒收后申请退款用户299的东西打7折多少钱客服原价299元折扣率0.7优惠后209.30元Agent自动识别意图、选工具、填参数、生成回复。十四、查看工具调用过程pythonresult agent.invoke({messages: [(user, 订单A1001什么状态)]}) for msg in result[messages]: msg_type msg.__class__.__name__ if msg_type ToolMessage: print(f[工具返回] {msg.content}) elif hasattr(msg, tool_calls) and msg.tool_calls: for tc in msg.tool_calls: print(f[调用工具] {tc[name]}({tc[args]})) else: print(f[{msg_type}] {msg.content[:50]})能看到用户消息→模型发起工具调用→工具返回→模型最终回答。如果Agent没调预期工具查工具名称、描述、参数类型是否准确。十五、工具设计原则职责单一。一个工具只做一件事不要搞大杂烩。返回结果要清楚。返回订单A1001状态已发货而不是成功。内部做参数校验。折扣率要检查范围订单号要检查格式。高风险操作要谨慎。查询类工具风险低写入类修改数据库、扣库存必须加权限校验和人工确认。十六、Agent适合什么场景任务步骤不固定的场景客服助手问题类型多变、数据分析助手查指标、算指标、解释、运维助手查日志、查状态。流程固定的场景用普通Chain就够了比如商品信息→生成文案没必要上Agent。常见问题工具docstring重要吗非常重要。模型靠它判断什么时候用工具。描述模糊模型可能不用或用错。Agent没调工具可能原因问题不需要工具、描述不清楚、参数缺失、模型判断直接回答更合适。Agent调错工具工具描述有重叠。把查询订单状态和查询订单物流区分清楚不要都写成查询订单信息。Tool能连数据库吗可以。Tool本质是Python函数内部可以查数据库、调HTTP接口、读文件、跑RAG检索。