Files
agent/qwen3_coder_with_qwen_agent.py
lingyuzeng 01a4190a28 first add
2025-08-27 16:14:23 +08:00

250 lines
8.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Qwen3-Coder 使用 Qwen-Agent 框架测试示例
这个示例演示了如何使用 Qwen-Agent 框架调用 qwen3-coder 模型进行工具调用测试。
工具配置说明:
1. MCP工具通过'mcpServers'配置需要安装对应的MCP服务器
- time: 获取当前时间的MCP工具
- fetch: 网络请求工具
- filesystem: 文件系统操作工具
这些工具需要额外安装对应的MCP服务器才能使用
2. 原生工具Qwen-Agent内置的工具直接可用
- 'code_interpreter': 代码解释器可以执行Python代码
- 'image_gen': 图像生成工具
- 'web_search': 网络搜索工具
- 'calculator''python_executor': Python代码执行器可作为计算器
环境变量说明:
- MAX_LLM_CALL_PER_RUN: 控制LLM调用的最大轮数不是工具调用次数
这个限制是针对整个对话的LLM调用轮数包括初始调用和后续基于工具结果的调用
- MAX_TOOL_CALLS_PER_TURN: 控制每轮LLM输出中可触发的工具调用数量
这个限制是针对单次LLM响应中可以触发的工具数量防止模型一次性触发过多工具
"""
import os
# 设置环境变量以控制工具调用行为
# MAX_LLM_CALL_PER_RUN: 控制LLM调用的最大轮数不是工具调用次数
# MAX_TOOL_CALLS_PER_TURN: 控制每轮LLM输出中可触发的工具调用数量
os.environ["MAX_LLM_CALL_PER_RUN"] = "8"
os.environ["MAX_TOOL_CALLS_PER_TURN"] = "8"
import sys
import traceback
from pathlib import Path
# 添加项目路径到Python路径
project_root = Path(__file__).parent.parent.parent
sys.path.insert(0, str(project_root))
try:
from qwen_agent.agents import Assistant
from qwen_agent.gui import WebUI
from qwen_agent.utils.output_beautify import typewriter_print
except ImportError as e:
print(f"❌ 导入失败: {e}")
print("请确保已安装 qwen-agent: pip install qwen-agent")
sys.exit(1)
def init_agent_service():
"""初始化Agent服务"""
# 配置API参数使用OpenAI兼容模式
llm_cfg = {
'model': 'qwen3-coder-flash-1M',
'model_server': 'https://ai.jmsu.top/v1',
'api_key': 'gpustack_96d105073565a038_23d7fe2768b4b27f9d92ab4661452ade',
'generate_cfg': {
# 使用API的原生工具调用接口
'temperature': 0.7,
'top_p': 0.8,
'fncall_prompt_type': 'qwen', # 对 Qwen3 通常更稳
},
}
# 配置工具
tools = [
{
'mcpServers': { # 指定MCP配置
'time': {
'command': 'uvx',
'args': ['mcp-server-time', '--local-timezone=Asia/Shanghai']
},
'fetch': {
'command': 'uvx',
'args': ['mcp-server-fetch']
},
'filesystem': {
'command': 'npx',
'args': [
'-y',
'@modelcontextprotocol/server-filesystem',
'~/Desktop/'
]
},
}
},
# 添加一些原生工具示例
'code_interpreter', # 代码解释器
'web_search', # 网络搜索
]
# 创建Agent
bot = Assistant(
llm=llm_cfg,
function_list=tools,
name='Qwen3-Coder Tool-calling Demo',
description="I'm a demo using the Qwen3-Coder tool calling. Welcome to add and play with your own tools!"
)
return bot
def test(query: str = '现在几点了?'):
"""测试函数"""
print("=== Qwen3-Coder 使用 Qwen-Agent 测试 ===\n")
# 初始化Agent
bot = init_agent_service()
# 进行对话
messages = [{'role': 'user', 'content': query}]
print(f"💬 用户: {query}")
print("🤖 助手: ", end='', flush=True)
# 缓存最终回复内容
final_response = ""
current_tool_call = ""
in_tool_call = False
try:
for response in bot.run(messages=messages):
# 处理响应
if response:
for msg in response:
if msg['role'] == 'assistant':
if msg.get('content'):
# 检查是否包含工具调用标记
if '[TOOL_CALL]' in msg['content']:
in_tool_call = True
current_tool_call = msg['content']
# 清空之前的输出,准备显示工具调用
print(f"\r🤖 助手: {msg['content']}", end='', flush=True)
elif in_tool_call:
# 继续工具调用信息
current_tool_call += msg['content']
print(msg['content'], end='', flush=True)
else:
# 普通回复内容
final_response += msg['content']
# 不再实时打印,等待工具调用完成后统一显示
# print(msg['content'], end='', flush=True)
elif msg['role'] == 'function':
# 工具响应,显示工具结果
in_tool_call = False
print(f"\n[TOOL_RESPONSE] {msg.get('name', 'unknown')}")
print(msg.get('content', ''))
# 重置最终回复内容,准备接收新的回复
final_response = ""
# 输出最终结果
if final_response:
print("\r🤖 助手: ", end='', flush=True)
print(final_response, end='', flush=True)
print() # 输出完成后换行
except Exception as e:
print(f"\n❌ 调用失败: {e}")
import traceback
traceback.print_exc()
def app_tui():
"""命令行交互模式"""
print("=== Qwen3-Coder 使用 Qwen-Agent 命令行交互模式 ===\n")
# 初始化Agent
bot = init_agent_service()
# 进行对话
messages = []
while True:
query = input('user question: ')
if query.lower() in ['quit', 'exit', '退出']:
print("👋 再见!")
break
messages.append({'role': 'user', 'content': query})
response = []
response_plain_text = ''
print("🤖 助手: ", end='', flush=True)
try:
for response in bot.run(messages=messages):
# 添加调试信息
# print(f"[DEBUG] 收到响应: {type(response)}", file=sys.stderr)
# 使用 typewriter_print 实现流式输出
if response:
try:
response_plain_text = typewriter_print(response, response_plain_text)
except Exception as e:
# 如果typewriter_print出错尝试直接打印
# print(f"[WARNING] typewriter_print出错: {e}", file=sys.stderr)
if isinstance(response, list):
for item in response:
if isinstance(item, dict) and 'content' in item:
print(item['content'], end='', flush=True)
elif isinstance(item, dict) and 'message' in item:
print(item['message'], end='', flush=True)
print() # 输出完成后换行
messages.extend(response)
except Exception as e:
print(f"\n❌ 调用失败: {e}")
import traceback
traceback.print_exc()
def app_gui():
"""图形界面模式"""
# 初始化Agent
bot = init_agent_service()
chatbot_config = {
'prompt.suggestions': [
'现在几点了?',
'请用Python写一个计算斐波那契数列的函数',
'帮我搜索一下Python装饰器的用法'
]
}
WebUI(
bot,
chatbot_config=chatbot_config,
).run()
def main():
"""主函数"""
print("🚀 Qwen3-Coder 使用 Qwen-Agent 测试示例")
print("=" * 50)
print("\n请选择运行模式:")
print("1. 简单测试 - 固定问题")
print("2. 命令行交互模式")
print("3. 图形界面模式")
choice = input("\n请输入选项 (1-3): ").strip()
if choice == "1":
test()
elif choice == "2":
app_tui()
elif choice == "3":
app_gui()
else:
print("❌ 无效选项,运行默认测试")
test()
if __name__ == '__main__':
main()