Package: rigging
RiggingRigging is a lightweight LLM interaction framework built on Pydantic XML and LiteLLM. It supports useful primitives for validating LLM output and adding tool calling abilities to models that don't natively support it. It also has various helpers for common tasks like structured object parsing, templating chats, overloading generation parameters, stripping chat segments, and continuing conversations.Modern python with type hints, pydantic validation, native serialization support, etc.Basic Chatsimportriggingasrggenerator=rg.get_generator("claude-2.1")chat=generator.chat([{"role":"system","content":"You are a wizard harry."},{"role":"user","content":"Say hello!"},]).run()print(chat.last)# [assistant]: Hello!print(f"{chat.last!r}")# Message(role='assistant', parts=[], content='Hello!')print(chat.prev)# [#   Message(role='system', parts=[], content='You are a wizard harry.'),#   Message(role='user', parts=[], content='Say hello!'),# ]print(chat.json)# [{ ... }]Model ParsingimportriggingasrgclassAnswer(rg.Model):content:strchat=(rg.get_generator("claude-2.1").chat([{"role":"user","content":f"Say your name between{Answer.xml_tags()}."},]).until_parsed_as(Answer).run())answer=chat.last.parse(Answer)print(answer.content)# "Claude"print(f"{chat.last!r}")# Message(role='assistant', parts=[#   ParsedMessagePart(model=Answer(content='Claude'), ref='<answer>Claude</answer>')# ], content='<Answer>Claude</Answer>')chat.last.content="new content"# Updating content strips parsed partsprint(f"{chat.last!r}")# Message(role='assistant', parts=[], content='new content')ToolsfromtypingimportAnnotatedimportriggingasrgclassWeatherTool(rg.Tool):@propertydefname(self)->str:return"weather"@propertydefdescription(self)->str:return"A tool to get the weather for a location"defget_for_city(self,city:Annotated[str,"The city name to get weather for"])->str:print(f"[=] get_for_city('{city}')")returnf"The weather in{city}is nice today"chat=(rg.get_generator("mistral/mistral-tiny").chat([{"role":"user","content":"What is the weather in London?"},]).using(WeatherTool()).run())# [=] get_for_city('London')print(chat.last.content)# "Based on the information I've received, the weather in London is nice today."Continuing Chatsimportriggingasrggenerator=rg.get_generator("gpt-3.5-turbo")chat=generator.chat([{"role":"user","content":"Hello, how are you?"},]).run()print(chat.last.content)# "Hello! I'm an AI language model, ..."cont=chat.continue_({"role":"user","content":"That's good, tell me a joke"}).run()print(cont.last.content)# "Sure, here's a joke for you: ..."Basic Templatingimportriggingasrgtemplate=rg.get_generator("gpt-4").chat([{"role":"user","content":"What is the capitol of $country?"},])forcountryin["France","Germany"]:print(template.apply(country=country).run().last)# The capital of France is Paris.# The capital of Germany is Berlin.Overload Generation Paramsimportriggingasrgpending=rg.get_generator("gpt-3.5-turbo,max_tokens=50").chat([{"role":"user","content":"Say a haiku about boats"},])fortempin[0.1,0.5,1.0]:print(pending.overload(temperature=temp).run().last.content)Strip Parsed SectionsimportriggingasrgclassReasoning(rg.Model):content:strmeaning=rg.get_generator("claude-2.1").chat([{"role":"user","content":"What is the meaning of life in one sentence? "f"Document your reasoning between{Reasoning.xml_tags()}tags.",},]).run()# Gracefully handle mising modelsreasoning=meaning.last.try_parse(Reasoning)ifreasoning:print("reasoning:",reasoning.content.strip())# Strip parsed content to avoid sharing# previous thoughts with the model.without_reasons=meaning.strip(Reasoning)print("meaning of life:",without_reasons.last.content.strip())# follow_up = without_thoughts.continue_(...)Custom GeneratorAny custom generator simply needs to implement acompletefunction, and
then it can be used anywhere inside rigging.classCustom(Generator):defcomplete(self,messages:t.Sequence[rg.Message],overloads:GenerateParams=GenerateParams(),)->rg.Message:# Access params where neededapi_key=self.params.api_keymodel_id=self.model# Merge in args for API overloadsmarged:dict[str,t.Any]=self._merge_params(overloads)# response = ...returnrg.Message("assistant",response)generator=Custom(model='foo')generator.chat(...)Note: we currently don't have anyway to "register" custom generators forget_generator.LoggingBy default rigging disables it's logger with loguru. To enable it run:fromloguruimportloggerlogger.enable('rigging')To configure loguru terminal + file logging format overrides:fromrigging.loggingimportconfigure_loggingconfigure_logging('info',# stderr level'out.log',# log file (optional)'trace'# log file level)(This will remove existing handlers, so you might prefer to configure them yourself)