LLM Wrappers
We don't provide built-in LLM wrappers. Instead, please implement your own by calling an LLM service from TypeScript (for example, the OpenAI Node.js library). You could also ask a ChatGPT-like assistant to "implement a callLLM
function that takes a prompt and returns the LLM response."
Below is a TypeScript example using OpenAI:
import { Configuration, OpenAIApi } from "openai";
/**
* callLLM
*
* An example function that sends a prompt to OpenAI's API and returns the response text.
* Make sure to store your API key in an environment variable like OPENAI_API_KEY.
*/
export async function callLLM(prompt: string): Promise<string> {
const config = new Configuration({
apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(config);
const response = await openai.createChatCompletion({
model: "gpt-4",
messages: [{ role: "user", content: prompt }],
});
// Safely handle the response
return response.data.choices?.[0]?.message?.content ?? "";
}
/**
* Example usage
*/
// (async () => {
// const reply = await callLLM("How are you?");
// console.log("LLM reply:", reply);
// })();
Always store the API key in a secure environment variable (e.g.,
OPENAI_API_KEY
) rather than hardcoding it.
{: .note }
Improvements
Feel free to enhance your callLLM
function as needed. Below are some common patterns:
1. Handling Chat History
Rather than a single prompt
, you might pass an array of messages:
import { Configuration, OpenAIApi, ChatCompletionRequestMessage } from "openai";
export async function callLLMWithHistory(messages: ChatCompletionRequestMessage[]): Promise<string> {
const config = new Configuration({
apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(config);
const response = await openai.createChatCompletion({
model: "gpt-4",
messages: messages,
});
return response.data.choices?.[0]?.message?.content ?? "";
}
2. Adding In-Memory Caching
Using the lru-cache or a similar library, you can cache responses to avoid repeating identical calls. Below is a sketch:
import LRU from "lru-cache";
import { Configuration, OpenAIApi } from "openai";
const llmCache = new LRU<string, string>({ max: 1000 });
export async function cachedCallLLM(prompt: string, useCache: boolean): Promise<string> {
// If caching is enabled and a cached value exists, return it
if (useCache && llmCache.has(prompt)) {
return llmCache.get(prompt) as string;
}
// Otherwise, call the LLM
const config = new Configuration({
apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(config);
const response = await openai.createChatCompletion({
model: "gpt-4",
messages: [{ role: "user", content: prompt }],
});
const text = response.data.choices?.[0]?.message?.content ?? "";
// Cache the result if desired
if (useCache) {
llmCache.set(prompt, text);
}
return text;
}
⚠️ Caching conflicts with Node retries, since retries yield the same result.
You could only use cached results on the first attempt and bypass the cache on subsequent retries.
{: .warning }
3. Enabling Logging
Use your logging framework (e.g., winston, pino, or Node.js console
) to track prompts and responses:
export async function callLLMWithLogging(prompt: string): Promise<string> {
console.info(`Prompt: ${prompt}`);
// ...Perform the call as shown above
// Example:
const reply = await callLLM(prompt);
console.info(`Response: ${reply}`);
return reply;
}
Why Not Provide Built-in LLM Wrappers?
It's considered bad practice to bundle specific LLM implementations inside a generic framework, for reasons such as:
- Frequent API Changes: LLM providers evolve their APIs rapidly. Hardcoding them makes maintenance difficult.
- Flexibility: You might switch vendors (OpenAI, Anthropic, or local models) or need to fine-tune your own models.
- Optimizations: You may need caching, request batching, or streaming—custom solutions are often essential.