Adding agents, RAG
@@ -1 +1,2 @@
|
||||
node_modules
|
||||
.env*
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import { config } from 'dotenv';
|
||||
config({ path: '.env.local' });
|
||||
|
||||
import { createWorkflow, workflowEvent } from "@llama-flow/core";
|
||||
import { pipeline } from "node:stream/promises";
|
||||
import { Anthropic } from "@llamaindex/anthropic";
|
||||
import {
|
||||
agent,
|
||||
AgentStream,
|
||||
tool,
|
||||
Settings,
|
||||
} from "llamaindex";
|
||||
import { z } from "zod";
|
||||
|
||||
////////// create the agent
|
||||
|
||||
Settings.llm = new Anthropic({
|
||||
apiKey: process.env.ANTHROPIC_API_KEY,
|
||||
model: "claude-3-7-sonnet-latest",
|
||||
});
|
||||
|
||||
const sumNumbers = ({ a, b }) => {
|
||||
return `${a + b}`;
|
||||
};
|
||||
|
||||
const addTool = tool({
|
||||
name: "sumNumbers",
|
||||
description: "Use this function to sum two numbers",
|
||||
parameters: z.object({
|
||||
a: z.number({
|
||||
description: "First number to sum",
|
||||
}),
|
||||
b: z.number({
|
||||
description: "Second number to sum",
|
||||
}),
|
||||
}),
|
||||
execute: sumNumbers,
|
||||
});
|
||||
|
||||
const tools = [addTool];
|
||||
|
||||
const myAgent = agent({ tools });
|
||||
|
||||
////////// define a workflow (optional for such a simple example!)
|
||||
|
||||
const startEvent = workflowEvent<string>();
|
||||
const stopEvent = workflowEvent<string>();
|
||||
|
||||
const workflow = createWorkflow();
|
||||
|
||||
// handle the start event
|
||||
workflow.handle([startEvent], async (start) => {
|
||||
console.log(`Started the workflow with question: ${start.data}`);
|
||||
|
||||
const response = await myAgent.run(start.data);
|
||||
return stopEvent.with(response.data.result);
|
||||
});
|
||||
|
||||
////////// run the workflow
|
||||
|
||||
// Create a workflow context and send the initial event
|
||||
const { stream, sendEvent } = workflow.createContext();
|
||||
sendEvent(startEvent.with("What is the sum of 2 and 8?"));
|
||||
|
||||
// Process the stream to get the result
|
||||
const result = await pipeline(stream, async function (source) {
|
||||
for await (const event of source) {
|
||||
if (stopEvent.include(event)) {
|
||||
return `Result: ${event.data}`;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log(result)
|
||||
@@ -0,0 +1,104 @@
|
||||
import { config } from 'dotenv';
|
||||
config({ path: '.env.local' });
|
||||
|
||||
import { createWorkflow, workflowEvent } from "@llama-flow/core";
|
||||
import { pipeline } from "node:stream/promises";
|
||||
import { Anthropic } from "@llamaindex/anthropic";
|
||||
import {
|
||||
agent,
|
||||
tool,
|
||||
Settings,
|
||||
QueryEngineTool,
|
||||
VectorStoreIndex,
|
||||
} from "llamaindex";
|
||||
import { HuggingFaceEmbedding } from "@llamaindex/huggingface";
|
||||
import { SimpleDirectoryReader } from "@llamaindex/readers/directory";
|
||||
import { z } from "zod";
|
||||
|
||||
////////// load data and create a RAG index, and create a query tool
|
||||
|
||||
Settings.llm = new Anthropic({
|
||||
apiKey: process.env.ANTHROPIC_API_KEY,
|
||||
model: "claude-3-7-sonnet-latest",
|
||||
});
|
||||
|
||||
Settings.embedModel = new HuggingFaceEmbedding({
|
||||
modelType: "BAAI/bge-small-en-v1.5",
|
||||
quantized: false,
|
||||
});
|
||||
|
||||
const reader = new SimpleDirectoryReader();
|
||||
const documents = await reader.loadData("./data");
|
||||
|
||||
const index = await VectorStoreIndex.fromDocuments(documents);
|
||||
|
||||
// You will want a persistent vector store! See https://ts.llamaindex.ai/docs/llamaindex/tutorials/agents/7_qdrant
|
||||
|
||||
const retriever = await index.asRetriever();
|
||||
|
||||
retriever.similarityTopK = 10;
|
||||
|
||||
const queryTool = index.queryTool({
|
||||
metadata: {
|
||||
name: "san_francisco_budget_tool",
|
||||
description: `This tool can answer detailed questions about the individual components of the budget of San Francisco in 2023-2024.`,
|
||||
},
|
||||
retriever: retriever,
|
||||
})
|
||||
|
||||
////////// create the origina number-summing tool
|
||||
|
||||
const sumNumbers = ({ a, b }) => {
|
||||
return `${a + b}`;
|
||||
};
|
||||
|
||||
const addTool = tool({
|
||||
name: "sumNumbers",
|
||||
description: "Use this function to sum two numbers",
|
||||
parameters: z.object({
|
||||
a: z.number({
|
||||
description: "First number to sum",
|
||||
}),
|
||||
b: z.number({
|
||||
description: "Second number to sum",
|
||||
}),
|
||||
}),
|
||||
execute: sumNumbers,
|
||||
});
|
||||
|
||||
////////// create the agent with both tools
|
||||
|
||||
const tools = [addTool, queryTool];
|
||||
const myAgent = agent({ tools });
|
||||
|
||||
////////// define a workflow (optional for such a simple example!)
|
||||
|
||||
const startEvent = workflowEvent<string>();
|
||||
const stopEvent = workflowEvent<string>();
|
||||
|
||||
const workflow = createWorkflow();
|
||||
|
||||
// handle the start event
|
||||
workflow.handle([startEvent], async (start) => {
|
||||
console.log(`Started the workflow with question: ${start.data}`);
|
||||
|
||||
const response = await myAgent.run(start.data);
|
||||
return stopEvent.with(response.data.result);
|
||||
});
|
||||
|
||||
////////// run the workflow
|
||||
|
||||
// Create a workflow context and send the initial event
|
||||
const { stream, sendEvent } = workflow.createContext();
|
||||
sendEvent(startEvent.with("What is the total budget of San Francisco in 2023-2024?"));
|
||||
|
||||
// Process the stream to get the result
|
||||
const result = await pipeline(stream, async function (source) {
|
||||
for await (const event of source) {
|
||||
if (stopEvent.include(event)) {
|
||||
return `Result: ${event.data}`;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log(result)
|
||||
@@ -7,15 +7,9 @@ import { pipeline } from "node:stream/promises";
|
||||
////////// define the workflow
|
||||
|
||||
const startEvent = workflowEvent<string>();
|
||||
const branchAEvent = workflowEvent<string>({
|
||||
type: "branchA"
|
||||
});
|
||||
const branchBEvent = workflowEvent<string>({
|
||||
type: "branchB"
|
||||
});
|
||||
const branchCEvent = workflowEvent<string>({
|
||||
type: "branchC"
|
||||
});
|
||||
const branchAEvent = workflowEvent<string>();
|
||||
const branchBEvent = workflowEvent<string>();
|
||||
const branchCEvent = workflowEvent<string>();
|
||||
const branchCompleteEvent = workflowEvent<string>();
|
||||
const allCompleteEvent = workflowEvent<string>();
|
||||
const stopEvent = workflowEvent<string>();
|
||||
@@ -42,7 +36,7 @@ workflow.handle([startEvent], async (start) => {
|
||||
);
|
||||
|
||||
console.log(`All branches completed`);
|
||||
console.log(results)
|
||||
console.log(results[0].data)
|
||||
return allCompleteEvent.with(results.join(", "));
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
import { config } from 'dotenv';
|
||||
config({ path: '.env.local' });
|
||||
|
||||
import { createWorkflow, workflowEvent, getContext } from "@llama-flow/core";
|
||||
import { until } from "@llama-flow/core/stream/until";
|
||||
import { collect } from "@llama-flow/core/stream/consumer";
|
||||
import { filter } from "@llama-flow/core/stream/filter";
|
||||
import { pipeline } from "node:stream/promises";
|
||||
import { Anthropic } from "@llamaindex/anthropic";
|
||||
|
||||
////////// define the workflow
|
||||
|
||||
const startEvent = workflowEvent<string>();
|
||||
const subquestionEvent = workflowEvent<string>();
|
||||
const questionAnsweredEvent = workflowEvent<string>();
|
||||
const synthesizeEvent = workflowEvent<string>();
|
||||
const stopEvent = workflowEvent<string>();
|
||||
|
||||
const workflow = createWorkflow();
|
||||
|
||||
// initialize the LLM
|
||||
const llm = new Anthropic({
|
||||
apiKey: process.env.ANTHROPIC_API_KEY,
|
||||
});
|
||||
|
||||
// handle the start event
|
||||
workflow.handle([startEvent], async (start) => {
|
||||
|
||||
// take a complicated question and split it up
|
||||
let prompt = `We have been ask a complicated question: <question>${start.data}</question>.
|
||||
Split it up into a few different questions that are easier to answer.
|
||||
Return the questions with one question per line.
|
||||
Do not include any other text, preamble or explanation in your response.
|
||||
`
|
||||
let result = await llm.complete({prompt:prompt})
|
||||
|
||||
// split up the result into an array of questions
|
||||
let questions = result.text.split("\n").map(q => q.trim()).filter(q => q !== "");
|
||||
console.log(`Questions: ${questions}`);
|
||||
|
||||
// emit the questions
|
||||
const { sendEvent, stream } = getContext();
|
||||
for (let question of questions) {
|
||||
sendEvent(subquestionEvent.with(question));
|
||||
}
|
||||
|
||||
// get all the answers to the questions
|
||||
let condition = 0;
|
||||
const results = await collect(
|
||||
until(
|
||||
filter(stream, (ev) => questionAnsweredEvent.include(ev)),
|
||||
() => {
|
||||
condition++;
|
||||
return condition === questions.length;
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
// synthesize the answers into a final answer
|
||||
let answers = results.map(r => r.data)
|
||||
console.log(answers)
|
||||
return synthesizeEvent.with({
|
||||
answers: answers.join("\n"),
|
||||
question: start.data
|
||||
});
|
||||
});
|
||||
|
||||
// handle each sub-question
|
||||
workflow.handle([subquestionEvent], async (subquestion) => {
|
||||
console.log(`Answering sub-question: ${subquestion.data}`);
|
||||
|
||||
let prompt = `Answer the question: <question>${subquestion.data}</question>.
|
||||
Return the answer as a short answer.
|
||||
`
|
||||
let result = await llm.complete({prompt:prompt})
|
||||
console.log(`Answer: ${result.text}`);
|
||||
return questionAnsweredEvent.with(result.text)
|
||||
});
|
||||
|
||||
// handle the collected results
|
||||
workflow.handle([synthesizeEvent], async (synthesize) => {
|
||||
|
||||
let prompt = `You were given the complicated question ${synthesize.data.question}.
|
||||
We split it into multiple simpler questions.
|
||||
The answers to the questions are: <answers>${synthesize.data.answers}</answers>.`
|
||||
console.log(`Synthesizing answer: ${prompt}`);
|
||||
let result = await llm.complete({prompt:prompt})
|
||||
return stopEvent.with(result.text);
|
||||
});
|
||||
|
||||
////////// run the workflow
|
||||
|
||||
// Create a workflow context and send the initial event
|
||||
const { stream, sendEvent } = workflow.createContext();
|
||||
sendEvent(startEvent.with("How has US tariff policy changed over the lifetime of the United States? Go back as far as you can."));
|
||||
|
||||
// Process the stream to get the result
|
||||
const result = await pipeline(stream, async function (source) {
|
||||
for await (const event of source) {
|
||||
if (stopEvent.include(event)) {
|
||||
return `Result: ${event.data}`;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log(result)
|
||||
@@ -1,36 +0,0 @@
|
||||
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, run the development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
# or
|
||||
pnpm dev
|
||||
# or
|
||||
bun dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||
|
||||
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
||||
|
||||
## Learn More
|
||||
|
||||
To learn more about Next.js, take a look at the following resources:
|
||||
|
||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||
|
||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
||||
|
||||
## Deploy on Vercel
|
||||
|
||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||
|
||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
||||
@@ -1,7 +1,4 @@
|
||||
import { createWorkflow, workflowEvent, getContext } from "@llama-flow/core";
|
||||
import { until } from "@llama-flow/core/stream/until";
|
||||
import { collect } from "@llama-flow/core/stream/consumer";
|
||||
import { filter } from "@llama-flow/core/stream/filter";
|
||||
import { pipeline } from "node:stream/promises";
|
||||
|
||||
////////// define the workflow
|
||||
@@ -0,0 +1,13 @@
|
||||
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, run the development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
This is a completely vanilla Next.js app. It's just a simple page that displays a list of events from a workflow.
|
||||
|
Before Width: | Height: | Size: 391 B After Width: | Height: | Size: 391 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 128 B After Width: | Height: | Size: 128 B |
|
Before Width: | Height: | Size: 385 B After Width: | Height: | Size: 385 B |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
@@ -1,36 +0,0 @@
|
||||
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, run the development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
# or
|
||||
pnpm dev
|
||||
# or
|
||||
bun dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||
|
||||
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
||||
|
||||
## Learn More
|
||||
|
||||
To learn more about Next.js, take a look at the following resources:
|
||||
|
||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||
|
||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
||||
|
||||
## Deploy on Vercel
|
||||
|
||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||
|
||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
||||
@@ -0,0 +1,23 @@
|
||||
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
||||
|
||||
## Getting Started
|
||||
|
||||
Install dependencies:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
Set an ANTHROPIC_API_KEY environment variable or put it in `.env.local`:
|
||||
|
||||
```bash
|
||||
export ANTHROPIC_API_KEY=<your-anthropic-api-key>
|
||||
```
|
||||
|
||||
Then run the development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
Before Width: | Height: | Size: 391 B After Width: | Height: | Size: 391 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 128 B After Width: | Height: | Size: 128 B |
|
Before Width: | Height: | Size: 385 B After Width: | Height: | Size: 385 B |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
@@ -0,0 +1 @@
|
||||
See 8_server/src/api/run-workflow/route.ts
|
||||
@@ -2,7 +2,12 @@
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@llama-flow/core": "^0.3.4",
|
||||
"@llamaindex/anthropic": "^0.3.3",
|
||||
"@llamaindex/huggingface": "^0.1.6",
|
||||
"@llamaindex/readers": "^3.0.2",
|
||||
"dotenv": "^16.5.0",
|
||||
"llamaindex": "^0.10.2",
|
||||
"tsx": "^4.19.3"
|
||||
"tsx": "^4.19.3",
|
||||
"zod": "^3.24.3"
|
||||
}
|
||||
}
|
||||
|
||||