-
Notifications
You must be signed in to change notification settings - Fork 2.3k
/
Copy pathopenai_runnable.ts
98 lines (95 loc) · 3.42 KB
/
openai_runnable.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import { AgentExecutor } from "langchain/agents";
import { ChatOpenAI } from "@langchain/openai";
import { Calculator } from "@langchain/community/tools/calculator";
import { OpenAIFunctionsAgentOutputParser } from "langchain/agents/openai/output_parser";
import { convertToOpenAIFunction } from "@langchain/core/utils/function_calling";
import {
ChatPromptTemplate,
MessagesPlaceholder,
} from "@langchain/core/prompts";
import {
AIMessage,
BaseMessage,
FunctionMessage,
} from "@langchain/core/messages";
import { AgentStep } from "@langchain/core/agents";
import { RunnableSequence } from "@langchain/core/runnables";
import { SerpAPI } from "@langchain/community/tools/serpapi";
/** Define your list of tools. */
const tools = [new Calculator(), new SerpAPI()];
/**
* Define your chat model to use.
* In this example we'll use gpt-4 as it is much better
* at following directions in an agent than other models.
*/
const model = new ChatOpenAI({ model: "gpt-4", temperature: 0 });
/**
* Define your prompt for the agent to follow
* Here we're using `MessagesPlaceholder` to contain our agent scratchpad
* This is important as later we'll use a util function which formats the agent
* steps into a list of `BaseMessages` which can be passed into `MessagesPlaceholder`
*/
const prompt = ChatPromptTemplate.fromMessages([
["system", "You are a helpful assistant"],
["human", "{input}"],
new MessagesPlaceholder("agent_scratchpad"),
]);
/**
* Bind the tools to the LLM.
* Here we're using the `convertToOpenAIFunction` util function
* to format our tools into the proper schema for OpenAI functions.
*/
const modelWithFunctions = model.bind({
functions: [...tools.map((tool) => convertToOpenAIFunction(tool))],
});
/**
* Define a new agent steps parser.
*/
const formatAgentSteps = (steps: AgentStep[]): BaseMessage[] =>
steps.flatMap(({ action, observation }) => {
if ("messageLog" in action && action.messageLog !== undefined) {
const log = action.messageLog as BaseMessage[];
return log.concat(new FunctionMessage(observation, action.tool));
} else {
return [new AIMessage(action.log)];
}
});
/**
* Construct the runnable agent.
*
* We're using a `RunnableSequence` which takes two inputs:
* - input --> the users input
* - agent_scratchpad --> the previous agent steps
*
* We're using the `formatForOpenAIFunctions` util function to format the agent
* steps into a list of `BaseMessages` which can be passed into `MessagesPlaceholder`
*/
const runnableAgent = RunnableSequence.from([
{
input: (i: { input: string; steps: AgentStep[] }) => i.input,
agent_scratchpad: (i: { input: string; steps: AgentStep[] }) =>
formatAgentSteps(i.steps),
},
prompt,
modelWithFunctions,
new OpenAIFunctionsAgentOutputParser(),
]);
/** Pass the runnable along with the tools to create the Agent Executor */
const executor = AgentExecutor.fromAgentAndTools({
agent: runnableAgent,
tools,
});
console.log("Loaded agent executor");
const query = "What is the weather in New York?";
console.log(`Calling agent executor with query: ${query}`);
const result = await executor.invoke({
input: query,
});
console.log(result);
/*
Loaded agent executor
Calling agent executor with query: What is the weather in New York?
{
output: 'The current weather in New York is sunny with a temperature of 66 degrees Fahrenheit. The humidity is at 54% and the wind is blowing at 6 mph. There is 0% chance of precipitation.'
}
*/