返回 Skill 列表
extension
分类: 开发与工程无需 API Key

"Convex Agents Debugging"

解决代理行为问题,记录LLM交互,并检查数据库状态。当响应不符合预期时使用此功能,以了解LLM接收到的上下文,或诊断数据问题。

person作者: jakexiaohubgithub

Purpose

Debugging tools help understand what's happening inside agents, what the LLM receives, and what's stored. Essential for developing reliable agent applications.

When to Use This Skill

  • Agent behavior is unexpected
  • LLM responses are off-target
  • Investigating why certain context isn't being used
  • Understanding message ordering
  • Checking file storage and references
  • Auditing tool calls and results
  • Profiling token usage

Log Raw LLM Requests and Responses

const myAgent = new Agent(components.agent, {
  name: "My Agent",
  languageModel: openai.chat("gpt-4o-mini"),
  rawRequestResponseHandler: async (ctx, { request, response }) => {
    console.log("LLM Request:", JSON.stringify(request, null, 2));
    console.log("LLM Response:", JSON.stringify(response, null, 2));

    await ctx.runMutation(internal.logging.saveLLMCall, {
      request,
      response,
      timestamp: Date.now(),
    });
  },
});

Log Context Messages

See exactly what context the LLM receives:

const myAgent = new Agent(components.agent, {
  name: "My Agent",
  languageModel: openai.chat("gpt-4o-mini"),
  contextHandler: async (ctx, args) => {
    console.log("Context Messages:", {
      recent: args.recent.length,
      search: args.search.length,
      input: args.inputMessages.length,
    });

    args.allMessages.forEach((msg, i) => {
      console.log(`Message ${i}:`, {
        role: msg.role,
        contentLength: typeof msg.content === "string"
          ? msg.content.length
          : JSON.stringify(msg.content).length,
      });
    });

    return args.allMessages;
  },
});

Inspect Database Tables

Query agent data directly:

export const getThreadMessages = query({
  args: { threadId: v.string() },
  handler: async (ctx, { threadId }) => {
    return await ctx.db
      .query(components.agent.tables.messages)
      .filter((msg) => msg.threadId === threadId)
      .collect();
  },
});

Fetch Context Manually

Inspect what context would be used:

import { fetchContextWithPrompt } from "@convex-dev/agent";

export const inspectContext = action({
  args: { threadId: v.string(), prompt: v.string() },
  handler: async (ctx, { threadId, prompt }) => {
    const { messages } = await fetchContextWithPrompt(ctx, components.agent, {
      threadId,
      prompt,
    });

    return {
      contextMessages: messages.length,
      messages: messages.map((msg) => ({
        role: msg.role,
        contentType: typeof msg.content,
      })),
    };
  },
});

Trace Tool Calls

Log all tool invocations:

export const myTool = createTool({
  description: "My tool",
  args: z.object({ query: z.string() }),
  handler: async (ctx, { query }): Promise<string> => {
    console.log("[TOOL] myTool called with:", query);
    const result = await someOperation(query);
    console.log("[TOOL] myTool returned:", result);
    return result;
  },
});

Fix Type Errors

Common circular reference issue:

// WRONG - no return type
export const myFunction = action({
  args: { prompt: v.string() },
  handler: async (ctx, { prompt }) => {
    return await someLogic();
  },
});

// CORRECT - explicit return type
export const myFunction = action({
  args: { prompt: v.string() },
  returns: v.string(),
  handler: async (ctx, { prompt }): Promise<string> => {
    return await someLogic();
  },
});

Analyze Message Structure

Debug message ordering:

export const analyzeMessages = query({
  args: { threadId: v.string() },
  handler: async (ctx, { threadId }) => {
    const messages = await listMessages(ctx, components.agent, {
      threadId,
      paginationOpts: { cursor: null, numItems: 100 },
    });

    return messages.results.map((msg) => ({
      order: msg.order,
      stepOrder: msg.stepOrder,
      role: msg.message.role,
      status: msg.status,
    }));
  },
});

Key Principles

  • Log early: Capture data while developing
  • Use console for quick checks: Fast iteration
  • Save important events: Archive LLM calls for analysis
  • Explicit return types: Prevents circular references
  • Dashboard inspection: Easiest way to see database state

Next Steps

  • See playground for interactive debugging
  • See fundamentals for agent setup
  • See context for context-aware debugging