|
@@ -864,6 +864,16 @@ class AgentRunner:
|
|
|
|
|
|
|
|
if self.trace_store:
|
|
if self.trace_store:
|
|
|
await self.trace_store.add_message(assistant_msg)
|
|
await self.trace_store.add_message(assistant_msg)
|
|
|
|
|
+ # 记录模型使用
|
|
|
|
|
+ await self.trace_store.record_model_usage(
|
|
|
|
|
+ trace_id=trace_id,
|
|
|
|
|
+ sequence=sequence - 1, # assistant_msg的sequence
|
|
|
|
|
+ role="assistant",
|
|
|
|
|
+ model=config.model,
|
|
|
|
|
+ prompt_tokens=prompt_tokens,
|
|
|
|
|
+ completion_tokens=completion_tokens,
|
|
|
|
|
+ cache_read_tokens=cache_read_tokens or 0,
|
|
|
|
|
+ )
|
|
|
|
|
|
|
|
yield assistant_msg
|
|
yield assistant_msg
|
|
|
head_seq = sequence
|
|
head_seq = sequence
|
|
@@ -927,12 +937,21 @@ class AgentRunner:
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
# --- 支持多模态工具反馈 ---
|
|
# --- 支持多模态工具反馈 ---
|
|
|
- # execute() 返回 dict{"text","images"} 或 str
|
|
|
|
|
- if isinstance(tool_result, dict) and tool_result.get("images"):
|
|
|
|
|
- tool_result_text = tool_result["text"]
|
|
|
|
|
|
|
+ # execute() 返回 dict{"text","images","tool_usage"} 或 str
|
|
|
|
|
+ # 统一为dict格式
|
|
|
|
|
+ if isinstance(tool_result, str):
|
|
|
|
|
+ tool_result = {"text": tool_result}
|
|
|
|
|
+
|
|
|
|
|
+ tool_text = tool_result.get("text", str(tool_result))
|
|
|
|
|
+ tool_images = tool_result.get("images", [])
|
|
|
|
|
+ tool_usage = tool_result.get("tool_usage") # 新增:提取tool_usage
|
|
|
|
|
+
|
|
|
|
|
+ # 处理多模态消息
|
|
|
|
|
+ if tool_images:
|
|
|
|
|
+ tool_result_text = tool_text
|
|
|
# 构建多模态消息格式
|
|
# 构建多模态消息格式
|
|
|
- tool_content_for_llm = [{"type": "text", "text": tool_result_text}]
|
|
|
|
|
- for img in tool_result["images"]:
|
|
|
|
|
|
|
+ tool_content_for_llm = [{"type": "text", "text": tool_text}]
|
|
|
|
|
+ for img in tool_images:
|
|
|
if img.get("type") == "base64" and img.get("data"):
|
|
if img.get("type") == "base64" and img.get("data"):
|
|
|
media_type = img.get("media_type", "image/png")
|
|
media_type = img.get("media_type", "image/png")
|
|
|
tool_content_for_llm.append({
|
|
tool_content_for_llm.append({
|
|
@@ -944,8 +963,8 @@ class AgentRunner:
|
|
|
img_count = len(tool_content_for_llm) - 1 # 减去 text 块
|
|
img_count = len(tool_content_for_llm) - 1 # 减去 text 块
|
|
|
print(f"[Runner] 多模态工具反馈: tool={tool_name}, images={img_count}, text_len={len(tool_result_text)}")
|
|
print(f"[Runner] 多模态工具反馈: tool={tool_name}, images={img_count}, text_len={len(tool_result_text)}")
|
|
|
else:
|
|
else:
|
|
|
- tool_result_text = str(tool_result)
|
|
|
|
|
- tool_content_for_llm = tool_result_text
|
|
|
|
|
|
|
+ tool_result_text = tool_text
|
|
|
|
|
+ tool_content_for_llm = tool_text
|
|
|
|
|
|
|
|
tool_msg = Message.create(
|
|
tool_msg = Message.create(
|
|
|
trace_id=trace_id,
|
|
trace_id=trace_id,
|
|
@@ -960,10 +979,22 @@ class AgentRunner:
|
|
|
|
|
|
|
|
if self.trace_store:
|
|
if self.trace_store:
|
|
|
await self.trace_store.add_message(tool_msg)
|
|
await self.trace_store.add_message(tool_msg)
|
|
|
|
|
+ # 记录工具的模型使用
|
|
|
|
|
+ if tool_usage:
|
|
|
|
|
+ await self.trace_store.record_model_usage(
|
|
|
|
|
+ trace_id=trace_id,
|
|
|
|
|
+ sequence=sequence,
|
|
|
|
|
+ role="tool",
|
|
|
|
|
+ tool_name=tool_name,
|
|
|
|
|
+ model=tool_usage.get("model"),
|
|
|
|
|
+ prompt_tokens=tool_usage.get("prompt_tokens", 0),
|
|
|
|
|
+ completion_tokens=tool_usage.get("completion_tokens", 0),
|
|
|
|
|
+ cache_read_tokens=tool_usage.get("cache_read_tokens", 0),
|
|
|
|
|
+ )
|
|
|
# 截图单独存为同名 PNG 文件
|
|
# 截图单独存为同名 PNG 文件
|
|
|
- if isinstance(tool_result, dict) and tool_result.get("images"):
|
|
|
|
|
|
|
+ if tool_images:
|
|
|
import base64 as b64mod
|
|
import base64 as b64mod
|
|
|
- for img in tool_result["images"]:
|
|
|
|
|
|
|
+ for img in tool_images:
|
|
|
if img.get("data"):
|
|
if img.get("data"):
|
|
|
png_path = self.trace_store._get_messages_dir(trace_id) / f"{tool_msg.message_id}.png"
|
|
png_path = self.trace_store._get_messages_dir(trace_id) / f"{tool_msg.message_id}.png"
|
|
|
png_path.write_bytes(b64mod.b64decode(img["data"]))
|
|
png_path.write_bytes(b64mod.b64decode(img["data"]))
|