ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

阿里 Qwen-Agent 开源框架:用 TaoToken 统一 Key 跑通多工具 Agent 示例

阿里 Qwen-Agent 开源框架:用 TaoToken 统一 Key 跑通多工具 Agent 示例

1. Qwen-Agent 多工具 Agent 到底解决什么问题

Qwen-Agent 是阿里开源的一套 Agent 开发框架,核心能力是把「大模型 + 工具调用 + 代码解释器 + 记忆 + RAG」打包成可复用的组件,让你用几十行 Python 就能跑起一个能画图、能读 PDF、能执行代码的智能体。它适合谁?适合已经会写 Python、想快速验证 Agent 工具链路、但不想从零手搓 function calling 协议的开发者。你不需要先去研究 OpenAI 的 tools schema 怎么拼,也不用自己写工具注册中心,框架里@register_tool一个装饰器就搞定。

但真正上手时,很多人卡在同一个地方:模型 endpoint 和鉴权分散。Qwen-Agent 默认走 DashScope,你得配DASHSCOPE_API_KEY;如果你想换成 OpenAI 兼容接口,又得改model_server和api_key;再叠加代码解释器、图像生成工具各自可能带独立 Key,一个 demo 里三四个 Key 到处飞,换台机器就报 401。我试过在三个工具之间来回切 Key,最后发现报错根本不是工具写错了,而是某个环境变量没导出。

这篇要做的,就是把 Qwen-Agent 的模型接入层统一收口到 TaoToken:一个 Base URL、一个 Key、一个 Model ID,多工具 Agent 共用同一套鉴权。跑通之后你会看到一次完整对话里,Agent 先调用图像生成工具拿到 URL,再调用代码解释器下载并旋转图片,整条链路只认一份配置。下面从环境准备到验证请求一步步来,配置片段可以直接复制。

2. TaoToken 前置准备与 Qwen-Agent 安装配置

先说清楚 TaoToken 在这里的角色:它是一个 OpenAI 兼容的模型接入服务,提供统一的 Base URL 和 API Key,让你用同一套凭证调用不同模型。对 Qwen-Agent 来说,只要把model_server指向它的兼容端点,框架就会按 OpenAI 协议发请求,工具调用(function calling)的返回结构也能正常解析。官网入口在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 端点是 https://taotoken.net/api ,注意这个地址后面不加任何查询参数。

第一步,去控制台创建 Key。打开 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite ,登录后在 API Keys 页面新建一个密钥,复制出来先存到本地临时文件。这个 Key 就是后面所有工具共用的那一份,不要再给单个工具单独配。如果你还没决定用哪个模型,可以先去模型对话页面 https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite 试一下qwen-max或qwen-plus的响应,确认账号可用。

第二步,装 Qwen-Agent。官方推荐从 PyPI 装带可选依赖的版本,因为我们要用代码解释器和图像工具,所以把code_interpreter和python_executor都带上:

pip install -U "qwen-agent[rag,code_interpreter,python_executor]"

如果你想要 Gradio 界面方便调试,再加gui:

pip install -U "qwen-agent[gui,rag,code_interpreter,python_executor]"

注意 GUI 要求 Python 3.10 或更高版本,低于这个版本会在导入qwen_agent.gui时报语法或类型错误。装完用下面这行确认版本和导入路径:

python -c "import qwen_agent; print(qwen_agent.__version__)"

第三步,设置环境变量。Qwen-Agent 读取 Key 的方式有两种:显式写在llm_cfg里,或者走环境变量。为了统一管理,我建议把 TaoToken 的 Key 导出成环境变量,然后在配置里引用。Linux/macOS:

export TAOTOKEN_API_KEY="sk-你的Key"

Windows PowerShell:

$env:TAOTOKEN_API_KEY="sk-你的Key"

这里有个坑要提前说:Qwen-Agent 默认会去找DASHSCOPE_API_KEY,如果你只导出了TAOTOKEN_API_KEY,但配置里没显式写api_key,框架会报找不到 DashScope Key。所以下一步的llm_cfg里必须把api_key字段填上,不能省。

3. 可复制配置:把 model_server 指向 TaoToken

这一节是核心,配置写对了后面基本不会出问题。Qwen-Agent 的llm_cfg是一个字典,关键字段有三个:model、model_server、api_key。当model_server是一个以http开头的 URL 时,框架会按 OpenAI 兼容协议处理,这正是我们要的。

先给一份最小可用的llm_cfg:

import os llm_cfg = { 'model': 'qwen-max', 'model_server': 'https://taotoken.net/api/v1', 'api_key': os.environ.get('TAOTOKEN_API_KEY'), 'generate_cfg': { 'top_p': 0.8 } }

