Building customised inference endpoint for foundation models chain

Lukasz Cmielowski, PhD
3 min readFeb 20, 2024

--

Written by: Lukasz Cmielowski, PhD

The task

Build the customised inference endpoint (REST API) for the foundation models chain. Chain of two foundation models is built using SequentialChain from Langchain. First of models generates the question based on provided topic that the second model needs to answer. For more details you can refer to medium story “Automating watsonx.ai foundation models with Langchain”.

In that story the focus is on moving the automation code to production environment as single inference endpoint that can be integrated with 3rd party web app.

The python function

watsonx.ai has capability to deploy python functions as online deployments (scoring endpoint). The code below shows how to wrap langchain automation code within such deployable function chain_text_generator(). The embedded function score() will be called each time the request to scoring endpoint is made. The outer function is executed only once (during deployment setup).

ai_params = {
"credentials": credentials,
"project_id": project_id,
"generation_parameters": parameters
}
def chain_text_generator(params=ai_params):
from ibm_watsonx_ai.foundation_models import Model
from ibm_watsonx_ai.foundation_models.utils.enums import ModelTypes
from langchain import PromptTemplate
from langchain.chains import LLMChain, SequentialChain

credentials = params["credentials"]
project_id = params['project_id']
parameters = params['generation_parameters']
flan_ul2 = Model(model_id=ModelTypes.FLAN_UL2, params=parameters, credentials=credentials, project_id=project_id)
flan_t5 = Model(model_id=ModelTypes.FLAN_T5_XXL, credentials=credentials, project_id=project_id)
prompt_1 = PromptTemplate(input_variables=["topic"], template="Generate a random question about {topic}: Question: ")
prompt_2 = PromptTemplate(input_variables=["question"], template="Answer the following question: {question}")
prompt_to_flan_ul2 = LLMChain(llm=flan_ul2.to_langchain(), prompt=prompt_1, output_key='question')
flan_to_t5 = LLMChain(llm=flan_t5.to_langchain(), prompt=prompt_2, output_key='answer')
chain = SequentialChain(chains=[prompt_to_flan_ul2, flan_to_t5], input_variables=["topic"], output_variables=['question', 'answer'])

def score(payload):
"""Generates question based on provided topic and returns the answer.
"""

answer = chain({"topic": payload["input_data"][0]['values'][0][0]})
return {'predictions': [{'fields': ['topic', 'question', 'answer'], 'values': [answer['topic'], answer['question'], answer['answer']]}]}

return score

Let’s test the function code locally before publishing and deploying.

sample_payload = {
"input_data": [
{
"fields": ["topic"],
"values": [["life"]]
}
]
}

inference = chain_text_generator()
inference(sample_payload)
{'predictions': [{'fields': ['topic', 'question', 'answer'],
'values': ['life',
'What is the most important element of life?',
'water']}]}

Software specification

Deployment service needs to know what extra packages are required to run our function code correctly. We need to create custom software specification that will add few packages to default python runtime (langchain is one of them).

config_yml =\
"""
name: python310
channels:
- empty
dependencies:
- pip:
- pydantic>=1.10.0
- langchain==0.0.340
- ibm-watsonx-ai
prefix: /opt/anaconda3/envs/python310
"""

with open("config.yaml", "w", encoding="utf-8") as f:
f.write(config_yml)
from ibm_watsonx_ai import APIClient

client = APIClient(credentials)
client.set.default_space(space_id)
base_sw_spec_uid = client.software_specifications.get_uid_by_name("runtime-23.1-py3.10")
meta_prop_pkg_extn = {
client.package_extensions.ConfigurationMetaNames.NAME: "langchain watsonx.ai env",
client.package_extensions.ConfigurationMetaNames.DESCRIPTION: "Environment with langchain",
client.package_extensions.ConfigurationMetaNames.TYPE: "conda_yml"
}

pkg_extn_details = client.package_extensions.store(meta_props=meta_prop_pkg_extn, file_path="config.yaml")
pkg_extn_uid = client.package_extensions.get_uid(pkg_extn_details)

After defining the package extensions let’s create langchain based software specification.

meta_prop_sw_spec = {
client.software_specifications.ConfigurationMetaNames.NAME: "langchain & watsonx.ai",
client.software_specifications.ConfigurationMetaNames.DESCRIPTION: "Software specification for langchain",
client.software_specifications.ConfigurationMetaNames.BASE_SOFTWARE_SPECIFICATION: {"guid": base_sw_spec_uid}
}

sw_spec_details = client.software_specifications.store(meta_props=meta_prop_sw_spec)
sw_spec_uid = client.software_specifications.get_uid(sw_spec_details)
client.software_specifications.add_package_extension(sw_spec_uid, pkg_extn_uid)

Our software specification is successfully stored and can be linked with our function.

Inference endpoint

As a next step the function needs to be stored and deployed as scoring endpoint.

meta_props = {
client.repository.FunctionMetaNames.NAME: "SequenceChain LLM function",
client.repository.FunctionMetaNames.SOFTWARE_SPEC_UID: sw_spec_uid
}

function_details = client.repository.store_function(meta_props=meta_props, function=chain_text_generator)
function_id = client.repository.get_function_id(function_details)

The function has been uploaded and can be deployed.

metadata = {
client.deployments.ConfigurationMetaNames.NAME: "Deployment of LLMs chain function",
client.deployments.ConfigurationMetaNames.ONLINE: {}
}

function_deployment = client.deployments.create(function_id, meta_props=metadata)

The online deployment is ready.

Put together all pieces

Using deployment details we can extract deployment id required to call our function.

deployment_id = client.deployments.get_id(function_deployment)

Next, using the score() method make the call to it.

client.deployments.score(deployment_id, sample_payload)
{'predictions': [{'fields': ['topic', 'question', 'answer'],
'values': [['life'],
'When did the first life forms appear on Earth?',
'3.8 billion years ago']}]}

If needed the scoring endpoint url can be extracted from deployment’s details and pure REST API request used to generate the text.

That’s all folks!

One more thing — you can find sample notebooks here.

--

--

Lukasz Cmielowski, PhD
Lukasz Cmielowski, PhD

Written by Lukasz Cmielowski, PhD

Senior Technical Staff Member at IBM, responsible for AutoAI (AutoML).

No responses yet