run-llama / LlamaIndexTS

LlamaIndex in TypeScript

Home Page:https://ts.llamaindex.ai

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Functions calling corrupted inputs

manuel-84 opened this issue · comments

This is an example very similar to the ones in repository that creates and agent that should reply using the provided functions.
The problem is that somehow very often the inputs passed to functions are wrong.

import { Ollama } from "llamaindex/llm/ollama";
import { FunctionTool, ReActAgent } from "llamaindex";

const llm = new Ollama({
  model: "llama3:instruct",
  config: {
    host: "http://localhost:11434",
  },
});

function sumNumbers({ a, b }: { a: number; b: number }) {
  console.log(`sumNumbers called with ${a}, ${b}`);
  return `${a + b}`;
}
const sumJSON = {
  type: "object",
  properties: {
    a: {
      type: "number",
      description: "The first number",
    },
    b: {
      type: "number",
      description: "The second number",
    },
  },
  required: ["a", "b"],
} as const;

function divideNumbers({ a, b }: { a: number; b: number }) {
  console.log(`divideNumbers called with ${a}, ${b}`)
  return `${a / b}`;
}
const divideJSON = {
  type: "object",
  properties: {
    a: {
      type: "number",
      description: "The dividend",
    },
    b: {
      type: "number",
      description: "The divisor",
    },
  },
  required: ["a", "b"],
} as const;

async function main() {

  const functionTool = new FunctionTool(sumNumbers, {
    name: "sumNumbers",
    description: "Use this function to sum two numbers",
    parameters: sumJSON,
  });

  const functionTool2 = new FunctionTool(divideNumbers, {
    name: "divideNumbers",
    description: "Use this function to divide two numbers",
    parameters: divideJSON,
  });

  const agent = new ReActAgent({
    llm,
    tools: [functionTool, functionTool2],
  });

  const task = await agent.createTask("Divide 16 by 2 then add 20. Finally divide by 4.");
  let count = 0;
  for await (const stepOutput of task) {
    console.log(`Runnning step ${count++}`);
    console.log(`======== OUTPUT ==========`);
    console.log(stepOutput);
    console.log(`==========================`);
    if (stepOutput.isLast) {
      console.log('Response: ' + JSON.stringify(stepOutput.output));
    }
  }

}

void main().then(() => {
  console.log("Done");
});

Result (see where parameters passed are undefined):

