Skip to content

Commit

Permalink
[cfi] update + batched in cf utils
Browse files Browse the repository at this point in the history
  • Loading branch information
yashbonde committed Oct 23, 2023
1 parent 3f223ce commit 077774a
Show file tree
Hide file tree
Showing 18 changed files with 130 additions and 1,019 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,5 @@ private.sh
api_docs/_build/
api_docs/_static/
cf
locust_file.py
demo/
logs.py
2 changes: 1 addition & 1 deletion api_docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
project = "ChainFury"
copyright = "2023, NimbleBox Engineering"
author = "NimbleBox Engineering"
release = "1.6.0"
release = "1.6.1"

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
Expand Down
56 changes: 56 additions & 0 deletions api_docs/examples/agent-theory.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
Fury Agents Manifesto
=====================

**Starting date: 21st October, 2023**


ChainFury's `first commit`_ was on 7th April, 2023. It has been about 6 months since then and it has undergone lot of
production usage. With multiple API changes and engines, we are now at a stable place. This is also a good time to check
up on the things that have released in the wild till now.

tl;dr
-----

Predictable automated chains as agents, that use tree searching algorithms to find solution to a problem with given set
of actions. Has ability to create new actions and learn from feedback.

Agents
------

There have been several "agent like" systems that have been released. Some can create code, others can perform advanced
searching. Ultimately all of them can be modelled as a Chain and use different algorithms. ``chainfury`` can support
all algorithms and has a type-based robust chaining engine. This means building agents is the next logical step. There
is a lot of theory and academic research done on the topic of agents. All of them have different tradeoffs. But first
let's start with the requirements of an agent.

* Agent should be able to execute task without human intervention
* Agent should stop when it can't proceed
* Agent should be interruptible to take in feedback
* Agent should take inputs from it's environment
* Agent should be able to remember things over time
* Agent should be predictable in its behaviour, debuggable

Von-Neumann machine
~~~~~~~~~~~~~~~~~~~

We are followers of the agent as a `Von-Neumann machine`_, which means each chain has a complete I/O mechanism where
each input and output can be accessed independently. ``chainfury`` can use different memory systems like VectorDB, etc.
meaning that it can persist data over time. For the CPU analogy we have :py:mod:`chainfury.base.Chain` which models the
execution as a DAG of :py:class:`chainfury.base.Node` objects. Each node contains the unit step of the chain. We can
parallellise and speed up executions by using :py:mod:`chainfury.utils.threaded_map`.

``chainfury`` is already being used in production and thus with the infrastructure layer sorted we can then think about
what to build on top of it.

Automated
~~~~~~~~~

One of the most important things is that these agents be automated and run without human in the loop.

Edits
-----

.. all the links here
.. _first commit: https://github.com/NimbleBoxAI/ChainFury/commit/64a5f7b0fcf3d8bcce0cde6ee974b659ebe01b68
.. _Von-Neumann machine: https://blog.nimblebox.ai/new-flow-engine-from-scratch
4 changes: 2 additions & 2 deletions api_docs/examples/qa-rag.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Question Answering using ChainFury
==================================
(RAG) Q/A with ChainFury
========================

One of the first use cases of LLM powered apps is question answering. This is how you should think about this problem:

Expand Down
6 changes: 6 additions & 0 deletions api_docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ Read the latest blog posts:
source/chainfury.components
examples/components-list

.. toctree::
:maxdepth: 2
:caption: Research

examples/agent-theory

.. toctree::
:maxdepth: 2
:caption: Server
Expand Down
2 changes: 1 addition & 1 deletion cf_internal
1 change: 1 addition & 0 deletions chainfury/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
Node,
Model,
Var,
Chain,
)

# Models
Expand Down
113 changes: 0 additions & 113 deletions chainfury/components/nbx/__init__.py

This file was deleted.

