Iterating, Debugging, Testing, Mocking
The 6 principles behind Chains
Atomic components
Modular scaling
Maximum composability
Type safety and validation
Local debugging
Incremental adoption
__main__
section: the Chains
framework runs various validations at
to help
you catch issues early.Additionally, running mypy
and fixing reported type errors can help you
find problems early in a rapid feedback loop, before attempting a (much
slower) deployment.__main__()
module is run, local instances of the Chainlets are
created, allowing you to test functionality of your chain just by executing the
Python file:
run_local()
to run your code locally requires that your development
environment have the compute resources and dependencies that each Chainlet
needs. But that often isn’t possible when building with AI models.
Chains offers a workaround, mocking, to let you test the coordination and
business logic of your multi-step inference pipeline without worrying about
running the model locally.
The second example in the getting started guide
implements a Truss Chain for generating poems with Phi-3.
This Chain has two Chainlets:
PhiLLM
Chainlet, which requires an NVIDIA A10G GPU.PoemGenerator
Chainlet, which easily runs on a CPU.PhiLLM
Chainlet that is infeasible to run locally so that we can
quickly test the PoemGenerator
Chainlet.
To do this, we define a mock Phi-3 model in our __main__
module and give it
a run_remote()
method that
produces a test output that matches the output type we expect from the real
Chainlet. Then, we inject an instance of this mock Chainlet into our Chain:
phi_llm
expects a type PhiLLM
, while we
pass an instance of FakePhiLLM
. These aren’t the same, which is formally a
type error.
However, this works at runtime because we constructed FakePhiLLM
to
implement the same protocol as the real thing. We can make this explicit by
defining a Protocol
as a type annotation:
PoemGenerator
: