Brock
10/02/2024, 7:07 PMJeremiah
import controlflow as cf
agent = cf.Agent(name='My Agent')
@cf.flow
def do_stuff(files: list[str]):
file_contents = []
for file in files:
file_contents.append(open(file).read())
return cf.run(
"analyze the file contents",
agent=agent,
context=dict(file_contents=file_contents)
)
Jeremiah
@cf.flow
decorator, only the flow context manager, which is an important oversight especially if you're thinking of threads the way the Assistants API worksJeremiah
flow
indicates that all CF tasks
in that function will be run in the same thread. You can provide a thread ID to a flow when you call it in order to load history from any previous flows run with that same thread ID
• inside the flow function, run whatever Python you want, including creating and running controlflow tasks. Each controlflow task delegates to an LLM agent, and asks it to use tools and available context to complete the task. The LLM make take many steps to complete the task (e.g. it may use 3 tools in a row), similar to how the Assistants API may take many steps to complete a "run"Jeremiah
Brock
10/02/2024, 8:57 PM@task
in the pipeline?
Also, as I am typing this, a separate question would be if its fair to say that the task in controlflow is intended to invoke a "chat completion" like response from an LLM. As opposed to say, invoking the run of a thread on OpenAI which is directionally similar but have different pathways for managing the prompt and other info (tools, files, etc.).
I fully admit my brain my be locked into my old approach and the steps of the Assistants API, and that may be hindering my review of controlflow, but that is the framing for my questions.Jeremiah
Task
is actually much closer to a "run" of an Assistants API thread than a chat completion in that when you call cf.run()
or Task.run()
your agent may take multiple actions, use multiple tools, etc. before it marks the task as complete. A task is sort of like a more structured version of kicking off an assistants API run. Unlike the assistants API, you can provide tools and context on a per-task basis instead of on a per-agent basis (though you can also give an agent tools!)
• To supply tools to a task:
cf.Task( # or cf.run to run immediatley
...,
tools=[pythonfn_1, python_fn_2, ...]
)
• To supply information to a task:
cf.Task( # or cf.run to run immediatley
...,
context=dict(
foo="foo",
bar="bar",
)
• So you can use tools
to let the agent interface with a system by caling an arbitrary function; and you can use context
to supply information directly to the agent.
• So to mimic the file API for assistants, you have two approaches:
◦ in normal python, load the files, extract relevant parts by any means you prefer, then provide them to your agent as context. This has the advantage of being straightforward and simple, but it makes it more complicated to let your agent decide what to look for in the files
◦ write a python function that takes a query string and searches the files, returning any relevant data. provide that function to your agent or to the task. Now the agent can decide to use that function if relevant, which is very similar to the assistants API's behaviorJeremiah
Brock
10/02/2024, 10:57 PM