mirror of
https://github.com/run-llama/LlamaIndexTS.git
synced 2026-07-02 20:13:52 -04:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 34ff2a9a0e | |||
| cc2c5f3c2e | |||
| 269f4f6703 |
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"llamaindex": patch
|
||||
---
|
||||
|
||||
feat: add filtering of metadata to PGVectorStore
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"llamaindex": patch
|
||||
---
|
||||
|
||||
feat(reranker): cohere reranker
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"llamaindex": patch
|
||||
---
|
||||
|
||||
feat: use batching in vector store index
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"create-llama": patch
|
||||
---
|
||||
|
||||
update fastapi for CVE-2024-24762
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"llamaindex": patch
|
||||
---
|
||||
|
||||
Add reader for LlamaParse
|
||||
@@ -9,7 +9,6 @@ module.exports = {
|
||||
},
|
||||
rules: {
|
||||
"max-params": ["error", 4],
|
||||
"prefer-const": "error",
|
||||
},
|
||||
ignorePatterns: ["dist/"],
|
||||
};
|
||||
|
||||
@@ -61,13 +61,10 @@ jobs:
|
||||
run: pnpm run build --filter llamaindex
|
||||
- name: Copy examples
|
||||
run: rsync -rv --exclude=node_modules ./examples ${{ runner.temp }}
|
||||
- name: Pack @llamaindex/env
|
||||
run: pnpm pack --pack-destination ${{ runner.temp }}
|
||||
working-directory: packages/env
|
||||
- name: Pack llamaindex
|
||||
- name: Pack
|
||||
run: pnpm pack --pack-destination ${{ runner.temp }}
|
||||
working-directory: packages/core
|
||||
- name: Install
|
||||
- name: Install llamaindex
|
||||
run: npm add ${{ runner.temp }}/*.tgz
|
||||
working-directory: ${{ runner.temp }}/examples
|
||||
- name: Run Type Check
|
||||
|
||||
Vendored
+1
@@ -5,6 +5,7 @@
|
||||
"[xml]": {
|
||||
"editor.defaultFormatter": "redhat.vscode-xml"
|
||||
},
|
||||
"jest.rootPath": "./packages/core",
|
||||
"[python]": {
|
||||
"editor.defaultFormatter": "ms-python.black-formatter"
|
||||
},
|
||||
|
||||
@@ -127,7 +127,6 @@ module.exports = nextConfig;
|
||||
- Anthropic Claude Instant and Claude 2
|
||||
- Llama2 Chat LLMs (70B, 13B, and 7B parameters)
|
||||
- MistralAI Chat LLMs
|
||||
- Fireworks Chat LLMs
|
||||
|
||||
## Contributing:
|
||||
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
label: "Agents"
|
||||
position: 3
|
||||
|
||||
@@ -1,314 +0,0 @@
|
||||
# Multi-Document Agent
|
||||
|
||||
In this guide, you learn towards setting up an agent that can effectively answer different types of questions over a larger set of documents.
|
||||
|
||||
These questions include the following
|
||||
|
||||
- QA over a specific doc
|
||||
- QA comparing different docs
|
||||
- Summaries over a specific doc
|
||||
- Comparing summaries between different docs
|
||||
|
||||
We do this with the following architecture:
|
||||
|
||||
- setup a “document agent” over each Document: each doc agent can do QA/summarization within its doc
|
||||
- setup a top-level agent over this set of document agents. Do tool retrieval and then do CoT over the set of tools to answer a question.
|
||||
|
||||
## Setup and Download Data
|
||||
|
||||
We first start by installing the necessary libraries and downloading the data.
|
||||
|
||||
```bash
|
||||
pnpm i llamaindex
|
||||
```
|
||||
|
||||
```ts
|
||||
import {
|
||||
Document,
|
||||
ObjectIndex,
|
||||
OpenAI,
|
||||
OpenAIAgent,
|
||||
QueryEngineTool,
|
||||
SimpleNodeParser,
|
||||
SimpleToolNodeMapping,
|
||||
SummaryIndex,
|
||||
VectorStoreIndex,
|
||||
serviceContextFromDefaults,
|
||||
storageContextFromDefaults,
|
||||
} from "llamaindex";
|
||||
```
|
||||
|
||||
And then for the data we will run through a list of countries and download the wikipedia page for each country.
|
||||
|
||||
```ts
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
const dataPath = path.join(__dirname, "tmp_data");
|
||||
|
||||
const extractWikipediaTitle = async (title: string) => {
|
||||
const fileExists = fs.existsSync(path.join(dataPath, `${title}.txt`));
|
||||
|
||||
if (fileExists) {
|
||||
console.log(`File already exists for the title: ${title}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const queryParams = new URLSearchParams({
|
||||
action: "query",
|
||||
format: "json",
|
||||
titles: title,
|
||||
prop: "extracts",
|
||||
explaintext: "true",
|
||||
});
|
||||
|
||||
const url = `https://en.wikipedia.org/w/api.php?${queryParams}`;
|
||||
|
||||
const response = await fetch(url);
|
||||
const data: any = await response.json();
|
||||
|
||||
const pages = data.query.pages;
|
||||
const page = pages[Object.keys(pages)[0]];
|
||||
const wikiText = page.extract;
|
||||
|
||||
await new Promise((resolve) => {
|
||||
fs.writeFile(path.join(dataPath, `${title}.txt`), wikiText, (err: any) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
resolve(title);
|
||||
return;
|
||||
}
|
||||
console.log(`${title} stored in file!`);
|
||||
|
||||
resolve(title);
|
||||
});
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
```ts
|
||||
export const extractWikipedia = async (titles: string[]) => {
|
||||
if (!fs.existsSync(dataPath)) {
|
||||
fs.mkdirSync(dataPath);
|
||||
}
|
||||
|
||||
for await (const title of titles) {
|
||||
await extractWikipediaTitle(title);
|
||||
}
|
||||
|
||||
console.log("Extration finished!");
|
||||
```
|
||||
|
||||
These files will be saved in the `tmp_data` folder.
|
||||
|
||||
Now we can call the function to download the data for each country.
|
||||
|
||||
```ts
|
||||
await extractWikipedia([
|
||||
"Brazil",
|
||||
"United States",
|
||||
"Canada",
|
||||
"Mexico",
|
||||
"Argentina",
|
||||
"Chile",
|
||||
"Colombia",
|
||||
"Peru",
|
||||
"Venezuela",
|
||||
"Ecuador",
|
||||
"Bolivia",
|
||||
"Paraguay",
|
||||
"Uruguay",
|
||||
"Guyana",
|
||||
"Suriname",
|
||||
"French Guiana",
|
||||
"Falkland Islands",
|
||||
]);
|
||||
```
|
||||
|
||||
## Load the data
|
||||
|
||||
Now that we have the data, we can load it into the LlamaIndex and store as a document.
|
||||
|
||||
```ts
|
||||
import { Document } from "llamaindex";
|
||||
|
||||
const countryDocs: Record<string, Document> = {};
|
||||
|
||||
for (const title of wikiTitles) {
|
||||
const path = `./agent/helpers/tmp_data/${title}.txt`;
|
||||
const text = await fs.readFile(path, "utf-8");
|
||||
const document = new Document({ text: text, id_: path });
|
||||
countryDocs[title] = document;
|
||||
}
|
||||
```
|
||||
|
||||
## Setup LLM and StorageContext
|
||||
|
||||
We will be using gpt-4 for this example and we will use the `StorageContext` to store the documents in-memory.
|
||||
|
||||
```ts
|
||||
const llm = new OpenAI({
|
||||
model: "gpt-4",
|
||||
});
|
||||
|
||||
const ctx = serviceContextFromDefaults({ llm });
|
||||
|
||||
const storageContext = await storageContextFromDefaults({
|
||||
persistDir: "./storage",
|
||||
});
|
||||
```
|
||||
|
||||
## Building Multi-Document Agents
|
||||
|
||||
In this section we show you how to construct the multi-document agent. We first build a document agent for each document, and then define the top-level parent agent with an object index.
|
||||
|
||||
```ts
|
||||
const documentAgents: Record<string, any> = {};
|
||||
const queryEngines: Record<string, any> = {};
|
||||
```
|
||||
|
||||
Now we iterate over each country and create a document agent for each one.
|
||||
|
||||
### Build Agent for each Document
|
||||
|
||||
In this section we define “document agents” for each document.
|
||||
|
||||
We define both a vector index (for semantic search) and summary index (for summarization) for each document. The two query engines are then converted into tools that are passed to an OpenAI function calling agent.
|
||||
|
||||
This document agent can dynamically choose to perform semantic search or summarization within a given document.
|
||||
|
||||
We create a separate document agent for each coutnry.
|
||||
|
||||
```ts
|
||||
for (const title of wikiTitles) {
|
||||
// parse the document into nodes
|
||||
const nodes = new SimpleNodeParser({
|
||||
chunkSize: 200,
|
||||
chunkOverlap: 20,
|
||||
}).getNodesFromDocuments([countryDocs[title]]);
|
||||
|
||||
// create the vector index for specific search
|
||||
const vectorIndex = await VectorStoreIndex.init({
|
||||
serviceContext: serviceContext,
|
||||
storageContext: storageContext,
|
||||
nodes,
|
||||
});
|
||||
|
||||
// create the summary index for broader search
|
||||
const summaryIndex = await SummaryIndex.init({
|
||||
serviceContext: serviceContext,
|
||||
nodes,
|
||||
});
|
||||
|
||||
const vectorQueryEngine = summaryIndex.asQueryEngine();
|
||||
const summaryQueryEngine = summaryIndex.asQueryEngine();
|
||||
|
||||
// create the query engines for each task
|
||||
const queryEngineTools = [
|
||||
new QueryEngineTool({
|
||||
queryEngine: vectorQueryEngine,
|
||||
metadata: {
|
||||
name: "vector_tool",
|
||||
description: `Useful for questions related to specific aspects of ${title} (e.g. the history, arts and culture, sports, demographics, or more).`,
|
||||
},
|
||||
}),
|
||||
new QueryEngineTool({
|
||||
queryEngine: summaryQueryEngine,
|
||||
metadata: {
|
||||
name: "summary_tool",
|
||||
description: `Useful for any requests that require a holistic summary of EVERYTHING about ${title}. For questions about more specific sections, please use the vector_tool.`,
|
||||
},
|
||||
}),
|
||||
];
|
||||
|
||||
// create the document agent
|
||||
const agent = new OpenAIAgent({
|
||||
tools: queryEngineTools,
|
||||
llm,
|
||||
verbose: true,
|
||||
});
|
||||
|
||||
documentAgents[title] = agent;
|
||||
queryEngines[title] = vectorIndex.asQueryEngine();
|
||||
}
|
||||
```
|
||||
|
||||
## Build Top-Level Agent
|
||||
|
||||
Now we define the top-level agent that can answer questions over the set of document agents.
|
||||
|
||||
This agent takes in all document agents as tools. This specific agent RetrieverOpenAIAgent performs tool retrieval before tool use (unlike a default agent that tries to put all tools in the prompt).
|
||||
|
||||
Here we use a top-k retriever, but we encourage you to customize the tool retriever method!
|
||||
|
||||
Firstly, we create a tool for each document agent
|
||||
|
||||
```ts
|
||||
const allTools: QueryEngineTool[] = [];
|
||||
```
|
||||
|
||||
```ts
|
||||
for (const title of wikiTitles) {
|
||||
const wikiSummary = `
|
||||
This content contains Wikipedia articles about ${title}.
|
||||
Use this tool if you want to answer any questions about ${title}
|
||||
`;
|
||||
|
||||
const docTool = new QueryEngineTool({
|
||||
queryEngine: documentAgents[title],
|
||||
metadata: {
|
||||
name: `tool_${title}`,
|
||||
description: wikiSummary,
|
||||
},
|
||||
});
|
||||
|
||||
allTools.push(docTool);
|
||||
}
|
||||
```
|
||||
|
||||
Our top level agent will use this document agents as tools and use toolRetriever to retrieve the best tool to answer a question.
|
||||
|
||||
```ts
|
||||
// map the tools to nodes
|
||||
const toolMapping = SimpleToolNodeMapping.fromObjects(allTools);
|
||||
|
||||
// create the object index
|
||||
const objectIndex = await ObjectIndex.fromObjects(
|
||||
allTools,
|
||||
toolMapping,
|
||||
VectorStoreIndex,
|
||||
{
|
||||
serviceContext,
|
||||
storageContext,
|
||||
},
|
||||
);
|
||||
|
||||
// create the top agent
|
||||
const topAgent = new OpenAIAgent({
|
||||
toolRetriever: await objectIndex.asRetriever({}),
|
||||
llm,
|
||||
verbose: true,
|
||||
prefixMessages: [
|
||||
{
|
||||
content:
|
||||
"You are an agent designed to answer queries about a set of given countries. Please always use the tools provided to answer a question. Do not rely on prior knowledge.",
|
||||
role: "system",
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
## Use the Agent
|
||||
|
||||
Now we can use the agent to answer questions.
|
||||
|
||||
```ts
|
||||
const response = await topAgent.chat({
|
||||
message: "Tell me the differences between Brazil and Canada economics?",
|
||||
});
|
||||
|
||||
// print output
|
||||
console.log(response);
|
||||
```
|
||||
|
||||
You can find the full code for this example [here](https://github.com/run-llama/LlamaIndexTS/tree/main/examples/agent/multi-document-agent.ts)
|
||||
@@ -1,7 +1,3 @@
|
||||
---
|
||||
sidebar_position: 0
|
||||
---
|
||||
|
||||
# OpenAI Agent
|
||||
|
||||
OpenAI API that supports function calling, it’s never been easier to build your own agent!
|
||||
@@ -86,7 +82,7 @@ const divideFunctionTool = new FunctionTool(divideNumbers, {
|
||||
Now we can create an OpenAIAgent with the function tools.
|
||||
|
||||
```ts
|
||||
const agent = new OpenAIAgent({
|
||||
const worker = new OpenAIAgent({
|
||||
tools: [sumFunctionTool, divideFunctionTool],
|
||||
verbose: true,
|
||||
});
|
||||
@@ -97,7 +93,7 @@ const agent = new OpenAIAgent({
|
||||
Now we can chat with the agent.
|
||||
|
||||
```ts
|
||||
const response = await agent.chat({
|
||||
const response = await worker.chat({
|
||||
message: "How much is 5 + 5? then divide by 2",
|
||||
});
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
# OpenAI Agent + QueryEngineTool
|
||||
|
||||
QueryEngineTool is a tool that allows you to query a vector index. In this example, we will create a vector index from a set of documents and then create a QueryEngineTool from the vector index. We will then create an OpenAIAgent with the QueryEngineTool and chat with the agent.
|
||||
|
||||
@@ -1,203 +0,0 @@
|
||||
# ReAct Agent
|
||||
|
||||
The ReAct agent is an AI agent that can reason over the next action, construct an action command, execute the action, and repeat these steps in an iterative loop until the task is complete.
|
||||
|
||||
In this notebook tutorial, we showcase how to write your ReAct agent using the `llamaindex` package.
|
||||
|
||||
## Setup
|
||||
|
||||
First, you need to install the `llamaindex` package. You can do this by running the following command in your terminal:
|
||||
|
||||
```bash
|
||||
pnpm i llamaindex
|
||||
```
|
||||
|
||||
And then you can import the `OpenAIAgent` and `FunctionTool` from the `llamaindex` package.
|
||||
|
||||
```ts
|
||||
import { FunctionTool, OpenAIAgent } from "llamaindex";
|
||||
```
|
||||
|
||||
Then we can define a function to sum two numbers and another function to divide two numbers.
|
||||
|
||||
```ts
|
||||
function sumNumbers({ a, b }: { a: number; b: number }): number {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
// Define a function to divide two numbers
|
||||
function divideNumbers({ a, b }: { a: number; b: number }): number {
|
||||
return a / b;
|
||||
}
|
||||
```
|
||||
|
||||
## Create a function tool
|
||||
|
||||
Now we can create a function tool from the sum function and another function tool from the divide function.
|
||||
|
||||
For the parameters of the sum function, we can define a JSON schema.
|
||||
|
||||
### JSON Schema
|
||||
|
||||
```ts
|
||||
const sumJSON = {
|
||||
type: "object",
|
||||
properties: {
|
||||
a: {
|
||||
type: "number",
|
||||
description: "The first number",
|
||||
},
|
||||
b: {
|
||||
type: "number",
|
||||
description: "The second number",
|
||||
},
|
||||
},
|
||||
required: ["a", "b"],
|
||||
};
|
||||
|
||||
const divideJSON = {
|
||||
type: "object",
|
||||
properties: {
|
||||
a: {
|
||||
type: "number",
|
||||
description: "The dividend a to divide",
|
||||
},
|
||||
b: {
|
||||
type: "number",
|
||||
description: "The divisor b to divide by",
|
||||
},
|
||||
},
|
||||
required: ["a", "b"],
|
||||
};
|
||||
|
||||
const sumFunctionTool = new FunctionTool(sumNumbers, {
|
||||
name: "sumNumbers",
|
||||
description: "Use this function to sum two numbers",
|
||||
parameters: sumJSON,
|
||||
});
|
||||
|
||||
const divideFunctionTool = new FunctionTool(divideNumbers, {
|
||||
name: "divideNumbers",
|
||||
description: "Use this function to divide two numbers",
|
||||
parameters: divideJSON,
|
||||
});
|
||||
```
|
||||
|
||||
## Create an ReAct
|
||||
|
||||
Now we can create an OpenAIAgent with the function tools.
|
||||
|
||||
```ts
|
||||
const agent = new ReActAgent({
|
||||
tools: [sumFunctionTool, divideFunctionTool],
|
||||
verbose: true,
|
||||
});
|
||||
```
|
||||
|
||||
## Chat with the agent
|
||||
|
||||
Now we can chat with the agent.
|
||||
|
||||
```ts
|
||||
const response = await agent.chat({
|
||||
message: "How much is 5 + 5? then divide by 2",
|
||||
});
|
||||
|
||||
console.log(String(response));
|
||||
```
|
||||
|
||||
The output will be:
|
||||
|
||||
```bash
|
||||
Thought: I need to use a tool to help me answer the question.
|
||||
Action: sumNumbers
|
||||
Action Input: {"a":5,"b":5}
|
||||
|
||||
Observation: 10
|
||||
Thought: I can answer without using any more tools.
|
||||
Answer: The sum of 5 and 5 is 10, and when divided by 2, the result is 5.
|
||||
|
||||
The sum of 5 and 5 is 10, and when divided by 2, the result is 5.
|
||||
```
|
||||
|
||||
## Full code
|
||||
|
||||
```ts
|
||||
import { FunctionTool, ReActAgent } from "llamaindex";
|
||||
|
||||
// Define a function to sum two numbers
|
||||
function sumNumbers({ a, b }: { a: number; b: number }): number {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
// Define a function to divide two numbers
|
||||
function divideNumbers({ a, b }: { a: number; b: number }): number {
|
||||
return a / b;
|
||||
}
|
||||
|
||||
// Define the parameters of the sum function as a JSON schema
|
||||
const sumJSON = {
|
||||
type: "object",
|
||||
properties: {
|
||||
a: {
|
||||
type: "number",
|
||||
description: "The first number",
|
||||
},
|
||||
b: {
|
||||
type: "number",
|
||||
description: "The second number",
|
||||
},
|
||||
},
|
||||
required: ["a", "b"],
|
||||
};
|
||||
|
||||
// Define the parameters of the divide function as a JSON schema
|
||||
const divideJSON = {
|
||||
type: "object",
|
||||
properties: {
|
||||
a: {
|
||||
type: "number",
|
||||
description: "The argument a to divide",
|
||||
},
|
||||
b: {
|
||||
type: "number",
|
||||
description: "The argument b to divide",
|
||||
},
|
||||
},
|
||||
required: ["a", "b"],
|
||||
};
|
||||
|
||||
async function main() {
|
||||
// Create a function tool from the sum function
|
||||
const sumFunctionTool = new FunctionTool(sumNumbers, {
|
||||
name: "sumNumbers",
|
||||
description: "Use this function to sum two numbers",
|
||||
parameters: sumJSON,
|
||||
});
|
||||
|
||||
// Create a function tool from the divide function
|
||||
const divideFunctionTool = new FunctionTool(divideNumbers, {
|
||||
name: "divideNumbers",
|
||||
description: "Use this function to divide two numbers",
|
||||
parameters: divideJSON,
|
||||
});
|
||||
|
||||
// Create an OpenAIAgent with the function tools
|
||||
const agent = new OpenAIAgent({
|
||||
tools: [sumFunctionTool, divideFunctionTool],
|
||||
verbose: true,
|
||||
});
|
||||
|
||||
// Chat with the agent
|
||||
const response = await agent.chat({
|
||||
message: "I want to sum 5 and 5 and then divide by 2",
|
||||
});
|
||||
|
||||
// Print the response
|
||||
console.log(String(response));
|
||||
}
|
||||
|
||||
main().then(() => {
|
||||
console.log("Done");
|
||||
});
|
||||
```
|
||||
@@ -5,7 +5,6 @@ sidebar_position: 4
|
||||
import CodeBlock from "@theme/CodeBlock";
|
||||
import CodeSource from "!raw-loader!../../../../examples/readers/src/simple-directory-reader";
|
||||
import CodeSource2 from "!raw-loader!../../../../examples/readers/src/custom-simple-directory-reader";
|
||||
import CodeSource3 from "!raw-loader!../../../../examples/readers/src/llamaparse";
|
||||
|
||||
# Loader
|
||||
|
||||
@@ -31,18 +30,6 @@ Or pass new readers for `fileExtToReader` to support more file types.
|
||||
{CodeSource2}
|
||||
</CodeBlock>
|
||||
|
||||
### LlamaParse
|
||||
|
||||
LlamaParse is an API created by LlamaIndex to efficiently parse files, e.g. it's great at converting PDF tables into markdown.
|
||||
|
||||
To use it, first login and get an API key from https://cloud.llamaindex.ai. Make sure to store the key in the environment variable `LLAMA_CLOUD_API_KEY`.
|
||||
|
||||
Then, you can use the `LlamaParseReader` class to read a local PDF file and convert it into a markdown document that can be used by LlamaIndex:
|
||||
|
||||
<CodeBlock language="ts">{CodeSource3}</CodeBlock>
|
||||
|
||||
Alternatively, you can set the [`resultType`](../api/classes/LlamaParseReader.md#resulttype) option to `text` to get the parsed document as a text string.
|
||||
|
||||
## API Reference
|
||||
|
||||
- [SimpleDirectoryReader](../api/classes/SimpleDirectoryReader.md)
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
sidebar_position: 4
|
||||
---
|
||||
|
||||
# Embedding
|
||||
|
||||
The embedding model in LlamaIndex is responsible for creating numerical representations of text. By default, LlamaIndex will use the `text-embedding-ada-002` model from OpenAI.
|
||||
@@ -12,11 +16,7 @@ const openaiEmbeds = new OpenAIEmbedding();
|
||||
const serviceContext = serviceContextFromDefaults({ embedModel: openaiEmbeds });
|
||||
```
|
||||
|
||||
## Local Embedding
|
||||
|
||||
For local embeddings, you can use the [HuggingFace](./available_embeddings/huggingface.md) embedding model.
|
||||
|
||||
## API Reference
|
||||
|
||||
- [OpenAIEmbedding](../../api/classes/OpenAIEmbedding.md)
|
||||
- [ServiceContext](../../api/interfaces//ServiceContext.md)
|
||||
- [OpenAIEmbedding](../api/classes/OpenAIEmbedding.md)
|
||||
- [ServiceContext](../api/interfaces//ServiceContext.md)
|
||||
@@ -1,2 +0,0 @@
|
||||
label: "Embeddings"
|
||||
position: 3
|
||||
@@ -1 +0,0 @@
|
||||
label: "Available Embeddings"
|
||||
@@ -1,25 +0,0 @@
|
||||
# HuggingFace
|
||||
|
||||
To use HuggingFace embeddings, you need to import `HuggingFaceEmbedding` from `llamaindex`.
|
||||
|
||||
```ts
|
||||
import { HuggingFaceEmbedding, serviceContextFromDefaults } from "llamaindex";
|
||||
|
||||
const huggingFaceEmbeds = new HuggingFaceEmbedding();
|
||||
|
||||
const serviceContext = serviceContextFromDefaults({ embedModel: openaiEmbeds });
|
||||
|
||||
const document = new Document({ text: essay, id_: "essay" });
|
||||
|
||||
const index = await VectorStoreIndex.fromDocuments([document], {
|
||||
serviceContext,
|
||||
});
|
||||
|
||||
const queryEngine = index.asQueryEngine();
|
||||
|
||||
const query = "What is the meaning of life?";
|
||||
|
||||
const results = await queryEngine.query({
|
||||
query,
|
||||
});
|
||||
```
|
||||
@@ -1,29 +0,0 @@
|
||||
# MistralAI
|
||||
|
||||
To use MistralAI embeddings, you need to import `MistralAIEmbedding` from `llamaindex`.
|
||||
|
||||
```ts
|
||||
import { MistralAIEmbedding, serviceContextFromDefaults } from "llamaindex";
|
||||
|
||||
const mistralEmbedModel = new MistralAIEmbedding({
|
||||
apiKey: "<YOUR_API_KEY>",
|
||||
});
|
||||
|
||||
const serviceContext = serviceContextFromDefaults({
|
||||
embedModel: mistralEmbedModel,
|
||||
});
|
||||
|
||||
const document = new Document({ text: essay, id_: "essay" });
|
||||
|
||||
const index = await VectorStoreIndex.fromDocuments([document], {
|
||||
serviceContext,
|
||||
});
|
||||
|
||||
const queryEngine = index.asQueryEngine();
|
||||
|
||||
const query = "What is the meaning of life?";
|
||||
|
||||
const results = await queryEngine.query({
|
||||
query,
|
||||
});
|
||||
```
|
||||
@@ -1,27 +0,0 @@
|
||||
# Ollama
|
||||
|
||||
To use Ollama embeddings, you need to import `Ollama` from `llamaindex`.
|
||||
|
||||
```ts
|
||||
import { Ollama, serviceContextFromDefaults } from "llamaindex";
|
||||
|
||||
const ollamaEmbedModel = new Ollama();
|
||||
|
||||
const serviceContext = serviceContextFromDefaults({
|
||||
embedModel: ollamaEmbedModel,
|
||||
});
|
||||
|
||||
const document = new Document({ text: essay, id_: "essay" });
|
||||
|
||||
const index = await VectorStoreIndex.fromDocuments([document], {
|
||||
serviceContext,
|
||||
});
|
||||
|
||||
const queryEngine = index.asQueryEngine();
|
||||
|
||||
const query = "What is the meaning of life?";
|
||||
|
||||
const results = await queryEngine.query({
|
||||
query,
|
||||
});
|
||||
```
|
||||
@@ -1,27 +0,0 @@
|
||||
# OpenAI
|
||||
|
||||
To use OpenAI embeddings, you need to import `OpenAIEmbedding` from `llamaindex`.
|
||||
|
||||
```ts
|
||||
import { OpenAIEmbedding, serviceContextFromDefaults } from "llamaindex";
|
||||
|
||||
const openaiEmbedModel = new OpenAIEmbedding();
|
||||
|
||||
const serviceContext = serviceContextFromDefaults({
|
||||
embedModel: openaiEmbedModel,
|
||||
});
|
||||
|
||||
const document = new Document({ text: essay, id_: "essay" });
|
||||
|
||||
const index = await VectorStoreIndex.fromDocuments([document], {
|
||||
serviceContext,
|
||||
});
|
||||
|
||||
const queryEngine = index.asQueryEngine();
|
||||
|
||||
const query = "What is the meaning of life?";
|
||||
|
||||
const results = await queryEngine.query({
|
||||
query,
|
||||
});
|
||||
```
|
||||
@@ -1,29 +0,0 @@
|
||||
# Together
|
||||
|
||||
To use together embeddings, you need to import `TogetherEmbedding` from `llamaindex`.
|
||||
|
||||
```ts
|
||||
import { TogetherEmbedding, serviceContextFromDefaults } from "llamaindex";
|
||||
|
||||
const togetherEmbedModel = new TogetherEmbedding({
|
||||
apiKey: "<YOUR_API_KEY>",
|
||||
});
|
||||
|
||||
const serviceContext = serviceContextFromDefaults({
|
||||
embedModel: togetherEmbedModel,
|
||||
});
|
||||
|
||||
const document = new Document({ text: essay, id_: "essay" });
|
||||
|
||||
const index = await VectorStoreIndex.fromDocuments([document], {
|
||||
serviceContext,
|
||||
});
|
||||
|
||||
const queryEngine = index.asQueryEngine();
|
||||
|
||||
const query = "What is the meaning of life?";
|
||||
|
||||
const results = await queryEngine.query({
|
||||
query,
|
||||
});
|
||||
```
|
||||
@@ -1,32 +0,0 @@
|
||||
import CodeBlock from "@theme/CodeBlock";
|
||||
import CodeSource from "!raw-loader!../../../../examples/cloud/chat.ts";
|
||||
|
||||
# LlamaCloud
|
||||
|
||||
LlamaCloud is a new generation of managed parsing, ingestion, and retrieval services, designed to bring production-grade context-augmentation to your LLM and RAG applications.
|
||||
|
||||
Currently, LlamaCloud supports
|
||||
|
||||
- Managed Ingestion API, handling parsing and document management
|
||||
- Managed Retrieval API, configuring optimal retrieval for your RAG system
|
||||
|
||||
## Access
|
||||
|
||||
We are opening up a private beta to a limited set of enterprise partners for the managed ingestion and retrieval API. If you’re interested in centralizing your data pipelines and spending more time working on your actual RAG use cases, come [talk to us.](https://www.llamaindex.ai/contact)
|
||||
|
||||
If you have access to LlamaCloud, you can visit [LlamaCloud](https://cloud.llamaindex.ai) to sign in and get an API key.
|
||||
|
||||
## Create a Managed Index
|
||||
|
||||
Currently, you can't create a managed index on LlamaCloud using LlamaIndexTS, but you can use an existing managed index for retrieval that was created by the Python version of LlamaIndex. See [the LlamaCloudIndex documentation](https://docs.llamaindex.ai/en/stable/module_guides/indexing/llama_cloud_index.html#usage) for more information on how to create a managed index.
|
||||
|
||||
## Use a Managed Index
|
||||
|
||||
Here's an example of how to use a managed index together with a chat engine:
|
||||
|
||||
<CodeBlock language="ts">{CodeSource}</CodeBlock>
|
||||
|
||||
## API Reference
|
||||
|
||||
- [LlamaCloudIndex](../api/classes/LlamaCloudIndex.md)
|
||||
- [LlamaCloudRetriever](../api/classes/LlamaCloudRetriever.md)
|
||||
@@ -50,7 +50,7 @@ const results = await queryEngine.query({
|
||||
|
||||
```ts
|
||||
import {
|
||||
OpenAI,
|
||||
Anthropic,
|
||||
Document,
|
||||
VectorStoreIndex,
|
||||
serviceContextFromDefaults,
|
||||
@@ -70,9 +70,6 @@ async function main() {
|
||||
serviceContext,
|
||||
});
|
||||
|
||||
// get retriever
|
||||
const retriever = index.asRetriever();
|
||||
|
||||
// Create a query engine
|
||||
const queryEngine = index.asQueryEngine({
|
||||
retriever,
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
# Fireworks LLM
|
||||
|
||||
Fireworks.ai focus on production use cases for open source LLMs, offering speed and quality.
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import { FireworksLLM, serviceContextFromDefaults } from "llamaindex";
|
||||
|
||||
const fireworksLLM = new FireworksLLM({
|
||||
apiKey: "<YOUR_API_KEY>",
|
||||
});
|
||||
|
||||
const serviceContext = serviceContextFromDefaults({ llm: fireworksLLM });
|
||||
```
|
||||
|
||||
## Load and index documents
|
||||
|
||||
For this example, we will load the Berkshire Hathaway 2022 annual report pdf
|
||||
|
||||
```ts
|
||||
const reader = new PDFReader();
|
||||
const documents = await reader.loadData("../data/brk-2022.pdf");
|
||||
|
||||
// Split text and create embeddings. Store them in a VectorStoreIndex
|
||||
const index = await VectorStoreIndex.fromDocuments(documents, {
|
||||
serviceContext,
|
||||
});
|
||||
```
|
||||
|
||||
## Query
|
||||
|
||||
```ts
|
||||
const queryEngine = index.asQueryEngine();
|
||||
const response = await queryEngine.query({
|
||||
query: "What mistakes did Warren E. Buffett make?",
|
||||
});
|
||||
```
|
||||
|
||||
## Full Example
|
||||
|
||||
```ts
|
||||
import { VectorStoreIndex } from "llamaindex";
|
||||
import { PDFReader } from "llamaindex/readers/PDFReader";
|
||||
|
||||
async function main() {
|
||||
// Load PDF
|
||||
const reader = new PDFReader();
|
||||
const documents = await reader.loadData("../data/brk-2022.pdf");
|
||||
|
||||
// Split text and create embeddings. Store them in a VectorStoreIndex
|
||||
const index = await VectorStoreIndex.fromDocuments(documents);
|
||||
|
||||
// Query the index
|
||||
const queryEngine = index.asQueryEngine();
|
||||
const response = await queryEngine.query({
|
||||
query: "What mistakes did Warren E. Buffett make?",
|
||||
});
|
||||
|
||||
// Output response
|
||||
console.log(response.toString());
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
```
|
||||
@@ -59,7 +59,7 @@ const results = await queryEngine.query({
|
||||
|
||||
```ts
|
||||
import {
|
||||
LlamaDeuce,
|
||||
Anthropic,
|
||||
Document,
|
||||
VectorStoreIndex,
|
||||
serviceContextFromDefaults,
|
||||
@@ -79,9 +79,6 @@ async function main() {
|
||||
serviceContext,
|
||||
});
|
||||
|
||||
// get retriever
|
||||
const retriever = index.asRetriever();
|
||||
|
||||
// Create a query engine
|
||||
const queryEngine = index.asQueryEngine({
|
||||
retriever,
|
||||
|
||||
@@ -41,7 +41,7 @@ const results = await queryEngine.query({
|
||||
|
||||
```ts
|
||||
import {
|
||||
MistralAI,
|
||||
Anthropic,
|
||||
Document,
|
||||
VectorStoreIndex,
|
||||
serviceContextFromDefaults,
|
||||
@@ -61,9 +61,6 @@ async function main() {
|
||||
serviceContext,
|
||||
});
|
||||
|
||||
// get retriever
|
||||
const retriever = index.asRetriever();
|
||||
|
||||
// Create a query engine
|
||||
const queryEngine = index.asQueryEngine({
|
||||
retriever,
|
||||
|
||||
@@ -7,10 +7,7 @@ import { Ollama, serviceContextFromDefaults } from "llamaindex";
|
||||
|
||||
const ollamaLLM = new Ollama({ model: "llama2", temperature: 0.75 });
|
||||
|
||||
const serviceContext = serviceContextFromDefaults({
|
||||
llm: ollamaLLM,
|
||||
embedModel: ollamaLLM,
|
||||
});
|
||||
const serviceContext = serviceContextFromDefaults({ llm: ollamaLLM });
|
||||
```
|
||||
|
||||
## Load and index documents
|
||||
@@ -41,25 +38,18 @@ const results = await queryEngine.query({
|
||||
|
||||
```ts
|
||||
import {
|
||||
Ollama,
|
||||
Anthropic,
|
||||
Document,
|
||||
VectorStoreIndex,
|
||||
serviceContextFromDefaults,
|
||||
} from "llamaindex";
|
||||
|
||||
import fs from "fs/promises";
|
||||
|
||||
async function main() {
|
||||
// Create an instance of the LLM
|
||||
const ollamaLLM = new Ollama({ model: "llama2", temperature: 0.75 });
|
||||
|
||||
const essay = await fs.readFile("./paul_graham_essay.txt", "utf-8");
|
||||
|
||||
// Create a service context
|
||||
const serviceContext = serviceContextFromDefaults({
|
||||
embedModel: ollamaLLM, // prevent 'Set OpenAI Key in OPENAI_API_KEY env variable' error
|
||||
llm: ollamaLLM,
|
||||
});
|
||||
const serviceContext = serviceContextFromDefaults({ llm: ollamaLLM });
|
||||
|
||||
const document = new Document({ text: essay, id_: "essay" });
|
||||
|
||||
@@ -68,9 +58,6 @@ async function main() {
|
||||
serviceContext,
|
||||
});
|
||||
|
||||
// get retriever
|
||||
const retriever = index.asRetriever();
|
||||
|
||||
// Create a query engine
|
||||
const queryEngine = index.asQueryEngine({
|
||||
retriever,
|
||||
|
||||
@@ -42,7 +42,7 @@ const results = await queryEngine.query({
|
||||
|
||||
```ts
|
||||
import {
|
||||
OpenAI,
|
||||
Anthropic,
|
||||
Document,
|
||||
VectorStoreIndex,
|
||||
serviceContextFromDefaults,
|
||||
@@ -62,9 +62,6 @@ async function main() {
|
||||
serviceContext,
|
||||
});
|
||||
|
||||
// get retriever
|
||||
const retriever = index.asRetriever();
|
||||
|
||||
// Create a query engine
|
||||
const queryEngine = index.asQueryEngine({
|
||||
retriever,
|
||||
|
||||
@@ -40,7 +40,7 @@ const results = await queryEngine.query({
|
||||
|
||||
```ts
|
||||
import {
|
||||
Portkey,
|
||||
Anthropic,
|
||||
Document,
|
||||
VectorStoreIndex,
|
||||
serviceContextFromDefaults,
|
||||
@@ -62,9 +62,6 @@ async function main() {
|
||||
serviceContext,
|
||||
});
|
||||
|
||||
// get retriever
|
||||
const retriever = index.asRetriever();
|
||||
|
||||
// Create a query engine
|
||||
const queryEngine = index.asQueryEngine({
|
||||
retriever,
|
||||
|
||||
@@ -40,7 +40,7 @@ const results = await queryEngine.query({
|
||||
|
||||
```ts
|
||||
import {
|
||||
TogetherLLM,
|
||||
Anthropic,
|
||||
Document,
|
||||
VectorStoreIndex,
|
||||
serviceContextFromDefaults,
|
||||
@@ -62,9 +62,6 @@ async function main() {
|
||||
serviceContext,
|
||||
});
|
||||
|
||||
// get retriever
|
||||
const retriever = index.asRetriever();
|
||||
|
||||
// Create a query engine
|
||||
const queryEngine = index.asQueryEngine({
|
||||
retriever,
|
||||
|
||||
@@ -28,10 +28,6 @@ export AZURE_OPENAI_ENDPOINT="<YOUR ENDPOINT, see https://learn.microsoft.com/en
|
||||
export AZURE_OPENAI_DEPLOYMENT="gpt-4" # or some other deployment name
|
||||
```
|
||||
|
||||
## Local LLM
|
||||
|
||||
For local LLMs, currently we recommend the use of [Ollama](./available_llms/ollama.md) LLM.
|
||||
|
||||
## API Reference
|
||||
|
||||
- [OpenAI](../api/classes/OpenAI.md)
|
||||
|
||||
@@ -27,71 +27,6 @@ const splitter = new SentenceSplitter({ chunkSize: 1 });
|
||||
const textSplits = splitter.splitText("Hello World");
|
||||
```
|
||||
|
||||
## MarkdownNodeParser
|
||||
|
||||
The `MarkdownNodeParser` is a more advanced `NodeParser` that can handle markdown documents. It will split the markdown into nodes and then parse the nodes into a `Document` object.
|
||||
|
||||
```typescript
|
||||
import { MarkdownNodeParser } from "llamaindex";
|
||||
|
||||
const nodeParser = new MarkdownNodeParser();
|
||||
|
||||
const nodes = nodeParser.getNodesFromDocuments([
|
||||
new Document({
|
||||
text: `# Main Header
|
||||
Main content
|
||||
|
||||
# Header 2
|
||||
Header 2 content
|
||||
|
||||
## Sub-header
|
||||
Sub-header content
|
||||
|
||||
`,
|
||||
}),
|
||||
]);
|
||||
```
|
||||
|
||||
The output metadata will be something like:
|
||||
|
||||
```bash
|
||||
[
|
||||
TextNode {
|
||||
id_: '008e41a8-b097-487c-bee8-bd88b9455844',
|
||||
metadata: { 'Header 1': 'Main Header' },
|
||||
excludedEmbedMetadataKeys: [],
|
||||
excludedLlmMetadataKeys: [],
|
||||
relationships: { PARENT: [Array] },
|
||||
hash: 'KJ5e/um/RkHaNR6bonj9ormtZY7I8i4XBPVYHXv1A5M=',
|
||||
text: 'Main Header\nMain content',
|
||||
textTemplate: '',
|
||||
metadataSeparator: '\n'
|
||||
},
|
||||
TextNode {
|
||||
id_: '0f5679b3-ba63-4aff-aedc-830c4208d0b5',
|
||||
metadata: { 'Header 1': 'Header 2' },
|
||||
excludedEmbedMetadataKeys: [],
|
||||
excludedLlmMetadataKeys: [],
|
||||
relationships: { PARENT: [Array] },
|
||||
hash: 'IP/g/dIld3DcbK+uHzDpyeZ9IdOXY4brxhOIe7wc488=',
|
||||
text: 'Header 2\nHeader 2 content',
|
||||
textTemplate: '',
|
||||
metadataSeparator: '\n'
|
||||
},
|
||||
TextNode {
|
||||
id_: 'e81e9bd0-121c-4ead-8ca7-1639d65fdf90',
|
||||
metadata: { 'Header 1': 'Header 2', 'Header 2': 'Sub-header' },
|
||||
excludedEmbedMetadataKeys: [],
|
||||
excludedLlmMetadataKeys: [],
|
||||
relationships: { PARENT: [Array] },
|
||||
hash: 'B3kYNnxaYi9ghtAgwza0ZEVKF4MozobkNUlcekDL7JQ=',
|
||||
text: 'Sub-header\nSub-header content',
|
||||
textTemplate: '',
|
||||
metadataSeparator: '\n'
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- [SimpleNodeParser](../api/classes/SimpleNodeParser.md)
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
label: "Prompts"
|
||||
position: 0
|
||||
@@ -1,76 +0,0 @@
|
||||
# Prompts
|
||||
|
||||
Prompting is the fundamental input that gives LLMs their expressive power. LlamaIndex uses prompts to build the index, do insertion, perform traversal during querying, and to synthesize the final answer.
|
||||
|
||||
Users may also provide their own prompt templates to further customize the behavior of the framework. The best method for customizing is copying the default prompt from the link above, and using that as the base for any modifications.
|
||||
|
||||
## Usage Pattern
|
||||
|
||||
Currently, there are two ways to customize prompts in LlamaIndex:
|
||||
|
||||
For both methods, you will need to create an function that overrides the default prompt.
|
||||
|
||||
```ts
|
||||
// Define a custom prompt
|
||||
const newTextQaPrompt: TextQaPrompt = ({ context, query }) => {
|
||||
return `Context information is below.
|
||||
---------------------
|
||||
${context}
|
||||
---------------------
|
||||
Given the context information and not prior knowledge, answer the query.
|
||||
Answer the query in the style of a Sherlock Holmes detective novel.
|
||||
Query: ${query}
|
||||
Answer:`;
|
||||
};
|
||||
```
|
||||
|
||||
### 1. Customizing the default prompt on initialization
|
||||
|
||||
The first method is to create a new instance of `ResponseSynthesizer` (or the module you would like to update the prompt) and pass the custom prompt to the `responseBuilder` parameter. Then, pass the instance to the `asQueryEngine` method of the index.
|
||||
|
||||
```ts
|
||||
// Create an instance of response synthesizer
|
||||
const responseSynthesizer = new ResponseSynthesizer({
|
||||
responseBuilder: new CompactAndRefine(serviceContext, newTextQaPrompt),
|
||||
});
|
||||
|
||||
// Create index
|
||||
const index = await VectorStoreIndex.fromDocuments([document], {
|
||||
serviceContext,
|
||||
});
|
||||
|
||||
// Query the index
|
||||
const queryEngine = index.asQueryEngine({ responseSynthesizer });
|
||||
|
||||
const response = await queryEngine.query({
|
||||
query: "What did the author do in college?",
|
||||
});
|
||||
```
|
||||
|
||||
### 2. Customizing submodules prompt
|
||||
|
||||
The second method is that most of the modules in LlamaIndex have a `getPrompts` and a `updatePrompt` method that allows you to override the default prompt. This method is useful when you want to change the prompt on the fly or in submodules on a more granular level.
|
||||
|
||||
```ts
|
||||
// Create index
|
||||
const index = await VectorStoreIndex.fromDocuments([document], {
|
||||
serviceContext,
|
||||
});
|
||||
|
||||
// Query the index
|
||||
const queryEngine = index.asQueryEngine();
|
||||
|
||||
// Get a list of prompts for the query engine
|
||||
const prompts = queryEngine.getPrompts();
|
||||
|
||||
// output: { "responseSynthesizer:textQATemplate": defaultTextQaPrompt, "responseSynthesizer:refineTemplate": defaultRefineTemplatePrompt }
|
||||
|
||||
// Now, we can override the default prompt
|
||||
queryEngine.updatePrompt({
|
||||
"responseSynthesizer:textQATemplate": newTextQaPrompt,
|
||||
});
|
||||
|
||||
const response = await queryEngine.query({
|
||||
query: "What did the author do in college?",
|
||||
});
|
||||
```
|
||||
@@ -1,3 +1,2 @@
|
||||
package-lock.json
|
||||
storage
|
||||
tmp_data
|
||||
@@ -1,55 +0,0 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
const dataPath = path.join(__dirname, "tmp_data");
|
||||
|
||||
const extractWikipediaTitle = async (title: string) => {
|
||||
const fileExists = fs.existsSync(path.join(dataPath, `${title}.txt`));
|
||||
|
||||
if (fileExists) {
|
||||
console.log(`Arquivo já existe para o título: ${title}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const queryParams = new URLSearchParams({
|
||||
action: "query",
|
||||
format: "json",
|
||||
titles: title,
|
||||
prop: "extracts",
|
||||
explaintext: "true",
|
||||
});
|
||||
|
||||
const url = `https://en.wikipedia.org/w/api.php?${queryParams}`;
|
||||
|
||||
const response = await fetch(url);
|
||||
const data: any = await response.json();
|
||||
|
||||
const pages = data.query.pages;
|
||||
const page = pages[Object.keys(pages)[0]];
|
||||
const wikiText = page.extract;
|
||||
|
||||
await new Promise((resolve) => {
|
||||
fs.writeFile(path.join(dataPath, `${title}.txt`), wikiText, (err: any) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
resolve(title);
|
||||
return;
|
||||
}
|
||||
console.log(`${title} stored!`);
|
||||
|
||||
resolve(title);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const extractWikipedia = async (titles: string[]) => {
|
||||
if (!fs.existsSync(dataPath)) {
|
||||
fs.mkdirSync(dataPath);
|
||||
}
|
||||
|
||||
for await (const title of titles) {
|
||||
await extractWikipediaTitle(title);
|
||||
}
|
||||
|
||||
console.log("Extration finished!");
|
||||
};
|
||||
@@ -1,157 +0,0 @@
|
||||
import fs from "node:fs/promises";
|
||||
|
||||
import {
|
||||
Document,
|
||||
ObjectIndex,
|
||||
OpenAI,
|
||||
OpenAIAgent,
|
||||
QueryEngineTool,
|
||||
SimpleNodeParser,
|
||||
SimpleToolNodeMapping,
|
||||
SummaryIndex,
|
||||
VectorStoreIndex,
|
||||
serviceContextFromDefaults,
|
||||
storageContextFromDefaults,
|
||||
} from "llamaindex";
|
||||
|
||||
import { extractWikipedia } from "./helpers/extractWikipedia";
|
||||
|
||||
const wikiTitles = ["Brazil", "Canada"];
|
||||
|
||||
async function main() {
|
||||
await extractWikipedia(wikiTitles);
|
||||
|
||||
const countryDocs: Record<string, Document> = {};
|
||||
|
||||
for (const title of wikiTitles) {
|
||||
const path = `./agent/helpers/tmp_data/${title}.txt`;
|
||||
const text = await fs.readFile(path, "utf-8");
|
||||
const document = new Document({ text: text, id_: path });
|
||||
countryDocs[title] = document;
|
||||
}
|
||||
|
||||
const llm = new OpenAI({
|
||||
model: "gpt-4",
|
||||
});
|
||||
|
||||
const serviceContext = serviceContextFromDefaults({ llm });
|
||||
const storageContext = await storageContextFromDefaults({
|
||||
persistDir: "./storage",
|
||||
});
|
||||
|
||||
// TODO: fix any
|
||||
const documentAgents: any = {};
|
||||
const queryEngines: any = {};
|
||||
|
||||
for (const title of wikiTitles) {
|
||||
console.log(`Processing ${title}`);
|
||||
|
||||
const nodes = new SimpleNodeParser({
|
||||
chunkSize: 200,
|
||||
chunkOverlap: 20,
|
||||
}).getNodesFromDocuments([countryDocs[title]]);
|
||||
|
||||
console.log(`Creating index for ${title}`);
|
||||
|
||||
const vectorIndex = await VectorStoreIndex.init({
|
||||
serviceContext: serviceContext,
|
||||
storageContext: storageContext,
|
||||
nodes,
|
||||
});
|
||||
|
||||
const summaryIndex = await SummaryIndex.init({
|
||||
serviceContext: serviceContext,
|
||||
nodes,
|
||||
});
|
||||
|
||||
console.log(`Creating query engines for ${title}`);
|
||||
|
||||
const vectorQueryEngine = summaryIndex.asQueryEngine();
|
||||
const summaryQueryEngine = summaryIndex.asQueryEngine();
|
||||
|
||||
const queryEngineTools = [
|
||||
new QueryEngineTool({
|
||||
queryEngine: vectorQueryEngine,
|
||||
metadata: {
|
||||
name: "vector_tool",
|
||||
description: `Useful for questions related to specific aspects of ${title} (e.g. the history, arts and culture, sports, demographics, or more).`,
|
||||
},
|
||||
}),
|
||||
new QueryEngineTool({
|
||||
queryEngine: summaryQueryEngine,
|
||||
metadata: {
|
||||
name: "summary_tool",
|
||||
description: `Useful for any requests that require a holistic summary of EVERYTHING about ${title}. For questions about more specific sections, please use the vector_tool.`,
|
||||
},
|
||||
}),
|
||||
];
|
||||
|
||||
console.log(`Creating agents for ${title}`);
|
||||
|
||||
const agent = new OpenAIAgent({
|
||||
tools: queryEngineTools,
|
||||
llm,
|
||||
verbose: true,
|
||||
});
|
||||
|
||||
documentAgents[title] = agent;
|
||||
queryEngines[title] = vectorIndex.asQueryEngine();
|
||||
}
|
||||
|
||||
const allTools: QueryEngineTool[] = [];
|
||||
|
||||
console.log(`Creating tools for all countries`);
|
||||
|
||||
for (const title of wikiTitles) {
|
||||
const wikiSummary = `This content contains Wikipedia articles about ${title}. Use this tool if you want to answer any questions about ${title}`;
|
||||
|
||||
console.log(`Creating tool for ${title}`);
|
||||
|
||||
const docTool = new QueryEngineTool({
|
||||
queryEngine: documentAgents[title],
|
||||
metadata: {
|
||||
name: `tool_${title}`,
|
||||
description: wikiSummary,
|
||||
},
|
||||
});
|
||||
|
||||
allTools.push(docTool);
|
||||
}
|
||||
|
||||
console.log("creating tool mapping");
|
||||
|
||||
const toolMapping = SimpleToolNodeMapping.fromObjects(allTools);
|
||||
|
||||
const objectIndex = await ObjectIndex.fromObjects(
|
||||
allTools,
|
||||
toolMapping,
|
||||
VectorStoreIndex,
|
||||
{
|
||||
serviceContext,
|
||||
storageContext,
|
||||
},
|
||||
);
|
||||
|
||||
const topAgent = new OpenAIAgent({
|
||||
toolRetriever: await objectIndex.asRetriever({}),
|
||||
llm,
|
||||
verbose: true,
|
||||
prefixMessages: [
|
||||
{
|
||||
content:
|
||||
"You are an agent designed to answer queries about a set of given countries. Please always use the tools provided to answer a question. Do not rely on prior knowledge.",
|
||||
role: "system",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const response = await topAgent.chat({
|
||||
message: "Tell me the differences between Brazil and Canada economics?",
|
||||
});
|
||||
|
||||
console.log({
|
||||
capitalOfBrazil: response,
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -1,46 +0,0 @@
|
||||
import {
|
||||
OpenAIAgent,
|
||||
QueryEngineTool,
|
||||
SimpleDirectoryReader,
|
||||
VectorStoreIndex,
|
||||
} from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
// Load the documents
|
||||
const documents = await new SimpleDirectoryReader().loadData({
|
||||
directoryPath: "node_modules/llamaindex/examples/",
|
||||
});
|
||||
|
||||
// Create a vector index from the documents
|
||||
const vectorIndex = await VectorStoreIndex.fromDocuments(documents);
|
||||
|
||||
// Create a query engine from the vector index
|
||||
const abramovQueryEngine = vectorIndex.asQueryEngine();
|
||||
|
||||
// Create a QueryEngineTool with the query engine
|
||||
const queryEngineTool = new QueryEngineTool({
|
||||
queryEngine: abramovQueryEngine,
|
||||
metadata: {
|
||||
name: "abramov_query_engine",
|
||||
description: "A query engine for the Abramov documents",
|
||||
},
|
||||
});
|
||||
|
||||
// Create an OpenAIAgent with the function tools
|
||||
const agent = new OpenAIAgent({
|
||||
tools: [queryEngineTool],
|
||||
verbose: true,
|
||||
});
|
||||
|
||||
// Chat with the agent
|
||||
const response = await agent.chat({
|
||||
message: "What was his salary?",
|
||||
});
|
||||
|
||||
// Print the response
|
||||
console.log(String(response));
|
||||
}
|
||||
|
||||
main().then(() => {
|
||||
console.log("Done");
|
||||
});
|
||||
@@ -1,76 +0,0 @@
|
||||
import { FunctionTool, ReActAgent } from "llamaindex";
|
||||
|
||||
// Define a function to sum two numbers
|
||||
function sumNumbers({ a, b }: { a: number; b: number }): number {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
// Define a function to divide two numbers
|
||||
function divideNumbers({ a, b }: { a: number; b: number }): number {
|
||||
return a / b;
|
||||
}
|
||||
|
||||
// Define the parameters of the sum function as a JSON schema
|
||||
const sumJSON = {
|
||||
type: "object",
|
||||
properties: {
|
||||
a: {
|
||||
type: "number",
|
||||
description: "The first number",
|
||||
},
|
||||
b: {
|
||||
type: "number",
|
||||
description: "The second number",
|
||||
},
|
||||
},
|
||||
required: ["a", "b"],
|
||||
};
|
||||
|
||||
const divideJSON = {
|
||||
type: "object",
|
||||
properties: {
|
||||
a: {
|
||||
type: "number",
|
||||
description: "The dividend",
|
||||
},
|
||||
b: {
|
||||
type: "number",
|
||||
description: "The divisor",
|
||||
},
|
||||
},
|
||||
required: ["a", "b"],
|
||||
};
|
||||
|
||||
async function main() {
|
||||
// Create a function tool from the sum function
|
||||
const functionTool = new FunctionTool(sumNumbers, {
|
||||
name: "sumNumbers",
|
||||
description: "Use this function to sum two numbers",
|
||||
parameters: sumJSON,
|
||||
});
|
||||
|
||||
// Create a function tool from the divide function
|
||||
const functionTool2 = new FunctionTool(divideNumbers, {
|
||||
name: "divideNumbers",
|
||||
description: "Use this function to divide two numbers",
|
||||
parameters: divideJSON,
|
||||
});
|
||||
|
||||
// Create an OpenAIAgent with the function tools
|
||||
const agent = new ReActAgent({
|
||||
tools: [functionTool, functionTool2],
|
||||
verbose: true,
|
||||
});
|
||||
|
||||
// Chat with the agent
|
||||
const response = await agent.chat({
|
||||
message: "Divide 16 by 2 then add 20",
|
||||
});
|
||||
|
||||
// Print the response
|
||||
console.log(String(response));
|
||||
}
|
||||
|
||||
main().then(() => {
|
||||
console.log("Done");
|
||||
});
|
||||
@@ -1,33 +0,0 @@
|
||||
# LlamaCloud Integration
|
||||
|
||||
## Getting started
|
||||
|
||||
To start the examples call them from the `examples` folder:
|
||||
|
||||
And make sure, you're setting your `LLAMA_CLOUD_API_KEY` in your environment variable:
|
||||
|
||||
```shell
|
||||
export LLAMA_CLOUD_API_KEY=your-api-key
|
||||
```
|
||||
|
||||
For using another environment, also set the `LLAMA_CLOUD_BASE_URL` environment variable:
|
||||
|
||||
```shell
|
||||
export LLAMA_CLOUD_BASE_URL="https://api.staging.llamaindex.ai"
|
||||
```
|
||||
|
||||
## Chat Engine
|
||||
|
||||
This example is using the managed index named `test` from the project `default` to create a chat engine.
|
||||
|
||||
```shell
|
||||
pnpx ts-node cloud/chat.ts
|
||||
```
|
||||
|
||||
## Query Engine
|
||||
|
||||
This example shows how to use the managed index with a query engine.
|
||||
|
||||
```shell
|
||||
pnpx ts-node cloud/query.ts
|
||||
```
|
||||
@@ -1,29 +0,0 @@
|
||||
import { stdin as input, stdout as output } from "node:process";
|
||||
import readline from "node:readline/promises";
|
||||
|
||||
import { ContextChatEngine, LlamaCloudIndex } from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
const index = new LlamaCloudIndex({
|
||||
name: "test",
|
||||
projectName: "default",
|
||||
baseUrl: process.env.LLAMA_CLOUD_BASE_URL,
|
||||
apiKey: process.env.LLAMA_CLOUD_API_KEY,
|
||||
});
|
||||
const retriever = index.asRetriever({
|
||||
similarityTopK: 5,
|
||||
});
|
||||
const chatEngine = new ContextChatEngine({ retriever });
|
||||
const rl = readline.createInterface({ input, output });
|
||||
|
||||
while (true) {
|
||||
const query = await rl.question("User: ");
|
||||
const stream = await chatEngine.chat({ message: query, stream: true });
|
||||
console.log();
|
||||
for await (const chunk of stream) {
|
||||
process.stdout.write(chunk.response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
@@ -1,31 +0,0 @@
|
||||
import { stdin as input, stdout as output } from "node:process";
|
||||
import readline from "node:readline/promises";
|
||||
|
||||
import { LlamaCloudIndex } from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
const index = new LlamaCloudIndex({
|
||||
name: "test",
|
||||
projectName: "default",
|
||||
baseUrl: process.env.LLAMA_CLOUD_BASE_URL,
|
||||
apiKey: process.env.LLAMA_CLOUD_API_KEY,
|
||||
});
|
||||
const queryEngine = index.asQueryEngine({
|
||||
denseSimilarityTopK: 5,
|
||||
});
|
||||
const rl = readline.createInterface({ input, output });
|
||||
|
||||
while (true) {
|
||||
const query = await rl.question("Query: ");
|
||||
const stream = await queryEngine.query({
|
||||
query,
|
||||
stream: true,
|
||||
});
|
||||
console.log();
|
||||
for await (const chunk of stream) {
|
||||
process.stdout.write(chunk.response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
@@ -1,24 +0,0 @@
|
||||
import { Document, MarkdownNodeParser } from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
const markdownParser = new MarkdownNodeParser();
|
||||
|
||||
const splits = markdownParser.getNodesFromDocuments([
|
||||
new Document({
|
||||
text: `# Main Header
|
||||
Main content
|
||||
|
||||
# Header 2
|
||||
Header 2 content
|
||||
|
||||
## Sub-header
|
||||
Sub-header content
|
||||
|
||||
`,
|
||||
}),
|
||||
]);
|
||||
|
||||
console.log(splits);
|
||||
}
|
||||
|
||||
main();
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { Ollama } from "llamaindex/llm/ollama";
|
||||
import { Ollama } from "llamaindex";
|
||||
|
||||
(async () => {
|
||||
const llm = new Ollama({ model: "llama2", temperature: 0.75 });
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
import {
|
||||
Document,
|
||||
ResponseSynthesizer,
|
||||
TreeSummarize,
|
||||
TreeSummarizePrompt,
|
||||
VectorStoreIndex,
|
||||
serviceContextFromDefaults,
|
||||
} from "llamaindex";
|
||||
|
||||
const treeSummarizePrompt: TreeSummarizePrompt = ({ context, query }) => {
|
||||
return `Context information from multiple sources is below.
|
||||
---------------------
|
||||
${context}
|
||||
---------------------
|
||||
Given the information from multiple sources and not prior knowledge.
|
||||
Answer the query in the style of a Shakespeare play"
|
||||
Query: ${query}
|
||||
Answer:`;
|
||||
};
|
||||
|
||||
async function main() {
|
||||
const documents = new Document({
|
||||
text: "The quick brown fox jumps over the lazy dog",
|
||||
});
|
||||
|
||||
const index = await VectorStoreIndex.fromDocuments([documents]);
|
||||
|
||||
const query = "The quick brown fox jumps over the lazy dog";
|
||||
|
||||
const ctx = serviceContextFromDefaults({});
|
||||
|
||||
const responseSynthesizer = new ResponseSynthesizer({
|
||||
responseBuilder: new TreeSummarize(ctx),
|
||||
});
|
||||
|
||||
const queryEngine = index.asQueryEngine({
|
||||
responseSynthesizer,
|
||||
});
|
||||
|
||||
console.log({
|
||||
promptsToUse: queryEngine.getPrompts(),
|
||||
});
|
||||
|
||||
queryEngine.updatePrompts({
|
||||
"responseSynthesizer:summaryTemplate": treeSummarizePrompt,
|
||||
});
|
||||
|
||||
await queryEngine.query({ query });
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -1,36 +0,0 @@
|
||||
import { FireworksEmbedding, FireworksLLM, VectorStoreIndex } from "llamaindex";
|
||||
import { PDFReader } from "llamaindex/readers/PDFReader";
|
||||
|
||||
import { serviceContextFromDefaults } from "llamaindex";
|
||||
|
||||
const embedModel = new FireworksEmbedding({
|
||||
model: "nomic-ai/nomic-embed-text-v1.5",
|
||||
});
|
||||
|
||||
const llm = new FireworksLLM({
|
||||
model: "accounts/fireworks/models/mixtral-8x7b-instruct",
|
||||
});
|
||||
|
||||
const serviceContext = serviceContextFromDefaults({ llm, embedModel });
|
||||
|
||||
async function main() {
|
||||
// Load PDF
|
||||
const reader = new PDFReader();
|
||||
const documents = await reader.loadData("../data/brk-2022.pdf");
|
||||
|
||||
// Split text and create embeddings. Store them in a VectorStoreIndex
|
||||
const index = await VectorStoreIndex.fromDocuments(documents, {
|
||||
serviceContext,
|
||||
});
|
||||
|
||||
// Query the index
|
||||
const queryEngine = index.asQueryEngine();
|
||||
const response = await queryEngine.query({
|
||||
query: "What mistakes did Warren E. Buffett make?",
|
||||
});
|
||||
|
||||
// Output response
|
||||
console.log(response.toString());
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
@@ -1,36 +0,0 @@
|
||||
import { OpenAI, OpenAIEmbedding, VectorStoreIndex } from "llamaindex";
|
||||
import { PDFReader } from "llamaindex/readers/PDFReader";
|
||||
|
||||
import { serviceContextFromDefaults } from "llamaindex";
|
||||
|
||||
const embedModel = new OpenAIEmbedding({
|
||||
model: "nomic-ai/nomic-embed-text-v1.5",
|
||||
});
|
||||
|
||||
const llm = new OpenAI({
|
||||
model: "accounts/fireworks/models/mixtral-8x7b-instruct",
|
||||
});
|
||||
|
||||
const serviceContext = serviceContextFromDefaults({ llm, embedModel });
|
||||
|
||||
async function main() {
|
||||
// Load PDF
|
||||
const reader = new PDFReader();
|
||||
const documents = await reader.loadData("../data/brk-2022.pdf");
|
||||
|
||||
// Split text and create embeddings. Store them in a VectorStoreIndex
|
||||
const index = await VectorStoreIndex.fromDocuments(documents, {
|
||||
serviceContext,
|
||||
});
|
||||
|
||||
// Query the index
|
||||
const queryEngine = index.asQueryEngine();
|
||||
const response = await queryEngine.query({
|
||||
query: "What mistakes did Warren E. Buffett make?",
|
||||
});
|
||||
|
||||
// Output response
|
||||
console.log(response.toString());
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
@@ -30,7 +30,6 @@ async function main() {
|
||||
|
||||
// Query the index
|
||||
const queryEngine = index.asQueryEngine();
|
||||
|
||||
const response = await queryEngine.query({
|
||||
query: "What did the author do in college?",
|
||||
});
|
||||
|
||||
@@ -18,12 +18,15 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@changesets/cli": "^2.27.1",
|
||||
"@types/jest": "^29.5.12",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-config-custom": "workspace:*",
|
||||
"husky": "^9.0.10",
|
||||
"jest": "^29.7.0",
|
||||
"lint-staged": "^15.2.2",
|
||||
"prettier": "^3.2.5",
|
||||
"prettier-plugin-organize-imports": "^3.2.4",
|
||||
"ts-jest": "^29.1.2",
|
||||
"turbo": "^1.12.3",
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"jsc": {
|
||||
"parser": {
|
||||
"syntax": "typescript"
|
||||
},
|
||||
"target": "esnext"
|
||||
},
|
||||
"module": {
|
||||
"type": "commonjs"
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"jsc": {
|
||||
"parser": {
|
||||
"syntax": "typescript"
|
||||
},
|
||||
"target": "esnext"
|
||||
}
|
||||
}
|
||||
@@ -1,41 +1,5 @@
|
||||
# llamaindex
|
||||
|
||||
## 0.1.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 7416a87: build: cjs file not found
|
||||
- Updated dependencies [7416a87]
|
||||
- @llamaindex/env@0.0.2
|
||||
|
||||
## 0.1.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- b8be4c0: build: use ESM as default
|
||||
- 65d8346: feat: abstract `@llamaindex/env` package
|
||||
|
||||
## 0.1.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- a5e4e6d: Add using a managed index from LlamaCloud
|
||||
- cfdd6db: fix: update pinecone vector store
|
||||
- 59f9fb6: Add Fireworks to LlamaIndex
|
||||
- 95add73: feat: multi-document agent
|
||||
|
||||
## 0.1.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 255ae7d: chore: update example (perfoms better with default model)
|
||||
- cf3b757: feat: add filtering of metadata to PGVectorStore
|
||||
- ee9f3f3: chore: refactor openai agent utils
|
||||
- e78e9f4: feat(reranker): cohere reranker
|
||||
- f205358: feat: markdown node parser
|
||||
- dd05413: feat: use batching in vector store index
|
||||
- 383933a: Add reader for LlamaParse
|
||||
|
||||
## 0.1.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/** @type {import('ts-jest').JestConfigWithTsJest} */
|
||||
module.exports = {
|
||||
preset: "ts-jest",
|
||||
testEnvironment: "node",
|
||||
testPathIgnorePatterns: ["/lib/", "/node_modules/", "/dist/"],
|
||||
};
|
||||
+152
-40
@@ -1,17 +1,14 @@
|
||||
{
|
||||
"name": "llamaindex",
|
||||
"version": "0.1.14",
|
||||
"private": true,
|
||||
"version": "0.1.10",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "^0.13.0",
|
||||
"@aws-crypto/sha256-js": "^5.2.0",
|
||||
"@datastax/astra-db-ts": "^0.1.4",
|
||||
"@llamaindex/cloud": "^0.0.1",
|
||||
"@llamaindex/env": "workspace:*",
|
||||
"@mistralai/mistralai": "^0.0.10",
|
||||
"@notionhq/client": "^2.2.14",
|
||||
"@pinecone-database/pinecone": "^2.0.1",
|
||||
"@pinecone-database/pinecone": "^1.1.3",
|
||||
"@qdrant/js-client-rest": "^1.7.0",
|
||||
"@xenova/transformers": "^2.15.0",
|
||||
"assemblyai": "^4.2.2",
|
||||
@@ -37,46 +34,160 @@
|
||||
"wink-nlp": "^1.14.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@swc/cli": "^0.3.9",
|
||||
"@swc/core": "^1.4.2",
|
||||
"@aws-crypto/sha256-js": "^5.2.0",
|
||||
"@types/edit-json-file": "^1.7.3",
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/lodash": "^4.14.202",
|
||||
"@types/node": "^18.19.14",
|
||||
"@types/papaparse": "^5.3.14",
|
||||
"@types/pg": "^8.11.0",
|
||||
"concurrently": "^8.2.2",
|
||||
"glob": "^10.3.10",
|
||||
"bunchee": "^4.4.6",
|
||||
"edit-json-file": "^1.8.0",
|
||||
"madge": "^6.1.0",
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"types": "./dist/type/index.d.ts",
|
||||
"main": "./dist/cjs/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"main": "./dist/index.js",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": {
|
||||
"types": "./dist/type/index.d.ts",
|
||||
"default": "./dist/index.js"
|
||||
},
|
||||
"edge-light": {
|
||||
"types": "./dist/type/index.d.ts",
|
||||
"default": "./dist/index.edge-light.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/type/index.d.ts",
|
||||
"default": "./dist/cjs/index.js"
|
||||
}
|
||||
"types": "./dist/index.d.mts",
|
||||
"import": "./dist/index.mjs",
|
||||
"edge-light": "./dist/index.edge-light.mjs",
|
||||
"require": "./dist/index.js"
|
||||
},
|
||||
"./*": {
|
||||
"import": {
|
||||
"types": "./dist/type/*.d.ts",
|
||||
"default": "./dist/*.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/type/*.d.ts",
|
||||
"default": "./dist/cjs/*.js"
|
||||
}
|
||||
"./env": {
|
||||
"types": "./dist/env.d.mts",
|
||||
"import": "./dist/env.mjs",
|
||||
"edge-light": "./dist/env.edge-light.mjs",
|
||||
"require": "./dist/env.js"
|
||||
},
|
||||
"./ChatEngine": {
|
||||
"types": "./dist/ChatEngine.d.mts",
|
||||
"import": "./dist/ChatEngine.mjs",
|
||||
"require": "./dist/ChatEngine.js"
|
||||
},
|
||||
"./ChatHistory": {
|
||||
"types": "./dist/ChatHistory.d.mts",
|
||||
"import": "./dist/ChatHistory.mjs",
|
||||
"require": "./dist/ChatHistory.js"
|
||||
},
|
||||
"./constants": {
|
||||
"types": "./dist/constants.d.mts",
|
||||
"import": "./dist/constants.mjs",
|
||||
"require": "./dist/constants.js"
|
||||
},
|
||||
"./GlobalsHelper": {
|
||||
"types": "./dist/GlobalsHelper.d.mts",
|
||||
"import": "./dist/GlobalsHelper.mjs",
|
||||
"require": "./dist/GlobalsHelper.js"
|
||||
},
|
||||
"./Node": {
|
||||
"types": "./dist/Node.d.mts",
|
||||
"import": "./dist/Node.mjs",
|
||||
"require": "./dist/Node.js"
|
||||
},
|
||||
"./OutputParser": {
|
||||
"types": "./dist/OutputParser.d.mts",
|
||||
"import": "./dist/OutputParser.mjs",
|
||||
"require": "./dist/OutputParser.js"
|
||||
},
|
||||
"./Prompt": {
|
||||
"types": "./dist/Prompt.d.mts",
|
||||
"import": "./dist/Prompt.mjs",
|
||||
"require": "./dist/Prompt.js"
|
||||
},
|
||||
"./PromptHelper": {
|
||||
"types": "./dist/PromptHelper.d.mts",
|
||||
"import": "./dist/PromptHelper.mjs",
|
||||
"require": "./dist/PromptHelper.js"
|
||||
},
|
||||
"./QueryEngine": {
|
||||
"types": "./dist/QueryEngine.d.mts",
|
||||
"import": "./dist/QueryEngine.mjs",
|
||||
"require": "./dist/QueryEngine.js"
|
||||
},
|
||||
"./QuestionGenerator": {
|
||||
"types": "./dist/QuestionGenerator.d.mts",
|
||||
"import": "./dist/QuestionGenerator.mjs",
|
||||
"require": "./dist/QuestionGenerator.js"
|
||||
},
|
||||
"./Response": {
|
||||
"types": "./dist/Response.d.mts",
|
||||
"import": "./dist/Response.mjs",
|
||||
"require": "./dist/Response.js"
|
||||
},
|
||||
"./ServiceContext": {
|
||||
"types": "./dist/ServiceContext.d.mts",
|
||||
"import": "./dist/ServiceContext.mjs",
|
||||
"require": "./dist/ServiceContext.js"
|
||||
},
|
||||
"./TextSplitter": {
|
||||
"types": "./dist/TextSplitter.d.mts",
|
||||
"import": "./dist/TextSplitter.mjs",
|
||||
"require": "./dist/TextSplitter.js"
|
||||
},
|
||||
"./tools": {
|
||||
"types": "./dist/tools.d.mts",
|
||||
"import": "./dist/tools.mjs",
|
||||
"require": "./dist/tools.js"
|
||||
},
|
||||
"./readers": {
|
||||
"types": "./dist/readers.d.mts",
|
||||
"import": "./dist/readers.mjs",
|
||||
"require": "./dist/readers.js"
|
||||
},
|
||||
"./readers/AssemblyAIReader": {
|
||||
"types": "./dist/readers/AssemblyAIReader.d.mts",
|
||||
"import": "./dist/readers/AssemblyAIReader.mjs",
|
||||
"require": "./dist/readers/AssemblyAIReader.js"
|
||||
},
|
||||
"./readers/CSVReader": {
|
||||
"types": "./dist/readers/CSVReader.d.mts",
|
||||
"import": "./dist/readers/CSVReader.mjs",
|
||||
"require": "./dist/readers/CSVReader.js"
|
||||
},
|
||||
"./readers/DocxReader": {
|
||||
"types": "./dist/readers/DocxReader.d.mts",
|
||||
"import": "./dist/readers/DocxReader.mjs",
|
||||
"require": "./dist/readers/DocxReader.js"
|
||||
},
|
||||
"./readers/HTMLReader": {
|
||||
"types": "./dist/readers/HTMLReader.d.mts",
|
||||
"import": "./dist/readers/HTMLReader.mjs",
|
||||
"require": "./dist/readers/HTMLReader.js"
|
||||
},
|
||||
"./readers/ImageReader": {
|
||||
"types": "./dist/readers/ImageReader.d.mts",
|
||||
"import": "./dist/readers/ImageReader.mjs",
|
||||
"require": "./dist/readers/ImageReader.js"
|
||||
},
|
||||
"./readers/MarkdownReader": {
|
||||
"types": "./dist/readers/MarkdownReader.d.mts",
|
||||
"import": "./dist/readers/MarkdownReader.mjs",
|
||||
"require": "./dist/readers/MarkdownReader.js"
|
||||
},
|
||||
"./readers/NotionReader": {
|
||||
"types": "./dist/readers/NotionReader.d.mts",
|
||||
"import": "./dist/readers/NotionReader.mjs",
|
||||
"require": "./dist/readers/NotionReader.js"
|
||||
},
|
||||
"./readers/PDFReader": {
|
||||
"types": "./dist/readers/PDFReader.d.mts",
|
||||
"import": "./dist/readers/PDFReader.mjs",
|
||||
"require": "./dist/readers/PDFReader.js"
|
||||
},
|
||||
"./readers/SimpleDirectoryReader": {
|
||||
"types": "./dist/readers/SimpleDirectoryReader.d.mts",
|
||||
"import": "./dist/readers/SimpleDirectoryReader.mjs",
|
||||
"require": "./dist/readers/SimpleDirectoryReader.js"
|
||||
},
|
||||
"./readers/SimpleMongoReader": {
|
||||
"types": "./dist/readers/SimpleMongoReader.d.mts",
|
||||
"import": "./dist/readers/SimpleMongoReader.mjs",
|
||||
"require": "./dist/readers/SimpleMongoReader.js"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
@@ -89,12 +200,13 @@
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint .",
|
||||
"build": "rm -rf ./dist && pnpm run build:esm && pnpm run build:cjs && pnpm run build:type",
|
||||
"build:esm": "swc src -d dist --strip-leading-paths --config-file .swcrc",
|
||||
"build:cjs": "swc src -d dist/cjs --strip-leading-paths --config-file .cjs.swcrc",
|
||||
"build:type": "tsc -p tsconfig.json",
|
||||
"postbuild": "node -e \"require('fs').writeFileSync('./dist/cjs/package.json', JSON.stringify({ type: 'commonjs' }))\"",
|
||||
"circular-check": "madge -c ./src/index.ts",
|
||||
"dev": "concurrently \"pnpm run build:esm --watch\" \"pnpm run build:cjs --watch\" \"pnpm run build:type --watch\""
|
||||
"test": "jest",
|
||||
"build": "rm -rf ./dist && NODE_OPTIONS=\"--max-old-space-size=8192\" bunchee",
|
||||
"postbuild": "pnpm run copy && pnpm run modify-package-json",
|
||||
"copy": "cp -r package.json CHANGELOG.md ../../README.md ../../LICENSE examples src dist/",
|
||||
"modify-package-json": "node ./scripts/modify-package-json.mjs",
|
||||
"prepublish": "pnpm run modify-package-json && echo \"please cd ./dist and run pnpm publish\" && exit 1",
|
||||
"dev": "NODE_OPTIONS=\"--max-old-space-size=8192\" bunchee -w",
|
||||
"circular-check": "madge -c ./src/index.ts"
|
||||
}
|
||||
}
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* This script is used to modify the package.json file in the dist folder
|
||||
* so that it can be published to npm.
|
||||
*/
|
||||
import editJsonFile from "edit-json-file";
|
||||
import fs from "node:fs/promises";
|
||||
|
||||
{
|
||||
await fs.copyFile("./package.json", "./dist/package.json");
|
||||
const file = editJsonFile("./dist/package.json");
|
||||
|
||||
file.unset("scripts");
|
||||
file.unset("private");
|
||||
await new Promise((resolve) => file.save(resolve));
|
||||
}
|
||||
{
|
||||
const packageJson = await fs.readFile("./dist/package.json", "utf8");
|
||||
const modifiedPackageJson = packageJson.replaceAll("./dist/", "./");
|
||||
await fs.writeFile(
|
||||
"./dist/package.json",
|
||||
JSON.stringify(JSON.parse(modifiedPackageJson), null, 2),
|
||||
"utf8",
|
||||
);
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
import { OpenAI } from "./llm/LLM.js";
|
||||
import { ChatMessage, LLM, MessageType } from "./llm/types.js";
|
||||
import { OpenAI } from "./llm/LLM";
|
||||
import { ChatMessage, LLM, MessageType } from "./llm/types";
|
||||
import {
|
||||
defaultSummaryPrompt,
|
||||
messagesToHistoryStr,
|
||||
SummaryPrompt,
|
||||
} from "./Prompt.js";
|
||||
} from "./Prompt";
|
||||
|
||||
/**
|
||||
* A ChatHistory is used to keep the state of back and forth chat messages
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { encodingForModel } from "js-tiktoken";
|
||||
|
||||
import { randomUUID } from "@llamaindex/env";
|
||||
import { Event, EventTag, EventType } from "./callbacks/CallbackManager.js";
|
||||
import { Event, EventTag, EventType } from "./callbacks/CallbackManager";
|
||||
import { randomUUID } from "./env";
|
||||
|
||||
export enum Tokenizers {
|
||||
CL100K_BASE = "cl100k_base",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createSHA256, path, randomUUID } from "@llamaindex/env";
|
||||
import _ from "lodash";
|
||||
import { createSHA256, path, randomUUID } from "./env";
|
||||
|
||||
export enum NodeRelationship {
|
||||
SOURCE = "SOURCE",
|
||||
@@ -353,10 +353,10 @@ export function splitNodesByType(nodes: BaseNode[]): {
|
||||
imageNodes: ImageNode[];
|
||||
textNodes: TextNode[];
|
||||
} {
|
||||
const imageNodes: ImageNode[] = [];
|
||||
const textNodes: TextNode[] = [];
|
||||
let imageNodes: ImageNode[] = [];
|
||||
let textNodes: TextNode[] = [];
|
||||
|
||||
for (const node of nodes) {
|
||||
for (let node of nodes) {
|
||||
if (node instanceof ImageNode) {
|
||||
imageNodes.push(node);
|
||||
} else if (node instanceof TextNode) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { SubQuestion } from "./engines/query/types.js";
|
||||
import { BaseOutputParser, StructuredOutput } from "./types.js";
|
||||
import { SubQuestion } from "./engines/query/types";
|
||||
import { BaseOutputParser, StructuredOutput } from "./types";
|
||||
|
||||
/**
|
||||
* Error class for output parsing. Due to the nature of LLMs, anytime we use LLM
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { SubQuestion } from "./engines/query/types.js";
|
||||
import { ChatMessage } from "./llm/types.js";
|
||||
import { ToolMetadata } from "./types.js";
|
||||
import { SubQuestion } from "./engines/query/types";
|
||||
import { ChatMessage } from "./llm/types";
|
||||
import { ToolMetadata } from "./types";
|
||||
|
||||
/**
|
||||
* A SimplePrompt is a function that takes a dictionary of inputs and returns a string.
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { globalsHelper } from "./GlobalsHelper.js";
|
||||
import { SimplePrompt } from "./Prompt.js";
|
||||
import { SentenceSplitter } from "./TextSplitter.js";
|
||||
import { globalsHelper } from "./GlobalsHelper";
|
||||
import { SimplePrompt } from "./Prompt";
|
||||
import { SentenceSplitter } from "./TextSplitter";
|
||||
import {
|
||||
DEFAULT_CHUNK_OVERLAP_RATIO,
|
||||
DEFAULT_CONTEXT_WINDOW,
|
||||
DEFAULT_NUM_OUTPUTS,
|
||||
DEFAULT_PADDING,
|
||||
} from "./constants.js";
|
||||
} from "./constants";
|
||||
|
||||
export function getEmptyPromptTxt(prompt: SimplePrompt) {
|
||||
return prompt({});
|
||||
|
||||
@@ -1,48 +1,28 @@
|
||||
import { SubQuestionOutputParser } from "./OutputParser.js";
|
||||
import { SubQuestionOutputParser } from "./OutputParser";
|
||||
import {
|
||||
SubQuestionPrompt,
|
||||
buildToolsText,
|
||||
defaultSubQuestionPrompt,
|
||||
} from "./Prompt.js";
|
||||
import { BaseQuestionGenerator, SubQuestion } from "./engines/query/types.js";
|
||||
import { OpenAI } from "./llm/LLM.js";
|
||||
import { LLM } from "./llm/types.js";
|
||||
import { PromptMixin } from "./prompts/index.js";
|
||||
import { BaseOutputParser, StructuredOutput, ToolMetadata } from "./types.js";
|
||||
} from "./Prompt";
|
||||
import { BaseQuestionGenerator, SubQuestion } from "./engines/query/types";
|
||||
import { OpenAI } from "./llm/LLM";
|
||||
import { LLM } from "./llm/types";
|
||||
import { BaseOutputParser, StructuredOutput, ToolMetadata } from "./types";
|
||||
|
||||
/**
|
||||
* LLMQuestionGenerator uses the LLM to generate new questions for the LLM using tools and a user query.
|
||||
*/
|
||||
export class LLMQuestionGenerator
|
||||
extends PromptMixin
|
||||
implements BaseQuestionGenerator
|
||||
{
|
||||
export class LLMQuestionGenerator implements BaseQuestionGenerator {
|
||||
llm: LLM;
|
||||
prompt: SubQuestionPrompt;
|
||||
outputParser: BaseOutputParser<StructuredOutput<SubQuestion[]>>;
|
||||
|
||||
constructor(init?: Partial<LLMQuestionGenerator>) {
|
||||
super();
|
||||
|
||||
this.llm = init?.llm ?? new OpenAI();
|
||||
this.prompt = init?.prompt ?? defaultSubQuestionPrompt;
|
||||
this.outputParser = init?.outputParser ?? new SubQuestionOutputParser();
|
||||
}
|
||||
|
||||
protected _getPrompts(): { [x: string]: SubQuestionPrompt } {
|
||||
return {
|
||||
subQuestion: this.prompt,
|
||||
};
|
||||
}
|
||||
|
||||
protected _updatePrompts(promptsDict: {
|
||||
subQuestion: SubQuestionPrompt;
|
||||
}): void {
|
||||
if ("subQuestion" in promptsDict) {
|
||||
this.prompt = promptsDict.subQuestion;
|
||||
}
|
||||
}
|
||||
|
||||
async generate(tools: ToolMetadata[], query: string): Promise<SubQuestion[]> {
|
||||
const toolsStr = buildToolsText(tools);
|
||||
const queryStr = query;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { BaseNode } from "./Node.js";
|
||||
import { BaseNode } from "./Node";
|
||||
|
||||
/**
|
||||
* Response is the output of a LLM
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Event } from "./callbacks/CallbackManager.js";
|
||||
import { NodeWithScore } from "./Node.js";
|
||||
import { ServiceContext } from "./ServiceContext.js";
|
||||
import { Event } from "./callbacks/CallbackManager";
|
||||
import { NodeWithScore } from "./Node";
|
||||
import { ServiceContext } from "./ServiceContext";
|
||||
|
||||
/**
|
||||
* Retrievers retrieve the nodes that most closely match our query in similarity.
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { PromptHelper } from "./PromptHelper.js";
|
||||
import { CallbackManager } from "./callbacks/CallbackManager.js";
|
||||
import { OpenAIEmbedding } from "./embeddings/OpenAIEmbedding.js";
|
||||
import { BaseEmbedding } from "./embeddings/types.js";
|
||||
import { LLM, OpenAI } from "./llm/index.js";
|
||||
import { SimpleNodeParser } from "./nodeParsers/SimpleNodeParser.js";
|
||||
import { NodeParser } from "./nodeParsers/types.js";
|
||||
import { CallbackManager } from "./callbacks/CallbackManager";
|
||||
import { BaseEmbedding, OpenAIEmbedding } from "./embeddings";
|
||||
import { LLM, OpenAI } from "./llm";
|
||||
import { NodeParser, SimpleNodeParser } from "./nodeParsers";
|
||||
import { PromptHelper } from "./PromptHelper";
|
||||
|
||||
/**
|
||||
* The ServiceContext is a collection of components that are used in different parts of the application.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { EOL } from "@llamaindex/env";
|
||||
import { EOL } from "./env";
|
||||
// GitHub translated
|
||||
import { globalsHelper } from "./GlobalsHelper.js";
|
||||
import { DEFAULT_CHUNK_OVERLAP, DEFAULT_CHUNK_SIZE } from "./constants.js";
|
||||
import { globalsHelper } from "./GlobalsHelper";
|
||||
import { DEFAULT_CHUNK_OVERLAP, DEFAULT_CHUNK_SIZE } from "./constants";
|
||||
|
||||
class TextSplit {
|
||||
textChunk: string;
|
||||
@@ -130,7 +130,7 @@ export class SentenceSplitter {
|
||||
|
||||
getParagraphSplits(text: string, effectiveChunkSize?: number): string[] {
|
||||
// get paragraph splits
|
||||
const paragraphSplits: string[] = text.split(this.paragraphSeparator);
|
||||
let paragraphSplits: string[] = text.split(this.paragraphSeparator);
|
||||
let idx = 0;
|
||||
if (effectiveChunkSize == undefined) {
|
||||
return paragraphSplits;
|
||||
@@ -155,9 +155,9 @@ export class SentenceSplitter {
|
||||
}
|
||||
|
||||
getSentenceSplits(text: string, effectiveChunkSize?: number): string[] {
|
||||
const paragraphSplits = this.getParagraphSplits(text, effectiveChunkSize);
|
||||
let paragraphSplits = this.getParagraphSplits(text, effectiveChunkSize);
|
||||
// Next we split the text using the chunk tokenizer fn/
|
||||
const splits = [];
|
||||
let splits = [];
|
||||
for (const parText of paragraphSplits) {
|
||||
const sentenceSplits = this.chunkingTokenizerFn(parText);
|
||||
|
||||
@@ -194,9 +194,9 @@ export class SentenceSplitter {
|
||||
}));
|
||||
}
|
||||
|
||||
const newSplits: SplitRep[] = [];
|
||||
let newSplits: SplitRep[] = [];
|
||||
for (const split of sentenceSplits) {
|
||||
const splitTokens = this.tokenizer(split);
|
||||
let splitTokens = this.tokenizer(split);
|
||||
const splitLen = splitTokens.length;
|
||||
if (splitLen <= effectiveChunkSize) {
|
||||
newSplits.push({ text: split, numTokens: splitLen });
|
||||
@@ -219,7 +219,7 @@ export class SentenceSplitter {
|
||||
// go through sentence splits, combine to chunks that are within the chunk size
|
||||
|
||||
// docs represents final list of text chunks
|
||||
const docs: TextSplit[] = [];
|
||||
let docs: TextSplit[] = [];
|
||||
// curChunkSentences represents the current list of sentence splits (that)
|
||||
// will be merged into a chunk
|
||||
let curChunkSentences: SplitRep[] = [];
|
||||
@@ -287,18 +287,18 @@ export class SentenceSplitter {
|
||||
return [];
|
||||
}
|
||||
|
||||
const effectiveChunkSize = this.getEffectiveChunkSize(extraInfoStr);
|
||||
const sentenceSplits = this.getSentenceSplits(text, effectiveChunkSize);
|
||||
let effectiveChunkSize = this.getEffectiveChunkSize(extraInfoStr);
|
||||
let sentenceSplits = this.getSentenceSplits(text, effectiveChunkSize);
|
||||
|
||||
// Check if any sentences exceed the chunk size. If they don't,
|
||||
// force split by tokenizer
|
||||
const newSentenceSplits = this.processSentenceSplits(
|
||||
let newSentenceSplits = this.processSentenceSplits(
|
||||
sentenceSplits,
|
||||
effectiveChunkSize,
|
||||
);
|
||||
|
||||
// combine sentence splits into chunks of text that can then be returned
|
||||
const combinedTextSplits = this.combineTextSplits(
|
||||
let combinedTextSplits = this.combineTextSplits(
|
||||
newSentenceSplits,
|
||||
effectiveChunkSize,
|
||||
);
|
||||
|
||||
@@ -1,5 +1,2 @@
|
||||
export * from "./openai/base.js";
|
||||
export * from "./openai/worker.js";
|
||||
export * from "./react/base.js";
|
||||
export * from "./react/worker.js";
|
||||
export * from "./types.js";
|
||||
export * from "./openai/base";
|
||||
export * from "./openai/worker";
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { CallbackManager } from "../../callbacks/CallbackManager.js";
|
||||
import { ChatMessage, OpenAI } from "../../llm/index.js";
|
||||
import { ObjectRetriever } from "../../objects/base.js";
|
||||
import { BaseTool } from "../../types.js";
|
||||
import { AgentRunner } from "../runner/base.js";
|
||||
import { OpenAIAgentWorker } from "./worker.js";
|
||||
import { CallbackManager } from "../../callbacks/CallbackManager";
|
||||
import { ChatMessage, OpenAI } from "../../llm";
|
||||
import { ObjectRetriever } from "../../objects/base";
|
||||
import { BaseTool } from "../../types";
|
||||
import { AgentRunner } from "../runner/base";
|
||||
import { OpenAIAgentWorker } from "./worker";
|
||||
|
||||
type OpenAIAgentParams = {
|
||||
tools?: BaseTool[];
|
||||
tools: BaseTool[];
|
||||
llm?: OpenAI;
|
||||
memory?: any;
|
||||
prefixMessages?: ChatMessage[];
|
||||
@@ -14,8 +14,7 @@ type OpenAIAgentParams = {
|
||||
maxFunctionCalls?: number;
|
||||
defaultToolChoice?: string;
|
||||
callbackManager?: CallbackManager;
|
||||
toolRetriever?: ObjectRetriever;
|
||||
systemPrompt?: string;
|
||||
toolRetriever?: ObjectRetriever<BaseTool>;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -34,29 +33,7 @@ export class OpenAIAgent extends AgentRunner {
|
||||
defaultToolChoice = "auto",
|
||||
callbackManager,
|
||||
toolRetriever,
|
||||
systemPrompt,
|
||||
}: OpenAIAgentParams) {
|
||||
prefixMessages = prefixMessages || [];
|
||||
|
||||
llm = llm ?? new OpenAI({ model: "gpt-3.5-turbo-0613" });
|
||||
|
||||
if (systemPrompt) {
|
||||
if (prefixMessages) {
|
||||
throw new Error("Cannot provide both systemPrompt and prefixMessages");
|
||||
}
|
||||
|
||||
prefixMessages = [
|
||||
{
|
||||
content: systemPrompt,
|
||||
role: "system",
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
if (!llm?.metadata.isFunctionCallingModel) {
|
||||
throw new Error("LLM model must be a function-calling model");
|
||||
}
|
||||
|
||||
const stepEngine = new OpenAIAgentWorker({
|
||||
tools,
|
||||
callbackManager,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ToolMetadata } from "../../types.js";
|
||||
import { ToolMetadata } from "../../types";
|
||||
|
||||
export type OpenAIFunction = {
|
||||
type: "function";
|
||||
|
||||
@@ -1,26 +1,23 @@
|
||||
// Assuming that the necessary interfaces and classes (like BaseTool, OpenAI, ChatMessage, CallbackManager, etc.) are defined elsewhere
|
||||
|
||||
import { randomUUID } from "@llamaindex/env";
|
||||
import { CallbackManager } from "../../callbacks/CallbackManager.js";
|
||||
import {
|
||||
AgentChatResponse,
|
||||
ChatResponseMode,
|
||||
} from "../../engines/chat/types.js";
|
||||
import { CallbackManager } from "../../callbacks/CallbackManager";
|
||||
import { AgentChatResponse, ChatResponseMode } from "../../engines/chat";
|
||||
import { randomUUID } from "../../env";
|
||||
import {
|
||||
ChatMessage,
|
||||
ChatResponse,
|
||||
ChatResponseChunk,
|
||||
OpenAI,
|
||||
} from "../../llm/index.js";
|
||||
import { ChatMemoryBuffer } from "../../memory/ChatMemoryBuffer.js";
|
||||
import { ObjectRetriever } from "../../objects/base.js";
|
||||
import { ToolOutput } from "../../tools/types.js";
|
||||
import { callToolWithErrorHandling } from "../../tools/utils.js";
|
||||
import { BaseTool } from "../../types.js";
|
||||
import { AgentWorker, Task, TaskStep, TaskStepOutput } from "../types.js";
|
||||
import { addUserStepToMemory, getFunctionByName } from "../utils.js";
|
||||
import { OpenAIToolCall } from "./types/chat.js";
|
||||
import { toOpenAiTool } from "./utils.js";
|
||||
} from "../../llm";
|
||||
import { ChatMemoryBuffer } from "../../memory/ChatMemoryBuffer";
|
||||
import { ObjectRetriever } from "../../objects/base";
|
||||
import { ToolOutput } from "../../tools/types";
|
||||
import { callToolWithErrorHandling } from "../../tools/utils";
|
||||
import { BaseTool } from "../../types";
|
||||
import { AgentWorker, Task, TaskStep, TaskStepOutput } from "../types";
|
||||
import { addUserStepToMemory, getFunctionByName } from "../utils";
|
||||
import { OpenAIToolCall } from "./types/chat";
|
||||
import { toOpenAiTool } from "./utils";
|
||||
|
||||
const DEFAULT_MAX_FUNCTION_CALLS = 5;
|
||||
|
||||
@@ -72,13 +69,13 @@ async function callFunction(
|
||||
}
|
||||
|
||||
type OpenAIAgentWorkerParams = {
|
||||
tools?: BaseTool[];
|
||||
tools: BaseTool[];
|
||||
llm?: OpenAI;
|
||||
prefixMessages?: ChatMessage[];
|
||||
verbose?: boolean;
|
||||
maxFunctionCalls?: number;
|
||||
callbackManager?: CallbackManager | undefined;
|
||||
toolRetriever?: ObjectRetriever;
|
||||
toolRetriever?: ObjectRetriever<BaseTool>;
|
||||
};
|
||||
|
||||
type CallFunctionOutput = {
|
||||
@@ -91,20 +88,20 @@ type CallFunctionOutput = {
|
||||
* This class is responsible for running the agent.
|
||||
*/
|
||||
export class OpenAIAgentWorker implements AgentWorker {
|
||||
private llm: OpenAI;
|
||||
private verbose: boolean;
|
||||
private maxFunctionCalls: number;
|
||||
private _llm: OpenAI;
|
||||
private _verbose: boolean;
|
||||
private _maxFunctionCalls: number;
|
||||
|
||||
public prefixMessages: ChatMessage[];
|
||||
public callbackManager: CallbackManager | undefined;
|
||||
|
||||
private _getTools: (input: string) => Promise<BaseTool[]>;
|
||||
private _getTools: (input: string) => BaseTool[];
|
||||
|
||||
/**
|
||||
* Initialize.
|
||||
*/
|
||||
constructor({
|
||||
tools = [],
|
||||
tools,
|
||||
llm,
|
||||
prefixMessages,
|
||||
verbose,
|
||||
@@ -112,21 +109,21 @@ export class OpenAIAgentWorker implements AgentWorker {
|
||||
callbackManager,
|
||||
toolRetriever,
|
||||
}: OpenAIAgentWorkerParams) {
|
||||
this.llm = llm ?? new OpenAI({ model: "gpt-3.5-turbo-0613" });
|
||||
this.verbose = verbose || false;
|
||||
this.maxFunctionCalls = maxFunctionCalls;
|
||||
this._llm = llm ?? new OpenAI({ model: "gpt-3.5-turbo-0613" });
|
||||
this._verbose = verbose || false;
|
||||
this._maxFunctionCalls = maxFunctionCalls;
|
||||
this.prefixMessages = prefixMessages || [];
|
||||
this.callbackManager = callbackManager || this.llm.callbackManager;
|
||||
this.callbackManager = callbackManager || this._llm.callbackManager;
|
||||
|
||||
if (tools.length > 0 && toolRetriever) {
|
||||
throw new Error("Cannot specify both tools and tool_retriever");
|
||||
} else if (tools.length > 0) {
|
||||
this._getTools = async () => tools;
|
||||
this._getTools = () => tools;
|
||||
} else if (toolRetriever) {
|
||||
this._getTools = async (message: string) =>
|
||||
toolRetriever.retrieve(message);
|
||||
// @ts-ignore
|
||||
this._getTools = (message: string) => toolRetriever.retrieve(message);
|
||||
} else {
|
||||
this._getTools = async () => [];
|
||||
this._getTools = () => [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,7 +191,6 @@ export class OpenAIAgentWorker implements AgentWorker {
|
||||
): AgentChatResponse | AsyncIterable<ChatResponseChunk> {
|
||||
const aiMessage = chatResponse.message;
|
||||
task.extraState.newMemory.put(aiMessage);
|
||||
|
||||
return new AgentChatResponse(aiMessage.content, task.extraState.sources);
|
||||
}
|
||||
|
||||
@@ -211,7 +207,7 @@ export class OpenAIAgentWorker implements AgentWorker {
|
||||
llmChatKwargs: any,
|
||||
): Promise<AgentChatResponse> {
|
||||
if (mode === ChatResponseMode.WAIT) {
|
||||
const chatResponse = (await this.llm.chat({
|
||||
const chatResponse = (await this._llm.chat({
|
||||
stream: false,
|
||||
...llmChatKwargs,
|
||||
})) as unknown as ChatResponse;
|
||||
@@ -240,7 +236,7 @@ export class OpenAIAgentWorker implements AgentWorker {
|
||||
throw new Error("Invalid tool_call object");
|
||||
}
|
||||
|
||||
const functionMessage = await callFunction(tools, toolCall, this.verbose);
|
||||
const functionMessage = await callFunction(tools, toolCall, this._verbose);
|
||||
|
||||
const message = functionMessage[0];
|
||||
const toolOutput = functionMessage[1];
|
||||
@@ -286,7 +282,7 @@ export class OpenAIAgentWorker implements AgentWorker {
|
||||
toolCalls: OpenAIToolCall[] | null,
|
||||
nFunctionCalls: number,
|
||||
): boolean {
|
||||
if (nFunctionCalls > this.maxFunctionCalls) {
|
||||
if (nFunctionCalls > this._maxFunctionCalls) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -302,7 +298,7 @@ export class OpenAIAgentWorker implements AgentWorker {
|
||||
* @param input: input
|
||||
* @returns: tools
|
||||
*/
|
||||
async getTools(input: string): Promise<BaseTool[]> {
|
||||
getTools(input: string): BaseTool[] {
|
||||
return this._getTools(input);
|
||||
}
|
||||
|
||||
@@ -312,10 +308,10 @@ export class OpenAIAgentWorker implements AgentWorker {
|
||||
mode: ChatResponseMode = ChatResponseMode.WAIT,
|
||||
toolChoice: string | { [key: string]: any } = "auto",
|
||||
): Promise<TaskStepOutput> {
|
||||
const tools = await this.getTools(task.input);
|
||||
const tools = this.getTools(task.input);
|
||||
|
||||
if (step.input) {
|
||||
addUserStepToMemory(step, task.extraState.newMemory, this.verbose);
|
||||
addUserStepToMemory(step, task.extraState.newMemory, this._verbose);
|
||||
}
|
||||
|
||||
const openaiTools = tools.map((tool) =>
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
import { CallbackManager } from "../../callbacks/CallbackManager.js";
|
||||
import { ChatMessage, LLM } from "../../llm/index.js";
|
||||
import { ObjectRetriever } from "../../objects/base.js";
|
||||
import { BaseTool } from "../../types.js";
|
||||
import { AgentRunner } from "../runner/base.js";
|
||||
import { ReActAgentWorker } from "./worker.js";
|
||||
|
||||
type ReActAgentParams = {
|
||||
tools: BaseTool[];
|
||||
llm?: LLM;
|
||||
memory?: any;
|
||||
prefixMessages?: ChatMessage[];
|
||||
verbose?: boolean;
|
||||
maxInteractions?: number;
|
||||
defaultToolChoice?: string;
|
||||
callbackManager?: CallbackManager;
|
||||
toolRetriever?: ObjectRetriever;
|
||||
};
|
||||
|
||||
/**
|
||||
* An agent that uses OpenAI's API to generate text.
|
||||
*
|
||||
* @category OpenAI
|
||||
*/
|
||||
export class ReActAgent extends AgentRunner {
|
||||
constructor({
|
||||
tools,
|
||||
llm,
|
||||
memory,
|
||||
prefixMessages,
|
||||
verbose,
|
||||
maxInteractions = 10,
|
||||
defaultToolChoice = "auto",
|
||||
callbackManager,
|
||||
toolRetriever,
|
||||
}: Partial<ReActAgentParams>) {
|
||||
const stepEngine = new ReActAgentWorker({
|
||||
tools: tools ?? [],
|
||||
callbackManager,
|
||||
llm,
|
||||
maxInteractions,
|
||||
toolRetriever,
|
||||
verbose,
|
||||
});
|
||||
|
||||
super({
|
||||
agentWorker: stepEngine,
|
||||
memory,
|
||||
callbackManager,
|
||||
defaultToolChoice,
|
||||
chatHistory: prefixMessages,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
import { ChatMessage } from "../../llm/index.js";
|
||||
import { BaseTool } from "../../types.js";
|
||||
import { getReactChatSystemHeader } from "./prompts.js";
|
||||
import { BaseReasoningStep, ObservationReasoningStep } from "./types.js";
|
||||
|
||||
function getReactToolDescriptions(tools: BaseTool[]): string[] {
|
||||
const toolDescs: string[] = [];
|
||||
for (const tool of tools) {
|
||||
// @ts-ignore
|
||||
const toolDesc = `> Tool Name: ${tool.metadata.name}\nTool Description: ${tool.metadata.description}\nTool Args: ${JSON.stringify(tool?.metadata?.parameters?.properties)}\n`;
|
||||
toolDescs.push(toolDesc);
|
||||
}
|
||||
return toolDescs;
|
||||
}
|
||||
|
||||
export interface BaseAgentChatFormatter {
|
||||
format(
|
||||
tools: BaseTool[],
|
||||
chatHistory: ChatMessage[],
|
||||
currentReasoning?: BaseReasoningStep[],
|
||||
): ChatMessage[];
|
||||
}
|
||||
|
||||
export class ReActChatFormatter implements BaseAgentChatFormatter {
|
||||
systemHeader: string = "";
|
||||
context: string = "'";
|
||||
|
||||
constructor(init?: Partial<ReActChatFormatter>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
|
||||
format(
|
||||
tools: BaseTool[],
|
||||
chatHistory: ChatMessage[],
|
||||
currentReasoning?: BaseReasoningStep[],
|
||||
): ChatMessage[] {
|
||||
currentReasoning = currentReasoning ?? [];
|
||||
|
||||
const formatArgs = {
|
||||
toolDesc: getReactToolDescriptions(tools).join("\n"),
|
||||
toolNames: tools.map((tool) => tool.metadata.name).join(", "),
|
||||
context: "",
|
||||
};
|
||||
|
||||
if (this.context) {
|
||||
formatArgs["context"] = this.context;
|
||||
}
|
||||
|
||||
const reasoningHistory = [];
|
||||
|
||||
for (const reasoningStep of currentReasoning) {
|
||||
let message: ChatMessage | undefined;
|
||||
|
||||
if (reasoningStep instanceof ObservationReasoningStep) {
|
||||
message = {
|
||||
content: reasoningStep.getContent(),
|
||||
role: "user",
|
||||
};
|
||||
} else {
|
||||
message = {
|
||||
content: reasoningStep.getContent(),
|
||||
role: "system",
|
||||
};
|
||||
}
|
||||
|
||||
reasoningHistory.push(message);
|
||||
}
|
||||
|
||||
const systemContent = getReactChatSystemHeader({
|
||||
toolDesc: formatArgs.toolDesc,
|
||||
toolNames: formatArgs.toolNames,
|
||||
});
|
||||
|
||||
return [
|
||||
{
|
||||
content: systemContent,
|
||||
role: "system",
|
||||
},
|
||||
...chatHistory,
|
||||
...reasoningHistory,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
import {
|
||||
ActionReasoningStep,
|
||||
BaseOutputParser,
|
||||
BaseReasoningStep,
|
||||
ResponseReasoningStep,
|
||||
} from "./types.js";
|
||||
|
||||
function extractJsonStr(text: string): string {
|
||||
const pattern = /\{.*\}/s;
|
||||
const match = text.match(pattern);
|
||||
|
||||
if (!match) {
|
||||
throw new Error(`Could not extract json string from output: ${text}`);
|
||||
}
|
||||
|
||||
return match[0];
|
||||
}
|
||||
|
||||
function extractToolUse(inputText: string): [string, string, string] {
|
||||
const pattern =
|
||||
/\s*Thought: (.*?)\nAction: ([a-zA-Z0-9_]+).*?\nAction Input: .*?(\{.*?\})/s;
|
||||
|
||||
const match = inputText.match(pattern);
|
||||
|
||||
if (!match) {
|
||||
throw new Error(`Could not extract tool use from input text: ${inputText}`);
|
||||
}
|
||||
|
||||
const thought = match[1].trim();
|
||||
const action = match[2].trim();
|
||||
const actionInput = match[3].trim();
|
||||
return [thought, action, actionInput];
|
||||
}
|
||||
|
||||
function actionInputParser(jsonStr: string): object {
|
||||
const processedString = jsonStr.replace(/(?<!\w)\'|\'(?!\w)/g, '"');
|
||||
const pattern = /"(\w+)":\s*"([^"]*)"/g;
|
||||
const matches = [...processedString.matchAll(pattern)];
|
||||
return Object.fromEntries(matches);
|
||||
}
|
||||
|
||||
function extractFinalResponse(inputText: string): [string, string] {
|
||||
const pattern = /\s*Thought:(.*?)Answer:(.*?)(?:$)/s;
|
||||
|
||||
const match = inputText.match(pattern);
|
||||
|
||||
if (!match) {
|
||||
throw new Error(
|
||||
`Could not extract final answer from input text: ${inputText}`,
|
||||
);
|
||||
}
|
||||
|
||||
const thought = match[1].trim();
|
||||
const answer = match[2].trim();
|
||||
return [thought, answer];
|
||||
}
|
||||
|
||||
export class ReActOutputParser extends BaseOutputParser {
|
||||
parse(output: string, isStreaming: boolean = false): BaseReasoningStep {
|
||||
if (!output.includes("Thought:")) {
|
||||
// NOTE: handle the case where the agent directly outputs the answer
|
||||
// instead of following the thought-answer format
|
||||
return new ResponseReasoningStep({
|
||||
thought: "(Implicit) I can answer without any more tools!",
|
||||
response: output,
|
||||
isStreaming,
|
||||
});
|
||||
}
|
||||
|
||||
if (output.includes("Answer:")) {
|
||||
const [thought, answer] = extractFinalResponse(output);
|
||||
return new ResponseReasoningStep({
|
||||
thought: thought,
|
||||
response: answer,
|
||||
isStreaming,
|
||||
});
|
||||
}
|
||||
|
||||
if (output.includes("Action:")) {
|
||||
const [thought, action, action_input] = extractToolUse(output);
|
||||
const json_str = extractJsonStr(action_input);
|
||||
|
||||
// First we try json, if this fails we use ast
|
||||
let actionInputDict;
|
||||
|
||||
try {
|
||||
actionInputDict = JSON.parse(json_str);
|
||||
} catch (e) {
|
||||
actionInputDict = actionInputParser(json_str);
|
||||
}
|
||||
|
||||
return new ActionReasoningStep({
|
||||
thought: thought,
|
||||
action: action,
|
||||
actionInput: actionInputDict,
|
||||
});
|
||||
}
|
||||
|
||||
throw new Error(`Could not parse output: ${output}`);
|
||||
}
|
||||
|
||||
format(output: string): string {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
type ReactChatSystemHeaderParams = {
|
||||
toolDesc: string;
|
||||
toolNames: string;
|
||||
};
|
||||
|
||||
export const getReactChatSystemHeader = ({
|
||||
toolDesc,
|
||||
toolNames,
|
||||
}: ReactChatSystemHeaderParams) =>
|
||||
`You are designed to help with a variety of tasks, from answering questions to providing summaries to other types of analyses.
|
||||
|
||||
## Tools
|
||||
You have access to a wide variety of tools. You are responsible for using
|
||||
the tools in any sequence you deem appropriate to complete the task at hand.
|
||||
This may require breaking the task into subtasks and using different tools
|
||||
to complete each subtask.
|
||||
|
||||
You have access to the following tools:
|
||||
${toolDesc}
|
||||
|
||||
## Output Format
|
||||
To answer the question, please use the following format.
|
||||
|
||||
"""
|
||||
Thought: I need to use a tool to help me answer the question.
|
||||
Action: tool name (one of ${toolNames}) if using a tool.
|
||||
Action Input: the input to the tool, in a JSON format representing the kwargs (e.g. {{"input": "hello world", "num_beams": 5}})
|
||||
"""
|
||||
|
||||
Please ALWAYS start with a Thought.
|
||||
|
||||
Please use a valid JSON format for the Action Input. Do NOT do this {{'input': 'hello world', 'num_beams': 5}}.
|
||||
|
||||
If this format is used, the user will respond in the following format:
|
||||
|
||||
""""
|
||||
Observation: tool response
|
||||
""""
|
||||
|
||||
You should keep repeating the above format until you have enough information
|
||||
to answer the question without using any more tools. At that point, you MUST respond
|
||||
in the one of the following two formats:
|
||||
|
||||
""""
|
||||
Thought: I can answer without using any more tools.
|
||||
Answer: [your answer here]
|
||||
""""
|
||||
|
||||
""""
|
||||
Thought: I cannot answer the question with the provided tools.
|
||||
Answer: Sorry, I cannot answer your query.
|
||||
""""
|
||||
|
||||
## Current Conversation
|
||||
Below is the current conversation consisting of interleaving human and assistant messages.
|
||||
`;
|
||||
@@ -1,88 +0,0 @@
|
||||
import { ChatMessage } from "../../llm/index.js";
|
||||
|
||||
export interface BaseReasoningStep {
|
||||
getContent(): string;
|
||||
isDone(): boolean;
|
||||
}
|
||||
|
||||
export class ObservationReasoningStep implements BaseReasoningStep {
|
||||
observation: string;
|
||||
|
||||
constructor(init?: Partial<ObservationReasoningStep>) {
|
||||
this.observation = init?.observation ?? "";
|
||||
}
|
||||
|
||||
getContent(): string {
|
||||
return `Observation: ${this.observation}`;
|
||||
}
|
||||
|
||||
isDone(): boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export class ActionReasoningStep implements BaseReasoningStep {
|
||||
thought: string;
|
||||
action: string;
|
||||
actionInput: Record<string, any>;
|
||||
|
||||
constructor(init?: Partial<ActionReasoningStep>) {
|
||||
this.thought = init?.thought ?? "";
|
||||
this.action = init?.action ?? "";
|
||||
this.actionInput = init?.actionInput ?? {};
|
||||
}
|
||||
|
||||
getContent(): string {
|
||||
return `Thought: ${this.thought}\nAction: ${this.action}\nAction Input: ${JSON.stringify(this.actionInput)}`;
|
||||
}
|
||||
|
||||
isDone(): boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class BaseOutputParser {
|
||||
abstract parse(output: string, isStreaming?: boolean): BaseReasoningStep;
|
||||
|
||||
format(output: string) {
|
||||
return output;
|
||||
}
|
||||
|
||||
formatMessages(messages: ChatMessage[]): ChatMessage[] {
|
||||
if (messages) {
|
||||
if (messages[0].role === "system") {
|
||||
messages[0].content = this.format(messages[0].content || "");
|
||||
} else {
|
||||
messages[messages.length - 1].content = this.format(
|
||||
messages[messages.length - 1].content || "",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
}
|
||||
|
||||
export class ResponseReasoningStep implements BaseReasoningStep {
|
||||
thought: string;
|
||||
response: string;
|
||||
isStreaming: boolean = false;
|
||||
|
||||
constructor(init?: Partial<ResponseReasoningStep>) {
|
||||
this.thought = init?.thought ?? "";
|
||||
this.response = init?.response ?? "";
|
||||
this.isStreaming = init?.isStreaming ?? false;
|
||||
}
|
||||
|
||||
getContent(): string {
|
||||
if (this.isStreaming) {
|
||||
return `Thought: ${this.thought}\nAnswer (Starts With): ${this.response} ...`;
|
||||
} else {
|
||||
return `Thought: ${this.thought}\nAnswer: ${this.response}`;
|
||||
}
|
||||
}
|
||||
|
||||
isDone(): boolean {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,395 +0,0 @@
|
||||
import { randomUUID } from "crypto";
|
||||
import { CallbackManager } from "../../callbacks/CallbackManager.js";
|
||||
import { AgentChatResponse } from "../../engines/chat/index.js";
|
||||
import { ChatResponse, LLM, OpenAI } from "../../llm/index.js";
|
||||
import { ChatMemoryBuffer } from "../../memory/ChatMemoryBuffer.js";
|
||||
import { ObjectRetriever } from "../../objects/base.js";
|
||||
import { ToolOutput } from "../../tools/index.js";
|
||||
import { BaseTool } from "../../types.js";
|
||||
import { AgentWorker, Task, TaskStep, TaskStepOutput } from "../types.js";
|
||||
import { ReActChatFormatter } from "./formatter.js";
|
||||
import { ReActOutputParser } from "./outputParser.js";
|
||||
import {
|
||||
ActionReasoningStep,
|
||||
BaseReasoningStep,
|
||||
ObservationReasoningStep,
|
||||
ResponseReasoningStep,
|
||||
} from "./types.js";
|
||||
|
||||
type ReActAgentWorkerParams = {
|
||||
tools: BaseTool[];
|
||||
llm?: LLM;
|
||||
maxInteractions?: number;
|
||||
reactChatFormatter?: ReActChatFormatter | undefined;
|
||||
outputParser?: ReActOutputParser | undefined;
|
||||
callbackManager?: CallbackManager | undefined;
|
||||
verbose?: boolean | undefined;
|
||||
toolRetriever?: ObjectRetriever | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param step
|
||||
* @param memory
|
||||
* @param currentReasoning
|
||||
* @param verbose
|
||||
*/
|
||||
function addUserStepToReasoning(
|
||||
step: TaskStep,
|
||||
memory: ChatMemoryBuffer,
|
||||
currentReasoning: BaseReasoningStep[],
|
||||
verbose: boolean = false,
|
||||
): void {
|
||||
if (step.stepState.isFirst) {
|
||||
memory.put({
|
||||
content: step.input,
|
||||
role: "user",
|
||||
});
|
||||
step.stepState.isFirst = false;
|
||||
} else {
|
||||
const reasoningStep = new ObservationReasoningStep({
|
||||
observation: step.input ?? undefined,
|
||||
});
|
||||
currentReasoning.push(reasoningStep);
|
||||
if (verbose) {
|
||||
console.log(`Added user message to memory: ${step.input}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ReAct agent worker.
|
||||
*/
|
||||
export class ReActAgentWorker implements AgentWorker {
|
||||
llm: LLM;
|
||||
verbose: boolean;
|
||||
|
||||
maxInteractions: number = 10;
|
||||
reactChatFormatter: ReActChatFormatter;
|
||||
outputParser: ReActOutputParser;
|
||||
|
||||
callbackManager: CallbackManager;
|
||||
|
||||
_getTools: (message: string) => Promise<BaseTool[]>;
|
||||
|
||||
constructor({
|
||||
tools,
|
||||
llm,
|
||||
maxInteractions,
|
||||
reactChatFormatter,
|
||||
outputParser,
|
||||
callbackManager,
|
||||
verbose,
|
||||
toolRetriever,
|
||||
}: ReActAgentWorkerParams) {
|
||||
this.llm = llm ?? new OpenAI({ model: "gpt-3.5-turbo-0613" });
|
||||
this.callbackManager = callbackManager || new CallbackManager();
|
||||
|
||||
this.maxInteractions = maxInteractions ?? 10;
|
||||
this.reactChatFormatter = reactChatFormatter ?? new ReActChatFormatter();
|
||||
this.outputParser = outputParser ?? new ReActOutputParser();
|
||||
this.verbose = verbose || false;
|
||||
|
||||
if (tools.length > 0 && toolRetriever) {
|
||||
throw new Error("Cannot specify both tools and tool_retriever");
|
||||
} else if (tools.length > 0) {
|
||||
this._getTools = async () => tools;
|
||||
} else if (toolRetriever) {
|
||||
this._getTools = async (message: string) =>
|
||||
toolRetriever.retrieve(message);
|
||||
} else {
|
||||
this._getTools = async () => [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a task step.
|
||||
* @param task - task
|
||||
* @param kwargs - keyword arguments
|
||||
* @returns - task step
|
||||
*/
|
||||
initializeStep(task: Task, kwargs?: any): TaskStep {
|
||||
const sources: ToolOutput[] = [];
|
||||
const currentReasoning: BaseReasoningStep[] = [];
|
||||
const newMemory = new ChatMemoryBuffer();
|
||||
|
||||
const taskState = {
|
||||
sources,
|
||||
currentReasoning,
|
||||
newMemory,
|
||||
};
|
||||
|
||||
task.extraState = {
|
||||
...task.extraState,
|
||||
...taskState,
|
||||
};
|
||||
|
||||
return new TaskStep(task.taskId, randomUUID(), task.input, {
|
||||
isFirst: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract reasoning step from chat response.
|
||||
* @param output - chat response
|
||||
* @param isStreaming - whether the chat response is streaming
|
||||
* @returns - [message content, reasoning steps, is done]
|
||||
*/
|
||||
extractReasoningStep(
|
||||
output: ChatResponse,
|
||||
isStreaming: boolean,
|
||||
): [string, BaseReasoningStep[], boolean] {
|
||||
if (!output.message.content) {
|
||||
throw new Error("Got empty message.");
|
||||
}
|
||||
|
||||
const messageContent = output.message.content;
|
||||
const currentReasoning: BaseReasoningStep[] = [];
|
||||
|
||||
let reasoningStep;
|
||||
|
||||
try {
|
||||
reasoningStep = this.outputParser.parse(
|
||||
messageContent,
|
||||
isStreaming,
|
||||
) as ActionReasoningStep;
|
||||
} catch (e) {
|
||||
throw new Error(`Could not parse output: ${e}`);
|
||||
}
|
||||
|
||||
if (this.verbose) {
|
||||
console.log(`${reasoningStep.getContent()}\n`);
|
||||
}
|
||||
|
||||
currentReasoning.push(reasoningStep);
|
||||
|
||||
if (reasoningStep.isDone()) {
|
||||
return [messageContent, currentReasoning, true];
|
||||
}
|
||||
|
||||
const actionReasoningStep = new ActionReasoningStep({
|
||||
thought: reasoningStep.getContent(),
|
||||
action: reasoningStep.action,
|
||||
actionInput: reasoningStep.actionInput,
|
||||
});
|
||||
|
||||
if (!(actionReasoningStep instanceof ActionReasoningStep)) {
|
||||
throw new Error(`Expected ActionReasoningStep, got ${reasoningStep}`);
|
||||
}
|
||||
|
||||
return [messageContent, currentReasoning, false];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process actions.
|
||||
* @param task - task
|
||||
* @param tools - tools
|
||||
* @param output - chat response
|
||||
* @param isStreaming - whether the chat response is streaming
|
||||
* @returns - [reasoning steps, is done]
|
||||
*/
|
||||
async _processActions(
|
||||
task: Task,
|
||||
tools: BaseTool[],
|
||||
output: ChatResponse,
|
||||
isStreaming: boolean = false,
|
||||
): Promise<[BaseReasoningStep[], boolean]> {
|
||||
const toolsDict: Record<string, BaseTool> = {};
|
||||
|
||||
for (const tool of tools) {
|
||||
toolsDict[tool.metadata.name] = tool;
|
||||
}
|
||||
|
||||
const [_, currentReasoning, isDone] = this.extractReasoningStep(
|
||||
output,
|
||||
isStreaming,
|
||||
);
|
||||
|
||||
if (isDone) {
|
||||
return [currentReasoning, true];
|
||||
}
|
||||
|
||||
const reasoningStep = currentReasoning[
|
||||
currentReasoning.length - 1
|
||||
] as ActionReasoningStep;
|
||||
|
||||
const actionReasoningStep = new ActionReasoningStep({
|
||||
thought: reasoningStep.getContent(),
|
||||
action: reasoningStep.action,
|
||||
actionInput: reasoningStep.actionInput,
|
||||
});
|
||||
|
||||
const tool = toolsDict[actionReasoningStep.action];
|
||||
|
||||
const toolOutput = await tool?.call?.(actionReasoningStep.actionInput);
|
||||
|
||||
task.extraState.sources.push(
|
||||
new ToolOutput(
|
||||
toolOutput,
|
||||
tool.metadata.name,
|
||||
actionReasoningStep.actionInput,
|
||||
toolOutput,
|
||||
),
|
||||
);
|
||||
|
||||
const observationStep = new ObservationReasoningStep({
|
||||
observation: toolOutput,
|
||||
});
|
||||
|
||||
currentReasoning.push(observationStep);
|
||||
|
||||
if (this.verbose) {
|
||||
console.log(`${observationStep.getContent()}`);
|
||||
}
|
||||
|
||||
return [currentReasoning, false];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get response.
|
||||
* @param currentReasoning - current reasoning steps
|
||||
* @param sources - tool outputs
|
||||
* @returns - agent chat response
|
||||
*/
|
||||
_getResponse(
|
||||
currentReasoning: BaseReasoningStep[],
|
||||
sources: ToolOutput[],
|
||||
): AgentChatResponse {
|
||||
if (currentReasoning.length === 0) {
|
||||
throw new Error("No reasoning steps were taken.");
|
||||
} else if (currentReasoning.length === this.maxInteractions) {
|
||||
throw new Error("Reached max iterations.");
|
||||
}
|
||||
|
||||
const responseStep = currentReasoning[currentReasoning.length - 1];
|
||||
|
||||
let responseStr: string;
|
||||
|
||||
if (responseStep instanceof ResponseReasoningStep) {
|
||||
responseStr = responseStep.response;
|
||||
} else {
|
||||
responseStr = responseStep.getContent();
|
||||
}
|
||||
|
||||
return new AgentChatResponse(responseStr, sources);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get task step response.
|
||||
* @param agentResponse - agent chat response
|
||||
* @param step - task step
|
||||
* @param isDone - whether the task is done
|
||||
* @returns - task step output
|
||||
*/
|
||||
_getTaskStepResponse(
|
||||
agentResponse: AgentChatResponse,
|
||||
step: TaskStep,
|
||||
isDone: boolean,
|
||||
): TaskStepOutput {
|
||||
let newSteps: TaskStep[] = [];
|
||||
|
||||
if (isDone) {
|
||||
newSteps = [];
|
||||
} else {
|
||||
newSteps = [step.getNextStep(randomUUID(), undefined)];
|
||||
}
|
||||
|
||||
return new TaskStepOutput(agentResponse, step, newSteps, isDone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a task step.
|
||||
* @param step - task step
|
||||
* @param task - task
|
||||
* @param kwargs - keyword arguments
|
||||
* @returns - task step output
|
||||
*/
|
||||
async _runStep(
|
||||
step: TaskStep,
|
||||
task: Task,
|
||||
kwargs?: any,
|
||||
): Promise<TaskStepOutput> {
|
||||
if (step.input) {
|
||||
addUserStepToReasoning(
|
||||
step,
|
||||
task.extraState.newMemory,
|
||||
task.extraState.currentReasoning,
|
||||
this.verbose,
|
||||
);
|
||||
}
|
||||
|
||||
const tools = await this._getTools(task.input);
|
||||
|
||||
const inputChat = this.reactChatFormatter.format(
|
||||
tools,
|
||||
[...task.memory.getAll(), ...task.extraState.newMemory.getAll()],
|
||||
task.extraState.currentReasoning,
|
||||
);
|
||||
|
||||
const chatResponse = await this.llm.chat({
|
||||
messages: inputChat,
|
||||
});
|
||||
|
||||
const [reasoningSteps, isDone] = await this._processActions(
|
||||
task,
|
||||
tools,
|
||||
chatResponse,
|
||||
);
|
||||
|
||||
task.extraState.currentReasoning.push(...reasoningSteps);
|
||||
|
||||
const agentResponse = this._getResponse(
|
||||
task.extraState.currentReasoning,
|
||||
task.extraState.sources,
|
||||
);
|
||||
|
||||
if (isDone) {
|
||||
task.extraState.newMemory.put({
|
||||
content: agentResponse.response,
|
||||
role: "assistant",
|
||||
});
|
||||
}
|
||||
|
||||
return this._getTaskStepResponse(agentResponse, step, isDone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a task step.
|
||||
* @param step - task step
|
||||
* @param task - task
|
||||
* @param kwargs - keyword arguments
|
||||
* @returns - task step output
|
||||
*/
|
||||
async runStep(
|
||||
step: TaskStep,
|
||||
task: Task,
|
||||
kwargs?: any,
|
||||
): Promise<TaskStepOutput> {
|
||||
return await this._runStep(step, task);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a task step.
|
||||
* @param step - task step
|
||||
* @param task - task
|
||||
* @param kwargs - keyword arguments
|
||||
* @returns - task step output
|
||||
*/
|
||||
streamStep(
|
||||
step: TaskStep,
|
||||
task: Task,
|
||||
kwargs?: any,
|
||||
): Promise<TaskStepOutput> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize a task.
|
||||
* @param task - task
|
||||
* @param kwargs - keyword arguments
|
||||
*/
|
||||
finalizeTask(task: Task, kwargs?: any): void {
|
||||
task.memory.set(task.memory.get() + task.extraState.newMemory.get());
|
||||
task.extraState.newMemory.reset();
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
import { randomUUID } from "crypto";
|
||||
import { CallbackManager } from "../../callbacks/CallbackManager.js";
|
||||
import { CallbackManager } from "../../callbacks/CallbackManager";
|
||||
import {
|
||||
AgentChatResponse,
|
||||
ChatEngineAgentParams,
|
||||
ChatResponseMode,
|
||||
} from "../../engines/chat/index.js";
|
||||
import { ChatMessage, LLM } from "../../llm/index.js";
|
||||
import { ChatMemoryBuffer } from "../../memory/ChatMemoryBuffer.js";
|
||||
import { BaseMemory } from "../../memory/types.js";
|
||||
import { AgentWorker, Task, TaskStep, TaskStepOutput } from "../types.js";
|
||||
import { AgentState, BaseAgentRunner, TaskState } from "./types.js";
|
||||
} from "../../engines/chat";
|
||||
import { ChatMessage, LLM } from "../../llm";
|
||||
import { ChatMemoryBuffer } from "../../memory/ChatMemoryBuffer";
|
||||
import { BaseMemory } from "../../memory/types";
|
||||
import { AgentWorker, Task, TaskStep, TaskStepOutput } from "../types";
|
||||
import { AgentState, BaseAgentRunner, TaskState } from "./types";
|
||||
|
||||
const validateStepFromArgs = (
|
||||
taskId: string,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AgentChatResponse } from "../../engines/chat/index.js";
|
||||
import { BaseAgent, Task, TaskStep, TaskStepOutput } from "../types.js";
|
||||
import { AgentChatResponse } from "../../engines/chat";
|
||||
import { BaseAgent, Task, TaskStep, TaskStepOutput } from "../types";
|
||||
|
||||
export class TaskState {
|
||||
task!: Task;
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import {
|
||||
AgentChatResponse,
|
||||
ChatEngineAgentParams,
|
||||
} from "../engines/chat/index.js";
|
||||
import { QueryEngineParamsNonStreaming } from "../types.js";
|
||||
import { AgentChatResponse, ChatEngineAgentParams } from "../engines/chat";
|
||||
import { QueryEngineParamsNonStreaming } from "../types";
|
||||
|
||||
export interface AgentWorker {
|
||||
initializeStep(task: Task, kwargs?: any): TaskStep;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ChatMessage } from "../llm/index.js";
|
||||
import { ChatMemoryBuffer } from "../memory/ChatMemoryBuffer.js";
|
||||
import { BaseTool } from "../types.js";
|
||||
import { TaskStep } from "./types.js";
|
||||
import { ChatMessage } from "../llm";
|
||||
import { ChatMemoryBuffer } from "../memory/ChatMemoryBuffer";
|
||||
import { BaseTool } from "../types";
|
||||
import { TaskStep } from "./types";
|
||||
|
||||
/**
|
||||
* Adds the user's input to the memory.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Anthropic } from "@anthropic-ai/sdk";
|
||||
import { NodeWithScore } from "../Node.js";
|
||||
import { NodeWithScore } from "../Node";
|
||||
|
||||
/*
|
||||
An event is a wrapper that groups related operations.
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
import { BaseRetriever } from "../Retriever.js";
|
||||
import { RetrieverQueryEngine } from "../engines/query/RetrieverQueryEngine.js";
|
||||
import { BaseNodePostprocessor } from "../postprocessors/types.js";
|
||||
import { BaseSynthesizer } from "../synthesizers/types.js";
|
||||
import { BaseQueryEngine } from "../types.js";
|
||||
import { LlamaCloudRetriever, RetrieveParams } from "./LlamaCloudRetriever.js";
|
||||
import { CloudConstructorParams } from "./types.js";
|
||||
|
||||
export class LlamaCloudIndex {
|
||||
params: CloudConstructorParams;
|
||||
|
||||
constructor(params: CloudConstructorParams) {
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
asRetriever(params: RetrieveParams = {}): BaseRetriever {
|
||||
return new LlamaCloudRetriever({ ...this.params, ...params });
|
||||
}
|
||||
|
||||
asQueryEngine(
|
||||
params?: {
|
||||
responseSynthesizer?: BaseSynthesizer;
|
||||
preFilters?: unknown;
|
||||
nodePostprocessors?: BaseNodePostprocessor[];
|
||||
} & RetrieveParams,
|
||||
): BaseQueryEngine {
|
||||
const retriever = new LlamaCloudRetriever({
|
||||
...this.params,
|
||||
...params,
|
||||
});
|
||||
return new RetrieverQueryEngine(
|
||||
retriever,
|
||||
params?.responseSynthesizer,
|
||||
params?.preFilters,
|
||||
params?.nodePostprocessors,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
import { PlatformApi, PlatformApiClient } from "@llamaindex/cloud";
|
||||
import { globalsHelper } from "../GlobalsHelper.js";
|
||||
import { NodeWithScore, ObjectType, jsonToNode } from "../Node.js";
|
||||
import { BaseRetriever } from "../Retriever.js";
|
||||
import {
|
||||
ServiceContext,
|
||||
serviceContextFromDefaults,
|
||||
} from "../ServiceContext.js";
|
||||
import { Event } from "../callbacks/CallbackManager.js";
|
||||
import {
|
||||
ClientParams,
|
||||
CloudConstructorParams,
|
||||
DEFAULT_PROJECT_NAME,
|
||||
} from "./types.js";
|
||||
import { getClient } from "./utils.js";
|
||||
|
||||
export type RetrieveParams = Omit<
|
||||
PlatformApi.RetrievalParams,
|
||||
"query" | "searchFilters" | "pipelineId" | "className"
|
||||
> & { similarityTopK?: number };
|
||||
|
||||
export class LlamaCloudRetriever implements BaseRetriever {
|
||||
client?: PlatformApiClient;
|
||||
clientParams: ClientParams;
|
||||
retrieveParams: RetrieveParams;
|
||||
projectName: string = DEFAULT_PROJECT_NAME;
|
||||
pipelineName: string;
|
||||
serviceContext: ServiceContext;
|
||||
|
||||
private resultNodesToNodeWithScore(
|
||||
nodes: PlatformApi.TextNodeWithScore[],
|
||||
): NodeWithScore[] {
|
||||
return nodes.map((node: PlatformApi.TextNodeWithScore) => {
|
||||
return {
|
||||
// Currently LlamaCloud only supports text nodes
|
||||
node: jsonToNode(node.node, ObjectType.TEXT),
|
||||
score: node.score,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
constructor(params: CloudConstructorParams & RetrieveParams) {
|
||||
this.clientParams = { apiKey: params.apiKey, baseUrl: params.baseUrl };
|
||||
if (params.similarityTopK) {
|
||||
params.denseSimilarityTopK = params.similarityTopK;
|
||||
}
|
||||
this.retrieveParams = params;
|
||||
this.pipelineName = params.name;
|
||||
if (params.projectName) {
|
||||
this.projectName = params.projectName;
|
||||
}
|
||||
this.serviceContext = params.serviceContext ?? serviceContextFromDefaults();
|
||||
}
|
||||
|
||||
private async getClient(): Promise<PlatformApiClient> {
|
||||
if (!this.client) {
|
||||
this.client = await getClient(this.clientParams);
|
||||
}
|
||||
return this.client;
|
||||
}
|
||||
|
||||
async retrieve(
|
||||
query: string,
|
||||
parentEvent?: Event | undefined,
|
||||
preFilters?: unknown,
|
||||
): Promise<NodeWithScore[]> {
|
||||
const pipelines = await (
|
||||
await this.getClient()
|
||||
).pipeline.searchPipelines({
|
||||
projectName: this.projectName,
|
||||
pipelineName: this.pipelineName,
|
||||
});
|
||||
if (pipelines.length !== 1 && !pipelines[0].id) {
|
||||
throw new Error(
|
||||
`No pipeline found with name ${this.pipelineName} in project ${this.projectName}`,
|
||||
);
|
||||
}
|
||||
const results = await (
|
||||
await this.getClient()
|
||||
).pipeline.runSearch(pipelines[0].id, {
|
||||
...this.retrieveParams,
|
||||
query,
|
||||
searchFilters: preFilters as Record<string, unknown[]>,
|
||||
});
|
||||
|
||||
const nodes = this.resultNodesToNodeWithScore(results.retrievalNodes);
|
||||
|
||||
if (this.serviceContext.callbackManager.onRetrieve) {
|
||||
this.serviceContext.callbackManager.onRetrieve({
|
||||
query,
|
||||
nodes,
|
||||
event: globalsHelper.createEvent({
|
||||
parentEvent,
|
||||
type: "retrieve",
|
||||
}),
|
||||
});
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
getServiceContext(): ServiceContext {
|
||||
return this.serviceContext;
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
export * from "./LlamaCloudIndex.js";
|
||||
export * from "./LlamaCloudRetriever.js";
|
||||
@@ -1,11 +0,0 @@
|
||||
import { ServiceContext } from "../ServiceContext.js";
|
||||
|
||||
export const DEFAULT_PROJECT_NAME = "default";
|
||||
export const DEFAULT_BASE_URL = "https://api.cloud.llamaindex.ai";
|
||||
|
||||
export type ClientParams = { apiKey?: string; baseUrl?: string };
|
||||
export type CloudConstructorParams = {
|
||||
name: string;
|
||||
projectName?: string;
|
||||
serviceContext?: ServiceContext;
|
||||
} & ClientParams;
|
||||
@@ -1,18 +0,0 @@
|
||||
import { PlatformApiClient } from "@llamaindex/cloud";
|
||||
import { ClientParams, DEFAULT_BASE_URL } from "./types.js";
|
||||
|
||||
export async function getClient({
|
||||
apiKey,
|
||||
baseUrl,
|
||||
}: ClientParams = {}): Promise<PlatformApiClient> {
|
||||
// Get the environment variables or use defaults
|
||||
baseUrl = baseUrl ?? process.env.LLAMA_CLOUD_BASE_URL ?? DEFAULT_BASE_URL;
|
||||
apiKey = apiKey ?? process.env.LLAMA_CLOUD_API_KEY;
|
||||
|
||||
const { PlatformApiClient } = await import("@llamaindex/cloud");
|
||||
|
||||
return new PlatformApiClient({
|
||||
token: apiKey,
|
||||
environment: baseUrl,
|
||||
});
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImageType } from "../Node.js";
|
||||
import { MultiModalEmbedding } from "./MultiModalEmbedding.js";
|
||||
import { readImage } from "./utils.js";
|
||||
import { ImageType } from "../Node";
|
||||
import { MultiModalEmbedding } from "./MultiModalEmbedding";
|
||||
import { readImage } from "./utils";
|
||||
|
||||
export enum ClipEmbeddingModelType {
|
||||
XENOVA_CLIP_VIT_BASE_PATCH32 = "Xenova/clip-vit-base-patch32",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { BaseEmbedding } from "./types.js";
|
||||
import { BaseEmbedding } from "./types";
|
||||
|
||||
export enum HuggingFaceEmbeddingModelType {
|
||||
XENOVA_ALL_MINILM_L6_V2 = "Xenova/all-MiniLM-L6-v2",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { MistralAISession } from "../llm/mistral.js";
|
||||
import { BaseEmbedding } from "./types.js";
|
||||
import { MistralAISession } from "../llm/mistral";
|
||||
import { BaseEmbedding } from "./types";
|
||||
|
||||
export enum MistralAIEmbeddingModelType {
|
||||
MISTRAL_EMBED = "mistral-embed",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ImageType } from "../Node.js";
|
||||
import { BaseEmbedding } from "./types.js";
|
||||
import { ImageType } from "../Node";
|
||||
import { BaseEmbedding } from "./types";
|
||||
|
||||
/*
|
||||
* Base class for Multi Modal embeddings.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Ollama } from "../llm/ollama.js";
|
||||
import { BaseEmbedding } from "./types.js";
|
||||
import { Ollama } from "../llm/ollama";
|
||||
import { BaseEmbedding } from "./types";
|
||||
|
||||
/**
|
||||
* OllamaEmbedding is an alias for Ollama that implements the BaseEmbedding interface.
|
||||
|
||||
@@ -5,9 +5,9 @@ import {
|
||||
getAzureConfigFromEnv,
|
||||
getAzureModel,
|
||||
shouldUseAzure,
|
||||
} from "../llm/azure.js";
|
||||
import { OpenAISession, getOpenAISession } from "../llm/open_ai.js";
|
||||
import { BaseEmbedding } from "./types.js";
|
||||
} from "../llm/azure";
|
||||
import { OpenAISession, getOpenAISession } from "../llm/open_ai";
|
||||
import { BaseEmbedding } from "./types";
|
||||
|
||||
export const ALL_OPENAI_EMBEDDING_MODELS = {
|
||||
"text-embedding-ada-002": {
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import { OpenAIEmbedding } from "./OpenAIEmbedding.js";
|
||||
|
||||
export class FireworksEmbedding extends OpenAIEmbedding {
|
||||
constructor(init?: Partial<OpenAIEmbedding>) {
|
||||
const {
|
||||
apiKey = process.env.FIREWORKS_API_KEY,
|
||||
additionalSessionOptions = {},
|
||||
model = "nomic-ai/nomic-embed-text-v1.5",
|
||||
...rest
|
||||
} = init ?? {};
|
||||
|
||||
if (!apiKey) {
|
||||
throw new Error("Set Fireworks Key in FIREWORKS_API_KEY env variable");
|
||||
}
|
||||
|
||||
additionalSessionOptions.baseURL =
|
||||
additionalSessionOptions.baseURL ??
|
||||
"https://api.fireworks.ai/inference/v1";
|
||||
|
||||
super({
|
||||
apiKey,
|
||||
additionalSessionOptions,
|
||||
model,
|
||||
...rest,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
export * from "./ClipEmbedding.js";
|
||||
export * from "./HuggingFaceEmbedding.js";
|
||||
export * from "./MistralAIEmbedding.js";
|
||||
export * from "./MultiModalEmbedding.js";
|
||||
export { OllamaEmbedding } from "./OllamaEmbedding.js";
|
||||
export * from "./OpenAIEmbedding.js";
|
||||
export { FireworksEmbedding } from "./fireworks.js";
|
||||
export { TogetherEmbedding } from "./together.js";
|
||||
export * from "./types.js";
|
||||
export * from "./utils.js";
|
||||
export * from "./ClipEmbedding";
|
||||
export * from "./HuggingFaceEmbedding";
|
||||
export * from "./MistralAIEmbedding";
|
||||
export * from "./MultiModalEmbedding";
|
||||
export { OllamaEmbedding } from "./OllamaEmbedding";
|
||||
export * from "./OpenAIEmbedding";
|
||||
export { TogetherEmbedding } from "./together";
|
||||
export * from "./types";
|
||||
export * from "./utils";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { OpenAIEmbedding } from "./OpenAIEmbedding.js";
|
||||
import { OpenAIEmbedding } from "./OpenAIEmbedding";
|
||||
|
||||
export class TogetherEmbedding extends OpenAIEmbedding {
|
||||
constructor(init?: Partial<OpenAIEmbedding>) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { BaseNode, MetadataMode } from "../Node.js";
|
||||
import { TransformComponent } from "../ingestion/types.js";
|
||||
import { SimilarityType, similarity } from "./utils.js";
|
||||
import { BaseNode, MetadataMode } from "../Node";
|
||||
import { TransformComponent } from "../ingestion";
|
||||
import { SimilarityType, similarity } from "./utils";
|
||||
|
||||
const DEFAULT_EMBED_BATCH_SIZE = 10;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { defaultFS } from "@llamaindex/env";
|
||||
import _ from "lodash";
|
||||
import { ImageType } from "../Node.js";
|
||||
import { DEFAULT_SIMILARITY_TOP_K } from "../constants.js";
|
||||
import { VectorStoreQueryMode } from "../storage/vectorStore/types.js";
|
||||
import { ImageType } from "../Node";
|
||||
import { DEFAULT_SIMILARITY_TOP_K } from "../constants";
|
||||
import { defaultFS } from "../env";
|
||||
import { VectorStoreQueryMode } from "../storage/vectorStore/types";
|
||||
|
||||
/**
|
||||
* Similarity type
|
||||
@@ -46,7 +46,7 @@ export function similarity(
|
||||
|
||||
switch (mode) {
|
||||
case SimilarityType.EUCLIDEAN: {
|
||||
const difference = embedding1.map((x, i) => x - embedding2[i]);
|
||||
let difference = embedding1.map((x, i) => x - embedding2[i]);
|
||||
return -norm(difference);
|
||||
}
|
||||
case SimilarityType.DOT_PRODUCT: {
|
||||
@@ -94,7 +94,7 @@ export function getTopKEmbeddings(
|
||||
);
|
||||
}
|
||||
|
||||
const similarities: { similarity: number; id: number }[] = [];
|
||||
let similarities: { similarity: number; id: number }[] = [];
|
||||
|
||||
for (let i = 0; i < embeddings.length; i++) {
|
||||
const sim = similarity(queryEmbedding, embeddings[i]);
|
||||
@@ -105,8 +105,8 @@ export function getTopKEmbeddings(
|
||||
|
||||
similarities.sort((a, b) => b.similarity - a.similarity); // Reverse sort
|
||||
|
||||
const resultSimilarities: number[] = [];
|
||||
const resultIds: any[] = [];
|
||||
let resultSimilarities: number[] = [];
|
||||
let resultIds: any[] = [];
|
||||
|
||||
for (let i = 0; i < similarityTopK; i++) {
|
||||
if (i >= similarities.length) {
|
||||
@@ -142,21 +142,21 @@ export function getTopKMMREmbeddings(
|
||||
_similarityCutoff: number | null = null,
|
||||
mmrThreshold: number | null = null,
|
||||
): [number[], any[]] {
|
||||
const threshold = mmrThreshold || 0.5;
|
||||
let threshold = mmrThreshold || 0.5;
|
||||
similarityFn = similarityFn || similarity;
|
||||
|
||||
if (embeddingIds === null || embeddingIds.length === 0) {
|
||||
embeddingIds = Array.from({ length: embeddings.length }, (_, i) => i);
|
||||
}
|
||||
const fullEmbedMap = new Map(embeddingIds.map((value, i) => [value, i]));
|
||||
const embedMap = new Map(fullEmbedMap);
|
||||
const embedSimilarity: Map<any, number> = new Map();
|
||||
let fullEmbedMap = new Map(embeddingIds.map((value, i) => [value, i]));
|
||||
let embedMap = new Map(fullEmbedMap);
|
||||
let embedSimilarity: Map<any, number> = new Map();
|
||||
let score: number = Number.NEGATIVE_INFINITY;
|
||||
let highScoreId: any | null = null;
|
||||
|
||||
for (let i = 0; i < embeddings.length; i++) {
|
||||
const emb = embeddings[i];
|
||||
const similarity = similarityFn(queryEmbedding, emb);
|
||||
let emb = embeddings[i];
|
||||
let similarity = similarityFn(queryEmbedding, emb);
|
||||
embedSimilarity.set(embeddingIds[i], similarity);
|
||||
if (similarity * threshold > score) {
|
||||
highScoreId = embeddingIds[i];
|
||||
@@ -164,18 +164,18 @@ export function getTopKMMREmbeddings(
|
||||
}
|
||||
}
|
||||
|
||||
const results: [number, any][] = [];
|
||||
let results: [number, any][] = [];
|
||||
|
||||
const embeddingLength = embeddings.length;
|
||||
const similarityTopKCount = similarityTopK || embeddingLength;
|
||||
let embeddingLength = embeddings.length;
|
||||
let similarityTopKCount = similarityTopK || embeddingLength;
|
||||
|
||||
while (results.length < Math.min(similarityTopKCount, embeddingLength)) {
|
||||
results.push([score, highScoreId]);
|
||||
embedMap.delete(highScoreId!);
|
||||
const recentEmbeddingId = highScoreId;
|
||||
let recentEmbeddingId = highScoreId;
|
||||
score = Number.NEGATIVE_INFINITY;
|
||||
for (const embedId of Array.from(embedMap.keys())) {
|
||||
const overlapWithRecent = similarityFn(
|
||||
for (let embedId of Array.from(embedMap.keys())) {
|
||||
let overlapWithRecent = similarityFn(
|
||||
embeddings[embedMap.get(embedId)!],
|
||||
embeddings[fullEmbedMap.get(recentEmbeddingId!)!],
|
||||
);
|
||||
@@ -192,8 +192,8 @@ export function getTopKMMREmbeddings(
|
||||
}
|
||||
}
|
||||
|
||||
const resultSimilarities = results.map(([s, _]) => s);
|
||||
const resultIds = results.map(([_, n]) => n);
|
||||
let resultSimilarities = results.map(([s, _]) => s);
|
||||
let resultIds = results.map(([_, n]) => n);
|
||||
|
||||
return [resultSimilarities, resultIds];
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user