humanlayer

lightsong發表於2024-11-10

humanlayer

https://github.com/humanlayer/humanlayer?tab=readme-ov-file

HumanLayer: A python toolkit to enable AI agents to communicate with humans in tool-based and asynchronous workflows. By incorporating humans-in-the-loop, agentic tools can be given access to much more powerful and meaningful tool calls and tasks.

Bring your LLM (OpenAI, Llama, Claude, etc) and Framework (LangChain, CrewAI, etc) and start giving your AI agents safe access to the world.

HumanLayer enables AI agents to communicate with humans in tool-based and async workflows. Guarantee human oversight of high-stakes function calls with approval workflows across slack, email and more. Bring your LLM and Framework of choice and start giving your AI agents safe access to the world. Agentic Workflows, human in the loop, tool calling

To better define what is meant by "high stakes", some examples:

  • Low Stakes: Read Access to public data (e.g. search wikipedia, access public APIs and DataSets)
  • Low Stakes: Communicate with agent author (e.g. an engineer might empower an agent to send them a private Slack message with updates on progress)
  • Medium Stakes: Read Access to Private Data (e.g. read emails, access calendars, query a CRM)
  • Medium Stakes: Communicate with strict rules (e.g. sending based on a specific sequence of hard-coded email templates)
  • High Stakes: Communicate on my Behalf or on behalf of my Company (e.g. send emails, post to slack, publish social/blog content)
  • High Stakes: Write Access to Private Data (e.g. update CRM records, modify feature toggles, update billing information)
Image showing the levels of function stakes stacked on top of one another

The high stakes functions are the ones that are the most valuable and promise the most impact in automating away human workflows. But they are also the ones where "90% accuracy" is not acceptable. Reliability is further impacted by today's LLMs' tendency to hallucinate or craft low-quality text that is clearly AI generated. The sooner teams can get Agents reliably and safely calling these tools with high-quality inputs, the sooner they can reap massive benefits.

HumanLayer provides a set of tools to deterministically guarantee human oversight of high stakes function calls. Even if the LLM makes a mistake or hallucinates, HumanLayer is baked into the tool/function itself, guaranteeing a human in the loop.

HumanLayer @require_approval decorator wrapping the Commnicate on my behalf function
HumanLayer provides a set of tools to *deterministically* guarantee human oversight of high stakes function calls

demo

https://github.com/humanlayer/humanlayer/blob/main/examples/crewai/crewai_onboarding_agent.py

from crewai import Agent, Crew, Task
from crewai_tools import tool
from dotenv import load_dotenv

load_dotenv()

from humanlayer import HumanLayer

hl = HumanLayer(
    # run_id is optional -it can be used to identify the agent in approval history
    run_id="crewai-onboarding-agent",
)

task_prompt = """

Your task is to check the list of recently signed up customers, get info about their onboarding progress,
and send each one an email to encourage them to complete the onboarding process. You should
offer a meeting to help them where it makes sense.

If they are fully onboard, you should simply request feedback and offer a meeting.

"""


@tool
def get_recently_signed_up_customers() -> list[str]:
    """get a list of customers that signed up recently"""
    return ["danny@metacorp.com", "terri@acmestuff.com"]


@tool
def get_info_about_customer(customer_email: str) -> str:
    """get info about a customer"""
    if customer_email == "danny@metacorp.com":
        return """
        This customer has completed most of the onboarding steps,
        but still needs to invite a few team members before they can be
        considered fully onboarded
        """
    else:
        return "This customer has completed all the of the onboarding steps and is actively using the product."


@tool
@hl.require_approval()
def send_email(to: str, subject: str, body: str) -> str:
    """Send an email to a user"""

    # write to a local file so we can inspect after
    with open("emails.md", "a") as f:
        f.write(
            f"""{subject}
=============

To: {to}
* * *

{body}

* * *\n\n\n\n"""
        )

    return f"Email sent to {to} with subject: {subject}"


general_agent = Agent(
    role="Onboarding Agent",
    goal="""Ensure all customers of the SaaS product, SuperCI, are onboarded successfully and
    getting value from all features.""",
    backstory="""
You are a seasoned customer success agent. You check on the progress customers
are making and get other information, then based on that info, you
send friendly and encouraging emails to customers to help them fully onboard
into the product.
""",
    allow_delegation=False,
    tools=[get_info_about_customer, get_recently_signed_up_customers, send_email],
    verbose=True,
    crew_sharing=False,
)

task = Task(
    description=task_prompt,
    agent=general_agent,
    expected_output="a summary of actions taken",
)

crew = Crew(agents=[general_agent], tasks=[task], verbose=True)


def main():
    return crew.kickoff()


if __name__ == "__main__":
    result = main()
    print("\n\n---------- RESULT ----------\n\n")
    print(result)