Welcome to part two of our series about using Temporal to improve the reliability of applications built around Large Language Models (LLM) like the one that powers ChatGPT. Part one explained how to build a Temporal Workflow to process a series of documents and make them accessible to your LLM. This post will show how to develop a Temporal Workflow to find documents relevant to a user’s query and supply them as context to a prompt sent to the LLM using Context Injection. You’ll also learn how Temporal's abstraction will make your application more reliable and make it easier for you to extend it with new features.
Subscribe
Get our best content on how to build better apps.
Subscribe
Get our best content on how to build better apps.
Got product development questions?
Join us on
Discord
Your Next AI Startup Should Be Built on Temporal [Part 1: Document Processing]
Taking advantage of the burgeoning AI trend, many of today's applications are built around AI tools like ChatGPT and other Large Language Models (LLMs). AI-optimized applications often have complex software pipelines for collecting and processing data with the LLM. Temporal provides an abstraction that can significantly simplify data pipelines, making them more reliable and accessible to develop. In this post, you’ll discover why you should use Temporal to build applications around LLMs.
Kevin Phillips
Director of Backend Development
Leveraging Temporal Cloud in FedRAMP Compliant Organizations
Implementing Temporal Cloud can present challenges for organizations offering cloud services that may be used by the federal government. One of the largest buyers of cloud technology, the federal government requires cloud services to be certified by the Federal Risk and Authorization Management Program (FedRAMP®). Each Cloud Service Offering (CSO) must have an independent authorization.
Kevin Phillips
Director of Backend Development
Temporal Is a Swiss Army Knife For Your Distributed Systems
Bitovi’s Backend Consulting team has had the pleasure of working with Temporal for several different use cases over the last few years. Temporal has greatly simplified complex distributed systems and helped our team focus more on achieving business goals and to spend less time handling errors, among many other things. Temporal isn’t a silver bullet, but it is helpful in a variety of different situations.
Kevin Phillips
Director of Backend Development
Node.js Consulting 101: Breaking Down Technical Requirements
A skill our Node.js Consulting team practices often is the process of breaking down new product requirements into actionable technical requirements. This is one of the most critical capabilities for a developer to learn in order to help their organization swiftly deliver new features to their users. In this post, we’ll talk through the process we use on our projects.
Kevin Phillips
Director of Backend Development
Four Lessons I Learned Node.js Consulting for a Fortune 500 Company
For the last few years, several members of my team and I have been working with a Fortune 500 global company to help build a Node.js ecommerce platform. We learned many valuable lessons along the way. Lessons we feel are too valuable not to share.
Kevin Phillips
Director of Backend Development
How to Use Node.js Temporal Workflows to Batch Process Operations
Temporal is a great tool for batch processing—in this post, we’ll show you all of the solutions that Temporal provides for when you need to handle tens, hundreds, or even thousands of operations.
Kevin Phillips
Director of Backend Development
Simplify your Unit Tests with Dependency Injection for JavaScript Modules
Note: Come join us for a live training on Dependency Injection with StealJS on Wednesday, March 16, 2016 at 12:30 PM CST.
Writing small modules with good unit tests greatly increases the maintainability of your code. However, it can be difficult to test a module without first understanding how its dependencies work. Dependency Injection (DI) allows you to isolate your tests to exactly what you’re trying to test.
While many Dependency Injection implementations require you to use them as plumbing throughout your code, you can use Dependency Injection with the JavaScript module format you’re already using by loading your modules with StealJS. No need to modify your code -- use Dependency Injection when you want it and your existing module format to load modules everywhere else.
What is Dependency Injection?
Dependency injection is a Computer Science design principle that has been around a long time. There are lots of articles (here are a few) that go in depth on this topic, but I’ll use this simple definition:
Dependency Injection - replacing the code that will be loaded when a JavaScript module is imported.
The most useful way to use DI in JavaScript is to simplify unit testing. To better understand this, we'll go over the simple example shown in the GIF above.
Take these two modules:
user
- exports aname
function that makes a call to the server and returns the current user’s name.navigation
- exports agreeting
function that uses theuser.name
function to display “Welcome Back, name!” if we know the user’s name or just “Welcome!” if we don’t.
In the next sections, we'll show how to unit test them, with and without using DI.
Testing Without Dependency Injection
If you want to test navigation.greeting
without Dependency Injection, you need user.name
to return a value. One way to do this is to intercept the request being made to the server and return a mocked AJAX response with the data needed for your test case.
With this approach, you’re testing more than just the greeting
function:
In order to set this up you also have to know implementation details about the user
module.
- What request is it making to the server?
- Is it using a library or framework to make the request?
- What does the server’s response look like?
If the user
module changes, you might have to modify your test, even if the changes don’t affect the navigation
module. Consider the following scenarios:
What happens if the server’s response changes?
What happens if the user
module starts caching its data in localStorage?
The paradigm of unit testing is broken. Unit testing should be isolating and testing a single module, but in practice, this unit test is dependent on many modules that we’re not trying to test.
The tight coupling of the navigation
module’s tests to the implementation of the user
module leads to brittle tests and lots of frustration - if you don’t just give up on testing the module altogether.
Testing With Dependency Injection
Testing the navigation
module becomes much easier when using dependency injection because you can inject a version of the user
module that does exactly what you need for your navigation
module’s tests:
Now if the implementation of user.name
changes, it won’t affect your tests at all.
Dependency Injection with StealJS
StealJS is a client-side JavaScript module loader. A recent extension to steal, steal-clone, added the ability to do dependency injection of JavaScript modules. Here is the navigation
example using steal-clone:
Navigation Module Code:
import { name } from 'models/user';
export class Navigation {
greeting() {
return name()
.then(name => {
return name ?
`Welcome Back, ${name}!` :
'Welcome!';
});
}
};
Navigation Test Code:
import QUnit from 'qunit';
import clone from 'steal-clone';
let navigation, name;
QUnit.module('navigation', {
beforeEach(assert) {
const done = assert.async();
clone({
'models/user': {
name() {
return Promise.resolve(name);
}
}
})
.import('navigation')
.then(({ Navigation }) => {
navigation = new Navigation();
done();
});
}
});
QUnit.test('greeting - no name', (assert) => {
const done = assert.async();
name = null;
navigation
.greeting()
.then(greeting => {
QUnit.equal(greeting, 'Welcome!');
done();
});
});
QUnit.test('greeting - with name', (assert) => {
const done = assert.async();
name = 'Kevin';
navigation
.greeting()
.then(greeting => {
QUnit.equal(greeting, 'Welcome Back, Kevin!');
done();
});
});
You’ll notice a few things in this code:
- This example is using ES6 module syntax, but if you prefer CommonJS or AMD that is fine too; steal-clone will work with whatever syntax you choose.
- You only use Dependency Injection exactly where you want it. You’re not forced to use any libraries or frameworks in your modules.
This simple example shows how Dependency Injection can isolate your tests to exactly the module you’re testing and how simple it is to use DI with StealJS and steal-clone. If you want to start simplifying your tests and you’re already using StealJS, take a look at the docs for steal-clone and start using it today. If you’re not using StealJS, take a look at its homepage and docs to get started.
Kevin Phillips
Director of Backend Development