add more logs around tool calling and recursion

This commit is contained in:
perf3ct 2025-04-17 16:10:13 +00:00
parent 6f3d2b6ee2
commit 9b5167231f
No known key found for this signature in database
GPG Key ID: 569C4EEC436F5232
3 changed files with 168 additions and 56 deletions

View File

@ -453,8 +453,11 @@ export class ChatPipeline {
); );
log.info(`========== TOOL EXECUTION RESULTS ==========`); log.info(`========== TOOL EXECUTION RESULTS ==========`);
log.info(`Received ${toolResultMessages.length} tool results`);
toolResultMessages.forEach((msg, idx) => { toolResultMessages.forEach((msg, idx) => {
log.info(`Tool result ${idx + 1}: tool_call_id=${msg.tool_call_id}, content=${msg.content.substring(0, 50)}...`); log.info(`Tool result ${idx + 1}: tool_call_id=${msg.tool_call_id}, content=${msg.content.substring(0, 100)}${msg.content.length > 100 ? '...' : ''}`);
log.info(`Tool result status: ${msg.content.startsWith('Error:') ? 'ERROR' : 'SUCCESS'}`);
log.info(`Tool result for: ${this.getToolNameFromToolCallId(currentMessages, msg.tool_call_id || '')}`);
// If streaming, show tool executions to the user // If streaming, show tool executions to the user
if (isStreaming && streamCallback) { if (isStreaming && streamCallback) {
@ -559,6 +562,30 @@ export class ChatPipeline {
// Generate a new completion with the updated messages // Generate a new completion with the updated messages
const followUpStartTime = Date.now(); const followUpStartTime = Date.now();
// Log messages being sent to LLM for tool follow-up
log.info(`========== SENDING TOOL RESULTS TO LLM FOR FOLLOW-UP ==========`);
log.info(`Total messages being sent: ${currentMessages.length}`);
// Log the most recent messages (last 3) for clarity
const recentMessages = currentMessages.slice(-3);
recentMessages.forEach((msg, idx) => {
const position = currentMessages.length - recentMessages.length + idx;
log.info(`Message ${position} (${msg.role}): ${msg.content?.substring(0, 100)}${msg.content?.length > 100 ? '...' : ''}`);
if (msg.tool_calls) {
log.info(` Has ${msg.tool_calls.length} tool calls`);
}
if (msg.tool_call_id) {
log.info(` Tool call ID: ${msg.tool_call_id}`);
}
});
log.info(`LLM follow-up request options: ${JSON.stringify({
model: modelSelection.options.model,
enableTools: true,
stream: modelSelection.options.stream,
provider: currentResponse.provider
})}`);
const followUpCompletion = await this.stages.llmCompletion.execute({ const followUpCompletion = await this.stages.llmCompletion.execute({
messages: currentMessages, messages: currentMessages,
options: { options: {
@ -573,6 +600,15 @@ export class ChatPipeline {
}); });
this.updateStageMetrics('llmCompletion', followUpStartTime); this.updateStageMetrics('llmCompletion', followUpStartTime);
// Log the follow-up response from the LLM
log.info(`========== LLM FOLLOW-UP RESPONSE RECEIVED ==========`);
log.info(`Follow-up response model: ${followUpCompletion.response.model}, provider: ${followUpCompletion.response.provider}`);
log.info(`Follow-up response text: ${followUpCompletion.response.text?.substring(0, 150)}${followUpCompletion.response.text?.length > 150 ? '...' : ''}`);
log.info(`Follow-up contains tool calls: ${!!followUpCompletion.response.tool_calls && followUpCompletion.response.tool_calls.length > 0}`);
if (followUpCompletion.response.tool_calls && followUpCompletion.response.tool_calls.length > 0) {
log.info(`Follow-up has ${followUpCompletion.response.tool_calls.length} new tool calls`);
}
// Update current response for the next iteration // Update current response for the next iteration
currentResponse = followUpCompletion.response; currentResponse = followUpCompletion.response;
@ -650,6 +686,12 @@ export class ChatPipeline {
} }
}); });
// Log the error follow-up response from the LLM
log.info(`========== ERROR FOLLOW-UP RESPONSE RECEIVED ==========`);
log.info(`Error follow-up response model: ${errorFollowUpCompletion.response.model}, provider: ${errorFollowUpCompletion.response.provider}`);
log.info(`Error follow-up response text: ${errorFollowUpCompletion.response.text?.substring(0, 150)}${errorFollowUpCompletion.response.text?.length > 150 ? '...' : ''}`);
log.info(`Error follow-up contains tool calls: ${!!errorFollowUpCompletion.response.tool_calls && errorFollowUpCompletion.response.tool_calls.length > 0}`);
// Update current response and break the tool loop // Update current response and break the tool loop
currentResponse = errorFollowUpCompletion.response; currentResponse = errorFollowUpCompletion.response;
break; break;

View File

@ -20,14 +20,38 @@ export class LLMCompletionStage extends BasePipelineStage<LLMCompletionInput, {
* and ensuring consistent handling of stream options. * and ensuring consistent handling of stream options.
*/ */
protected async process(input: LLMCompletionInput): Promise<{ response: ChatResponse }> { protected async process(input: LLMCompletionInput): Promise<{ response: ChatResponse }> {
const { messages, options, provider } = input; const { messages, options } = input;
// Log input options // Add detailed logging about the input messages, particularly useful for tool follow-ups
log.info(`[LLMCompletionStage] Input options: ${JSON.stringify({ log.info(`========== LLM COMPLETION STAGE - INPUT MESSAGES ==========`);
model: options.model, log.info(`Total input messages: ${messages.length}`);
provider,
// Log if tool messages are present (used for follow-ups)
const toolMessages = messages.filter(m => m.role === 'tool');
if (toolMessages.length > 0) {
log.info(`Contains ${toolMessages.length} tool result messages - likely a tool follow-up request`);
}
// Log the last few messages to understand conversation context
const lastMessages = messages.slice(-3);
lastMessages.forEach((msg, idx) => {
const msgPosition = messages.length - lastMessages.length + idx;
log.info(`Message ${msgPosition} (${msg.role}): ${msg.content?.substring(0, 150)}${msg.content?.length > 150 ? '...' : ''}`);
if (msg.tool_calls) {
log.info(` Contains ${msg.tool_calls.length} tool calls`);
}
if (msg.tool_call_id) {
log.info(` Tool call ID: ${msg.tool_call_id}`);
}
});
// Log completion options
log.info(`LLM completion options: ${JSON.stringify({
model: options.model || 'default',
temperature: options.temperature,
enableTools: options.enableTools,
stream: options.stream, stream: options.stream,
enableTools: options.enableTools hasToolExecutionStatus: !!options.toolExecutionStatus
})}`); })}`);
// Create a deep copy of options to avoid modifying the original // Create a deep copy of options to avoid modifying the original
@ -70,8 +94,8 @@ export class LLMCompletionStage extends BasePipelineStage<LLMCompletionInput, {
} }
// Determine which provider to use // Determine which provider to use
let selectedProvider = provider; let selectedProvider = '';
if (!selectedProvider && updatedOptions.providerMetadata?.provider) { if (updatedOptions.providerMetadata?.provider) {
selectedProvider = updatedOptions.providerMetadata.provider; selectedProvider = updatedOptions.providerMetadata.provider;
log.info(`Using provider ${selectedProvider} from metadata for model ${updatedOptions.model}`); log.info(`Using provider ${selectedProvider} from metadata for model ${updatedOptions.model}`);
} }
@ -108,6 +132,28 @@ export class LLMCompletionStage extends BasePipelineStage<LLMCompletionInput, {
}; };
} }
// Add enhanced logging for debugging tool execution follow-ups
if (toolMessages.length > 0) {
if (response.tool_calls && response.tool_calls.length > 0) {
log.info(`Response contains ${response.tool_calls.length} tool calls`);
response.tool_calls.forEach((toolCall: any, idx: number) => {
log.info(`Tool call ${idx + 1}: ${toolCall.function?.name || 'unnamed'}`);
const args = typeof toolCall.function?.arguments === 'string'
? toolCall.function?.arguments
: JSON.stringify(toolCall.function?.arguments);
log.info(`Arguments: ${args?.substring(0, 100) || '{}'}`);
});
} else {
log.info(`Response contains no tool calls - plain text response`);
}
if (toolMessages.length > 0 && !response.tool_calls) {
log.info(`This appears to be a final response after tool execution (no new tool calls)`);
} else if (toolMessages.length > 0 && response.tool_calls && response.tool_calls.length > 0) {
log.info(`This appears to be a continued tool execution flow (tools followed by more tools)`);
}
}
return { response }; return { response };
} }
@ -133,6 +179,28 @@ export class LLMCompletionStage extends BasePipelineStage<LLMCompletionInput, {
}; };
} }
// Add enhanced logging for debugging tool execution follow-ups
if (toolMessages.length > 0) {
if (response.tool_calls && response.tool_calls.length > 0) {
log.info(`Response contains ${response.tool_calls.length} tool calls`);
response.tool_calls.forEach((toolCall: any, idx: number) => {
log.info(`Tool call ${idx + 1}: ${toolCall.function?.name || 'unnamed'}`);
const args = typeof toolCall.function?.arguments === 'string'
? toolCall.function?.arguments
: JSON.stringify(toolCall.function?.arguments);
log.info(`Arguments: ${args?.substring(0, 100) || '{}'}`);
});
} else {
log.info(`Response contains no tool calls - plain text response`);
}
if (toolMessages.length > 0 && !response.tool_calls) {
log.info(`This appears to be a final response after tool execution (no new tool calls)`);
} else if (toolMessages.length > 0 && response.tool_calls && response.tool_calls.length > 0) {
log.info(`This appears to be a continued tool execution flow (tools followed by more tools)`);
}
}
return { response }; return { response };
} }
} }

