| const { Agent } = require('langchain/agents'); |
| const { LLMChain } = require('langchain/chains'); |
| const { FunctionChatMessage, AIChatMessage } = require('langchain/schema'); |
| const { |
| ChatPromptTemplate, |
| MessagesPlaceholder, |
| SystemMessagePromptTemplate, |
| HumanMessagePromptTemplate, |
| } = require('langchain/prompts'); |
| const { logger } = require('~/config'); |
|
|
| const PREFIX = 'You are a helpful AI assistant.'; |
|
|
| function parseOutput(message) { |
| if (message.additional_kwargs.function_call) { |
| const function_call = message.additional_kwargs.function_call; |
| return { |
| tool: function_call.name, |
| toolInput: function_call.arguments ? JSON.parse(function_call.arguments) : {}, |
| log: message.text, |
| }; |
| } else { |
| return { returnValues: { output: message.text }, log: message.text }; |
| } |
| } |
|
|
| class FunctionsAgent extends Agent { |
| constructor(input) { |
| super({ ...input, outputParser: undefined }); |
| this.tools = input.tools; |
| } |
|
|
| lc_namespace = ['langchain', 'agents', 'openai']; |
|
|
| _agentType() { |
| return 'openai-functions'; |
| } |
|
|
| observationPrefix() { |
| return 'Observation: '; |
| } |
|
|
| llmPrefix() { |
| return 'Thought:'; |
| } |
|
|
| _stop() { |
| return ['Observation:']; |
| } |
|
|
| static createPrompt(_tools, fields) { |
| const { prefix = PREFIX, currentDateString } = fields || {}; |
|
|
| return ChatPromptTemplate.fromMessages([ |
| SystemMessagePromptTemplate.fromTemplate(`Date: ${currentDateString}\n${prefix}`), |
| new MessagesPlaceholder('chat_history'), |
| HumanMessagePromptTemplate.fromTemplate('Query: {input}'), |
| new MessagesPlaceholder('agent_scratchpad'), |
| ]); |
| } |
|
|
| static fromLLMAndTools(llm, tools, args) { |
| FunctionsAgent.validateTools(tools); |
| const prompt = FunctionsAgent.createPrompt(tools, args); |
| const chain = new LLMChain({ |
| prompt, |
| llm, |
| callbacks: args?.callbacks, |
| }); |
| return new FunctionsAgent({ |
| llmChain: chain, |
| allowedTools: tools.map((t) => t.name), |
| tools, |
| }); |
| } |
|
|
| async constructScratchPad(steps) { |
| return steps.flatMap(({ action, observation }) => [ |
| new AIChatMessage('', { |
| function_call: { |
| name: action.tool, |
| arguments: JSON.stringify(action.toolInput), |
| }, |
| }), |
| new FunctionChatMessage(observation, action.tool), |
| ]); |
| } |
|
|
| async plan(steps, inputs, callbackManager) { |
| |
| const thoughts = await this.constructScratchPad(steps); |
| const newInputs = Object.assign({}, inputs, { agent_scratchpad: thoughts }); |
| if (this._stop().length !== 0) { |
| newInputs.stop = this._stop(); |
| } |
|
|
| |
| const llm = this.llmChain.llm; |
| const valuesForPrompt = Object.assign({}, newInputs); |
| const valuesForLLM = { |
| tools: this.tools, |
| }; |
| for (let i = 0; i < this.llmChain.llm.callKeys.length; i++) { |
| const key = this.llmChain.llm.callKeys[i]; |
| if (key in inputs) { |
| valuesForLLM[key] = inputs[key]; |
| delete valuesForPrompt[key]; |
| } |
| } |
|
|
| const promptValue = await this.llmChain.prompt.formatPromptValue(valuesForPrompt); |
| const message = await llm.predictMessages( |
| promptValue.toChatMessages(), |
| valuesForLLM, |
| callbackManager, |
| ); |
| logger.debug('[FunctionsAgent] plan message', message); |
| return parseOutput(message); |
| } |
| } |
|
|
| module.exports = FunctionsAgent; |
|
|