brainlid / langchain

Elixir implementation of a LangChain style framework.
https://hexdocs.pm/langchain/
Other
503 stars 58 forks source link

Begin support for Agents #89

Open brainlid opened 3 months ago

brainlid commented 3 months ago

Agents can act autonomously and perform more complex, multi-step activities.

poffdeluxe commented 1 month ago

I've spent some time building a graph-style agent framework with executor on top of this langchain library. Let me know if its something you'd like a demo on and we could possibly discuss how to integrate it

brainlid commented 1 month ago

I'm definitely interested in what you've built.

What do you mean by a graph style agent? I've researched the way the TS LangChain library does agents but I wouldn't describe it as graph related.

poffdeluxe commented 1 month ago

So, what I've been working on is more akin to the LangGraph libraries

For example, in my work, a simple agent that might do some self-reflection to write an essay is defined like this:

  %GraphAgent{
      name: "Essay Writer",
      final_output_property: :latest_revision,
      state: %EssayWriterState{}
    }
    |> GraphAgent.add_node(:first_draft, write_first_draft_node)
    |> GraphAgent.add_node(:write, write_node)
    |> GraphAgent.add_node(:provide_feedback, feedback_node)
    |> GraphAgent.set_entry_point(:first_draft)
    |> GraphAgent.add_edge(:first_draft, :provide_feedback)
    |> GraphAgent.add_edge(:provide_feedback, :write)
    |> GraphAgent.add_conditional_edges(:write, [:end, :provide_feedback], should_continue)

Currently, each node is a function that expects a chain in one argument and the input state. Each node returns the new output state.

This style of agent implementation feels really nice and natural in Elixir!

nileshtrivedi commented 3 weeks ago

I have started porting Microsoft's Autogen to Elixir here. The goal will be to stay close to Autogen's conversation patterns, such as resumable GroupChats and Nested chats.

Here's a sample conversation between two agents:

joe = %XAgent{
  name: "Joe",
  system_message: "Your name is Joe and you are a part of a duo of comedians.",
  type: :conversable_agent,
  llm_config: %{temperature: 0.9},
  human_input_mode: "NEVER",
  max_consecutive_auto_reply: 1,
  is_termination_msg: fn msg -> String.contains?(String.downcase(msg.content), "bye") end
}

cathy = %XAgent{
  name: "Cathy",
  system_message: "Your name is Cathy and you are a part of a duo of comedians.",
  type: :conversable_agent,
  llm_config: %{temperature: 0.7},
  human_input_mode: "NEVER"
}

XAgent.initiate_chat(
  from_agent: joe,
  to_agent: cathy,
  message: "Cathy, tell me a joke and then say the words GOOD BYE..",
  max_turns: 2
)