AI Engineer Summit 2023
Building Reactive AI Apps
Read the talk
Building Reactive AI Apps with AI.JSX
Compose prompts, tools, retrieval, and streaming output as a TypeScript component tree, then follow that application model into an embedded chat interface and a voice ordering demo.
From a talk by Matt Welsh
Before you start: Familiarity with TypeScript, JSX, and basic LLM prompts will help you follow the component examples.
The application is more than an LLM call
How do you turn a language model into a high-quality application without making every developer assemble the surrounding infrastructure? A useful product needs more than a prompt: vector databases, context-window management, retrieval-augmented generation, and tools all become part of the job. Matt Welsh introduces Fixie’s open-source AI.JSX framework to make those pieces easier to compose.
The deliberately theatrical reveal is angle brackets: JSX, used to express AI applications in TypeScript. The intended audience is frontend and full-stack developers—the people building the interfaces through which users experience AI. Welsh argues that this community lacks good tools and, by his account, contains more JavaScript developers than the Python community. The goal is to bring AI application development into their existing programming environment.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
A completion expressed as components
The first application asks for a Shakespearean sonnet about large language models. ChatCompletion represents the model call; its UserMessage child supplies the prompt. The essential JSX expression is small:
tsx
const sonnet = (
<ChatCompletion>
<UserMessage>
Write a Shakespearean sonnet about large language models.
</UserMessage>
</ChatCompletion>
);
Rendering this component tree produces the model’s response. The sonnet is the Hello World example: a single prompt inside a single completion.
React provides a useful analogy for this programming model, but AI.JSX is a separate framework with React integration. The component names and behavior here follow the presentation’s API rather than a claim about current package compatibility. Welsh’s tour expands from the completion into several capabilities:
- Model providers: support for Anthropic and OpenAI.
- React integration: AI functionality that can be incorporated into a full-stack application.
- Retrieval: built-in RAG support, multiple vector databases, and the option to connect your own database.
- Tools: calls to custom functions and external APIs.
- Generated interfaces: UI components produced through the application’s component representation.
- Extensibility: custom behavior written in TypeScript.
The UI capability follows from working with a structured component representation: an application can produce interface components as well as text.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
From a prompt to an asynchronous tree
A reusable MakeSetting component asks the model to write a one-paragraph description of a story setting. It accepts children and inserts them into that request. Those children can be a literal string describing the desired setting, or another JSX subtree whose rendered result becomes part of the prompt. Calling MakeSetting therefore means instantiating the component with the setting you want as its child. The component owns the instruction; its caller supplies the material.
That alone could look like ordinary function composition with extra punctuation. The substantive difference is the rendering tree: AI.JSX renders nodes asynchronously, in parallel, and as streams. Where React renders an interface toward the browser DOM, this tree assembles inputs and produces LLM output. Nesting expresses dependencies between pieces of generation, rather than merely formatting a prompt string.
The story example makes the execution model concrete. MakeStory contains separate children for the character, setting, and plot. In the story example, three child LLM calls run and stream concurrently. Their tokens flow back into the parent’s rendering process, and MakeStory streams the resulting story outward. This is the concurrency described for the component tree; it does not specify a provider-level guarantee about when a parent model request can begin consuming an unfinished prompt. The useful abstraction is that independent branches can generate their material concurrently while the application presents streaming output.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Use a wrapper to transform generated output
The next composition puts one generation around another. KidSafe supplies a system message asking the model to rewrite text so it is safe for children. Its children’s rendered content becomes the user message for that rewrite. Wrapping an existing component in KidSafe therefore applies the transformation without changing the wrapped component’s own prompt or implementation.
The separation is useful: the inner component generates content, and the outer component requests a transformation of that content. Here, “kid-safe” describes the requested rewrite, not a verified safety guarantee. The mechanism is another prompted model call over child output.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Make an external API available during rendering
The GitHub example extends the tree beyond text generation. A record defines the tools available to the LLM, with one entry for calling GitHub’s GraphQL API. That tool pairs an English description with a JavaScript function. The description explains what the tool does; the function performs the request using fetch. Welsh omits the function body from the presentation, so the example establishes the tool boundary rather than showing the complete HTTP implementation.
The application then instantiates UseTools and passes it the tool set. Components that need those tools during rendering can invoke them. Defining the operation and making it available to the application are separate steps: the record describes the callable capability, while UseTools supplies access within the rendering process.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Put retrieved context inside the prompt
Retrieval-augmented generation uses the same composition mechanism. A ChatCompletion contains a SystemMessage and a UserMessage. The system message tells the model to use supplied information when answering the user, and a nested DocsQA component supplies that information. Welsh describes the displayed RAG composition as roughly ten lines of code. That compactness applies to the composition, not to the work of preparing the corpus.
The data path is explicit:
- Prepare the corpus. Documents have already been crawled, indexed, and placed in a vector database.
- Retrieve for the query.
DocsQAreceives the corpus configuration and the user’s query, then returns relevant chunks. - Assemble the completion. Those chunks appear inside the
SystemMessage, beside the instruction to use them. - Ask the question. The
UserMessagecontains the query again, and the enclosing completion generates the answer.
The query serves two purposes: selecting context and asking the final question. Putting both uses in the component tree makes their relationship visible. Welsh argues that this representation is easier to understand, modify, and integrate than coordinating many separate library calls.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Embed the interface and manage the backend
Once the AI application is built, FloatingFixieEmbed provides the transition into a React interface. Instantiating it supplies a chat window with session management, Markdown rendering, and custom UI support. Welsh’s one-line embedding description refers to instantiating this supplied interface, not implementing the application behind it.
The framework and the hosted service have different responsibilities. AI.JSX expresses the application; the Fixie platform presented here hosts, runs, deploys, and manages it. Its managed RAG pipeline covers document ingestion, chunking, embedding, the vector database, and document storage. It also manages conversational state so later user-agent exchanges retain context. Welsh describes the platform’s LLM interfaces as tuned for performance and low latency, without supplying benchmark results.
The platform offered two authoring paths: build through its no-code web interface, or write a custom AI.JSX application and embed it in a site. At presentation time, Welsh invited developers to sign up with a free starting option. Using the hosted service was optional: the open-source framework could also be used independently of Fixie.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Extend the application to spoken interaction
The final capability is bidirectional voice: a user speaks to the agent, and the agent speaks back. Responsiveness becomes especially visible in this interface because a pause after every turn interrupts the conversation. Welsh estimates a four-to-five-second response gap in the recent ChatGPT voice demos he had seen. That is his estimate of particular demos, not a measured comparison with Fixie or a claim about present-day ChatGPT.
The voice system is presented as grounded in the application’s documents and data. Welsh calls its performance state of the art, but demonstrates it through a recording rather than a latency benchmark. To avoid venue Wi-Fi problems, CTO Justin recorded the interaction the previous day; Welsh says it was unstaged, untrimmed, and not sped up.
Welsh points the audience to a demo address for trying it themselves, then sets up the scenario: a fictional restaurant called Dr. Donut. The customer is at the drive-through, and the AI plays the employee taking the order. This turns the voice interface into a specific application task with menu questions, quantities, and an eventual order recap.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Take the order, answer a question, and retain context
The agent opens with a restaurant greeting. The customer asks for two pumpkin spice iced donuts, and the agent confirms adding them to the order. Next, the customer asks for the best coffee. Instead of treating that as another order item, the agent recommends seasonal pumpkin spice coffee and the year-round caramel macchiato. The customer chooses two macchiatos, and the agent confirms adding two caramel macchiatos. The exchange moves from ordering to recommendation and back to ordering without requiring the customer to repeat the donuts.
The customer then asks what the agent thinks about large language models. Its response preserves the restaurant role: “Sir, this is a Dr. Donut.” The customer returns to the order, and the agent recaps two pumpkin spice iced donuts and two caramel macchiatos, states a total of $9.56, and directs the customer to the next window. These are spoken confirmations within the demonstration; no underlying payment or order transaction implementation is shown.
The demonstration brings the earlier pieces into a user-facing interaction: conversational context survives a recommendation and an off-topic question, and the agent produces a coherent final recap. Welsh closes by explaining that the full Fixie platform supplies the backend and that developers can build the same kind of application with Fixie and AI.JSX. The latency and quality work serves that practical outcome: an application that can carry a task through successive spoken turns.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Resources
From the talk
Source code and examples for composing LLM applications with JSX, including a sonnet-generating completion.
Further reading
- Welcome to AI.JSXDocumentation
An introduction to using JSX for AI applications and integrating the framework with React.
The original announcement of ChatGPT voice conversations, including transcription and speech-generation components.
Updates since the talk
The GPT-4o announcement reports average latency for the preceding GPT-3.5 and GPT-4 voice pipelines.
Read the complete timestamped transcript
- 0:00
[upbeat music] How's everybody doing this morning?
- 0:17
All right? Yeah? I can't see anybody past the first two rows, so I assume you're all there. Now, I know what you're all thinking. I look way better in person than that AI-generated headshot, right?
- 0:28
Well, we're, we're gonna work on that. We're gonna... You know, the AI models are not perfect yet, but we'll get there. I need the clicker. Did that... Oh, oh, it's up here.
- 0:36
Awesome. All right. Well, today I'm super excited to talk to you about what we've been working on at Fixie for a while, which is a open source framework for building what we call reactive AI applications called AI.jsx.
- 0:51
So let's get into it. First of all, what's the problem we're trying to solve? Well, I think most of us here know this already, but building and deploying high quality LLM apps is still super hard.
- 1:03
It's a lot of pieces you gotta worry about. You got your vector databases, your context window limits, your RAG stack, your tool sets, all that stuff. Now, most of us in this room enjoy solving those problems.
- 1:16
That's why we're here. But we think most developers probably would rather not have to solve these problems themselves, so we wanna do this for them.
- 1:26
So at Fixie, we are aiming to solve this problem by inventing the future of AI application development.
- 1:36
Today I'm going to be announcing something that I think everyone here will agree is the most revolutionary technology in the AI development landscape. It is going to change the way we all think about building AI powered applications.
- 1:52
It's going to blow you all away. And so ladies and gentlemen, may I introduce to you the future of AI application development. Imagine the 2001 theme playing. [singing]
- 2:08
Angle brackets. This is the future. [clapping] Yes. [upbeat music] There was supposed to be sound with that. That's all right. Okay. [laughs]
- 2:19
It was better with the sound. All right. So this is AI JSX, and I'm gonna talk about this a bit. Think about this as elegant LLM development for, uh, you know, a more civilized age in TypeScript.
- 2:32
Okay. So before I get into what AI JSX is, you might be wondering why TypeScript, right? Well, we believe that there are many front end and full stack devs that are just...
- 2:43
They don't have good tools for building AI powered applications today. There are some stuff, right?
- 2:49
But we also think that the AI devs, uh, the front end devs are the ones building the AI experiences of the future. But today they're kind of like that bear staring in the window, right?
- 3:00
They're saying, "Hey, we want a piece of the action. We want to get involved in AI development." But it's all the Python devs that are in the back end that are having all the fun here, right?
- 3:09
So why should the Python devs have all the fun? There's also a lot more JavaScript developers in the world than there are Python developers. So we think that helping this community that hasn't been well served so far makes a lot of sense.
- 3:23
So without AI JSX, this is what an AI engineer looks like today. I think I met that guy out in the hall yesterday. But with AI JSX, we can all be Hacker Man or Hacker Woman.
- 3:35
Yes. All right. [clapping] So get ready. I'm gonna rock you with this whole presentation on this. Okay. So let's just show a Hello World of AI JSX. It's a very simple example.
- 3:47
What we're doing here is defining a complete application
- 3:52
that uses a chat completion component. That's the foundation of anything that might call into an LLM, and we're providing it a user message prompt in the form of, you know, write a Shakespearean son- uh, sonnet about large language models.
- 4:08
You might get a result something like this. It's actually pretty good.
- 4:13
That's a Hello World though. That's very simple. But let's talk a little bit about what AI JSX is. Think about it like React, but for building LLM apps. Uh, my colleague, uh, at Fixie pointed out to me that we actually have a page on our documentation site that says that AI JSX is not React, but clearly that's
- 4:34
wrong because here I am telling you it is. Anyway. So AI JSX, it's built in TypeScript, which means you get all the safety and performance of JavaScript with the exciting adventure of fucking around with your dev tooling. [laughs]
- 4:49
Uh, any model, any provider, uh, we can support both Anthropic and OpenAI.
- 4:56
Uh, full React integration. This is great for building full stack applications where you just wanna drop your AI powered stuff into your React app.
- 5:06
AI JSX supports RAG out of the box, uses multiple vector DBs behind the, behind the scenes. You can plug in your own as well.
- 5:15
You can use it to invoke custom tools and APIs. So you can use AI JSX in situations where you want to invoke an external service or an API.
- 5:25
One of the cool features of AI JSX is the ability to have the AI generate UI components for you. Because the AI JSX program is operating on effectively the in...
- 5:37
the, the DOM, if you will, as React components, you can use it to generate UI components.
- 5:44
And of course, it's fully programmable and extensible, so you can basically build whatever you want.
- 5:49
I'm gonna give you a whirlwind tour of all this, show you what's, what's possible. Um,
- 5:55
basic idea is you build components just like you do in React. Here I'm defining a component called MakeSetting. Might c- define a setting for a story that we might wanna write.
- 6:05
And this component takes in its children elements as a parameter,
- 6:12
and we basically say, "Write a one-paragraph description of this setting," and put the children components right there. Those children components can be anything. They can be a string or they can be the result of a different tree of JSX nodes that have been rendered and placed in line in that prompt.
- 6:31
So to call it, all I need to do is say, take the MakeSetting component, instantiate it, and give it the prompt that I want.
- 6:40
Okay. It's pretty cool, very easy to use. But you might be saying to yourself, "Come on. This is basically writing Python code with different syntax." Right? This is... The angle brackets are a little bit overplayed here.
- 6:55
Um, but it's not just about syntax, right? JSX defines an entire tree of nodes that are rendered as a stream asynchronously and in parallel. So instead of rendering to the DOM like React does, we're re-rendering, uh, we're rendering effectively to the LLM, if you will.
- 7:16
Um, so this allows us to do extremely powerful forms of composition. So here's a simple example of writing a story where I have a MakeStory component with three child components.
- 7:28
One is defining the character, another is defining the setting, and a third is defining the plot.
- 7:35
When we render this application, all three of those components are going to run in parallel, and they're all streaming in parallel. There's three concurrent LLM calls going on, and they're streaming their tokens back to the MakeStory component in real time.
- 7:57
And so as this is being rendered, the, all the tokens are streaming through, the MakeStory component is then streaming its output out to the result of that render, which might result in a story that looks like this.
- 8:10
So far, I'm just showing you some basic things with text to give you some intuition around the ideas, but of course, you can take this a lot further.
- 8:18
Um, one thing you might say about this tree-based structure in AI.jsx is that it allows you to break free of your chains. Sorry, I know that was a groaner.
- 8:30
Okay. Sorry. Okay. So, [coughs] here's another example of what you might be able to do. Um, let's wrap one component in another in order to constrain the former, uh, the latter component's output.
- 8:43
So we're gonna define a KidSafe component. This component takes in a system message that says, "Rewrite the following text so it's safe for kids," and the child components of that component are placed into the user message of that prompt.
- 8:59
Then when we just wrap any component we want in a KidSafe component, it automatically will rewrite the output to be kid-safe, right? So very, very powerful composition.
- 9:12
Let me show you a quick example of how you use AI.jsx to call out to tools and third-party APIs. In this case, we're going to define a record, which is a set of tools that we want to give the LLM access to.
- 9:25
We're just gonna define one tool here. This is a tool that calls the GitHub GraphQL API.
- 9:32
And we're gonna give it an English description of the tool, and there's a JavaScript function there. I've taken out the code for the JavaScript function because that's not interesting for this talk, but that's just calling, using the fetch API to call the GraphQL endpoint at GitHub.
- 9:48
To use the tool in an application then, all I have to do is instantiate a UseTools component, give it that set of tools, and then anything that might need to use those tools as part of the rendering process can now invoke them.
- 10:03
And so I can build very powerful applications in this way.
- 10:09
This is RAG, retrieval-augmented generation, in something like ten lines of code. In AI.jsx, we have a ChatCompletion. There's two children of that, the SystemMessage and the UserMessage. The SystemMessage says, "Use the following information to answer the user's query," and it gets that information by using a DocsQA component.
- 10:31
The DocsQA component is configured with a corpus of documents that you've crawled and indexed and placed in a vector database.
- 10:39
You provide the user's query. The DocsQA component returns the chunks that are relevant to that query,
- 10:46
places them right there in the SystemMessage, and then the UserMessage contains the query again, and the final result is you effectively have retrieval-augmented generation.
- 10:59
I think this is a lot easier to understand. It's a lot easier to manipulate. It's a lot easier to integrate with other applications when expressed this way rather than have a whole lot of different, uh, libraries that you have to invoke.
- 11:13
And finally, when you're done building an AI.jsx application and you wanna place it into your website or your web app or your mobile app or whatever it is, you can just drop it right in as a React component, right?
- 11:26
So in this case, we're showing you use the FloatingFixieEmbed component that when you instantiate this, gives you a fully rendered UI for your AI.jsx application with a chat window, with session management, markdown, uh, rendering, custom UI, all the things that you might want out of such a thing in effectively one line of code.
- 11:54
I've been talking a lot about AI.jsx as an open source project. Of course, I'm standing in front of you as a founder of a startup, so we gotta make money somehow [laughs].
- 12:03
And so we're talking about the Fixie platform as a really effective way to take AI.jsx applications and host them and run them and manage them in the cloud.
- 12:13
So we make it really easy to build and deploy these things. The Fixie cloud service has a fully managed RAG pipeline that does document ingestion, chunking, embedding, vector database, document storage, and all of the things that you need there.
- 12:30
It fully manages the conversational state between the end user and the agent that you've built so that you can have full context as part of that interaction with the user.
- 12:42
We provide interfaces to all the popular LLMs, and those are really tuned for high performance and low latency so that we get really good performance out of this.
- 12:51
You can build your applications either in a no-code way completely in the web UI here, or you can use AI JSX to build a completely custom thing. And as I showed earlier, embedding it on your website is super easy.
- 13:06
So that's the Fixie platform. Um, right. So with that, you know, I'd encourage you all to try it out. Just go to Fixie.ai. You can sign up. Um, it's free to start out.
- 13:17
Uh, start building. AI JSX is open source. You can use that without using Fixie if you want. Um, so go check that out. I'd really, really love to get your feedback and hear more about what you wanna build and what kind of things you wanna do.
- 13:32
But one more thing. This is invoking, of course, Steve.
- 13:40
Another thing we built with AI JSX is the ability to support real-time voice interaction. That means bi-directional. You can speak to the agent, and it can speak back to you.
- 13:51
And we've done a ton of work to make the performance as just incredible, just amazing as possible. If you've seen the ChatGPT voice demos that they did, uh, last week or so, there's something like a four or five-second gap after you talk to it and it talks back to you.
- 14:07
I'm gonna show you a demo in a moment that I think will, uh, be fairly impressive.
- 14:14
So we get state-of-the-art performance, real-time bi-directional conversations, and of course, it's all grounded on your docs and your data. So I'm not foolish enough with the Wi-Fi that's here to do a live demo, so fortunately, our CTO, Justin, recorded a video of this.
- 14:31
But I want to assure you that nothing in this video is staged. Nothing has been trimmed out. Nothing has been sped up. This is real-time, you know, live video recording from yesterday.
- 14:42
And you can try it out yourself at voice.fixie.ai if you don't believe me. Just go try it on your own machine. Not now. [laughs]
- 14:49
Not here, please. Uh, but the idea of this demo is we have a fictional donut restaurant called Dr. Donut,
- 14:58
and you're at the drive-through. You drive up in your Tesla or whatever you're driving, roll down the window, and you're talking to the drive-through window at the Dr. Donut, and the AI is acting to take your order.
- 15:10
And so with that, I'm gonna see if this works. Hopefully, we have sound on the video, and let's take it away.
- 15:17
Welcome to Dr. Donut, home of the best donuts in town. How can I help you?
- 15:22
Yeah. Could I get two of the pumpkin spice iced donuts?
- 15:28
Sure. I've added two pumpkin spice iced donuts to your order. Can I assist you with anything else?
- 15:34
Uh, what's your best coffee?
- 15:40
Our pumpkin spice coffee is a popular choice this season, and our caramel macchiato is a favorite all year round. Which one would you prefer?
- 15:48
Yeah. Let's go with two of the macchiatos.
- 15:52
Great. I've added two caramel macchiatos to your order. Can I get you anything else?
- 15:59
Yeah. What are your thoughts on, uh, large language models?
- 16:04
Sir, this is a Dr. Donut.
- 16:08
Uh, okay. Just the donuts and the coffee then.
- 16:14
Sure. Your order is two pumpkin spice iced donuts and two caramel macchiatos. The total is $9.56. Please pull up to the next window.
- 16:25
And that was all... Like, you can go try it yourself. Um, we've done a ton of work to make the latency really low, to make the quality really high.
- 16:31
It's using the full Fixie platform as a back end. And of course, if you're building with Fixie and AI JSX, you can build the same thing for yourself, uh, donuts or not, right?
- 16:40
Okay. So that's basically all I have. I'd really love to get you all to check it out. We are, of course, hiring, and so there's our careers page. And, uh, please, uh, you know, don't forget to smash that like button.
- 16:53
Thank you very much. [upbeat music]