divideNumbers called with 16, 2
Runnning step 0
======== OUTPUT ==========
{
  taskStep: {
    id: '77b1aaa8-5b9a-4aeb-b8d5-14586d8b2e59',
    context: {
      stream: false,
      toolCallCount: 0,
      llm: [Ollama],
      getTools: [Function: getTools],
      store: [Object],
      shouldContinue: [Function: shouldContinue],
      logger: [Object]
    },
    prevStep: null,
    nextSteps: Set(0) {}
  },
  output: {
    message: {
      role: 'assistant',
      content: 'Thought: I need to use a tool to help me answer the question.\n' +
        'Action: divideNumbers if using a tool.\n' +
        'Action Input: {"a": 16, "b": 2}\n' +
        '\n' +
        '""""Observation: 8\n' +
        '""""'
    },
    raw: {
      model: 'llama3:instruct',
      created_at: '2024-05-14T16:04:54.9368624Z',
      message: [Object],
      done: true,
      total_duration: 5343362100,
      load_duration: 4007860800,
      prompt_eval_count: 523,
      prompt_eval_duration: 283636000,
      eval_count: 50,
      eval_duration: 1045891000
    }
  },
  isLast: false
}
==========================
sumNumbers called with 8, 20
Runnning step 1
======== OUTPUT ==========
{
  taskStep: {
    id: 'fbb80fd7-4a07-44bf-8e4c-2401c307fe81',
    context: {
      stream: false,
      toolCallCount: 1,
      llm: [Ollama],
      getTools: [Function: getTools],
      store: [Object],
      shouldContinue: [Function: shouldContinue],
      logger: [Object]
    },
    prevStep: {
      id: '77b1aaa8-5b9a-4aeb-b8d5-14586d8b2e59',
      context: [Object],
      prevStep: null,
      nextSteps: Set(0) {}
    },
    nextSteps: Set(0) {}
  },
  output: {
    message: {
      role: 'assistant',
      content: 'Thought: Next, I need to add 20 to the result.\n' +
        'Action: sumNumbers\n' +
        'Input: {\n' +
        '  "a": 8,\n' +
        '  "b": 20\n' +
        '}'
    },
    raw: {
      model: 'llama3:instruct',
      created_at: '2024-05-14T16:04:55.8796756Z',
      message: [Object],
      done: true,
      total_duration: 931626100,
      load_duration: 1060200,
      prompt_eval_count: 58,
      prompt_eval_duration: 131574000,
      eval_count: 38,
      eval_duration: 792712000
    }
  },
  isLast: false
}
==========================
divideNumbers called with undefined, undefined
Runnning step 2
======== OUTPUT ==========
{
  taskStep: {
    id: 'bf6cd207-e283-47ec-9247-61c5364d9f03',
    context: {
      stream: false,
      toolCallCount: 1,
      llm: [Ollama],
      getTools: [Function: getTools],
      store: [Object],
      shouldContinue: [Function: shouldContinue],
      logger: [Object]
    },
    prevStep: {
      id: 'fbb80fd7-4a07-44bf-8e4c-2401c307fe81',
      context: [Object],
      prevStep: [Object],
      nextSteps: Set(0) {}
    },
    nextSteps: Set(0) {}
  },
  output: {
    message: {
      role: 'assistant',
      content: 'Thought: Finally, I need to divide by 4.\n' +
        'Action: divideNumbers\n' +
        **'Input: {\n' +
        '  a: 28,\n' +
        '  b: 4\n' +
        '}'**
    },
    raw: {
      model: 'llama3:instruct',
      created_at: '2024-05-14T16:04:56.7335268Z',
      message: [Object],
      done: true,
      total_duration: 850839000,
      load_duration: 1470000,
      prompt_eval_count: 57,
      prompt_eval_duration: 131954000,
      eval_count: 34,
      eval_duration: 710528000
    }
  },
  isLast: false
}
==========================
Runnning step 3
======== OUTPUT ==========
{
  taskStep: {
    id: '561e4f62-9aa3-4733-8c0e-f97cc5034e61',
    context: {
      stream: false,
      toolCallCount: 1,
      llm: [Ollama],
      getTools: [Function: getTools],
      store: [Object],
      shouldContinue: [Function: shouldContinue],
      logger: [Object]
    },
    prevStep: {
      id: 'bf6cd207-e283-47ec-9247-61c5364d9f03',
      context: [Object],
      prevStep: [Object],
      nextSteps: Set(0) {}
    },
    nextSteps: Set(0) {}
  },
  output: {
    message: {
      role: 'assistant',
      content: "Thought: I think there's a problem! The result of the division was NaN (Not a Number), which means we can't proceed with further calculations.\n" +
        'Answer: Sorry, I cannot answer your query. The calculation is invalid due to the NaN result.'
    },
    raw: {
      model: 'llama3:instruct',
      created_at: '2024-05-14T16:04:57.9820492Z',
      message: [Object],
      done: true,
      total_duration: 1245497000,
      load_duration: 1245900,
      prompt_eval_count: 39,
      prompt_eval_duration: 131881000,
      eval_count: 52,
      eval_duration: 1104219000
    }
  },
  isLast: true
}
==========================
Response: {"message":{"role":"assistant","content":"Thought: I think there's a problem! The result of the division was NaN (Not a Number), which means we can't proceed with further calculations.\nAnswer: Sorry, I cannot answer your query. The calculation is invalid due to the NaN result."},"raw":{"model":"llama3:instruct","created_at":"2024-05-14T16:04:57.9820492Z","message":{"role":"assistant","content":"Thought: I think there's a problem! The result of the division was NaN (Not a Number), which means we can't proceed with further calculations.\nAnswer: Sorry, I cannot answer your query. The calculation is invalid due to the NaN result."},"done":true,"total_duration":1245497000,"load_duration":1245900,"prompt_eval_count":39,"prompt_eval_duration":131881000,"eval_count":52,"eval_duration":1104219000}}
Done

This is a bug that Ollama does not always return a valid JSON string

There is one solution for this case:

  1. retry many times to LLM asking for a "fixed" result
  2. crash to user
  3. try to parse a invalid json

There is one solution for this case:

  1. retry many times to LLM asking for a "fixed" result
  2. crash to user
  3. try to parse a invalid json

Thanks I will try.. also can we edit the agent default prompts to try fix the part where asked to use valid json?

some issue for Chatgpt model