From a9d8e946fd1741ec4209ee5cf438628feb13da6c Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Date: Sun, 12 May 2024 21:43:22 -0400 Subject: [PATCH 1/2] Add docs --- docs/api/index.md | 0 docs/concepts/agents.md | 84 +++++++++++ docs/concepts/flows.md | 70 +++++++++ docs/concepts/iteration.md | 85 +++++++++++ docs/concepts/tasks.md | 75 ++++++++++ docs/contributing.md | 0 docs/examples/index.md | 0 docs/getting_started.md | 0 docs/guides/best_practices.md | 0 docs/guides/index.md | 0 docs/index.md | 69 ++++----- mkdocs.yml | 43 ++++++ pyproject.toml | 8 +- requirements-dev.lock | 233 ++++++++++++++++++++++++++-- requirements.lock | 275 +++++++++++++++++++++++++++++++++- 15 files changed, 888 insertions(+), 54 deletions(-) create mode 100644 docs/api/index.md create mode 100644 docs/concepts/agents.md create mode 100644 docs/concepts/flows.md create mode 100644 docs/concepts/iteration.md create mode 100644 docs/concepts/tasks.md create mode 100644 docs/contributing.md create mode 100644 docs/examples/index.md create mode 100644 docs/getting_started.md create mode 100644 docs/guides/best_practices.md create mode 100644 docs/guides/index.md create mode 100644 mkdocs.yml diff --git a/docs/api/index.md b/docs/api/index.md new file mode 100644 index 00000000..e69de29b diff --git a/docs/concepts/agents.md b/docs/concepts/agents.md new file mode 100644 index 00000000..fadca68a --- /dev/null +++ b/docs/concepts/agents.md @@ -0,0 +1,84 @@ +# Agents + +In the ControlFlow framework, an `Agent` represents an AI entity capable of performing tasks and interacting with other agents to achieve desired outcomes. Agents are powered by specialized AI models that excel at specific tasks, such as text generation, decision-making based on unstructured data, or engaging in interactive conversations. + +## The Role of Agents in ControlFlow + +Agents play a crucial role in the execution of tasks within the ControlFlow framework. When a task is defined and added to a workflow, it is assigned to one or more agents responsible for completing the task based on the provided objectives, instructions, and context. + +ControlFlow treats agents as autonomous entities with their own knowledge, capabilities, and tools. By assigning tasks to agents and allowing them to collaborate and communicate with each other, ControlFlow enables the creation of complex AI-powered workflows that can adapt to different scenarios and requirements. + +## Defining Agents + +To create an agent in ControlFlow, you can use the `Agent` class, which provides a flexible way to define an agent's properties and capabilities. + +```python +from controlflow import Agent + +writer_agent = Agent( + name="WriterAgent", + description="An AI agent specializing in creative writing tasks.", + tools=[generate_text, summarize_text], + user_access=False +) +``` + +In this example, we define an agent named "WriterAgent" with a description of its specialization. We also specify the tools available to the agent, which are functions or callable objects that the agent can use to perform specific actions or computations. The `user_access` parameter indicates whether the agent is allowed to interact directly with human users. + +## Agent Properties + +Agents have several key properties that define their characteristics and capabilities: + +- `name` (str): The name of the agent, used for identification and communication purposes. +- `description` (str, optional): A brief description of the agent's specialization or role. +- `tools` (list[AssistantTool | Callable], optional): A list of tools or functions available to the agent for performing tasks. +- `user_access` (bool, optional): Indicates whether the agent is allowed to interact directly with human users. + +## Assigning Tasks to Agents + +When defining a task using the `Task` class or the `@ai_task` decorator, you can specify the agents responsible for completing the task by setting the `agents` parameter. + +```python +from controlflow import Task + +write_story_task = Task( + objective="Write a short story about a mysterious artifact.", + result_type=str, + agents=[writer_agent, editor_agent] +) +``` + +In this example, we assign the "write_story_task" to two agents: "writer_agent" and "editor_agent". These agents will collaborate to complete the task based on their individual capabilities and tools. + +## Agent Execution and Communication + +During the execution of a workflow, agents assigned to tasks take turns performing actions and communicating with each other to progress towards completing the tasks. The `run()` method of a task automatically handles the selection and iteration of agents until the task is complete. + +Agents can communicate with each other by posting messages within the context of a task. These messages are visible to all agents involved in the task and can be used to share information, provide updates, or request assistance. + +```python +from controlflow import Flow + +with Flow(): + story_task = Task( + objective="Write a short story and provide feedback.", + result_type=str, + agents=[writer_agent, editor_agent] + ) + result = story_task.run() +``` + +In this example, the "writer_agent" and "editor_agent" will take turns working on the "story_task". They can communicate with each other by posting messages within the task's context, allowing them to collaborate and provide feedback until the task is complete. + +## Agent Tools and User Access + +Agents can be equipped with tools, which are functions or callable objects that provide additional capabilities or actions that the agent can perform. These tools can be used by the agent during task execution to perform specific computations, access external resources, or interact with other systems. + +The `user_access` property of an agent determines whether the agent is allowed to interact directly with human users. If `user_access` is set to `True`, the agent can use special tools, such as `talk_to_human()`, to send messages to and receive input from human users. This feature is useful for tasks that require human feedback or intervention. + + +## Conclusion + +Agents are a fundamental concept in the ControlFlow framework, representing the AI entities responsible for executing tasks and collaborating to achieve desired outcomes. By defining agents with specific capabilities, tools, and user access permissions, and assigning them to tasks within a workflow, you can create powerful and adaptable AI-powered applications. + +ControlFlow provides a flexible and intuitive way to orchestrate the interaction between agents and tasks, enabling developers to focus on defining the objectives and dependencies of their workflows while the framework handles the complexities of agent coordination and communication. \ No newline at end of file diff --git a/docs/concepts/flows.md b/docs/concepts/flows.md new file mode 100644 index 00000000..a4c641cb --- /dev/null +++ b/docs/concepts/flows.md @@ -0,0 +1,70 @@ +# Flows + +In the ControlFlow framework, a `Flow` represents a container for an AI-enhanced workflow. It serves as the top-level object that encapsulates tasks, agents, tools, and context, providing a structured environment for AI-powered applications. + +## The Role of Flows + +Flows play a crucial role in organizing and managing the execution of AI-powered workflows. They provide a high-level abstraction for defining the overall structure and dependencies of tasks, agents, and tools, allowing developers to focus on the desired outcomes rather than the low-level details of agent coordination and communication. + +Key aspects of flows include: + +- **Task Management**: Flows contain a collection of tasks that define the discrete objectives and goals of the workflow. Tasks can be added to a flow explicitly or implicitly through the use of the `@ai_task` decorator or the `Task` class. + +- **Agent Coordination**: Flows manage the assignment and orchestration of agents to tasks. By default, flows are initialized with a default agent, but custom agents can be specified to handle specific tasks or parts of the workflow. + +- **Tool Management**: Flows provide a centralized place to define and manage tools that are available to agents throughout the workflow. Tools can be functions or callable objects that agents can use to perform specific actions or computations. + +- **Context Sharing**: Flows maintain a consistent context across tasks and agents, allowing for seamless sharing of information and state throughout the workflow. The flow's context can be accessed and modified by tasks and agents, enabling dynamic and adaptive behavior. + +## Creating a Flow + +To create a flow, you can use the `@flow` decorator on a Python function. The decorated function becomes the entry point for the AI-powered workflow. + +```python +from controlflow import flow + +@flow +def my_flow(): + # Define tasks, agents, and tools here + ... +``` + +Alternatively, you can create a flow object directly using the `Flow` class: + +```python +from controlflow import Flow + +flow = Flow() +``` + +## Flow Properties + +Flows have several key properties that define their behavior and capabilities: + +- `thread` (Thread): The thread associated with the flow, which stores the conversation history and context. +- `tools` (list[AssistantTool | Callable]): A list of tools that are available to all agents in the flow. +- `agents` (list[Agent]): The default agents for the flow, which are used for tasks that do not specify agents explicitly. +- `context` (dict): Additional context or information that is shared across tasks and agents in the flow. + +## Running a Flow + +To run a flow, you can simply call the decorated function: + +```python +@flow +def my_flow(): + # Define tasks, agents, and tools here + ... + +my_flow() +``` + +When a flow is run, it executes the defined tasks, assigning agents and tools as needed. The flow manages the context across agents. + + + +## Conclusion + +Flows are a fundamental concept in the ControlFlow framework, providing a structured and flexible way to define, organize, and execute AI-powered workflows. By encapsulating tasks, agents, tools, and context within a flow, developers can create complex and dynamic applications that leverage the power of AI while maintaining a clear and maintainable structure. + +Flows abstract away the low-level details of agent coordination and communication, allowing developers to focus on defining the desired outcomes and objectives of their workflows. With the `@flow` decorator and the `Flow` class, creating and running AI-powered workflows becomes a straightforward and intuitive process. \ No newline at end of file diff --git a/docs/concepts/iteration.md b/docs/concepts/iteration.md new file mode 100644 index 00000000..834e1050 --- /dev/null +++ b/docs/concepts/iteration.md @@ -0,0 +1,85 @@ +# Iterative Control + +Iterative control lies at the core of agentic workflows, enabling the creation of dynamic and adaptive AI-powered applications. In traditional approaches, the iterative logic is often deeply nested within monolithic AI models, making it challenging to understand, customize, and maintain. ControlFlow takes a different approach by elevating iterative control to a first-class citizen in its API, empowering developers to harness the power of iteration with ease and flexibility. + +## The Importance of Iteration in Agentic Workflows + +Agentic workflows are characterized by their ability to make decisions, take actions, and adapt based on feedback and changing conditions. This inherent adaptability is achieved through iteration - the process of repeatedly executing a series of steps until a desired outcome is reached. + +Consider a simple example of an AI-powered task management system. The system needs to continuously monitor incoming tasks, prioritize them based on predefined criteria, assign them to appropriate agents, and track their progress until completion. This workflow requires iterative control to handle the dynamic nature of tasks and to ensure that the system remains responsive and efficient. + +Without iterative control, the system would be limited to handling a fixed set of tasks in a predefined order, lacking the flexibility to adapt to real-world scenarios. Iterative control allows the system to continuously loop through the task management process, making decisions and taking actions based on the current state of tasks and agents. + +## ControlFlow: Making Iterative Control Accessible + +ControlFlow recognizes the critical role of iterative control in agentic workflows and provides a high-level API that makes it accessible and intuitive for developers. By bringing the concept of iteration to the forefront, ControlFlow enables developers to focus on defining the logic and behavior of their workflows, without getting bogged down in low-level implementation details. + +At the heart of ControlFlow's iterative control mechanism lies the `Task` class. A task represents a unit of work that needs to be accomplished by one or more agents. It encapsulates the necessary information, such as the objective, dependencies, and agents responsible for its execution. + +To iterate over tasks, ControlFlow provides the `run()` method. This method abstracts away the underlying while loop, allowing developers to express their workflow logic in a concise and readable manner. Under the hood, `run()` intelligently selects agents, manages dependencies, and orchestrates the execution of tasks until the desired outcome is achieved. + +Here's an example of how iterative control can be achieved using `run()`: + +```python +task = Task(objective="Analyze sales data") +task.run() +``` + +In this example, the `run()` method takes care of the iterative control flow, repeatedly executing the necessary steps until the task is marked as complete. It handles agent selection, dependency resolution, and progress tracking, freeing developers from the complexities of manual iteration. + +## Granular Control with `run_once()` and `agent.run()` + +While `run()` provides a high-level abstraction for iterative control, ControlFlow also offers more granular control options through the `run_once()` method and the `agent.run()` function. + +The `run_once()` method allows developers to take control of the iteration process by executing a single step at a time. It provides the flexibility to inject custom logic, perform additional checks, or handle specific edge cases within each iteration. By combining `while task.is_incomplete()` with `run_once()`, developers can create custom iteration patterns tailored to their specific requirements. + +Here's an example showcasing the usage of `run_once()`: + +```python +while task.is_incomplete(): + task.run_once() + # Perform additional checks or custom logic + if some_condition: + break +``` + +In this example, the `run_once()` method is called repeatedly within a while loop until the task is marked as complete. This granular control enables developers to incorporate custom logic, such as breaking out of the loop based on certain conditions or performing additional actions between iterations. + +For even more fine-grained control, ControlFlow provides the `agent.run()` function. This function allows developers to explicitly invoke a specific agent to execute a task, bypassing the automated agent selection process. It gives developers complete control over which agent handles a particular task and enables them to create custom agent orchestration patterns. + +Here's an example demonstrating the usage of `agent.run()`: + +```python +agent1 = Agent(name="DataAnalyst") +agent2 = Agent(name="ReportGenerator") + +task1 = Task(objective="Analyze sales data") +task2 = Task(objective="Generate sales report") + +agent1.run(task1) +agent2.run(task2) +``` + +In this example, `agent1` is explicitly assigned to execute `task1`, while `agent2` is assigned to execute `task2`. This level of control is particularly useful when dealing with specialized agents or when implementing complex workflows that require precise agent assignment. + +## Balancing Simplicity and Control + +One of the key strengths of ControlFlow is its ability to provide a high-level API for iterative control without sacrificing the ability to dive into lower-level details when needed. The framework strikes a balance between simplicity and control, catering to the needs of both rapid development and fine-grained customization. + +Developers can start by using the high-level `run()` method to quickly prototype and iterate on their workflows. As their requirements grow more complex, they can gradually transition to using `run_once()` and `agent.run()` to incorporate custom logic and take control of the iteration process. + +This gradual descent into lower-level control is made possible by ControlFlow's thoughtful API design. The lower-level methods, such as `run_once()` and `agent.run()`, are not buried deep within the framework but are readily accessible as part of the public API. This accessibility ensures that developers can seamlessly transition between different levels of control without having to navigate through complex abstractions or modify the underlying framework. + +Moreover, even at the lowest level of control, ControlFlow maintains a relatively high level of abstraction compared to traditional approaches. Developers can focus on expressing their workflow logic using intuitive concepts like tasks, agents, and dependencies, rather than dealing with raw loops, conditionals, and state management. + +This balance between simplicity and control empowers developers to build sophisticated agentic workflows without getting overwhelmed by complexity. It enables them to start simple, iterate quickly, and gradually introduce more advanced control mechanisms as their understanding of the problem domain grows. + +## Conclusion + +Iterative control is the driving force behind agentic workflows, enabling the creation of dynamic, adaptive, and intelligent AI-powered applications. ControlFlow recognizes the importance of iteration and provides a high-level API that makes it accessible and intuitive for developers. + +By offering a spectrum of control options, from the high-level `run()` method to the more granular `run_once()` and `agent.run()` functions, ControlFlow empowers developers to choose the level of control that best suits their needs. Whether they prefer the simplicity of automatic iteration or the precision of manual control, ControlFlow provides a seamless and expressive way to build iterative workflows. + +As developers explore the capabilities of ControlFlow, they can leverage the power of iterative control to create sophisticated agentic systems. They can start with the high-level abstractions, gradually diving into lower-level control mechanisms as their requirements evolve. This progressive approach to iterative control enables developers to build robust, adaptive, and maintainable AI-powered workflows. + +With ControlFlow, the iterative control flow is no longer an obscure concept hidden within monolithic models but a central and accessible part of the development process. By embracing the power of iteration and leveraging ControlFlow's intuitive API, developers can unlock the full potential of agentic workflows and create intelligent, dynamic, and efficient AI-powered applications. \ No newline at end of file diff --git a/docs/concepts/tasks.md b/docs/concepts/tasks.md new file mode 100644 index 00000000..efbda388 --- /dev/null +++ b/docs/concepts/tasks.md @@ -0,0 +1,75 @@ +# Tasks + +In ControlFlow, a `Task` is the fundamental unit of work that represents a specific objective or goal within an AI-powered workflow. Tasks are the primary means of defining and structuring the desired outcomes of an application, acting as a bridge between the AI agents and the application logic. + +## The Philosophy of Task-Centric Workflows + +ControlFlow takes a unique approach to AI-powered workflows by placing tasks at the center of the design process. Instead of focusing on directly controlling the AI agents' behavior, which can be unpredictable and difficult to manage, ControlFlow encourages developers to define clear, discrete tasks that specify what needs to be accomplished. + +By defining tasks with specific objectives, inputs, outputs, and dependencies, developers can create a structured workflow that guides the AI agents towards the desired outcomes. This task-centric approach allows for more predictable and manageable AI integrations, as the agents are dispatched to complete well-defined tasks rather than being controlled through a complex script that attempts to respond to their stochastic behavior. + +## Defining Tasks + +In ControlFlow, tasks are typically defined using the `Task` class, which provides a flexible and expressive way to specify task properties and requirements. However, for convenience, ControlFlow also offers the `@ai_task` decorator, which can be used to define tasks using Python functions. + +### Using the `Task` Class + +The `Task` class is the standard way to define tasks in ControlFlow. It allows you to specify various properties and requirements for a task, such as its objective, instructions, assigned agents, context, dependencies, and more. + +```python +from controlflow import Task + +interests = Task( + objective="Ask user for three interests", + result_type=list[str], + user_access=True, + instructions="Politely ask the user to provide three of their interests or hobbies." +) +``` + +### Using the `@ai_task` Decorator + +The `@ai_task` decorator provides a convenient way to define tasks using Python functions. The decorator accepts many of the same arguments as the `Task` class, and it automatically infers the task's objective, context, and result type from the function definition. + +```python +from controlflow import ai_task + +@ai_task(user_access=True) +def get_user_name() -> str: + "Politely ask the user for their name." + pass +``` + +When a decorator-based task is called, it automatically invokes the `run()` method, executing the task and returning its result. + +## Task Properties + +Tasks have several key properties that define their behavior and requirements: + +- `objective` (str): A brief description of the task's goal or desired outcome. +- `instructions` (str, optional): Detailed instructions or guidelines for completing the task. +- `agents` (list[Agent], optional): The AI agents assigned to work on the task. +- `context` (dict, optional): Additional context or information required for the task. +- `subtasks` (list[Task], optional): A list of subtasks that are part of the main task. +- `depends_on` (list[Task], optional): Tasks that must be completed before this task can be executed. +- `result_type` (type, optional): The expected type of the task's result. +- `tools` (list[AssistantTool | Callable], optional): Tools or functions available to the agents for completing the task. +- `user_access` (bool, optional): Indicates whether the task requires human user interaction. + +## Task Execution and Results + +Tasks can be executed using the `run()` method, which intelligently selects the appropriate agents and iterates until the task is complete. The `run_once()` method allows for more fine-grained control, executing a single step of the task with a selected agent. + +The `result` property of a task holds the outcome or output of the task execution. By specifying a clear `result_type`, developers can ensure that the task's result is structured and can be easily integrated into the application logic. This makes it possible to create complex workflows where the results of one task can be used as inputs for subsequent tasks. + +## Task Dependencies and Subtasks + +Tasks can have dependencies on other tasks, which must be completed before the dependent task can be executed. Dependencies can be specified explicitly using the `depends_on` property or implicitly by providing tasks as values in the `context` dictionary. + +Subtasks are tasks that are part of a larger, parent task. They can be added to a parent task using the `add_subtask()` method or by creating tasks within a context manager (e.g., `with Task():`). Parent tasks cannot be completed until all their subtasks are finished, although subtasks can be skipped using a special `skip` tool. + +## Modeling Application State with Tasks + +In ControlFlow, tasks are used to model the internal state of an AI-powered application. By defining tasks with clear objectives, dependencies, and result types, developers can create a structured representation of the application's desired outcomes and the steps required to achieve them. + +This task-centric approach allows for a more modular and manageable integration of AI capabilities into traditional software development workflows. By focusing on defining what needs to be done rather than attempting to control the AI's behavior directly, ControlFlow enables developers to create robust, scalable, and maintainable AI-powered applications. diff --git a/docs/contributing.md b/docs/contributing.md new file mode 100644 index 00000000..e69de29b diff --git a/docs/examples/index.md b/docs/examples/index.md new file mode 100644 index 00000000..e69de29b diff --git a/docs/getting_started.md b/docs/getting_started.md new file mode 100644 index 00000000..e69de29b diff --git a/docs/guides/best_practices.md b/docs/guides/best_practices.md new file mode 100644 index 00000000..e69de29b diff --git a/docs/guides/index.md b/docs/guides/index.md new file mode 100644 index 00000000..e69de29b diff --git a/docs/index.md b/docs/index.md index 51a03aa2..47c477fa 100644 --- a/docs/index.md +++ b/docs/index.md @@ -6,64 +6,61 @@ ControlFlow provides a structured and intuitive way to create complex AI-powered !!! question "What's an agentic workflow?" - An agentic workflow is a process that treats AI agents as autonomous entities capable of performing tasks, making decisions, and communicating with each other. ControlFlow provides a structured and intuitive way to define, organize, and execute such AI-powered workflows, enabling developers to create complex applications that leverage the power of AI agents while maintaining a clear, maintainable, and debuggable structure. + An agentic workflow is a process that treats LLMs as autonomous entities capable of making decisions and performing complex tasks through iterative interactions. -## Let's see it -```python -from controlflow import flow, Task, Agent -agent = Agent(name='Marvin', description='An expert screewriter.') -@flow -def my_flow(): +## Design principles +ControlFlow's design is informed by a strong opinon: LLMs are powerful tools, but they are most effective when applied to small, well-defined tasks within a structured workflow. - genre = Task('Choose a movie genre', result_type=['sci-fi', 'western', 'comedy', 'action', 'romance'], agents=[agent]) - plot = Task('Generate a plot outline', result_type=str, context=dict(genre=genre), agents=[agent]) - title = Task('Come up with a title', result_type=str, context=dict(genre=genre, plot=plot), agents=[agent]) +This belief leads to three core design principles that underpin ControlFlow's architecture: - # run the last task in the chain - title.run() +### 🛠️ Specialized over generalized +ControlFlow believes that **single-purpose agents dedicated to a specific tasks** will be more effective than monolithic models that attempt to do everything. By assigning specific tasks to purpose-built models, developers can always ensure that the right tool is used for each job, leading to more efficient, cost-effective, and higher-quality results. - return dict(genre=genre.result, plot=plot.result, title=title.result) +### 🎯 Outcome over process +ControlFlow defines AI workflows in terms of desired outcomes rather than writing prompts to steer LLM behavior. This **declarative, task-centric approach** lets developers focus on what needs to be done while letting the framework orchestrate agents to achieve those outcomes. -my_flow() -``` -## Why ControlFlow? - -Building AI applications with large language models (LLMs) is a complex endeavor. Many frameworks rely on monolithic "super-agents" that attempt to handle a wide range of tasks autonomously, but this approach often leads to opaque, hard-to-control workflows that are difficult to integrate with traditional software development practices. ControlFlow offers a better way, guided by three core design principles: - -1. **Specialized agents**: ControlFlow advocates for the use of specialized, single-purpose LLMs rather than monolithic models that try to do everything. By assigning specific tasks to purpose-built models, ControlFlow ensures that the right tool is used for each job, leading to more efficient, cost-effective, and higher-quality results. +### 🎛️ Control over autonomy +ControlFlow views agentic workflows as an extension of traditional software development practices. Instead of relying on end-to-end AI systems that make all workflow decisions autonomously, ControlFlow is **explicit by default**, allowing developers to delegate only as much work to AI as they require. This ensures that developers maintain visibility and control over their applications, as well as their preferred methods of testing and debugging. -2. **Declarative tasks**: ControlFlow embraces a declarative approach to defining AI workflows, allowing developers to focus on the desired outcomes rather than the intricacies of steering LLM behavior. By specifying tasks and their requirements using intuitive constructs like the `@task` decorator, developers can express what needs to be done without worrying about the details of how it will be accomplished. -3. **Integrated control**: ControlFlow recognizes the importance of balancing AI capabilities with traditional software development practices. Instead of relying on end-to-end AI systems that make all workflow decisions autonomously, ControlFlow allows developers to have as much or as little AI input as needed, ensuring that they maintain visibility and control over their applications. -These design principles manifest in several key features of ControlFlow: +## Why ControlFlow? +The three design principles of ControlFlow lead to a number of key features that make it a powerful tool for building AI-powered applications: -### Modular architecture -ControlFlow breaks down AI workflows into discrete, self-contained tasks, each with a specific objective and set of requirements. This modular approach promotes transparency, reusability, and maintainability, making it easier to develop, test, and optimize individual components of the AI workflow. +### 🧩 Task-centric architecture +ControlFlow breaks down AI workflows into discrete, self-contained tasks, each with a specific objective and set of requirements. This declarative, modular approach lets developers focus on the high-level logic of their applications while allowing the framework to manage the details of coordinating agents and data flow between tasks. -### Agent orchestration +### 🕵️ Agent orchestration ControlFlow's runtime engine handles the orchestration of specialized AI agents, assigning tasks to the most appropriate models and managing the flow of data between them. This orchestration layer abstracts away the complexities of coordinating multiple AI components, allowing developers to focus on the high-level logic of their applications. -### Native debugging and observability +### 🔍 Native debugging and observability ControlFlow prioritizes transparency and ease of debugging by providing native tools for monitoring and inspecting the execution of AI tasks. Developers can easily track the progress of their workflows, identify bottlenecks or issues, and gain insights into the behavior of individual agents, ensuring that their AI applications are functioning as intended. -### Seamless integration +### 🤝 Seamless integration ControlFlow is designed to integrate seamlessly with existing Python codebases, treating AI tasks as first-class citizens in the application logic. The `Task` class provides a clean interface for defining the inputs, outputs, and requirements of each task, making it easy to incorporate AI capabilities into traditional software workflows. This seamless integration allows for a gradual and controlled adoption of AI, reducing the risk and complexity of introducing AI into existing systems. -By adhering to these principles and leveraging these features, ControlFlow empowers developers to build AI applications that are more transparent, maintainable, and aligned with software engineering best practices. Whether you're looking to introduce AI capabilities into an existing system or build a new AI-powered application from scratch, ControlFlow provides a flexible, pragmatic, and developer-friendly framework for harnessing the power of LLMs while maintaining control and visibility over your workflow. With ControlFlow, you can focus on delivering high-quality AI solutions without sacrificing the robustness and reliability of traditional software development approaches. -## Key Concepts +## Key concepts + +### 🌊 Flow +Flows are containers for agentic workflows, and maintain consistent context and history across all of their tasks. + +### 🚦 Task +Tasks represent discrete objectives for agents to solve. By specifing the expected inputs and outputs, as well as any additional tools, instructions, or collaborators, tasks provide a clear structure for agents to follow. Completing its tasks is the primary objective of a ControlFlow agent. + +### 🤖 Agent +AI agents are assigned to tasks and responsible for completing them. Each agent is designed to be "single-serving," optimized only for completing its task in cooperation with other agents and the broader workflow. -- **Flow**: Flows are containers for agentic workflows, and maintain consistent context and history across all of their tasks. -- **Task**: Tasks represent discrete objectives for agents to solve. By specifing the expected inputs and outputs, as well as any additional tools, instructions, or collaborators, tasks provide a clear structure for agents to follow. Completing its tasks is the primary objective of a ControlFlow agent. +## Why not "super-agents"? -- **Agent**: AI agents are assigned to tasks and responsible for completing them. Each agent is designed to be "single-serving," optimized only for completing its task in cooperation with other agents and the broader workflow. +Many agentic LLM frameworks rely on monolithic "super-agents": powerful, unconstrained models that are expected to achieve their goals by autonomously handling a wide range of tasks, tools, and behaviors. The resulting workflows are opaque, unpredictable, and difficult to debug. -## Getting Started +This approach naively assumes that the technology is more advanced than it actually is. LLMs feel like magic because they can perform a wide variety of non-algorithmic tasks, but they are still fundamentally limited when it comes to generalizing beyond their traning data and techniques. Moreover, the failure modes of agentic LLMs are difficult to identify, let alone fix, making them difficult to trust in production environments or with mission-critical tasks. +## Getting started To get started with ControlFlow, install it using pip: @@ -73,13 +70,13 @@ pip install controlflow Check out the [Quickstart](quickstart.md) guide for a step-by-step walkthrough of creating your first ControlFlow application. -## Dive Deeper +## Dive deeper - Explore the [Concepts](concepts/index.md) section to learn more about the core components of ControlFlow. - Refer to the [API Reference](api/index.md) for detailed information on the classes and functions provided by the framework. - Browse the [Examples](examples/index.md) to see ControlFlow in action across various use cases. -## Get Involved +## Get involved ControlFlow is an open-source project, and we welcome contributions from the community. If you encounter a bug, have a feature request, or want to contribute code, please visit our [GitHub repository](https://github.com/jlowin/controlflow). diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 00000000..e556d660 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,43 @@ +site_name: ControlFlow +site_url: https://controlflow.ai +theme: + name: material + font: + text: Inter + palette: + scheme: default + primary: white + accent: light blue + features: + - navigation.instant + - navigation.instant.progress + - navigation.tabs + - navigation.tracking + # - navigation.sections + - search.suggest + - search.highlight + # - toc.integrate + - toc.follow +plugins: + - search + - social +markdown_extensions: + - abbr + - admonition + - attr_list + - md_in_html + - tables + - toc: + permalink: true + - pymdownx.emoji: + emoji_index: !!python/name:material.extensions.emoji.twemoji + emoji_generator: !!python/name:material.extensions.emoji.to_svg + - pymdownx.highlight: + anchor_linenums: true + - pymdownx.superfences + - pymdownx.inlinehilite + - pymdownx.keys + - pymdownx.tabbed: + alternate_style: true + - pymdownx.tasklist: + custom_checkbox: true diff --git a/pyproject.toml b/pyproject.toml index ed18ea4a..9b33854e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,13 @@ tests = [ "pytest-xdist", "pre-commit>=3.7.0", ] -dev = ["controlflow[tests]", "ipython>=8.22.2", "pdbpp>=0.10.3", "ruff>=0.3.4"] +dev = [ + "controlflow[tests]", + "ipython>=8.22.2", + "pdbpp>=0.10.3", + "ruff>=0.3.4", + "mkdocs-material>=9.5.21", +] [build-system] requires = ["hatchling"] diff --git a/requirements-dev.lock b/requirements-dev.lock index ec274063..cf3d8e5c 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -19,6 +19,7 @@ anyio==3.7.1 # via openai # via prefect # via starlette + # via watchfiles apprise==1.7.5 # via prefect asgi-lifespan==2.1.0 @@ -28,13 +29,30 @@ asttokens==2.4.1 asyncpg==0.29.0 # via prefect attrs==23.2.0 + # via cattrs + # via ddtrace # via jsonschema # via referencing - # via wmctrl +babel==2.15.0 + # via mkdocs-material +boto3==1.34.103 + # via moto +botocore==1.34.103 + # via boto3 + # via moto + # via s3transfer +bytecode==0.15.1 + # via ddtrace cachetools==5.3.3 # via google-auth # via marvin # via prefect +cairocffi==1.7.0 + # via cairosvg +cairosvg==2.7.1 + # via prefect +cattrs==23.2.3 + # via ddtrace certifi==2024.2.2 # via apprise # via httpcore @@ -42,6 +60,7 @@ certifi==2024.2.2 # via kubernetes # via requests cffi==1.16.0 + # via cairocffi # via cryptography cfgv==3.4.0 # via pre-commit @@ -49,23 +68,41 @@ charset-normalizer==3.3.2 # via requests click==8.1.7 # via apprise + # via mkdocs + # via mkdocstrings # via prefect # via typer-slim # via uvicorn cloudpickle==3.0.0 # via prefect +codespell==2.2.6 + # via prefect colorama==0.4.6 # via griffe + # via mkdocs-material coolname==2.2.0 # via prefect +coverage==7.5.1 + # via pytest-cov croniter==2.0.3 # via prefect cryptography==42.0.5 + # via moto # via prefect +cssselect2==0.7.0 + # via cairosvg dateparser==1.2.0 # via prefect +ddsketch==3.0.1 + # via ddtrace +ddtrace==2.8.4 + # via prefect decorator==5.1.1 # via ipython +defusedxml==0.7.1 + # via cairosvg +deprecated==1.2.14 + # via opentelemetry-api distlib==0.3.8 # via virtualenv distro==1.9.0 @@ -76,16 +113,20 @@ docker==6.1.3 # via prefect email-validator==2.1.1 # via pydantic +envier==0.5.1 + # via ddtrace +execnet==2.1.1 + # via pytest-xdist executing==2.0.1 # via stack-data -fancycompleter==0.9.1 - # via pdbpp fastapi==0.110.0 # via marvin filelock==3.13.3 # via virtualenv fsspec==2024.3.1 # via prefect +ghp-import==2.1.0 + # via mkdocs google-auth==2.29.0 # via kubernetes graphviz==0.20.3 @@ -93,6 +134,7 @@ graphviz==0.20.3 greenlet==3.0.3 # via sqlalchemy griffe==0.42.1 + # via mkdocstrings-python # via prefect h11==0.14.0 # via httpcore @@ -108,6 +150,10 @@ httpx==0.27.0 # via marvin # via openai # via prefect + # via respx +humanize==4.9.0 + # via jinja2-humanize-extension + # via prefect hyperframe==6.0.1 # via h2 identify==2.5.35 @@ -117,18 +163,34 @@ idna==3.6 # via email-validator # via httpx # via requests +importlib-metadata==7.0.0 + # via mike + # via opentelemetry-api importlib-resources==6.1.3 + # via mike # via prefect iniconfig==2.0.0 # via pytest ipython==8.22.2 + # via prefect itsdangerous==2.1.2 # via prefect jedi==0.19.1 # via ipython jinja2==3.1.3 + # via jinja2-humanize-extension # via marvin + # via mike + # via mkdocs + # via mkdocs-material + # via mkdocstrings + # via moto + # via prefect +jinja2-humanize-extension==0.4.0 # via prefect +jmespath==1.0.1 + # via boto3 + # via botocore jsonpatch==1.33 # via marvin # via prefect @@ -144,55 +206,114 @@ mako==1.3.2 # via alembic markdown==3.6 # via apprise + # via mkdocs + # via mkdocs-autorefs + # via mkdocs-material + # via mkdocstrings + # via pymdown-extensions markdown-it-py==3.0.0 # via rich markupsafe==2.1.5 # via jinja2 # via mako -marvin==2.3.1 + # via mkdocs + # via mkdocs-autorefs + # via mkdocstrings + # via werkzeug +marvin @ git+https://github.com/prefecthq/marvin@8c0c083aab5c9c2ca6f800fd392bef2a5d3dd9ca # via control-flow matplotlib-inline==0.1.6 # via ipython mdurl==0.1.2 # via markdown-it-py +mergedeep==1.3.4 + # via mkdocs + # via mkdocs-get-deps +mike==2.1.1 + # via prefect +mkdocs==1.6.0 + # via mike + # via mkdocs-autorefs + # via mkdocs-gen-files + # via mkdocs-material + # via mkdocstrings + # via prefect +mkdocs-autorefs==1.0.1 + # via mkdocstrings +mkdocs-gen-files==0.5.0 + # via prefect +mkdocs-get-deps==0.2.0 + # via mkdocs +mkdocs-material==9.5.21 + # via prefect +mkdocs-material-extensions==1.3.1 + # via mkdocs-material +mkdocstrings==0.25.1 + # via mkdocstrings-python +mkdocstrings-python==1.9.2 + # via prefect +moto==5.0.6 + # via prefect +mypy==1.10.0 + # via prefect +mypy-extensions==1.0.0 + # via mypy nodeenv==1.8.0 # via pre-commit +numpy==1.26.4 + # via prefect oauthlib==3.2.2 # via kubernetes # via requests-oauthlib -openai==1.14.3 +openai==1.28.1 # via marvin +opentelemetry-api==1.24.0 + # via ddtrace orjson==3.10.0 # via prefect packaging==24.0 # via docker + # via mkdocs # via prefect # via pytest +paginate==0.5.6 + # via mkdocs-material parso==0.8.3 # via jedi partialjson==0.0.7 # via marvin pathspec==0.12.1 + # via mkdocs # via prefect -pdbpp==0.10.3 pendulum==3.0.0 # via prefect pexpect==4.9.0 # via ipython +pillow==10.3.0 + # via cairosvg + # via prefect platformdirs==4.2.0 + # via mkdocs-get-deps + # via mkdocstrings # via virtualenv pluggy==1.4.0 + # via prefect # via pytest pre-commit==3.7.0 -prefect @ git+https://github.com/prefecthq/prefect@a7f93ae5e84a11d79c43bf5b9dfeff926c3a0eca + # via prefect +prefect @ git+https://github.com/prefecthq/prefect@3f5d6afbc4e1b5cea416c64d28e4b6feb7c2d656 # via control-flow prompt-toolkit==3.0.43 # via ipython # via marvin +protobuf==5.26.1 + # via ddtrace ptyprocess==0.7.0 # via pexpect pure-eval==0.2.2 # via stack-data +py-cpuinfo==9.0.0 + # via pytest-benchmark pyasn1==0.6.0 # via pyasn1-modules # via rsa @@ -214,15 +335,43 @@ pydantic-settings==2.2.1 # via marvin pygments==2.17.2 # via ipython - # via pdbpp + # via mkdocs-material # via rich -pyrepl==0.9.0 - # via fancycompleter -pytest==8.1.1 +pymdown-extensions==10.8.1 + # via mkdocs-material + # via mkdocstrings +pyparsing==3.1.2 + # via mike +pytest==7.4.4 + # via prefect + # via pytest-asyncio + # via pytest-benchmark + # via pytest-cov + # via pytest-env + # via pytest-flakefinder + # via pytest-timeout + # via pytest-xdist +pytest-asyncio==0.21.2 + # via prefect +pytest-benchmark==4.0.0 + # via prefect +pytest-cov==5.0.0 + # via prefect +pytest-env==1.1.3 + # via prefect +pytest-flakefinder==1.1.0 + # via prefect +pytest-timeout==2.3.1 + # via prefect +pytest-xdist==3.3.1 + # via prefect python-dateutil==2.9.0.post0 + # via botocore # via croniter # via dateparser + # via ghp-import # via kubernetes + # via moto # via pendulum # via prefect # via time-machine @@ -232,6 +381,8 @@ python-multipart==0.0.9 # via prefect python-slugify==8.0.4 # via prefect +pytkdocs==0.16.1 + # via prefect pytz==2024.1 # via croniter # via dateparser @@ -239,8 +390,17 @@ pytz==2024.1 pyyaml==6.0.1 # via apprise # via kubernetes + # via mike + # via mkdocs + # via mkdocs-get-deps # via pre-commit # via prefect + # via pymdown-extensions + # via pyyaml-env-tag + # via responses +pyyaml-env-tag==0.1 + # via mike + # via mkdocs readchar==4.0.6 # via prefect referencing==0.34.0 @@ -248,16 +408,25 @@ referencing==0.34.0 # via jsonschema-specifications regex==2023.12.25 # via dateparser + # via mkdocs-material # via tiktoken requests==2.31.0 # via apprise # via docker # via kubernetes + # via mkdocs-material + # via moto + # via prefect # via requests-oauthlib + # via responses # via tiktoken requests-oauthlib==2.0.0 # via apprise # via kubernetes +responses==0.25.0 + # via moto +respx==0.21.1 + # via prefect rfc3339-validator==0.1.4 # via prefect rich==13.7.1 @@ -274,13 +443,19 @@ ruamel-yaml==0.18.6 ruamel-yaml-clib==0.2.8 # via ruamel-yaml ruff==0.3.4 + # via prefect +s3transfer==0.10.1 + # via boto3 setuptools==69.2.0 + # via ddtrace # via nodeenv # via readchar shellingham==1.5.4 # via typer-slim six==1.16.0 # via asttokens + # via ddsketch + # via ddtrace # via kubernetes # via python-dateutil # via rfc3339-validator @@ -293,6 +468,8 @@ sniffio==1.3.1 sqlalchemy==2.0.29 # via alembic # via prefect +sqlparse==0.5.0 + # via ddtrace stack-data==0.6.3 # via ipython starlette==0.36.3 @@ -303,6 +480,9 @@ tiktoken==0.6.0 # via marvin time-machine==2.14.1 # via pendulum +tinycss2==1.3.0 + # via cairosvg + # via cssselect2 toml==0.10.2 # via prefect tqdm==4.66.2 @@ -318,11 +498,17 @@ typer-cli==0.12.0 typer-slim==0.12.0 # via typer # via typer-cli +types-cachetools==5.3.0.7 + # via prefect +types-pyyaml==6.0.12.20240311 + # via prefect typing-extensions==4.10.0 # via aiosqlite # via alembic + # via ddtrace # via fastapi # via marvin + # via mypy # via openai # via prefect # via pydantic @@ -337,20 +523,41 @@ tzlocal==5.2 ujson==5.9.0 # via prefect urllib3==2.2.1 + # via botocore # via docker # via kubernetes # via requests + # via responses uvicorn==0.28.1 # via marvin # via prefect +vermin==1.6.0 + # via prefect +verspec==0.1.0 + # via mike virtualenv==20.25.1 # via pre-commit + # via prefect +watchdog==4.0.0 + # via mkdocs +watchfiles==0.21.0 + # via prefect wcwidth==0.2.13 # via prompt-toolkit +webencodings==0.5.1 + # via cssselect2 + # via tinycss2 websocket-client==1.7.0 # via docker # via kubernetes websockets==12.0 # via prefect -wmctrl==0.5 - # via pdbpp +werkzeug==3.0.3 + # via moto +wrapt==1.16.0 + # via deprecated +xmltodict==0.13.0 + # via ddtrace + # via moto +zipp==3.18.1 + # via importlib-metadata diff --git a/requirements.lock b/requirements.lock index 37f8f4f6..c261dff4 100644 --- a/requirements.lock +++ b/requirements.lock @@ -19,19 +19,40 @@ anyio==3.7.1 # via openai # via prefect # via starlette + # via watchfiles apprise==1.7.5 # via prefect asgi-lifespan==2.1.0 # via prefect +asttokens==2.4.1 + # via stack-data asyncpg==0.29.0 # via prefect attrs==23.2.0 + # via cattrs + # via ddtrace # via jsonschema # via referencing +babel==2.15.0 + # via mkdocs-material +boto3==1.34.103 + # via moto +botocore==1.34.103 + # via boto3 + # via moto + # via s3transfer +bytecode==0.15.1 + # via ddtrace cachetools==5.3.3 # via google-auth # via marvin # via prefect +cairocffi==1.7.0 + # via cairosvg +cairosvg==2.7.1 + # via prefect +cattrs==23.2.3 + # via ddtrace certifi==2024.2.2 # via apprise # via httpcore @@ -39,26 +60,51 @@ certifi==2024.2.2 # via kubernetes # via requests cffi==1.16.0 + # via cairocffi # via cryptography +cfgv==3.4.0 + # via pre-commit charset-normalizer==3.3.2 # via requests click==8.1.7 # via apprise + # via mkdocs + # via mkdocstrings # via prefect # via typer-slim # via uvicorn cloudpickle==3.0.0 # via prefect +codespell==2.2.6 + # via prefect colorama==0.4.6 # via griffe + # via mkdocs-material coolname==2.2.0 # via prefect +coverage==7.5.1 + # via pytest-cov croniter==2.0.3 # via prefect cryptography==42.0.5 + # via moto # via prefect +cssselect2==0.7.0 + # via cairosvg dateparser==1.2.0 # via prefect +ddsketch==3.0.1 + # via ddtrace +ddtrace==2.8.4 + # via prefect +decorator==5.1.1 + # via ipython +defusedxml==0.7.1 + # via cairosvg +deprecated==1.2.14 + # via opentelemetry-api +distlib==0.3.8 + # via virtualenv distro==1.9.0 # via openai dnspython==2.6.1 @@ -67,10 +113,20 @@ docker==6.1.3 # via prefect email-validator==2.1.1 # via pydantic +envier==0.5.1 + # via ddtrace +execnet==2.1.1 + # via pytest-xdist +executing==2.0.1 + # via stack-data fastapi==0.110.0 # via marvin +filelock==3.14.0 + # via virtualenv fsspec==2024.3.1 # via prefect +ghp-import==2.1.0 + # via mkdocs google-auth==2.29.0 # via kubernetes graphviz==0.20.3 @@ -78,6 +134,7 @@ graphviz==0.20.3 greenlet==3.0.3 # via sqlalchemy griffe==0.42.1 + # via mkdocstrings-python # via prefect h11==0.14.0 # via httpcore @@ -93,20 +150,47 @@ httpx==0.27.0 # via marvin # via openai # via prefect + # via respx +humanize==4.9.0 + # via jinja2-humanize-extension + # via prefect hyperframe==6.0.1 # via h2 +identify==2.5.36 + # via pre-commit idna==3.6 # via anyio # via email-validator # via httpx # via requests +importlib-metadata==7.0.0 + # via mike + # via opentelemetry-api importlib-resources==6.1.3 + # via mike + # via prefect +iniconfig==2.0.0 + # via pytest +ipython==8.24.0 # via prefect itsdangerous==2.1.2 # via prefect +jedi==0.19.1 + # via ipython jinja2==3.1.3 + # via jinja2-humanize-extension # via marvin + # via mike + # via mkdocs + # via mkdocs-material + # via mkdocstrings + # via moto # via prefect +jinja2-humanize-extension==0.4.0 + # via prefect +jmespath==1.0.1 + # via boto3 + # via botocore jsonpatch==1.33 # via marvin # via prefect @@ -122,35 +206,114 @@ mako==1.3.2 # via alembic markdown==3.6 # via apprise + # via mkdocs + # via mkdocs-autorefs + # via mkdocs-material + # via mkdocstrings + # via pymdown-extensions markdown-it-py==3.0.0 # via rich markupsafe==2.1.5 # via jinja2 # via mako -marvin==2.3.1 + # via mkdocs + # via mkdocs-autorefs + # via mkdocstrings + # via werkzeug +marvin @ git+https://github.com/prefecthq/marvin@8c0c083aab5c9c2ca6f800fd392bef2a5d3dd9ca # via control-flow +matplotlib-inline==0.1.7 + # via ipython mdurl==0.1.2 # via markdown-it-py +mergedeep==1.3.4 + # via mkdocs + # via mkdocs-get-deps +mike==2.1.1 + # via prefect +mkdocs==1.6.0 + # via mike + # via mkdocs-autorefs + # via mkdocs-gen-files + # via mkdocs-material + # via mkdocstrings + # via prefect +mkdocs-autorefs==1.0.1 + # via mkdocstrings +mkdocs-gen-files==0.5.0 + # via prefect +mkdocs-get-deps==0.2.0 + # via mkdocs +mkdocs-material==9.5.21 + # via prefect +mkdocs-material-extensions==1.3.1 + # via mkdocs-material +mkdocstrings==0.25.1 + # via mkdocstrings-python +mkdocstrings-python==1.9.2 + # via prefect +moto==5.0.6 + # via prefect +mypy==1.10.0 + # via prefect +mypy-extensions==1.0.0 + # via mypy +nodeenv==1.8.0 + # via pre-commit +numpy==1.26.4 + # via prefect oauthlib==3.2.2 # via kubernetes # via requests-oauthlib -openai==1.14.3 +openai==1.28.1 # via marvin +opentelemetry-api==1.24.0 + # via ddtrace orjson==3.10.0 # via prefect packaging==24.0 # via docker + # via mkdocs # via prefect + # via pytest +paginate==0.5.6 + # via mkdocs-material +parso==0.8.4 + # via jedi partialjson==0.0.7 # via marvin pathspec==0.12.1 + # via mkdocs # via prefect pendulum==3.0.0 # via prefect -prefect @ git+https://github.com/prefecthq/prefect@a7f93ae5e84a11d79c43bf5b9dfeff926c3a0eca +pexpect==4.9.0 + # via ipython +pillow==10.3.0 + # via cairosvg + # via prefect +platformdirs==4.2.1 + # via mkdocs-get-deps + # via mkdocstrings + # via virtualenv +pluggy==1.5.0 + # via prefect + # via pytest +pre-commit==3.7.1 + # via prefect +prefect @ git+https://github.com/prefecthq/prefect@3f5d6afbc4e1b5cea416c64d28e4b6feb7c2d656 # via control-flow prompt-toolkit==3.0.43 + # via ipython # via marvin +protobuf==5.26.1 + # via ddtrace +ptyprocess==0.7.0 + # via pexpect +pure-eval==0.2.2 + # via stack-data +py-cpuinfo==9.0.0 + # via pytest-benchmark pyasn1==0.6.0 # via pyasn1-modules # via rsa @@ -171,11 +334,44 @@ pydantic-core==2.16.3 pydantic-settings==2.2.1 # via marvin pygments==2.17.2 + # via ipython + # via mkdocs-material # via rich +pymdown-extensions==10.8.1 + # via mkdocs-material + # via mkdocstrings +pyparsing==3.1.2 + # via mike +pytest==7.4.4 + # via prefect + # via pytest-asyncio + # via pytest-benchmark + # via pytest-cov + # via pytest-env + # via pytest-flakefinder + # via pytest-timeout + # via pytest-xdist +pytest-asyncio==0.21.2 + # via prefect +pytest-benchmark==4.0.0 + # via prefect +pytest-cov==5.0.0 + # via prefect +pytest-env==1.1.3 + # via prefect +pytest-flakefinder==1.1.0 + # via prefect +pytest-timeout==2.3.1 + # via prefect +pytest-xdist==3.3.1 + # via prefect python-dateutil==2.9.0.post0 + # via botocore # via croniter # via dateparser + # via ghp-import # via kubernetes + # via moto # via pendulum # via prefect # via time-machine @@ -185,6 +381,8 @@ python-multipart==0.0.9 # via prefect python-slugify==8.0.4 # via prefect +pytkdocs==0.16.1 + # via prefect pytz==2024.1 # via croniter # via dateparser @@ -192,7 +390,17 @@ pytz==2024.1 pyyaml==6.0.1 # via apprise # via kubernetes - # via prefect + # via mike + # via mkdocs + # via mkdocs-get-deps + # via pre-commit + # via prefect + # via pymdown-extensions + # via pyyaml-env-tag + # via responses +pyyaml-env-tag==0.1 + # via mike + # via mkdocs readchar==4.0.6 # via prefect referencing==0.34.0 @@ -200,16 +408,25 @@ referencing==0.34.0 # via jsonschema-specifications regex==2023.12.25 # via dateparser + # via mkdocs-material # via tiktoken requests==2.31.0 # via apprise # via docker # via kubernetes + # via mkdocs-material + # via moto + # via prefect # via requests-oauthlib + # via responses # via tiktoken requests-oauthlib==2.0.0 # via apprise # via kubernetes +responses==0.25.0 + # via moto +respx==0.21.1 + # via prefect rfc3339-validator==0.1.4 # via prefect rich==13.7.1 @@ -225,11 +442,20 @@ ruamel-yaml==0.18.6 # via prefect ruamel-yaml-clib==0.2.8 # via ruamel-yaml +ruff==0.4.4 + # via prefect +s3transfer==0.10.1 + # via boto3 setuptools==69.2.0 + # via ddtrace + # via nodeenv # via readchar shellingham==1.5.4 # via typer-slim six==1.16.0 + # via asttokens + # via ddsketch + # via ddtrace # via kubernetes # via python-dateutil # via rfc3339-validator @@ -242,6 +468,10 @@ sniffio==1.3.1 sqlalchemy==2.0.29 # via alembic # via prefect +sqlparse==0.5.0 + # via ddtrace +stack-data==0.6.3 + # via ipython starlette==0.36.3 # via fastapi text-unidecode==1.3 @@ -250,10 +480,16 @@ tiktoken==0.6.0 # via marvin time-machine==2.14.1 # via pendulum +tinycss2==1.3.0 + # via cairosvg + # via cssselect2 toml==0.10.2 # via prefect tqdm==4.66.2 # via openai +traitlets==5.14.3 + # via ipython + # via matplotlib-inline typer==0.12.0 # via marvin # via prefect @@ -262,11 +498,17 @@ typer-cli==0.12.0 typer-slim==0.12.0 # via typer # via typer-cli +types-cachetools==5.3.0.7 + # via prefect +types-pyyaml==6.0.12.20240311 + # via prefect typing-extensions==4.10.0 # via aiosqlite # via alembic + # via ddtrace # via fastapi # via marvin + # via mypy # via openai # via prefect # via pydantic @@ -281,16 +523,41 @@ tzlocal==5.2 ujson==5.9.0 # via prefect urllib3==2.2.1 + # via botocore # via docker # via kubernetes # via requests + # via responses uvicorn==0.28.1 # via marvin # via prefect +vermin==1.6.0 + # via prefect +verspec==0.1.0 + # via mike +virtualenv==20.26.1 + # via pre-commit + # via prefect +watchdog==4.0.0 + # via mkdocs +watchfiles==0.21.0 + # via prefect wcwidth==0.2.13 # via prompt-toolkit +webencodings==0.5.1 + # via cssselect2 + # via tinycss2 websocket-client==1.7.0 # via docker # via kubernetes websockets==12.0 # via prefect +werkzeug==3.0.3 + # via moto +wrapt==1.16.0 + # via deprecated +xmltodict==0.13.0 + # via ddtrace + # via moto +zipp==3.18.1 + # via importlib-metadata From e9f45e4276d5a1922689ae8d4acf32b36a5bbab7 Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Date: Sun, 12 May 2024 21:53:15 -0400 Subject: [PATCH 2/2] add best practices notes --- docs/guides/best_practices.md | 8 ++++++++ docs/index.md | 4 +--- mkdocs.yml | 1 + 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/guides/best_practices.md b/docs/guides/best_practices.md index e69de29b..85348950 100644 --- a/docs/guides/best_practices.md +++ b/docs/guides/best_practices.md @@ -0,0 +1,8 @@ +# Best Practices + +## Designing workflows +- Break down sequences into discrete tasks, even if they could be sent as a single prompt to an LLM. This forces the LLM to output intermediate results, which enhance the quality of the final output. This is akin to implementing "chain of thoughts" or similar techniques, but in a more controllable way. +- Use the task objective to describe the desired output; use task instructions to provide context and constraints. This helps the LLM understand the goal and the constraints it should adhere to. + +## Agents +- An agent's `name` and `description` are visible to all other agents; its `instructions` are private and only visible to itself. \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index 47c477fa..9fbbff63 100644 --- a/docs/index.md +++ b/docs/index.md @@ -6,9 +6,7 @@ ControlFlow provides a structured and intuitive way to create complex AI-powered !!! question "What's an agentic workflow?" - An agentic workflow is a process that treats LLMs as autonomous entities capable of making decisions and performing complex tasks through iterative interactions. - - + An agentic workflow treats LLMs as autonomous entities capable of making decisions and performing complex tasks through iterative interactions. At least some of the workflow logic is carried out by the LLMs themselves. ## Design principles diff --git a/mkdocs.yml b/mkdocs.yml index e556d660..29533b9c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -29,6 +29,7 @@ markdown_extensions: - tables - toc: permalink: true + toc_depth: 3 - pymdownx.emoji: emoji_index: !!python/name:material.extensions.emoji.twemoji emoji_generator: !!python/name:material.extensions.emoji.to_svg