feat: 更新工具调用处理逻辑,支持新旧格式兼容并优化工具调用参数合并
This commit is contained in:
parent
107ec04dba
commit
093084ef7f
@ -131,6 +131,7 @@ uv run scripts/batch_upload.py \
|
||||
--wait-for-completion \
|
||||
--poll-interval 5 \
|
||||
--recursive \
|
||||
--enable-ocr mineru_ocr \ # mineru_official, paddlex_ocr, onnx_rapid_ocr
|
||||
--record-file scripts/tmp/batch_processed_files_1029.txt
|
||||
```
|
||||
|
||||
|
||||
@ -388,6 +388,7 @@ const resetOnGoingConv = (threadId = null, preserveMessages = false) => {
|
||||
const _processStreamChunk = (chunk, threadId) => {
|
||||
const { status, msg, request_id, message } = chunk;
|
||||
const threadState = getThreadState(threadId);
|
||||
// console.log('msg:', msg);
|
||||
|
||||
if (!threadState) return false;
|
||||
|
||||
|
||||
@ -33,8 +33,8 @@
|
||||
<span v-else-if="message.error_type === 'unexpect'">生成过程中出现异常</span>
|
||||
</div>
|
||||
|
||||
<div v-if="message.tool_calls && Object.keys(message.tool_calls).length > 0" class="tool-calls-container">
|
||||
<div v-for="(toolCall, index) in message.tool_calls || {}" :key="index" class="tool-call-container">
|
||||
<div v-if="validToolCalls && validToolCalls.length > 0" class="tool-calls-container">
|
||||
<div v-for="(toolCall, index) in validToolCalls" :key="toolCall.id || index" class="tool-call-container">
|
||||
<div v-if="toolCall" class="tool-call-display" :class="{ 'is-collapsed': !expandedToolCalls.has(toolCall.id) }">
|
||||
<div class="tool-header" @click="toggleToolCall(toolCall.id)">
|
||||
<span v-if="!toolCall.tool_call_result">
|
||||
@ -47,15 +47,17 @@
|
||||
</span>
|
||||
</div>
|
||||
<div class="tool-content" v-show="expandedToolCalls.has(toolCall.id)">
|
||||
<div class="tool-params" v-if="toolCall.args || toolCall.function.arguments">
|
||||
<div class="tool-params" v-if="toolCall.args || toolCall.function?.arguments">
|
||||
<div class="tool-params-content">
|
||||
<strong>参数:</strong> {{ toolCall.args || toolCall.function.arguments }}
|
||||
<strong>参数:</strong>
|
||||
<span v-if="getFormattedToolArgs(toolCall)">{{ getFormattedToolArgs(toolCall) }}</span>
|
||||
<span v-else>{{ toolCall.args || toolCall.function?.arguments }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tool-result" v-if="toolCall.tool_call_result && toolCall.tool_call_result.content">
|
||||
<div class="tool-result-content" :data-tool-call-id="toolCall.id">
|
||||
<ToolResultRenderer
|
||||
:tool-name="toolCall.name || toolCall.function.name"
|
||||
:tool-name="toolCall.name || toolCall.function?.name"
|
||||
:result-content="toolCall.tool_call_result.content"
|
||||
/>
|
||||
</div>
|
||||
@ -146,13 +148,51 @@ const { availableTools } = storeToRefs(agentStore);
|
||||
|
||||
// 工具相关方法
|
||||
const getToolNameByToolCall = (toolCall) => {
|
||||
const toolId = toolCall.name || toolCall.function.name;
|
||||
const toolId = toolCall.name || toolCall.function?.name;
|
||||
const toolsList = availableTools.value ? Object.values(availableTools.value) : [];
|
||||
const tool = toolsList.find(t => t.id === toolId);
|
||||
return tool ? tool.name : toolId;
|
||||
};
|
||||
|
||||
const getFormattedToolArgs = (toolCall) => {
|
||||
const args = toolCall.args || toolCall.function?.arguments;
|
||||
if (!args) return '';
|
||||
|
||||
try {
|
||||
// 尝试解析JSON格式的参数
|
||||
if (typeof args === 'string' && args.trim().startsWith('{')) {
|
||||
const parsed = JSON.parse(args);
|
||||
return JSON.stringify(parsed, null, 2);
|
||||
}
|
||||
} catch (e) {
|
||||
// 如果解析失败,直接返回原始字符串
|
||||
}
|
||||
|
||||
return args;
|
||||
};
|
||||
|
||||
// 过滤有效的工具调用
|
||||
const validToolCalls = computed(() => {
|
||||
if (!props.message.tool_calls || !Array.isArray(props.message.tool_calls)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return props.message.tool_calls.filter(toolCall => {
|
||||
// 过滤掉无效的工具调用
|
||||
return toolCall &&
|
||||
(toolCall.id || toolCall.name) &&
|
||||
(toolCall.args !== undefined ||
|
||||
toolCall.function?.arguments !== undefined ||
|
||||
toolCall.tool_call_result !== undefined);
|
||||
});
|
||||
});
|
||||
|
||||
const parsedData = computed(() => {
|
||||
// 调试工具调用处理
|
||||
if (validToolCalls.value && validToolCalls.value.length > 0) {
|
||||
console.log('Valid tool calls in message:', validToolCalls.value);
|
||||
}
|
||||
|
||||
// Start with default values from the prop to avoid mutation.
|
||||
let content = props.message.content.trim() || '';
|
||||
let reasoning_content = props.message.additional_kwargs?.reasoning_content || '';
|
||||
|
||||
@ -12,8 +12,12 @@ export class MessageProcessor {
|
||||
|
||||
// 构建工具响应映射
|
||||
for (const item of msgs) {
|
||||
if (item.type === 'tool' && item.tool_call_id) {
|
||||
toolResponseMap.set(item.tool_call_id, item);
|
||||
if (item.type === 'tool') {
|
||||
// 使用多种可能的ID字段来匹配工具调用
|
||||
const toolCallId = item.tool_call_id || item.id;
|
||||
if (toolCallId) {
|
||||
toolResponseMap.set(toolCallId, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,13 +131,14 @@ export class MessageProcessor {
|
||||
result.additional_kwargs.reasoning_content += chunk.additional_kwargs.reasoning_content;
|
||||
}
|
||||
|
||||
// 合并tool_calls
|
||||
// 合并tool_calls (处理新的数据结构)
|
||||
MessageProcessor._mergeToolCalls(result, chunk);
|
||||
}
|
||||
|
||||
// 处理AIMessageChunk类型
|
||||
if (result.type === 'AIMessageChunk') {
|
||||
result.type = 'ai';
|
||||
// 将tool_calls从additional_kwargs移到顶层,并确保格式正确
|
||||
if (result.additional_kwargs?.tool_calls) {
|
||||
result.tool_calls = result.additional_kwargs.tool_calls;
|
||||
}
|
||||
@ -149,6 +154,7 @@ export class MessageProcessor {
|
||||
* @param {Object} chunk - 当前块
|
||||
*/
|
||||
static _mergeToolCalls(result, chunk) {
|
||||
// 1. 处理 additional_kwargs.tool_calls (旧格式,保持兼容性)
|
||||
if (chunk.additional_kwargs?.tool_calls) {
|
||||
if (!result.additional_kwargs) result.additional_kwargs = {};
|
||||
if (!result.additional_kwargs.tool_calls) result.additional_kwargs.tool_calls = [];
|
||||
@ -169,6 +175,100 @@ export class MessageProcessor {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 处理顶层的 tool_calls (新格式)
|
||||
if (chunk.tool_calls) {
|
||||
if (!result.tool_calls) result.tool_calls = [];
|
||||
|
||||
for (const toolCall of chunk.tool_calls) {
|
||||
// 过滤掉无效的工具调用(没有id或name的空对象)
|
||||
if (!toolCall.id && !toolCall.name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const existingToolCall = result.tool_calls.find(t => t.id === toolCall.id);
|
||||
|
||||
if (existingToolCall) {
|
||||
// 合并相同ID的tool call的args
|
||||
if (toolCall.args && existingToolCall.args !== undefined) {
|
||||
existingToolCall.args += toolCall.args;
|
||||
}
|
||||
} else {
|
||||
// 添加新的tool call
|
||||
result.tool_calls.push(JSON.parse(JSON.stringify(toolCall)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 处理 tool_call_chunks (分片的工具调用参数)
|
||||
if (chunk.tool_call_chunks) {
|
||||
if (!result.tool_call_chunks) result.tool_call_chunks = [];
|
||||
|
||||
for (const toolCallChunk of chunk.tool_call_chunks) {
|
||||
// 过滤掉无效的chunk(没有id、name和args的空对象)
|
||||
if (!toolCallChunk.id && !toolCallChunk.name && !toolCallChunk.args) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const existingChunk = result.tool_call_chunks.find(
|
||||
t => (t.id === toolCallChunk.id || (t.index === toolCallChunk.index && t.index !== null))
|
||||
);
|
||||
|
||||
if (existingChunk) {
|
||||
// 合并参数字符串
|
||||
if (toolCallChunk.args && existingChunk.args !== undefined) {
|
||||
existingChunk.args += toolCallChunk.args;
|
||||
}
|
||||
// 更新工具名称
|
||||
if (toolCallChunk.name && !existingChunk.name) {
|
||||
existingChunk.name = toolCallChunk.name;
|
||||
}
|
||||
} else {
|
||||
// 添加新的chunk
|
||||
result.tool_call_chunks.push(JSON.parse(JSON.stringify(toolCallChunk)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 同步 tool_call_chunks 到 tool_calls (构建完整的工具调用)
|
||||
if (result.tool_call_chunks && result.tool_call_chunks.length > 0) {
|
||||
if (!result.tool_calls) result.tool_calls = [];
|
||||
|
||||
for (const chunk of result.tool_call_chunks) {
|
||||
if (chunk.name && chunk.args) {
|
||||
const existingToolCall = result.tool_calls.find(t => t.id === chunk.id);
|
||||
|
||||
if (!existingToolCall) {
|
||||
// 创建新的完整工具调用
|
||||
result.tool_calls.push({
|
||||
id: chunk.id,
|
||||
name: chunk.name,
|
||||
args: chunk.args,
|
||||
type: 'tool_call'
|
||||
});
|
||||
} else {
|
||||
// 更新现有工具调用的参数
|
||||
existingToolCall.args = chunk.args;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 清理无效的工具调用
|
||||
if (result.tool_calls) {
|
||||
result.tool_calls = result.tool_calls.filter(toolCall => {
|
||||
// 保留有id或有name的工具调用,并且不是空的args对象
|
||||
return (toolCall.id || toolCall.name) &&
|
||||
(toolCall.args !== undefined || toolCall.function?.arguments);
|
||||
});
|
||||
}
|
||||
|
||||
// 清理空的tool_call_chunks
|
||||
if (result.tool_call_chunks) {
|
||||
result.tool_call_chunks = result.tool_call_chunks.filter(chunk => {
|
||||
return (chunk.id || chunk.name || chunk.args);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Loading…
Reference in New Issue
Block a user