跳转至

函数调用 (Typescript)

函数调用

在某些模型中添加的功能之一是“函数调用”。这个名字有点让人困惑。如果您认为这意味着模型可以调用函数,那是可以理解的,但实际并非如此。函数调用仅仅意味着模型的输出格式为JSON,使用预配置的模式,并使用预期的类型。然后您的代码可以使用模型的输出并用它来调用函数。使用Ollama中的JSON格式,您可以使用任何模型进行函数调用。

提供的两个示例可以从提供的文本中提取信息。第一个示例使用列夫·托尔斯泰的《战争与和平》前几章,并提取故事中介绍的角色的名称和头衔。第二个示例使用更复杂的模式从一系列电子邮件中提取地址和事件信息。

运行示例

  1. 克隆此仓库并导航至 examples/typescript-functioncalling 目录。
  2. 使用 npm install 安装依赖项。
  3. 查看 wp.txt 文件。
  4. 运行 tsx extractwp.ts
  5. 查看 info.txt 文件。
  6. 运行 tsx extractemail.ts

代码审查

这两个示例大致做同样的事情,但使用不同的源材料。它们都使用相同的系统提示,该提示告诉模型要预期一些指令和一个模式。然后我们将模式注入到提示中并生成答案。

第一个示例 extractwp.ts,将结果以JSON格式输出到控制台,列出《战争与和平》开头介绍的角色。第二个示例 extractemail.ts,稍微复杂一些,提取两种不同类型的信息:地址和事件。它将结果输出到一个JSON块中,然后将地址交给一个名为 reportAddresses 的函数,将事件交给另一个名为 reportEvents 的函数。

注意,这两个示例都在使用来自Intel的名为 neural-chat 的模型。这不是为函数调用优化的模型,但它在这项任务上表现非常出色。

接下来的步骤

尝试将您的一些真实电子邮件导出到输入文件中,看看模型的表现如何。尝试将第一个示例指向其他书籍。您甚至可以让它遍历所有章节,也许还可以计算书中任何角色出现的次数,以确定最重要的角色。您也可以尝试不同的模型。

源码

extractemail.ts

import { Ollama } from "ollama-node";
import { readFile } from "fs/promises";

// function to be called on events
function reportEvents(name: string, date: string, location: string) {
  const nameString = name ? `${name}` : `an event`;
  const dateString = date ? ` on ${date}` : ``;
  const locationString = location ? ` at ${location}` : ``;
  console.log(`You have an event: ${nameString}${dateString}${locationString}`)
}

// function to be called on addresses
function reportAddresses(address) {
  for (const field in address) {
    if (address[field]) {
      if (field === "city") {
        const city = address.city;
        const state = address.state ? `, ${address.state}` : '';
        const zip = address.zip ? ` ${address.zip}` : '';
        console.log(`${city}${state}${zip}`);
        break;
      } else {
        console.log(`${address[field]}`);
      }
    }
  }
  console.log(``);
}

async function main() {

  const ollama = new Ollama();

  const systemprompt = `You will be given a text along with a prompt and a schema. You will have to extract the information requested in the prompt from the text and generate output in JSON observing the schema provided. If the schema shows a type of integer or number, you must only show a integer for that field. A string should always be a valid string. If a value is unknown, leave it empty. Output the JSON with extra spaces to ensure that it pretty prints.`

  const schema = {
    "eventsQuantity": {
      "type": "integer",
      "description": "The number of events in the source text"
    },
    "addressesQuantity": {
      "type": "integer",
      "description": "The number of addresses in the source text"
    },
    "events": [{
      name: {
        "type": "string",
        description: "Name of the event"
      },
      "date": {
        "type": "string",
        "description": "Date of the event"
      },
      "location": {
        "type": "string",
        "description": "Location of the event"
      },
      "extraInfo": {
        "type": "string",
        "description": "Any extra information that is provided about the event."
      }
    }],
    "people": [{
      "name": {
        "type": "string",
        "description": "Name of the person"
      },
      "company": {
        "type": "string",
        "description": "Name of the company where they work"
      },
      "street": {
        "type": "string",
        "description": "Street address of the person or company. This is only the street name and the numerical address. Do not include city, state, or zip of the address in this field."
      },
      "city": {
        "type": "string",
        "description": "City portion of the address of the person or company"
      },
      "state": {
        "type": "string",
        "description": "State portion of the address of the person or company"
      },
      "zip": {
        "type": "string",
        "description": "Zip code of the person or company"
      },
      "extraInfo": {
        "type": "string",
        "description": "Any extra information that is provided about the location."
      }
    }]
  }

  const textcontent = await readFile("./info.txt", "utf-8").then((text) => text.split(" ").slice(0, 2000).join(" "));

  const prompt = `The source text is a series of emails that have been put into a single file. They are separated by three dashes. Review the source text and determine the full address of the person sending each of the emails as well as any events that we need to track. If they provide a company address use that. If any extra info is provided, such as a description of the place, or a floor, add it to extraInfo. The first field in the address JSON is quantity of events and should be set to the number of events tracked and the second field should be set to the number of addresses tracked in the file. Don't stuff an event into the output that isn't an event. Only add data to the mostly appropriate field. Don't make up fields that aren't in the schema. If there isn't a value for a field, use null. Output should be in JSON.\n\nSchema: \n${JSON.stringify(schema, null, 2)}\n\nSource Text:\n${textcontent}`

  await ollama.setModel("neural-chat");
  ollama.setSystemPrompt(systemprompt);
  ollama.setJSONFormat(true);
  const data = await ollama.generate(prompt);
  const output = JSON.parse(data.output);
  const events = output.events;
  const addresses = output.people;

  console.log(`Here are your ${output.eventsQuantity} events:`);
  for (const event of events) {
    reportEvents(event.name, event.date, event.location);
  }

  console.log(`\n\nHere are your ${output.addressesQuantity} addresses:`);
  for (const address of addresses) {
    reportAddresses(address);
  }
}

main();

extractwp.ts

import { Ollama } from "ollama-node";
import { readFile } from "fs/promises";

async function main() {

  const ollama = new Ollama();

  // Set the system prompt to prepare the model to receive a prompt and a schema and set some rules for the output.
  const systemprompt = `You will be given a text along with a prompt and a schema. You will have to extract the information requested in the prompt from the text and generate output in JSON observing the schema provided. If the schema shows a type of integer or number, you must only show a integer for that field. A string should always be a valid string. If a value is unknown, leave it empty. Output the JSON with extra spaces to ensure that it pretty prints.`

  const schema = {
    "people": [{
      "name": {
        "type": "string",
        "description": "Name of the person"
      },
      "title": {
        "type": "string",
        "description": "Title of the person"
      }
    }],
  }

  // Depending on the model chosen, you may be limited by the size of the context window, so limit the context to 2000 words.
  const textcontent = await readFile("./wp.txt", "utf-8").then((text) => text.split(" ").slice(0, 2000).join(" "));

  // Specific instructions for this task
  const prompt = `Review the source text and determine the 10 most important people to focus on. Then extract the name and title for those people. Output should be in JSON.\n\nSchema: \n${JSON.stringify(schema, null, 2)}\n\nSource Text:\n${textcontent}`

  await ollama.setModel("neural-chat");
  ollama.setSystemPrompt(systemprompt);

  // setJSONFormat is the equivalent of setting 'format: json' in the API
  ollama.setJSONFormat(true);
  await ollama.streamingGenerate(prompt, (word) => { process.stdout.write(word) })
}

main();

仓库地址

typescript-functioncalling