This is the Typescript version of promptflow. join us to make prompt flow better by participating discussions, opening issues, submitting PRs.
Prompt flow is a suite of development tools designed to streamline the end-to-end development cycle of LLM-based AI applications, from ideation, prototyping, testing, evaluation to production deployment and monitoring. It makes prompt engineering much easier and enables you to build LLM apps with production quality.
With prompt flow, you will be able to:
- Create and iteratively develop flow
- Create executable flows that link LLMs, prompts, JavaScript code and other together.
- Debug and iterate your flows, especially the interaction with LLMs with ease.
- Evaluate flow quality and performance
- Evaluate your flow's quality and performance with larger datasets.
- Streamlined development cycle for production
- Deploy your flow to the serving platform you choose or integrate into your app's code base easily.
Feature | promptflowx | promptflow |
---|---|---|
Programming Approach | TypeScript | Python Code |
IDE | ChatDev | VS Code |
WorkFlow | ✅ | ✅ |
Supported Context | ✅ | ❌ |
One-click Deployment | ✅ | ❌ |
To get started quickly, you can use a pre-built development environment. Click the button below to edit your promptflowx in the Extension, and then continue the readme!
more detail: https://github.com/10cl/chatdev?tab=readme-ov-file#-installation
If you want to get started in your local environment, first install the packages:
Ensure you have a node
environment.
npm install promptflowx
Create a chatbot with prompt flow
creates folder named my_chatbot
and initiate a prompt flow(flow.dag.yaml
) from a chat template like:
desc: "ChatBot Template"
outputs:
reference: ${ChatBot_Template}
nodes:
- name: ChatBot_Template
source:
code: "{intro}, we are chatting. I say to you: {prompt}. what you might say?"
inputs:
prompt: ${inputs.input_text}
intro: "I want you to play a text-based adventure game. I play a character in this text-based adventure game."
Setup a connection for your LLM API
For LLM request, establish a connection by your define, each node will request the api, you can change the node Context or other things here:
export async function nodeRequest(node: PromptFlowNode, prompt: string): Promise<string> {
try {
console.log("\n>>>>>>>>>>> Prompt START >>>>>>>>>>>>>>>>\n" + prompt + "\n>>>>>>>>>>> Prompt END >>>>>>>>>>>>>>>>\n");
const response = await axios.get('https://api.example.com/data');
return response.data.data;
} catch (error) {
// Handle errors that occur during fetching
console.error('Error fetching data from LLM API:', error);
throw error; // You can choose to throw the error or return a default value
}
}
Chat with your flow
In the my_chatbot
folder, there's a flow.dag.yaml
file that outlines the flow, including inputs/outputs, nodes, connection, and the LLM model, etc
Interact with your chatbot by execute the code:
const yaml = fs.readFileSync(path.join(__dirname, "flow.dag.yaml"), "utf8");
const context = {
/* for defined your own api*/
promptflowx: {
libs: await promptflowx.buildLib(yaml, __dirname),
request: nodeRequest,
}
} as Context
await promptflowx.execute(context, yaml, 'Hello.');
Next Step! Continue with the Tutorial 👇 section to delve deeper into prompt flow.
Prompt flow is a tool designed to build high quality LLM apps, the development process in prompt flow follows these steps: develop a flow, improve the flow quality, deploy the flow to production.
We also offer a Browser extension (a flow designer) for an interactive flow development experience with UI.
You can install it from the chrome store.
Each node will as the Global scope
within the flow operates in JavaScript.
for example, in ChatDev, we set window
as the Context scope.
await promptflowx.execute(window/*Context*/, yaml, 'Hello.'/*prompt*/);
promptflowx template is a string that contains any number of template tags. Tags are indicated by the double mustaches that surround them. {{person}}
is a tag, as is {{person}}
. In both examples we refer to person
as the tag's key. There are several types of tags available in promptflowx, described below.
The most basic tag type is a simple variable. A {{name}}
tag renders the value of the name
key in the current context. If there is no such key, nothing is rendered.
All variables are HTML-escaped by default. If you want to render unescaped HTML, use the triple mustache: {{{name}}}
. You can also use &
to unescape a variable.
View:
{
"name": "Chris",
"company": "<b>GitHub</b>"
}
Template:
* {{name}}
* {{age}}
* {{company}}
* {{{company}}}
* {{&company}}
{{=<% %>=}}
* {{company}}
<%={{ }}=%>
Output:
* Chris
*
* <b>GitHub</b>
* <b>GitHub</b>
* <b>GitHub</b>
* {{company}}
JavaScript's dot notation may be used to access keys that are properties of objects in a view.
View:
{
"name": {
"first": "Michael",
"last": "Jackson"
},
"age": "RIP"
}
Template:
* {{name.first}} {{name.last}}
* {{age}}
Output:
* Michael Jackson
* RIP
Sections render blocks of text zero or more times, depending on the value of the key in the current context.
A section begins with a pound and ends with a slash. That is, {{person}}
begins a person
section, while {{/person}}
ends it. The text between the two tags is referred to as that section's "block".
The behavior of the section is determined by the value of the key.
If the person
key does not exist, or exists and has a value of null
, undefined
, false
, 0
, or NaN
, or is an empty string or an empty list, the block will not be rendered.
View:
{
"person": false
}
Template:
Shown.
{{person}}
Never shown!
{{/person}}
Output:
Shown.
If the person
key exists and is not null
, undefined
, or false
, and is not an empty list the block will be rendered one or more times.
When the value is a list, the block is rendered once for each item in the list. The context of the block is set to the current item in the list for each iteration. In this way we can loop over collections.
View:
{
"stooges": [
{ "name": "Moe" },
{ "name": "Larry" },
{ "name": "Curly" }
]
}
Template:
{{stooges}}
<b>{{name}}</b>
{{/stooges}}
Output:
<b>Moe</b>
<b>Larry</b>
<b>Curly</b>
When looping over an array of strings, a .
can be used to refer to the current item in the list.
View:
{
"musketeers": ["Athos", "Aramis", "Porthos", "D'Artagnan"]
}
Template:
{{musketeers}}
* {{.}}
{{/musketeers}}
Output:
* Athos
* Aramis
* Porthos
* D'Artagnan
If the value of a section variable is a function, it will be called in the context of the current item in the list on each iteration.
View:
{
"beatles": [
{ "firstName": "John", "lastName": "Lennon" },
{ "firstName": "Paul", "lastName": "McCartney" },
{ "firstName": "George", "lastName": "Harrison" },
{ "firstName": "Ringo", "lastName": "Starr" }
],
"name": function () {
return this.firstName + " " + this.lastName;
}
}
Template:
{{beatles}}
* {{name}}
{{/beatles}}
Output:
* John Lennon
* Paul McCartney
* George Harrison
* Ringo Starr
If the value of a section key is a function, it is called with the section's literal block of text, un-rendered, as its first argument. The second argument is a special rendering function that uses the current view as its view argument. It is called in the context of the current view object.
View:
{
"name": "Tater",
"bold": function () {
return function (text, render) {
return "<b>" + render(text) + "</b>";
}
}
}
Template:
{{bold}}Hi {{name}}.{{/bold}}
Output:
<b>Hi Tater.</b>
An inverted section opens with {{^section}}
instead of {{section}}
. The block of an inverted section is rendered only if the value of that section's tag is null
, undefined
, false
, falsy or an empty list.
View:
{
"repos": []
}
Template:
{{repos}}<b>{{name}}</b>{{/repos}}
{{^repos}}No repos :({{/repos}}
Output:
No repos :(
Comments begin with a bang and are ignored. The following template:
<h1>Today{{! ignore me }}.</h1>
Will render as follows:
<h1>Today.</h1>
Comments may contain newlines.
If you would like to contribute to this project, follow these steps:
- Fork the repository.
- Create your feature branch:
git checkout -b my-new-feature
- Commit your changes:
git commit -am 'Add some feature'
- Push to the branch:
git push origin my-new-feature
- Submit a pull request 😄
promptflowx is authored and maintained by 10cl and released under the MIT License. Special thanks to all the contributors (list) who have helped improve this