[{"data":1,"prerenderedAt":1091},["ShallowReactive",2],{"article-agent\u002F01-single-tool":3},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"date":10,"tags":11,"body":14,"_type":1085,"_id":1086,"_source":1087,"_file":1088,"_stem":1089,"_extension":1090},"\u002Farticles\u002Fagent\u002F01-single-tool","agent",false,"","01-Function Calling 入门：单工具单次调用","从零理解 Function Calling 的完整流程——模型只负责决策和输出参数，真正执行函数的是你自己的代码。通过单工具天气查询示例，掌握工具调用的三步闭环。","2026-06-10",[12,13],"Agent开发","人工智能",{"type":15,"children":16,"toc":1082},"root",[17,25,1076],{"type":18,"tag":19,"props":20,"children":22},"element","h3",{"id":21},"直接看代码注释",[23],{"type":24,"value":21},"text",{"type":18,"tag":26,"props":27,"children":31},"pre",{"className":28,"code":29,"language":30,"meta":7,"style":7},"language-python shiki shiki-themes github-dark","\"\"\"练习 1：Function Calling —— 单工具、单次调用\n\n本练习只想说明一件事：\n    模型【不会】执行函数。它只负责【决定要不要调用】以及【吐出参数】，\n    真正去执行 get_weather() 的，是下面我们自己写的 Python 代码。\n\n一次完整的工具调用包含三步：\n    1) 我们把「问题 + 工具说明」发给模型；\n    2) 模型回一个 tool_call（函数名 + JSON 参数），它自己不执行；\n    3) 我们用这些参数真正运行函数，把结果再发回给模型，让它说人话。\n\n云服务用 DeepSeek（OpenAI 兼容接口），密钥\u002F地址\u002F模型名都在根目录 .env：\n    DEEPSEEK_API_KEY、DEEPSEEK_BASE_URL、MODEL\n\"\"\"\n\nimport json\nimport os\n\nfrom dotenv import load_dotenv\nfrom openai import OpenAI\n\n# 从根目录 .env 读取配置\nload_dotenv()\n\nclient = OpenAI(\n    api_key=os.environ[\"DEEPSEEK_API_KEY\"],\n    base_url=os.environ[\"DEEPSEEK_BASE_URL\"],\n)\nMODEL = os.environ[\"MODEL\"]\n\n\n# ── 第 1 步：我们的「手」——一个真实的本地函数 ────────────────────────────\n# 这就是会被真正执行的代码。这里用假数据，重点不在天气，而在“谁来执行”。\ndef get_weather(city: str) -> dict:\n    \"\"\"根据城市名返回天气（演示用假数据）。\"\"\"\n    fake_db = {\n        \"北京\": {\"weather\": \"晴\", \"temperature\": 26},\n        \"上海\": {\"weather\": \"多云\", \"temperature\": 24},\n        \"广州\": {\"weather\": \"雷阵雨\", \"temperature\": 30},\n    }\n    return fake_db.get(city, {\"weather\": \"未知\", \"temperature\": None})\n\n\n# ── 第 2 步：工具 schema —— 给模型看的「说明书」 ──────────────────────────\n# 注意 description 写的是【什么时候用】，而不是【做什么】。这是 schema 设计的黄金规则。\nTOOLS = [\n    {\n        \"type\": \"function\",\n        \"function\": {\n            \"name\": \"get_weather\",\n            \"description\": \"当用户询问某个城市当前的天气状况或气温时调用。\",\n            \"parameters\": {\n                \"type\": \"object\",\n                \"properties\": {\n                    \"city\": {\n                        \"type\": \"string\",\n                        \"description\": \"城市名称，例如：北京、上海\",\n                    }\n                },\n                \"required\": [\"city\"],\n            },\n        },\n    }\n]\n\n\ndef run(user_question: str) -> str:\n    \"\"\"跑一遍完整的单工具调用流程，返回模型最终的自然语言回答。\"\"\"\n    messages = [{\"role\": \"user\", \"content\": user_question}]\n\n    # ── 第 3 步：把问题 + 工具说明发给模型，看它要不要调用 ──────────────\n    first = client.chat.completions.create(\n        model=MODEL,\n        messages=messages,\n        tools=TOOLS,\n    )\n    msg = first.choices[0].message\n\n    # 模型决定不调用工具，直接回答（说明这个问题不需要工具）\n    if not msg.tool_calls:\n        print(\"【模型判断】无需工具，直接回答。\")\n        return msg.content\n\n    # ── 第 4 步：模型决定调用，但它只给了「函数名 + 参数」，并没有执行 ──\n    tool_call = msg.tool_calls[0]\n    fn_name = tool_call.function.name\n    fn_args = json.loads(tool_call.function.arguments)  # 模型吐出的 JSON 参数\n    print(f\"【模型决定】调用 {fn_name}，参数 = {fn_args}\")\n\n    # ── 第 5 步：真正执行的是我们的代码，不是模型 ──────────────────────\n    if fn_name == \"get_weather\":\n        result = get_weather(**fn_args)\n    else:\n        result = {\"error\": f\"未知工具 {fn_name}\"}\n    print(f\"【我们执行】{fn_name} 返回 = {result}\")\n\n    # ── 第 6 步：把执行结果发回模型，让它结合结果说人话 ────────────────\n    messages.append(msg)  # 模型刚才那条「我要调用工具」的消息\n    messages.append(\n        {\n            \"role\": \"tool\",\n            \"tool_call_id\": tool_call.id,\n            \"content\": json.dumps(result, ensure_ascii=False),\n        }\n    )\n    second = client.chat.completions.create(\n        model=MODEL,\n        messages=messages,\n        tools=TOOLS,\n    )\n    return second.choices[0].message.content\n\n\nif __name__ == \"__main__\":\n    question = \"北京今天天气怎么样？\"\n    print(f\"【用户提问】{question}\\n\")\n    answer = run(question)\n    print(f\"\\n【最终回答】{answer}\")\n","python",[32],{"type":18,"tag":33,"props":34,"children":35},"code",{"__ignoreMap":7},[36,47,57,66,75,84,92,101,110,119,128,136,145,154,163,171,180,189,197,206,215,223,232,241,249,258,267,276,285,294,302,310,319,328,337,346,355,364,373,382,391,400,408,416,425,434,443,452,461,470,479,488,497,506,515,524,533,542,551,560,569,578,587,595,604,612,620,629,638,647,655,664,673,682,691,700,709,718,726,735,744,753,762,770,779,788,797,806,815,823,832,841,850,859,868,877,885,894,903,912,921,930,939,948,957,965,974,982,990,998,1006,1015,1023,1031,1040,1049,1058,1067],{"type":18,"tag":37,"props":38,"children":41},"span",{"class":39,"line":40},"line",1,[42],{"type":18,"tag":37,"props":43,"children":44},{},[45],{"type":24,"value":46},"\"\"\"练习 1：Function Calling —— 单工具、单次调用\n",{"type":18,"tag":37,"props":48,"children":50},{"class":39,"line":49},2,[51],{"type":18,"tag":37,"props":52,"children":54},{"emptyLinePlaceholder":53},true,[55],{"type":24,"value":56},"\n",{"type":18,"tag":37,"props":58,"children":60},{"class":39,"line":59},3,[61],{"type":18,"tag":37,"props":62,"children":63},{},[64],{"type":24,"value":65},"本练习只想说明一件事：\n",{"type":18,"tag":37,"props":67,"children":69},{"class":39,"line":68},4,[70],{"type":18,"tag":37,"props":71,"children":72},{},[73],{"type":24,"value":74},"    模型【不会】执行函数。它只负责【决定要不要调用】以及【吐出参数】，\n",{"type":18,"tag":37,"props":76,"children":78},{"class":39,"line":77},5,[79],{"type":18,"tag":37,"props":80,"children":81},{},[82],{"type":24,"value":83},"    真正去执行 get_weather() 的，是下面我们自己写的 Python 代码。\n",{"type":18,"tag":37,"props":85,"children":87},{"class":39,"line":86},6,[88],{"type":18,"tag":37,"props":89,"children":90},{"emptyLinePlaceholder":53},[91],{"type":24,"value":56},{"type":18,"tag":37,"props":93,"children":95},{"class":39,"line":94},7,[96],{"type":18,"tag":37,"props":97,"children":98},{},[99],{"type":24,"value":100},"一次完整的工具调用包含三步：\n",{"type":18,"tag":37,"props":102,"children":104},{"class":39,"line":103},8,[105],{"type":18,"tag":37,"props":106,"children":107},{},[108],{"type":24,"value":109},"    1) 我们把「问题 + 工具说明」发给模型；\n",{"type":18,"tag":37,"props":111,"children":113},{"class":39,"line":112},9,[114],{"type":18,"tag":37,"props":115,"children":116},{},[117],{"type":24,"value":118},"    2) 模型回一个 tool_call（函数名 + JSON 参数），它自己不执行；\n",{"type":18,"tag":37,"props":120,"children":122},{"class":39,"line":121},10,[123],{"type":18,"tag":37,"props":124,"children":125},{},[126],{"type":24,"value":127},"    3) 我们用这些参数真正运行函数，把结果再发回给模型，让它说人话。\n",{"type":18,"tag":37,"props":129,"children":131},{"class":39,"line":130},11,[132],{"type":18,"tag":37,"props":133,"children":134},{"emptyLinePlaceholder":53},[135],{"type":24,"value":56},{"type":18,"tag":37,"props":137,"children":139},{"class":39,"line":138},12,[140],{"type":18,"tag":37,"props":141,"children":142},{},[143],{"type":24,"value":144},"云服务用 DeepSeek（OpenAI 兼容接口），密钥\u002F地址\u002F模型名都在根目录 .env：\n",{"type":18,"tag":37,"props":146,"children":148},{"class":39,"line":147},13,[149],{"type":18,"tag":37,"props":150,"children":151},{},[152],{"type":24,"value":153},"    DEEPSEEK_API_KEY、DEEPSEEK_BASE_URL、MODEL\n",{"type":18,"tag":37,"props":155,"children":157},{"class":39,"line":156},14,[158],{"type":18,"tag":37,"props":159,"children":160},{},[161],{"type":24,"value":162},"\"\"\"\n",{"type":18,"tag":37,"props":164,"children":166},{"class":39,"line":165},15,[167],{"type":18,"tag":37,"props":168,"children":169},{"emptyLinePlaceholder":53},[170],{"type":24,"value":56},{"type":18,"tag":37,"props":172,"children":174},{"class":39,"line":173},16,[175],{"type":18,"tag":37,"props":176,"children":177},{},[178],{"type":24,"value":179},"import json\n",{"type":18,"tag":37,"props":181,"children":183},{"class":39,"line":182},17,[184],{"type":18,"tag":37,"props":185,"children":186},{},[187],{"type":24,"value":188},"import os\n",{"type":18,"tag":37,"props":190,"children":192},{"class":39,"line":191},18,[193],{"type":18,"tag":37,"props":194,"children":195},{"emptyLinePlaceholder":53},[196],{"type":24,"value":56},{"type":18,"tag":37,"props":198,"children":200},{"class":39,"line":199},19,[201],{"type":18,"tag":37,"props":202,"children":203},{},[204],{"type":24,"value":205},"from dotenv import load_dotenv\n",{"type":18,"tag":37,"props":207,"children":209},{"class":39,"line":208},20,[210],{"type":18,"tag":37,"props":211,"children":212},{},[213],{"type":24,"value":214},"from openai import OpenAI\n",{"type":18,"tag":37,"props":216,"children":218},{"class":39,"line":217},21,[219],{"type":18,"tag":37,"props":220,"children":221},{"emptyLinePlaceholder":53},[222],{"type":24,"value":56},{"type":18,"tag":37,"props":224,"children":226},{"class":39,"line":225},22,[227],{"type":18,"tag":37,"props":228,"children":229},{},[230],{"type":24,"value":231},"# 从根目录 .env 读取配置\n",{"type":18,"tag":37,"props":233,"children":235},{"class":39,"line":234},23,[236],{"type":18,"tag":37,"props":237,"children":238},{},[239],{"type":24,"value":240},"load_dotenv()\n",{"type":18,"tag":37,"props":242,"children":244},{"class":39,"line":243},24,[245],{"type":18,"tag":37,"props":246,"children":247},{"emptyLinePlaceholder":53},[248],{"type":24,"value":56},{"type":18,"tag":37,"props":250,"children":252},{"class":39,"line":251},25,[253],{"type":18,"tag":37,"props":254,"children":255},{},[256],{"type":24,"value":257},"client = OpenAI(\n",{"type":18,"tag":37,"props":259,"children":261},{"class":39,"line":260},26,[262],{"type":18,"tag":37,"props":263,"children":264},{},[265],{"type":24,"value":266},"    api_key=os.environ[\"DEEPSEEK_API_KEY\"],\n",{"type":18,"tag":37,"props":268,"children":270},{"class":39,"line":269},27,[271],{"type":18,"tag":37,"props":272,"children":273},{},[274],{"type":24,"value":275},"    base_url=os.environ[\"DEEPSEEK_BASE_URL\"],\n",{"type":18,"tag":37,"props":277,"children":279},{"class":39,"line":278},28,[280],{"type":18,"tag":37,"props":281,"children":282},{},[283],{"type":24,"value":284},")\n",{"type":18,"tag":37,"props":286,"children":288},{"class":39,"line":287},29,[289],{"type":18,"tag":37,"props":290,"children":291},{},[292],{"type":24,"value":293},"MODEL = os.environ[\"MODEL\"]\n",{"type":18,"tag":37,"props":295,"children":297},{"class":39,"line":296},30,[298],{"type":18,"tag":37,"props":299,"children":300},{"emptyLinePlaceholder":53},[301],{"type":24,"value":56},{"type":18,"tag":37,"props":303,"children":305},{"class":39,"line":304},31,[306],{"type":18,"tag":37,"props":307,"children":308},{"emptyLinePlaceholder":53},[309],{"type":24,"value":56},{"type":18,"tag":37,"props":311,"children":313},{"class":39,"line":312},32,[314],{"type":18,"tag":37,"props":315,"children":316},{},[317],{"type":24,"value":318},"# ── 第 1 步：我们的「手」——一个真实的本地函数 ────────────────────────────\n",{"type":18,"tag":37,"props":320,"children":322},{"class":39,"line":321},33,[323],{"type":18,"tag":37,"props":324,"children":325},{},[326],{"type":24,"value":327},"# 这就是会被真正执行的代码。这里用假数据，重点不在天气，而在“谁来执行”。\n",{"type":18,"tag":37,"props":329,"children":331},{"class":39,"line":330},34,[332],{"type":18,"tag":37,"props":333,"children":334},{},[335],{"type":24,"value":336},"def get_weather(city: str) -> dict:\n",{"type":18,"tag":37,"props":338,"children":340},{"class":39,"line":339},35,[341],{"type":18,"tag":37,"props":342,"children":343},{},[344],{"type":24,"value":345},"    \"\"\"根据城市名返回天气（演示用假数据）。\"\"\"\n",{"type":18,"tag":37,"props":347,"children":349},{"class":39,"line":348},36,[350],{"type":18,"tag":37,"props":351,"children":352},{},[353],{"type":24,"value":354},"    fake_db = {\n",{"type":18,"tag":37,"props":356,"children":358},{"class":39,"line":357},37,[359],{"type":18,"tag":37,"props":360,"children":361},{},[362],{"type":24,"value":363},"        \"北京\": {\"weather\": \"晴\", \"temperature\": 26},\n",{"type":18,"tag":37,"props":365,"children":367},{"class":39,"line":366},38,[368],{"type":18,"tag":37,"props":369,"children":370},{},[371],{"type":24,"value":372},"        \"上海\": {\"weather\": \"多云\", \"temperature\": 24},\n",{"type":18,"tag":37,"props":374,"children":376},{"class":39,"line":375},39,[377],{"type":18,"tag":37,"props":378,"children":379},{},[380],{"type":24,"value":381},"        \"广州\": {\"weather\": \"雷阵雨\", \"temperature\": 30},\n",{"type":18,"tag":37,"props":383,"children":385},{"class":39,"line":384},40,[386],{"type":18,"tag":37,"props":387,"children":388},{},[389],{"type":24,"value":390},"    }\n",{"type":18,"tag":37,"props":392,"children":394},{"class":39,"line":393},41,[395],{"type":18,"tag":37,"props":396,"children":397},{},[398],{"type":24,"value":399},"    return fake_db.get(city, {\"weather\": \"未知\", \"temperature\": None})\n",{"type":18,"tag":37,"props":401,"children":403},{"class":39,"line":402},42,[404],{"type":18,"tag":37,"props":405,"children":406},{"emptyLinePlaceholder":53},[407],{"type":24,"value":56},{"type":18,"tag":37,"props":409,"children":411},{"class":39,"line":410},43,[412],{"type":18,"tag":37,"props":413,"children":414},{"emptyLinePlaceholder":53},[415],{"type":24,"value":56},{"type":18,"tag":37,"props":417,"children":419},{"class":39,"line":418},44,[420],{"type":18,"tag":37,"props":421,"children":422},{},[423],{"type":24,"value":424},"# ── 第 2 步：工具 schema —— 给模型看的「说明书」 ──────────────────────────\n",{"type":18,"tag":37,"props":426,"children":428},{"class":39,"line":427},45,[429],{"type":18,"tag":37,"props":430,"children":431},{},[432],{"type":24,"value":433},"# 注意 description 写的是【什么时候用】，而不是【做什么】。这是 schema 设计的黄金规则。\n",{"type":18,"tag":37,"props":435,"children":437},{"class":39,"line":436},46,[438],{"type":18,"tag":37,"props":439,"children":440},{},[441],{"type":24,"value":442},"TOOLS = [\n",{"type":18,"tag":37,"props":444,"children":446},{"class":39,"line":445},47,[447],{"type":18,"tag":37,"props":448,"children":449},{},[450],{"type":24,"value":451},"    {\n",{"type":18,"tag":37,"props":453,"children":455},{"class":39,"line":454},48,[456],{"type":18,"tag":37,"props":457,"children":458},{},[459],{"type":24,"value":460},"        \"type\": \"function\",\n",{"type":18,"tag":37,"props":462,"children":464},{"class":39,"line":463},49,[465],{"type":18,"tag":37,"props":466,"children":467},{},[468],{"type":24,"value":469},"        \"function\": {\n",{"type":18,"tag":37,"props":471,"children":473},{"class":39,"line":472},50,[474],{"type":18,"tag":37,"props":475,"children":476},{},[477],{"type":24,"value":478},"            \"name\": \"get_weather\",\n",{"type":18,"tag":37,"props":480,"children":482},{"class":39,"line":481},51,[483],{"type":18,"tag":37,"props":484,"children":485},{},[486],{"type":24,"value":487},"            \"description\": \"当用户询问某个城市当前的天气状况或气温时调用。\",\n",{"type":18,"tag":37,"props":489,"children":491},{"class":39,"line":490},52,[492],{"type":18,"tag":37,"props":493,"children":494},{},[495],{"type":24,"value":496},"            \"parameters\": {\n",{"type":18,"tag":37,"props":498,"children":500},{"class":39,"line":499},53,[501],{"type":18,"tag":37,"props":502,"children":503},{},[504],{"type":24,"value":505},"                \"type\": \"object\",\n",{"type":18,"tag":37,"props":507,"children":509},{"class":39,"line":508},54,[510],{"type":18,"tag":37,"props":511,"children":512},{},[513],{"type":24,"value":514},"                \"properties\": {\n",{"type":18,"tag":37,"props":516,"children":518},{"class":39,"line":517},55,[519],{"type":18,"tag":37,"props":520,"children":521},{},[522],{"type":24,"value":523},"                    \"city\": {\n",{"type":18,"tag":37,"props":525,"children":527},{"class":39,"line":526},56,[528],{"type":18,"tag":37,"props":529,"children":530},{},[531],{"type":24,"value":532},"                        \"type\": \"string\",\n",{"type":18,"tag":37,"props":534,"children":536},{"class":39,"line":535},57,[537],{"type":18,"tag":37,"props":538,"children":539},{},[540],{"type":24,"value":541},"                        \"description\": \"城市名称，例如：北京、上海\",\n",{"type":18,"tag":37,"props":543,"children":545},{"class":39,"line":544},58,[546],{"type":18,"tag":37,"props":547,"children":548},{},[549],{"type":24,"value":550},"                    }\n",{"type":18,"tag":37,"props":552,"children":554},{"class":39,"line":553},59,[555],{"type":18,"tag":37,"props":556,"children":557},{},[558],{"type":24,"value":559},"                },\n",{"type":18,"tag":37,"props":561,"children":563},{"class":39,"line":562},60,[564],{"type":18,"tag":37,"props":565,"children":566},{},[567],{"type":24,"value":568},"                \"required\": [\"city\"],\n",{"type":18,"tag":37,"props":570,"children":572},{"class":39,"line":571},61,[573],{"type":18,"tag":37,"props":574,"children":575},{},[576],{"type":24,"value":577},"            },\n",{"type":18,"tag":37,"props":579,"children":581},{"class":39,"line":580},62,[582],{"type":18,"tag":37,"props":583,"children":584},{},[585],{"type":24,"value":586},"        },\n",{"type":18,"tag":37,"props":588,"children":590},{"class":39,"line":589},63,[591],{"type":18,"tag":37,"props":592,"children":593},{},[594],{"type":24,"value":390},{"type":18,"tag":37,"props":596,"children":598},{"class":39,"line":597},64,[599],{"type":18,"tag":37,"props":600,"children":601},{},[602],{"type":24,"value":603},"]\n",{"type":18,"tag":37,"props":605,"children":607},{"class":39,"line":606},65,[608],{"type":18,"tag":37,"props":609,"children":610},{"emptyLinePlaceholder":53},[611],{"type":24,"value":56},{"type":18,"tag":37,"props":613,"children":615},{"class":39,"line":614},66,[616],{"type":18,"tag":37,"props":617,"children":618},{"emptyLinePlaceholder":53},[619],{"type":24,"value":56},{"type":18,"tag":37,"props":621,"children":623},{"class":39,"line":622},67,[624],{"type":18,"tag":37,"props":625,"children":626},{},[627],{"type":24,"value":628},"def run(user_question: str) -> str:\n",{"type":18,"tag":37,"props":630,"children":632},{"class":39,"line":631},68,[633],{"type":18,"tag":37,"props":634,"children":635},{},[636],{"type":24,"value":637},"    \"\"\"跑一遍完整的单工具调用流程，返回模型最终的自然语言回答。\"\"\"\n",{"type":18,"tag":37,"props":639,"children":641},{"class":39,"line":640},69,[642],{"type":18,"tag":37,"props":643,"children":644},{},[645],{"type":24,"value":646},"    messages = [{\"role\": \"user\", \"content\": user_question}]\n",{"type":18,"tag":37,"props":648,"children":650},{"class":39,"line":649},70,[651],{"type":18,"tag":37,"props":652,"children":653},{"emptyLinePlaceholder":53},[654],{"type":24,"value":56},{"type":18,"tag":37,"props":656,"children":658},{"class":39,"line":657},71,[659],{"type":18,"tag":37,"props":660,"children":661},{},[662],{"type":24,"value":663},"    # ── 第 3 步：把问题 + 工具说明发给模型，看它要不要调用 ──────────────\n",{"type":18,"tag":37,"props":665,"children":667},{"class":39,"line":666},72,[668],{"type":18,"tag":37,"props":669,"children":670},{},[671],{"type":24,"value":672},"    first = client.chat.completions.create(\n",{"type":18,"tag":37,"props":674,"children":676},{"class":39,"line":675},73,[677],{"type":18,"tag":37,"props":678,"children":679},{},[680],{"type":24,"value":681},"        model=MODEL,\n",{"type":18,"tag":37,"props":683,"children":685},{"class":39,"line":684},74,[686],{"type":18,"tag":37,"props":687,"children":688},{},[689],{"type":24,"value":690},"        messages=messages,\n",{"type":18,"tag":37,"props":692,"children":694},{"class":39,"line":693},75,[695],{"type":18,"tag":37,"props":696,"children":697},{},[698],{"type":24,"value":699},"        tools=TOOLS,\n",{"type":18,"tag":37,"props":701,"children":703},{"class":39,"line":702},76,[704],{"type":18,"tag":37,"props":705,"children":706},{},[707],{"type":24,"value":708},"    )\n",{"type":18,"tag":37,"props":710,"children":712},{"class":39,"line":711},77,[713],{"type":18,"tag":37,"props":714,"children":715},{},[716],{"type":24,"value":717},"    msg = first.choices[0].message\n",{"type":18,"tag":37,"props":719,"children":721},{"class":39,"line":720},78,[722],{"type":18,"tag":37,"props":723,"children":724},{"emptyLinePlaceholder":53},[725],{"type":24,"value":56},{"type":18,"tag":37,"props":727,"children":729},{"class":39,"line":728},79,[730],{"type":18,"tag":37,"props":731,"children":732},{},[733],{"type":24,"value":734},"    # 模型决定不调用工具，直接回答（说明这个问题不需要工具）\n",{"type":18,"tag":37,"props":736,"children":738},{"class":39,"line":737},80,[739],{"type":18,"tag":37,"props":740,"children":741},{},[742],{"type":24,"value":743},"    if not msg.tool_calls:\n",{"type":18,"tag":37,"props":745,"children":747},{"class":39,"line":746},81,[748],{"type":18,"tag":37,"props":749,"children":750},{},[751],{"type":24,"value":752},"        print(\"【模型判断】无需工具，直接回答。\")\n",{"type":18,"tag":37,"props":754,"children":756},{"class":39,"line":755},82,[757],{"type":18,"tag":37,"props":758,"children":759},{},[760],{"type":24,"value":761},"        return msg.content\n",{"type":18,"tag":37,"props":763,"children":765},{"class":39,"line":764},83,[766],{"type":18,"tag":37,"props":767,"children":768},{"emptyLinePlaceholder":53},[769],{"type":24,"value":56},{"type":18,"tag":37,"props":771,"children":773},{"class":39,"line":772},84,[774],{"type":18,"tag":37,"props":775,"children":776},{},[777],{"type":24,"value":778},"    # ── 第 4 步：模型决定调用，但它只给了「函数名 + 参数」，并没有执行 ──\n",{"type":18,"tag":37,"props":780,"children":782},{"class":39,"line":781},85,[783],{"type":18,"tag":37,"props":784,"children":785},{},[786],{"type":24,"value":787},"    tool_call = msg.tool_calls[0]\n",{"type":18,"tag":37,"props":789,"children":791},{"class":39,"line":790},86,[792],{"type":18,"tag":37,"props":793,"children":794},{},[795],{"type":24,"value":796},"    fn_name = tool_call.function.name\n",{"type":18,"tag":37,"props":798,"children":800},{"class":39,"line":799},87,[801],{"type":18,"tag":37,"props":802,"children":803},{},[804],{"type":24,"value":805},"    fn_args = json.loads(tool_call.function.arguments)  # 模型吐出的 JSON 参数\n",{"type":18,"tag":37,"props":807,"children":809},{"class":39,"line":808},88,[810],{"type":18,"tag":37,"props":811,"children":812},{},[813],{"type":24,"value":814},"    print(f\"【模型决定】调用 {fn_name}，参数 = {fn_args}\")\n",{"type":18,"tag":37,"props":816,"children":818},{"class":39,"line":817},89,[819],{"type":18,"tag":37,"props":820,"children":821},{"emptyLinePlaceholder":53},[822],{"type":24,"value":56},{"type":18,"tag":37,"props":824,"children":826},{"class":39,"line":825},90,[827],{"type":18,"tag":37,"props":828,"children":829},{},[830],{"type":24,"value":831},"    # ── 第 5 步：真正执行的是我们的代码，不是模型 ──────────────────────\n",{"type":18,"tag":37,"props":833,"children":835},{"class":39,"line":834},91,[836],{"type":18,"tag":37,"props":837,"children":838},{},[839],{"type":24,"value":840},"    if fn_name == \"get_weather\":\n",{"type":18,"tag":37,"props":842,"children":844},{"class":39,"line":843},92,[845],{"type":18,"tag":37,"props":846,"children":847},{},[848],{"type":24,"value":849},"        result = get_weather(**fn_args)\n",{"type":18,"tag":37,"props":851,"children":853},{"class":39,"line":852},93,[854],{"type":18,"tag":37,"props":855,"children":856},{},[857],{"type":24,"value":858},"    else:\n",{"type":18,"tag":37,"props":860,"children":862},{"class":39,"line":861},94,[863],{"type":18,"tag":37,"props":864,"children":865},{},[866],{"type":24,"value":867},"        result = {\"error\": f\"未知工具 {fn_name}\"}\n",{"type":18,"tag":37,"props":869,"children":871},{"class":39,"line":870},95,[872],{"type":18,"tag":37,"props":873,"children":874},{},[875],{"type":24,"value":876},"    print(f\"【我们执行】{fn_name} 返回 = {result}\")\n",{"type":18,"tag":37,"props":878,"children":880},{"class":39,"line":879},96,[881],{"type":18,"tag":37,"props":882,"children":883},{"emptyLinePlaceholder":53},[884],{"type":24,"value":56},{"type":18,"tag":37,"props":886,"children":888},{"class":39,"line":887},97,[889],{"type":18,"tag":37,"props":890,"children":891},{},[892],{"type":24,"value":893},"    # ── 第 6 步：把执行结果发回模型，让它结合结果说人话 ────────────────\n",{"type":18,"tag":37,"props":895,"children":897},{"class":39,"line":896},98,[898],{"type":18,"tag":37,"props":899,"children":900},{},[901],{"type":24,"value":902},"    messages.append(msg)  # 模型刚才那条「我要调用工具」的消息\n",{"type":18,"tag":37,"props":904,"children":906},{"class":39,"line":905},99,[907],{"type":18,"tag":37,"props":908,"children":909},{},[910],{"type":24,"value":911},"    messages.append(\n",{"type":18,"tag":37,"props":913,"children":915},{"class":39,"line":914},100,[916],{"type":18,"tag":37,"props":917,"children":918},{},[919],{"type":24,"value":920},"        {\n",{"type":18,"tag":37,"props":922,"children":924},{"class":39,"line":923},101,[925],{"type":18,"tag":37,"props":926,"children":927},{},[928],{"type":24,"value":929},"            \"role\": \"tool\",\n",{"type":18,"tag":37,"props":931,"children":933},{"class":39,"line":932},102,[934],{"type":18,"tag":37,"props":935,"children":936},{},[937],{"type":24,"value":938},"            \"tool_call_id\": tool_call.id,\n",{"type":18,"tag":37,"props":940,"children":942},{"class":39,"line":941},103,[943],{"type":18,"tag":37,"props":944,"children":945},{},[946],{"type":24,"value":947},"            \"content\": json.dumps(result, ensure_ascii=False),\n",{"type":18,"tag":37,"props":949,"children":951},{"class":39,"line":950},104,[952],{"type":18,"tag":37,"props":953,"children":954},{},[955],{"type":24,"value":956},"        }\n",{"type":18,"tag":37,"props":958,"children":960},{"class":39,"line":959},105,[961],{"type":18,"tag":37,"props":962,"children":963},{},[964],{"type":24,"value":708},{"type":18,"tag":37,"props":966,"children":968},{"class":39,"line":967},106,[969],{"type":18,"tag":37,"props":970,"children":971},{},[972],{"type":24,"value":973},"    second = client.chat.completions.create(\n",{"type":18,"tag":37,"props":975,"children":977},{"class":39,"line":976},107,[978],{"type":18,"tag":37,"props":979,"children":980},{},[981],{"type":24,"value":681},{"type":18,"tag":37,"props":983,"children":985},{"class":39,"line":984},108,[986],{"type":18,"tag":37,"props":987,"children":988},{},[989],{"type":24,"value":690},{"type":18,"tag":37,"props":991,"children":993},{"class":39,"line":992},109,[994],{"type":18,"tag":37,"props":995,"children":996},{},[997],{"type":24,"value":699},{"type":18,"tag":37,"props":999,"children":1001},{"class":39,"line":1000},110,[1002],{"type":18,"tag":37,"props":1003,"children":1004},{},[1005],{"type":24,"value":708},{"type":18,"tag":37,"props":1007,"children":1009},{"class":39,"line":1008},111,[1010],{"type":18,"tag":37,"props":1011,"children":1012},{},[1013],{"type":24,"value":1014},"    return second.choices[0].message.content\n",{"type":18,"tag":37,"props":1016,"children":1018},{"class":39,"line":1017},112,[1019],{"type":18,"tag":37,"props":1020,"children":1021},{"emptyLinePlaceholder":53},[1022],{"type":24,"value":56},{"type":18,"tag":37,"props":1024,"children":1026},{"class":39,"line":1025},113,[1027],{"type":18,"tag":37,"props":1028,"children":1029},{"emptyLinePlaceholder":53},[1030],{"type":24,"value":56},{"type":18,"tag":37,"props":1032,"children":1034},{"class":39,"line":1033},114,[1035],{"type":18,"tag":37,"props":1036,"children":1037},{},[1038],{"type":24,"value":1039},"if __name__ == \"__main__\":\n",{"type":18,"tag":37,"props":1041,"children":1043},{"class":39,"line":1042},115,[1044],{"type":18,"tag":37,"props":1045,"children":1046},{},[1047],{"type":24,"value":1048},"    question = \"北京今天天气怎么样？\"\n",{"type":18,"tag":37,"props":1050,"children":1052},{"class":39,"line":1051},116,[1053],{"type":18,"tag":37,"props":1054,"children":1055},{},[1056],{"type":24,"value":1057},"    print(f\"【用户提问】{question}\\n\")\n",{"type":18,"tag":37,"props":1059,"children":1061},{"class":39,"line":1060},117,[1062],{"type":18,"tag":37,"props":1063,"children":1064},{},[1065],{"type":24,"value":1066},"    answer = run(question)\n",{"type":18,"tag":37,"props":1068,"children":1070},{"class":39,"line":1069},118,[1071],{"type":18,"tag":37,"props":1072,"children":1073},{},[1074],{"type":24,"value":1075},"    print(f\"\\n【最终回答】{answer}\")\n",{"type":18,"tag":1077,"props":1078,"children":1079},"style",{},[1080],{"type":24,"value":1081},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":7,"searchDepth":49,"depth":49,"links":1083},[1084],{"id":21,"depth":59,"text":21},"markdown","content:articles:agent:01-single-tool.md","content","articles\u002Fagent\u002F01-single-tool.md","articles\u002Fagent\u002F01-single-tool","md",1781678620540]