2 changes: 1 addition & 1 deletion chainfury/components/stability/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
You need to have `stability_sdk` installed to use this component. You can install it with:
.. code-block:: bash
pip install chainfury[stability]
# or to install all the components, note this will keep on growing
pip install chainfury[all]
Expand Down
54 changes: 51 additions & 3 deletions chainfury/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,10 @@ def get_logger() -> logging.Logger:
logger.setLevel(getattr(logging, lvl))
log_handler = logging.StreamHandler()
log_handler.setFormatter(
logging.Formatter("[%(asctime)s] [%(levelname)s] [%(filename)s:%(lineno)d] %(message)s", datefmt="%Y-%m-%dT%H:%M:%S%z")
logging.Formatter(
"[%(asctime)s] [%(levelname)s] [%(filename)s:%(lineno)d] %(message)s",
datefmt="%Y-%m-%dT%H:%M:%S%z",
)
)
logger.addHandler(log_handler)
return logger
Expand Down Expand Up @@ -208,14 +211,15 @@ def exponential_backoff(foo, *args, max_retries=2, retry_delay=1, **kwargs) -> D

def get_files_in_folder(
folder,
ext=["*"],
ext="*",
ig_pat: str = "",
abs_path: bool = True,
followlinks: bool = False,
) -> List[str]:
"""Get files with `ext` in `folder`"""
# this method is faster than glob
all_paths = []
ext = [ext] if isinstance(ext, str) else ext
_all = "*" in ext # wildcard means everything so speed up
ignore_pat = re.compile(ig_pat)

Expand Down Expand Up @@ -252,7 +256,9 @@ def joinp(x: str, *args) -> str:
"""


def threaded_map(fn, inputs: List[Tuple[Any]], wait: bool = True, max_threads=20, _name: str = "") -> Union[Dict[Future, int], List[Any]]:
def threaded_map(
fn, inputs: List[Tuple], wait: bool = True, max_threads=20, post_fn=None, _name: str = ""
) -> Union[Dict[Future, int], List[Any]]:
"""
inputs is a list of tuples, each tuple is the input for single invocation of fn. order is preserved.
Expand All @@ -261,6 +267,7 @@ def threaded_map(fn, inputs: List[Tuple[Any]], wait: bool = True, max_threads=20
inputs (List[Tuple[Any]]): All the inputs to the function, can be a generator
wait (bool, optional): If true, wait for all the threads to finish, otherwise return a dict of futures. Defaults to True.
max_threads (int, optional): The maximum number of threads to use. Defaults to 20.
post_fn (function, optional): A function to call with the result. Defaults to None.
_name (str, optional): The name of the thread pool. Defaults to "".
"""
_name = _name or str(uuid4())
Expand All @@ -273,12 +280,48 @@ def threaded_map(fn, inputs: List[Tuple[Any]], wait: bool = True, max_threads=20
for future in as_completed(futures):
try:
i, res = future.result()
if post_fn:
res = post_fn(res)
results[i] = res
except Exception as e:
raise e
return results


def batched(iterable, n):
"""Convert any ``iterable`` to a generator of batches of size ``n``, last one may be smaller.
Python 3.12 has ``itertools.batched`` which does the same thing.
Example:
>>> for x in batched(range(10), 3):
... print(x)
[0, 1, 2]
[3, 4, 5]
[6, 7, 8]
[9]
Args:
iterable (Iterable): The iterable to convert to batches
n (int): The batch size
Yields:
Iterator: The batched iterator
"""
done = False
buffer = []
_iter = iter(iterable)
while not done:
try:
buffer.append(next(_iter))
if len(buffer) == n:
yield buffer
buffer = []
except StopIteration:
done = True
if buffer:
yield buffer


"""
Ser/Deser
"""
Expand Down Expand Up @@ -326,6 +369,11 @@ def from_json(fp: str = "") -> Dict[str, Any]:
return json.loads(fp)


"""
Time management should be dead easy.
"""


class SimplerTimes:
"""
A class that provides a simpler interface to datetime and time modules.
Expand Down
2 changes: 1 addition & 1 deletion chainfury/version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "1.6.0"
__version__ = "1.6.1"
_major, _minor, _patch = __version__.split(".")
_major = int(_major)
_minor = int(_minor)
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "chainfury"
version = "1.6.0"
version = "1.6.1"
description = "ChainFury is a powerful tool that simplifies the creation and management of chains of prompts, making it easier to build complex chat applications using LLMs."
authors = ["NimbleBox Engineering <[email protected]>"]
license = "Apache 2.0"
Expand Down
Loading

0 comments on commit 077774a

Please sign in to comment.