Adding agents, RAG

This commit is contained in:
Laurie Voss
2025-04-20 13:52:36 -07:00
parent a2e5f9419b
commit 8c183d61e6
45 changed files with 2843 additions and 87 deletions
+1
View File
@@ -1 +1,2 @@
node_modules
.env*
+74
View File
@@ -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)
+104
View File
@@ -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)
+4 -10
View File
@@ -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(", "));
});
+106
View File
@@ -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)
-36
View File
@@ -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.
-3
View File
@@ -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
+13
View File
@@ -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

-36
View File
@@ -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.
+23
View File
@@ -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

+1
View File
@@ -0,0 +1 @@
See 8_server/src/api/run-workflow/route.ts
Binary file not shown.
+2511 -1
View File
File diff suppressed because it is too large Load Diff
+6 -1
View File
@@ -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"
}
}