agent-Specialization/users/jojo/project/user_upload/tool_thinking_test.py
2025-11-14 16:44:12 +08:00

205 lines
6.5 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.

import json
import httpx
import openai
import time
base_url= "https://api.moonshot.cn/v1"
api_key= "sk-xW0xjfQM6Mp9ZCWMLlnHiRJcpEOIZPTkXcN0dQ15xpZSuw2y" # 如有需要可放置独立密钥
class FormulaChatClient:
def __init__(self, base_url: str, api_key: str):
"""初始化 Formula 客户端"""
self.base_url = base_url
self.api_key = api_key
self.openai = openai.Client(
base_url=base_url,
api_key=api_key,
)
self.httpx = httpx.Client(
base_url=base_url,
headers={"Authorization": f"Bearer {api_key}"},
timeout=30.0,
)
self.model = "kimi-k2-thinking"
def get_tools(self, formula_uri: str):
"""从 Formula API 获取工具定义"""
response = self.httpx.get(f"/formulas/{formula_uri}/tools")
response.raise_for_status() # 检查 HTTP 状态码
try:
return response.json().get("tools", [])
except json.JSONDecodeError as e:
print(f"错误: 无法解析响应为 JSON (状态码: {response.status_code})")
print(f"响应内容: {response.text[:500]}")
raise
def call_tool(self, formula_uri: str, function: str, args: dict):
"""调用官方工具"""
response = self.httpx.post(
f"/formulas/{formula_uri}/fibers",
json={"name": function, "arguments": json.dumps(args)},
)
response.raise_for_status() # 检查 HTTP 状态码
fiber = response.json()
if fiber.get("status", "") == "succeeded":
return fiber["context"].get("output") or fiber["context"].get("encrypted_output")
if "error" in fiber:
return f"Error: {fiber['error']}"
if "error" in fiber.get("context", {}):
return f"Error: {fiber['context']['error']}"
return "Error: Unknown error"
def close(self):
"""关闭客户端连接"""
self.httpx.close()
# 初始化客户端 - 使用硬编码配置
base_url = "https://api.moonshot.cn/v1"
api_key = "sk-xW0xjfQM6Mp9ZCWMLlnHiRJcpEOIZPTkXcN0dQ15xpZSuw2y"
print(f"Base URL: {base_url}")
print(f"API Key: {api_key[:10]}...{api_key[-10:] if len(api_key) > 20 else api_key}\n")
# 等待一段时间避免并发限制
print("等待5秒避免组织并发限制...")
time.sleep(5)
client = FormulaChatClient(base_url, api_key)
# 定义要使用的官方工具 Formula URI
formula_uris = [
"moonshot/date:latest",
"moonshot/web-search:latest"
]
# 加载所有工具定义并建立映射
print("正在加载官方工具...")
all_tools = []
tool_to_uri = {} # function.name -> formula_uri 的映射
for uri in formula_uris:
try:
tools = client.get_tools(uri)
for tool in tools:
func = tool.get("function")
if func:
func_name = func.get("name")
if func_name:
tool_to_uri[func_name] = uri
all_tools.append(tool)
print(f" 已加载工具: {func_name} from {uri}")
except Exception as e:
print(f" 警告: 加载工具 {uri} 失败: {e}")
continue
print(f"总共加载 {len(all_tools)} 个工具\n")
if not all_tools:
raise ValueError("未能加载任何工具,请检查 API 密钥和网络连接")
# 初始化消息列表
messages = [
{
"role": "system",
"content": "你是 Kimi一个专业的新闻分析师。你擅长收集、分析和整理信息生成高质量的新闻报告。",
},
]
# 用户请求生成今日新闻报告
user_request = "请帮我生成一份今日新闻报告,包含重要的科技、经济和社会新闻。"
messages.append({
"role": "user",
"content": user_request
})
print(f"用户请求: {user_request}\n")
max_iterations = 5 # 防止无限循环减少API调用次数
for iteration in range(max_iterations):
# 添加延迟避免速率限制
print(f"等待3秒避免速率限制...\n")
time.sleep(3)
# 调用模型
try:
completion = client.openai.chat.completions.create(
model=client.model,
messages=messages,
max_tokens=1024 * 32,
tools=all_tools,
temperature=1.0,
)
except openai.AuthenticationError as e:
print(f"认证错误: {e}")
print("请检查 API key 是否正确,以及 API key 是否有权限访问该端点")
raise
except Exception as e:
print(f"调用模型时发生错误: {e}")
raise
# 获取响应
message = completion.choices[0].message
# 打印思考过程
if hasattr(message, "reasoning_content"):
print(f"=============第 {iteration + 1} 轮思考开始=============")
reasoning = getattr(message, "reasoning_content")
if reasoning:
print(reasoning[:500] + "..." if len(reasoning) > 500 else reasoning)
print(f"=============第 {iteration + 1} 轮思考结束=============\n")
# 添加 assistant 消息到上下文(保留 reasoning_content
messages.append(message)
# 如果模型没有调用工具,说明对话结束
if not message.tool_calls:
print("=============最终回答=============")
print(message.content)
break
# 处理工具调用
print(f"模型决定调用 {len(message.tool_calls)} 个工具:\n")
for tool_call in message.tool_calls:
func_name = tool_call.function.name
args = json.loads(tool_call.function.arguments)
print(f"调用工具: {func_name}")
print(f"参数: {json.dumps(args, ensure_ascii=False, indent=2)}")
# 获取对应的 formula_uri
formula_uri = tool_to_uri.get(func_name)
if not formula_uri:
print(f"错误: 找不到工具 {func_name} 对应的 Formula URI")
continue
# 调用工具
result = client.call_tool(formula_uri, func_name, args)
# 打印结果(截断过长内容)
if len(str(result)) > 200:
print(f"工具结果: {str(result)[:200]}...\n")
else:
print(f"工具结果: {result}\n")
# 添加工具结果到消息列表
tool_message = {
"role": "tool",
"tool_call_id": tool_call.id,
"name": func_name,
"content": result
}
messages.append(tool_message)
print("\n对话完成!")
# 清理资源
client.close()