注意model_server的写法:TaoToken 的 API 根是https://taotoken.net/api,OpenAI 兼容的 chat completions 路径是/v1/chat/completions,所以 Qwen-Agent 里填https://taotoken.net/api/v1。如果你填成https://taotoken.net/api不带/v1,框架拼出来的请求地址会少一段,返回 404。这个路径细节很多人第一次会踩。

model字段填你要用的模型 ID,比如qwen-max、qwen-plus。Model ID 必须和 TaoToken 侧支持的名称一致,写错了会返回模型不存在的错误。你可以先在模型对话页面确认可用名称。

接下来是完整的多工具 Agent 示例,包含自定义图像工具和框架自带的代码解释器:

import pprint import urllib.parse import json5 from qwen_agent.agents import Assistant from qwen_agent.tools.base import BaseTool, register_tool @register_tool('my_image_gen') class MyImageGen(BaseTool): description = 'AI 绘画(图像生成)服务,输入文本描述,返回基于文本信息绘制的图像 URL。' parameters = [{ 'name': 'prompt', 'type': 'string', 'description': '期望的图像内容的详细描述', 'required': True }] def call(self, params: str, **kwargs) -> str: prompt = json5.loads(params)['prompt'] prompt = urllib.parse.quote(prompt) return json5.dumps( {'image_url': f'https://image.pollinations.ai/prompt/{prompt}'}, ensure_ascii=False) llm_cfg = { 'model': 'qwen-max', 'model_server': 'https://taotoken.net/api/v1', 'api_key': os.environ.get('TAOTOKEN_API_KEY'), 'generate_cfg': {'top_p': 0.8} } system_instruction = '''你是一个乐于助人的AI助手。 在收到用户的请求后,你应该: - 首先绘制一幅图像,得到图像的url, - 然后运行代码`request.get`以下载该图像的url, - 最后从给定的文档中选择一个图像操作进行图像处理。 用 `plt.show()` 展示图像。 你总是用中文回复用户。''' tools = ['my_image_gen', 'code_interpreter'] files = ['./examples/resource/doc.pdf'] bot = Assistant(llm=llm_cfg, system_message=system_instruction, function_list=tools, files=files) messages = [] while True: query = input('用户请求: ') messages.append({'role': 'user', 'content': query}) response = [] for response in bot.run(messages=messages): print('机器人回应:') pprint.pprint(response, indent=2) messages.extend(response)

这份配置里,my_image_gen和code_interpreter两个工具共用同一个llm_cfg,也就是共用同一份 TaoToken Key。你不需要给代码解释器单独配 Key,它执行的是本地 Python,模型调用仍然走llm_cfg。这就是「统一 Key」的实际含义:所有需要模型推理的环节,都从这一个配置取凭证。

如果你想把配置抽成独立文件方便复用,可以建一个config.toml:

[llm] model = "qwen-max" model_server = "https://taotoken.net/api/v1" api_key_env = "TAOTOKEN_API_KEY" top_p = 0.8

然后在 Python 里读取。不过 Qwen-Agent 原生不解析 TOML,你需要自己用tomllib(Python 3.11+)或tomli读进来再拼成字典。对大多数 demo 来说,直接写在 Python 里更省事。

4. 验证请求:一次完整对话确认工具调用链路

配置写好后,怎么确认工具调用真的通了?不要只看模型有没有回文字,要看它有没有触发tool_calls。下面给一个可观测的验证流程。

先跑一个最小脚本,只验证模型连通性,不挂工具:

import os from qwen_agent.llm import get_chat_model llm_cfg = { 'model': 'qwen-max', 'model_server': 'https://taotoken.net/api/v1', 'api_key': os.environ.get('TAOTOKEN_API_KEY'), } llm = get_chat_model(llm_cfg) messages = [{'role': 'user', 'content': '用一句话说明什么是 Agent。'}] for chunk in llm.chat(messages=messages): print(chunk)

如果这一步能打印出流式文本,说明 Base URL、Key、Model ID 三件套正确。如果报 401,说明 Key 无效或没读到;如果报 404,多半是model_server路径少了/v1;如果报模型不存在,检查model字段拼写。

连通性通过后,跑完整的多工具 Agent。启动上面的完整示例,输入这句请求:

绘制一只狗并将其旋转 90 度

预期行为是:Agent 先调用my_image_gen,参数里带prompt,工具返回一个image_url;然后 Agent 调用code_interpreter,执行类似requests.get(image_url)下载图片,再用 PIL 旋转 90 度,最后plt.show()。你在终端会看到多轮pprint输出,每一轮里function_call字段会显示当前调用的工具名和参数。

判断链路是否正常,看三个信号:第一,输出里出现my_image_gen的 function_call;第二,紧接着出现code_interpreter的 function_call;第三,最终回复里包含图像处理完成的描述。三个都出现,说明多工具编排和统一鉴权都工作正常。

