Class: Langchain::Assistant

Inherits:
Object
  • Object
show all
Defined in:
lib/langchain/assistants/assistant.rb

Overview

Assistants are Agent-like objects that leverage helpful instructions, LLMs, tools and knowledge to respond to user queries. Assistants can be configured with an LLM of your choice (currently only OpenAI), any vector search database and easily extended with additional tools.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(llm:, thread:, tools: [], instructions: nil) ⇒ Assistant

Create a new assistant

Parameters:

  • llm (Langchain::LLM::Base)

    LLM instance that the assistant will use

  • thread (Langchain::Thread)

    The thread that’ll keep track of the conversation

  • tools (Array<Langchain::Tool::Base>) (defaults to: [])

    Tools that the assistant has access to

  • instructions (String) (defaults to: nil)

    The system instructions to include in the thread

Raises:

  • (ArgumentError)


16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/langchain/assistants/assistant.rb', line 16

def initialize(
  llm:,
  thread:,
  tools: [],
  instructions: nil
)
  raise ArgumentError, "Invalid LLM; currently only Langchain::LLM::OpenAI is supported" unless llm.instance_of?(Langchain::LLM::OpenAI)
  raise ArgumentError, "Thread must be an instance of Langchain::Thread" unless thread.is_a?(Langchain::Thread)
  raise ArgumentError, "Tools must be an array of Langchain::Tool::Base instance(s)" unless tools.is_a?(Array) && tools.all? { |tool| tool.is_a?(Langchain::Tool::Base) }

  @llm = llm
  @thread = thread
  @tools = tools
  @instructions = instructions

  # The first message in the thread should be the system instructions
  # TODO: What if the user added old messages and the system instructions are already in there? Should this overwrite the existing instructions?
  add_message(role: "system", content: instructions) if instructions
end

Instance Attribute Details

#instructionsObject

Returns the value of attribute instructions.



7
8
9
# File 'lib/langchain/assistants/assistant.rb', line 7

def instructions
  @instructions
end

#llmObject (readonly)

Returns the value of attribute llm.



7
8
9
# File 'lib/langchain/assistants/assistant.rb', line 7

def llm
  @llm
end

#threadObject (readonly)

Returns the value of attribute thread.



7
8
9
# File 'lib/langchain/assistants/assistant.rb', line 7

def thread
  @thread
end

#toolsObject

Returns the value of attribute tools.



8
9
10
# File 'lib/langchain/assistants/assistant.rb', line 8

def tools
  @tools
end

Instance Method Details

#add_message(content: nil, role: "user", tool_calls: [], tool_call_id: nil) ⇒ Array<Langchain::Message>

Add a user message to the thread

Parameters:

  • content (String) (defaults to: nil)

    The content of the message

  • role (String) (defaults to: "user")

    The role attribute of the message. Default: “user”

  • tool_calls (Array<Hash>) (defaults to: [])

    The tool calls to include in the message

  • tool_call_id (String) (defaults to: nil)

    The ID of the tool call to include in the message

Returns:



43
44
45
46
# File 'lib/langchain/assistants/assistant.rb', line 43

def add_message(content: nil, role: "user", tool_calls: [], tool_call_id: nil)
  message = build_message(role: role, content: content, tool_calls: tool_calls, tool_call_id: tool_call_id)
  thread.add_message(message)
end

#add_message_and_run(content:, auto_tool_execution: false) ⇒ Array<Langchain::Message>

Add a user message to the thread and run the assistant

Parameters:

  • content (String)

    The content of the message

  • auto_tool_execution (Boolean) (defaults to: false)

    Whether or not to automatically run tools

Returns:



113
114
115
116
# File 'lib/langchain/assistants/assistant.rb', line 113

def add_message_and_run(content:, auto_tool_execution: false)
  add_message(content: content, role: "user")
  run(auto_tool_execution: auto_tool_execution)
end

#clear_thread!Array

Delete all messages in the thread

Returns:

  • (Array)

    Empty messages array



131
132
133
134
# File 'lib/langchain/assistants/assistant.rb', line 131

def clear_thread!
  # TODO: If this a bug? Should we keep the "system" message?
  thread.messages = []
end

#run(auto_tool_execution: false) ⇒ Array<Langchain::Message>

Run the assistant

Parameters:

  • auto_tool_execution (Boolean) (defaults to: false)

    Whether or not to automatically run tools

Returns:



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
99
100
101
102
103
104
105
106
# File 'lib/langchain/assistants/assistant.rb', line 52

def run(auto_tool_execution: false)
  if thread.messages.empty?
    Langchain.logger.warn("No messages in the thread")
    return
  end

  running = true

  while running
    # TODO: I think we need to look at all messages and not just the last one.
    case (last_message = thread.messages.last).role
    when "system"
      # Do nothing
      running = false
    when "assistant"
      if last_message.tool_calls.any?
        if auto_tool_execution
          run_tools(last_message.tool_calls)
        else
          # Maybe log and tell the user that there's outstanding tool calls?
          running = false
        end
      else
        # Last message was from the assistant without any tools calls.
        # Do nothing
        running = false
      end
    when "user"
      # Run it!
      response = chat_with_llm

      if response.tool_calls
        # Re-run the while(running) loop to process the tool calls
        running = true
        add_message(role: response.role, tool_calls: response.tool_calls)
      elsif response.chat_completion
        # Stop the while(running) loop and add the assistant's response to the thread
        running = false
        add_message(role: response.role, content: response.chat_completion)
      end
    when "tool"
      # Run it!
      response = chat_with_llm
      running = true

      if response.tool_calls
        add_message(role: response.role, tool_calls: response.tool_calls)
      elsif response.chat_completion
        add_message(role: response.role, content: response.chat_completion)
      end
    end
  end

  thread.messages
end

#submit_tool_output(tool_call_id:, output:) ⇒ Array<Langchain::Message>

Submit tool output to the thread

Parameters:

  • tool_call_id (String)

    The ID of the tool call to submit output for

  • output (String)

    The output of the tool

Returns:



123
124
125
126
# File 'lib/langchain/assistants/assistant.rb', line 123

def submit_tool_output(tool_call_id:, output:)
  # TODO: Validate that `tool_call_id` is valid
  add_message(role: "tool", content: output, tool_call_id: tool_call_id)
end