Skip to content

Commit 79891d6

Browse files
committed
fix: prompt improvements
1 parent 3b79ada commit 79891d6

File tree

236 files changed

+16813
-95
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

236 files changed

+16813
-95
lines changed

src/ax/dsp/prompt.ts

+27-26
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export class AxPromptTemplate {
3535
const inArgs = this.renderDescFields(this.sig.getInputFields())
3636
const outArgs = this.renderDescFields(this.sig.getOutputFields())
3737
const task = [
38-
`#Task\nGiven the fields ${inArgs}, produce the fields ${outArgs}.`,
38+
`You will be provided with the following fields: ${inArgs}. Your task is to generate two new fields: ${outArgs}.`,
3939
]
4040

4141
const fnNames = functions?.map((f) => {
@@ -45,40 +45,36 @@ export class AxPromptTemplate {
4545
return f.name
4646
})
4747

48-
const funcList = fnNames?.map((fname) => `'${fname}'`).join(', ')
48+
const funcList = fnNames?.map((fname) => `\`${fname}\``).join(', ')
4949

5050
if (funcList && funcList.length > 0) {
5151
task.push(
52-
`Use the following functions ${funcList} to complete the task. The functions must be used to resolve the output field values.`
52+
`Complete the task, using the following functions as needed: ${funcList}. Refer to the function descriptions for proper usage. The output field values may be generated by applying these functions if appropriate for the task.`
5353
)
5454
}
5555

5656
const desc = this.sig.getDescription()
5757
if (desc) {
58-
task.push(desc.endsWith('.') ? desc : desc + '.')
58+
task.push(capitalizeFirstLetter(desc.endsWith('.') ? desc : desc + '.'))
5959
}
6060

61-
task.push(
62-
'Ensure the output strictly follows a plain text format, `key: value` separated by a new line.'
63-
)
64-
6561
const inputFields = this.renderFields(this.sig.getInputFields())
62+
task.push(`## Input Fields\n${inputFields}`)
63+
6664
const outputFields = this.renderFields(this.sig.getOutputFields())
65+
task.push(`## Output Fields\n${outputFields}`)
6766

6867
task.push(
69-
[
70-
'\n',
71-
'## Input Fields',
72-
inputFields,
73-
'\n',
74-
'## Output Fields',
75-
outputFields,
76-
].join('\n')
68+
'Output must be in plain text, with each `key: value` pair on a new line. The format of each `value` should strictly adhere to the formatting instructions for its corresponding `key`, as defined earlier in this prompt.'
69+
)
70+
71+
task.push(
72+
'No additional text or formatting is permitted. The specific formatting rules for each key are provided above; ensure the corresponding values follow those rules precisely.'
7773
)
7874

7975
this.task = {
8076
type: 'text' as const,
81-
text: task.join(' '),
77+
text: task.join('\n\n'),
8278
}
8379
}
8480

@@ -95,7 +91,7 @@ export class AxPromptTemplate {
9591
): AxChatRequest['chatPrompt'] => {
9692
const renderedExamples = examples
9793
? [
98-
{ type: 'text' as const, text: 'Examples:\n' },
94+
{ type: 'text' as const, text: '\n## Examples:\n' },
9995
...this.renderExamples(examples),
10096
]
10197
: []
@@ -400,22 +396,20 @@ export class AxPromptTemplate {
400396
list.map((v) => `\`${v.title}\``).join(', ')
401397

402398
private renderFields = (fields: readonly AxField[]) => {
403-
// Header
404-
const header = 'Field Name | Field Type | Required/Optional | Description'
405-
const separator = '|'
406-
407399
// Transform each field into table row
408400
const rows = fields.map((field) => {
409401
const name = field.title
410402
const type = field.type?.name ? toFieldType(field.type) : 'string'
411403
const required = field.isOptional ? 'optional' : 'required'
412-
const description = field.description ?? ''
404+
const description = field.description
405+
? `: ${capitalizeFirstLetter(field.description)}`
406+
: ''
413407

414-
return [name, type, required, description].join(` ${separator} `).trim()
408+
// Eg. - `Conversation` (string, optional): The conversation context.
409+
return `- \`${name}\` (${type}, ${required})${description}`.trim()
415410
})
416411

417-
// Combine header and rows
418-
return [header, ...rows].join('\n')
412+
return rows.join('\n')
419413
}
420414
}
421415

@@ -519,3 +513,10 @@ const isEmptyValue = (
519513
}
520514
return false
521515
}
516+
517+
function capitalizeFirstLetter(str: string) {
518+
if (str.length === 0) {
519+
return ''
520+
}
521+
return `${str.charAt(0).toUpperCase()}${str.slice(1)}`
522+
}

src/ax/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"fix": "run-s fix:*",
2626
"fix:lint": "eslint --fix",
2727
"fix:format": "prettier --write \"**/*.{ts,json,md}\"",
28-
"doc:build:markdown": "typedoc",
28+
"doc:build:markdown": "typedoc --readme none",
2929
"coverage": "c8 ava",
3030
"prepare": "husky install",
3131
"tsx": "node --env-file=.env --import=tsx",

src/docs/README.md

-54
This file was deleted.

src/docs/src/content/docs/01-start/01-about.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Building intelligent agents is a breeze with the Ax framework, inspired by the p
77

88
Large language models (LLMs) are becoming really powerful and have reached a point where they can work as the backend for your entire product. However, there's still a lot of complexity to manage from using the correct prompts, models, streaming, function calls, error correction, and much more. We aim help manage this complexity via this easy-to-use library that can work with all state-of-the-art LLMs. Additionally, we are using the latest research to add new capabilities like DSPy to the library.
99

10-
## Install
10+
### Install
1111

1212
With NPM
1313

@@ -37,7 +37,7 @@ yarn add @ax-llm/ax
3737
- Lite weight, zero-dependencies
3838

3939

40-
## Quick Start
40+
### Quick Start
4141

4242
1. Pick an AI to work with
4343

@@ -69,6 +69,6 @@ const res = await ai.chat([
6969
]);
7070
```
7171

72-
## Reach out
72+
### Reach out
7373

7474
https://twitter.com/dosco

src/docs/src/content/docs/01-start/02-signatures.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Efficient type-safe prompts are auto-generated from a simple signature. A prompt
99

1010
You can have multiple input and output fields, and each field can be of the types `string``number``boolean``date`, `datetime`, `class "class1, class2"`, `JSON`, or an array of any of these, e.g., `string[]`. When a type is not defined, it defaults to `string`. The underlying AI is encouraged to generate the correct JSON when the `JSON` type is used.
1111

12-
## Output Field Types
12+
### Output Field Types
1313

1414
| Type | Description | Usage | Example Output |
1515
|---------------------------|-----------------------------------|----------------------------|----------------------------------------------------|

src/docs/src/content/docs/01-start/04-quick.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ description: A more detailed guide to using Ax
44
---
55

66

7-
## Pick an LLM
7+
### Pick an LLM
88

99
Ax is a zero-dependency framework. Every LLM API integration we build is solid, works well with Ax, and supports all required features, such as function calling, multi-modal, JSON, streaming, etc.
1010

@@ -19,7 +19,7 @@ const ai = new AxAI({
1919

2020
The LLMs are pre-configured with sensible defaults such as models and other conifgurations such as topK, temperature, etc
2121

22-
## Prompting
22+
### Prompting
2323

2424
Prompts are usually stressful and complex. You never know what the right prompt is, and blobs of text in your code are hard to deal with. We fix this by adopting the prompt signatures from the popular Stanford DSPy paper.
2525

@@ -46,7 +46,7 @@ question:string, animalImage:image -> answer:string
4646
question:string, answers:string[] -> rating:number[]
4747
```
4848

49-
## Putting it all together
49+
### Putting it all together
5050

5151
Use the above AI and a prompt to build an LLM-powered program to summarize the text.
5252

@@ -80,7 +80,7 @@ tsx example.ts
8080
}
8181
```
8282

83-
## Build your first agent
83+
### Build your first agent
8484

8585
Ax makes it really simple to build agents. An agent requires a `name`, `description` and `signature`. it can optionally use `functions` and other `agents`.
8686

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
---
2+
title: RAG & Vector DBs
3+
description: A guide on working with vector databases and Retrieval Augmented Generation (RAG) in ax.
4+
---
5+
6+
Vector databases are critical to building LLM workflows. We have clean abstractions over popular vector databases and our own quick in-memory vector database.
7+
8+
| Provider | Tested |
9+
| ---------- | ------- |
10+
| In Memory | 🟢 100% |
11+
| Weaviate | 🟢 100% |
12+
| Cloudflare | 🟡 50% |
13+
| Pinecone | 🟡 50% |
14+
15+
```typescript
16+
// Create embeddings from text using an LLM
17+
const ret = await this.ai.embed({ texts: 'hello world' });
18+
19+
// Create an in memory vector db
20+
const db = new axDB('memory');
21+
22+
// Insert into vector db
23+
await this.db.upsert({
24+
id: 'abc',
25+
table: 'products',
26+
values: ret.embeddings[0]
27+
});
28+
29+
// Query for similar entries using embeddings
30+
const matches = await this.db.query({
31+
table: 'products',
32+
values: embeddings[0]
33+
});
34+
```
35+
36+
Alternatively you can use the `AxDBManager` which handles smart chunking, embedding and querying everything
37+
for you, it makes things almost too easy.
38+
39+
```typescript
40+
const manager = new AxDBManager({ ai, db });
41+
await manager.insert(text);
42+
43+
const matches = await manager.query(
44+
'John von Neumann on human intelligence and singularity.'
45+
);
46+
console.log(matches);
47+
```
48+
49+
### RAG Documents
50+
51+
Using documents like PDF, DOCX, PPT, XLS, etc., with LLMs is a huge pain. We make it easy with Apache Tika, an open-source document processing engine.
52+
53+
Launch Apache Tika
54+
55+
```shell
56+
docker run -p 9998:9998 apache/tika
57+
```
58+
59+
Convert documents to text and embed them for retrieval using the `AxDBManager`, which also supports a reranker and query rewriter. Two default implementations, `AxDefaultResultReranker` and `AxDefaultQueryRewriter`, are available.
60+
61+
```typescript
62+
const tika = new AxApacheTika();
63+
const text = await tika.convert('/path/to/document.pdf');
64+
65+
const manager = new AxDBManager({ ai, db });
66+
await manager.insert(text);
67+
68+
const matches = await manager.query('Find some text');
69+
console.log(matches);
70+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
title: Multi-modal DSPy
3+
description: Using multi-modal inputs like images and audio with DSPy pipelines and LLMs
4+
---
5+
6+
When using models like `GPT-4o` and `Gemini` that support multi-modal prompts, we support using image fields, and this works with the whole DSP pipeline.
7+
8+
```typescript
9+
const image = fs
10+
.readFileSync('./src/examples/assets/kitten.jpeg')
11+
.toString('base64');
12+
13+
const gen = new AxChainOfThought(`question, animalImage:image -> answer`);
14+
15+
const res = await gen.forward(ai, {
16+
question: 'What family does this animal belong to?',
17+
animalImage: { mimeType: 'image/jpeg', data: image }
18+
});
19+
```
20+
21+
When using models like `gpt-4o-audio-preview` that support multi-modal prompts with audio support, we support using audio fields, and this works with the whole DSP pipeline.
22+
23+
```typescript
24+
const audio = fs
25+
.readFileSync('./src/examples/assets/comment.wav')
26+
.toString('base64');
27+
28+
const gen = new AxGen(`question, commentAudio:audio -> answer`);
29+
30+
const res = await gen.forward(ai, {
31+
question: 'What family does this animal belong to?',
32+
commentAudio: { format: 'wav', data: audio }
33+
});
34+
```

0 commit comments

Comments
 (0)