View File

@ -362,53 +362,55 @@ export class ToolCallingStage extends BasePipelineStage<ToolExecutionInput, { re
log.info(`========== TOOL EXECUTION COMPLETE ==========`); log.info(`========== TOOL EXECUTION COMPLETE ==========`);
log.info(`Completed execution of ${toolResults.length} tools in ${totalExecutionTime}ms`); log.info(`Completed execution of ${toolResults.length} tools in ${totalExecutionTime}ms`);
// Add tool results as messages // Add each tool result to the messages array
toolResults.forEach(result => { const toolResultMessages: Message[] = [];
// Format the result content based on type
let content: string;
if (typeof result.result === 'string') { for (const result of toolResults) {
content = result.result; const { toolCallId, name, result: toolResult } = result;
log.info(`Tool returned string result (${content.length} chars)`);
} else {
// For object results, format as JSON
try {
content = JSON.stringify(result.result, null, 2);
log.info(`Tool returned object result with keys: ${Object.keys(result.result).join(', ')}`);
} catch (error) {
content = String(result.result);
log.info(`Failed to stringify object result: ${error}`);
}
}
log.info(`Adding tool result message - Tool: ${result.name}, ID: ${result.toolCallId || 'unknown'}, Length: ${content.length}`); // Format result for message
const resultContent = typeof toolResult === 'string'
? toolResult
: JSON.stringify(toolResult, null, 2);
// Create a properly formatted tool response message // Add a new message for the tool result
updatedMessages.push({ const toolMessage: Message = {
role: 'tool', role: 'tool',
content: content, content: resultContent,
name: result.name, name: name,
tool_call_id: result.toolCallId tool_call_id: toolCallId
}); };
// Log a sample of the content for debugging // Log detailed info about each tool result
const contentPreview = content.substring(0, 100) + (content.length > 100 ? '...' : ''); log.info(`-------- Tool Result for ${name} (ID: ${toolCallId}) --------`);
log.info(`Tool result preview: ${contentPreview}`); log.info(`Result type: ${typeof toolResult}`);
}); log.info(`Result preview: ${resultContent.substring(0, 150)}${resultContent.length > 150 ? '...' : ''}`);
log.info(`Tool result status: ${resultContent.startsWith('Error:') ? 'ERROR' : 'SUCCESS'}`);
log.info(`Added ${toolResults.length} tool results to conversation`); updatedMessages.push(toolMessage);
toolResultMessages.push(toolMessage);
// If we have tool results, we need a follow-up call to the LLM
const needsFollowUp = toolResults.length > 0;
if (needsFollowUp) {
log.info(`Tool execution complete, LLM follow-up required with ${updatedMessages.length} messages`);
} }
// Log the decision about follow-up
log.info(`========== FOLLOW-UP DECISION ==========`);
const hasToolResults = toolResultMessages.length > 0;
const hasErrors = toolResultMessages.some(msg => msg.content.startsWith('Error:'));
const needsFollowUp = hasToolResults;
log.info(`Follow-up needed: ${needsFollowUp}`);
log.info(`Reasoning: ${hasToolResults ? 'Has tool results to process' : 'No tool results'} ${hasErrors ? ', contains errors' : ''}`);
log.info(`Total messages to return to pipeline: ${updatedMessages.length}`);
log.info(`Last 3 messages in conversation:`);
const lastMessages = updatedMessages.slice(-3);
lastMessages.forEach((msg, idx) => {
const position = updatedMessages.length - lastMessages.length + idx;
log.info(`Message ${position} (${msg.role}): ${msg.content?.substring(0, 100)}${msg.content?.length > 100 ? '...' : ''}`);
});
return { return {
response, response,
needsFollowUp, messages: updatedMessages,
messages: updatedMessages needsFollowUp
}; };
} }