{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# 读取环境变量\n", "from dotenv import load_dotenv\n", "load_dotenv() # 加载 .env 文件" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from langsmith import traceable" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# 使用通义千问\n", "from langchain_community.llms import Tongyi\n", "\n", "import os\n", "\n", "# 初始化通义模型(以qwen-max为例)\n", "llm_tongyi = Tongyi(\n", " model_name=\"qwen-turbo\",\n", " dashscope_api_key=os.getenv(\"DASHSCOPE_API_KEY\")\n", ")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from typing import Callable, List, Dict, Any\n", "import inspect\n", "\n", "@traceable\n", "def build_tool_prompt(tools: List[Callable], user_input: str) -> str:\n", " \"\"\"\n", " 构造多工具调用提示,用于引导模型调用正确工具。\n", " \"\"\"\n", " tool_descriptions = []\n", " for tool in tools:\n", " sig = inspect.signature(tool)\n", " params = \", \".join(f\"{name}: {param.annotation.__name__}\"\n", " for name, param in sig.parameters.items())\n", " doc = inspect.getdoc(tool) or \"无描述\"\n", " tool_descriptions.append(f\"\"\"工具名:{tool.__name__}\n", "描述:{doc}\n", "参数:{params}\n", "\"\"\")\n", " \n", " tool_block = \"\\n\\n\".join(tool_descriptions)\n", " prompt = f\"\"\"\n", "你是一个助手,有以下工具可以调用:\n", "\n", "{tool_block}\n", "\n", "请根据用户请求,选择最合适的工具,并以如下格式返回调用指令(请使用英文括号):\n", "调用:<工具名>(参数名1=值1, 参数名2=值2)\n", "\n", "如果不需要调用任何工具,请回复:无需调用工具\n", "\n", "用户请求:{user_input}\n", "\"\"\"\n", " return prompt\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# 示例工具\n", "@traceable\n", "def multiply(a: int, b: int) -> int:\n", " \"\"\"两个整数相乘\"\"\"\n", " return a * b\n", "\n", "@traceable\n", "def add(a: int, b: int) -> int:\n", " \"\"\"两个整数相加\"\"\"\n", " return a + b\n", "\n", "TOOLS = [multiply, add]\n", "TOOL_MAP = {fn.__name__: fn for fn in TOOLS}\n", "\n", "# 用户输入\n", "user_input = \"23和34的和是多少\"\n", "\n", "# 构造提示并调用模型\n", "prompt = build_tool_prompt(TOOLS, user_input)\n", "response = llm_tongyi.invoke(prompt)\n", "\n", "print(\"🔍 模型响应:\", response)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import re\n", "\n", "@traceable\n", "def extract_tool_call(response: str) -> Dict[str, Any]:\n", " \"\"\"\n", " 从模型响应中提取工具调用命令。\n", " 返回格式:{ \"tool_name\": str, \"args\": dict }\n", " \"\"\"\n", " pattern = r\"调用:(\\w+)\\((.*?)\\)\"\n", " match = re.search(pattern, response)\n", " if not match:\n", " return {}\n", " \n", " tool_name, args_str = match.groups()\n", " args = {}\n", " for part in args_str.split(\",\"):\n", " if \"=\" in part:\n", " key, value = part.split(\"=\")\n", " key = key.strip()\n", " value = value.strip()\n", " try:\n", " value = eval(value) # 小心执行不可信输入\n", " except:\n", " pass\n", " args[key] = value\n", " return {\"tool_name\": tool_name, \"args\": args}" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# 解析调用\n", "tool_call = extract_tool_call(response)\n", "if tool_call:\n", " tool_fn = TOOL_MAP.get(tool_call[\"tool_name\"])\n", " if tool_fn:\n", " result = tool_fn(**tool_call[\"args\"])\n", " print(\"✅ 工具执行结果:\", result)\n", " else:\n", " print(\"⚠️ 未知工具:\", tool_call[\"tool_name\"])\n", "else:\n", " print(\"ℹ️ 模型未调用任何工具\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(tool_call)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.3" } }, "nbformat": 4, "nbformat_minor": 4 }