如果你想要更直观的界面,用 Gradio 包一层:

from qwen_agent.gui import WebUI WebUI(bot).run()

启动后浏览器打开本地地址,在输入框里发同样的请求,能看到工具调用的中间步骤和最终图片。注意 GUI 需要 Python 3.10+,且qwen-agent[gui]已安装。

验证时还有一个细节:files=['./examples/resource/doc.pdf']这行要求你本地真的有这个 PDF。如果你没有,直接删掉files参数,否则 Agent 初始化时会报文件不存在。这个报错和鉴权无关,但容易和 401 混淆,排查时先确认文件路径。

5. 本篇常见错误排查:401、local proxy failed、reading choices

这一节按真实报错来对。你在 Qwen-Agent + TaoToken 组合里最可能遇到下面几类。

401 Unauthorized / invalid api key。最常见的原因是api_key没传进去。Qwen-Agent 在model_server为 URL 时,会优先用llm_cfg['api_key'],如果这个字段是None,它会回退去找DASHSCOPE_API_KEY环境变量,找不到就报鉴权失败。解决方法是显式写'api_key': os.environ.get('TAOTOKEN_API_KEY'),并确认环境变量在当前 shell 里真的存在,用echo $TAOTOKEN_API_KEY检查。另一个原因是 Key 复制时带了空格或换行,建议重新从控制台复制。

local proxy failed / connection error。这个报错通常出现在model_server地址写错或网络不通时。先确认地址是https://taotoken.net/api/v1,不要写成http,也不要漏掉/v1。如果你在公司网络里,检查是否有本地代理拦截了 HTTPS 请求。这个报错和 Key 无关,纯粹是请求没发出去。

Error reading choices / choices 字段为空。这个报错说明请求发出去了、也返回了,但返回体结构不符合 OpenAI 格式,框架解析choices时拿不到内容。常见原因是model_server指向了一个非 OpenAI 兼容的端点,或者模型名不被支持导致返回了错误 JSON。解决方法是先用curl直接打一次接口,看返回结构:

curl https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"qwen-max","messages":[{"role":"user","content":"hi"}]}'

如果返回里有choices数组,说明端点没问题,问题在 Qwen-Agent 配置;如果返回的是错误对象,看error.message定位。

OAuth / token expired。如果你用的是带过期时间的凭证,过期后会返回 401 或 403。重新在控制台生成 Key 并更新环境变量即可。注意 Qwen-Agent 不会自动刷新凭证,每次启动进程都要确保环境变量是最新的。

工具调用不触发。模型回复了文字但没有 function_call,通常是system_message里没有明确要求使用工具,或者function_list里的工具名和@register_tool注册的名字不一致。检查tools = ['my_image_gen', 'code_interpreter']里的字符串是否和装饰器参数完全一致,大小写敏感。

排查顺序建议:先curl验证端点,再跑最小get_chat_model验证鉴权,最后跑完整 Agent 验证工具编排。这样能把问题范围一步步缩小,不会在多个变量之间来回猜。

6. 长期跑 Agent 的接入建议与下一步

如果你只是验证 demo,上面的配置够用了。但如果你打算把 Qwen-Agent 用在长期运行的编码助手或自动化任务里,有几个点值得提前处理。

第一,把 Key 从代码里彻底剥离。不要写'api_key': 'sk-xxx'硬编码,用环境变量或密钥管理服务。Qwen-Agent 支持从环境变量读,你只要保证进程启动时变量已注入。如果你用 systemd 或 Docker,在 service 文件或docker run -e里传。

第二,模型 ID 做成可配置。qwen-max适合复杂推理,qwen-plus适合成本敏感场景。把model字段抽成环境变量TAOTOKEN_MODEL,切换时不用改代码。TaoToken 的模型列表可以在模型对话页面确认,改完直接重启进程。

第三,多工具场景下注意超时。代码解释器执行下载和图像处理可能耗时较长,Qwen-Agent 默认的请求超时可能不够。你可以在generate_cfg里加'timeout': 120之类的参数,具体字段名以框架版本为准。如果频繁超时,考虑把重活拆到独立工具里异步执行。

第四,如果你要做更复杂的 Agent 编排,比如多 Agent 协作或带记忆的长期会话,Qwen-Agent 提供了Agent基类可以继承。这时候统一鉴权的价值更明显:所有子 Agent 共用一份llm_cfg,不会出现某个子 Agent 因为 Key 没配而静默失败。

需要长期跑编码类 Agent 的话,可以了解 Coding Plan 的接入方式:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite 。如果你更想先把模型对话和工具调用调顺,直接去 API Keys 页面建 Key、对照接入文档改配置就行:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite ,文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 。配置改完,跑一次「绘制一只狗并旋转 90 度」,看到两段 function_call 依次出现,这条链路就算真正通了。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进