Introduction
Large Language Model's (LLMs) are changing the way we write code. As developers many times we come across unfamiliar libraries that we need to use to develop something in such cases rather than directly going through its documentation we can use LLM's to generate code which we can test and fix later as per our requirements. Many developers are using LLM's in many ways to speed up their work. In this blog you will learn some of the emerging best practices including how to get a LLM to help you with error handling, performance improvement and lot more.
Here we will learn how to use an LLM to simplify and improve the code, write test cases, debug the code, refractor the code, work with complex existing codebase where there maybe technical debt where LLM can help you explain document and format that existing code base.
Getting Started
PaLM API
The PaLM API is a simple entry point for Google’s large language models, which can be used for a variety of applications. It will provide developers access to models that are optimized for multi-turn use cases, such as content generation and chat, and general purpose models that are optimized for use cases such as summarization, classification, and more.
Setup
If you wanted to use the PaLM API on your own machine, you would first install the library:
pip install -q google.generativeai
The optional flag
-q
installs "quietly" without printing out details of the installation.Get your own API key for your project from the below link https://developers.generativeai.google/
Set the MakerSuite API key with the provided helper function.
from utils import get_api_key
from utils import get_api_key
import google.generativeai as palm
palm.configure(api_key=get_api_key())
Explore the available models
for m in palm.list_models():
print(f"name: {m.name}")
print(f"description: {m.description}")
print(f"generation methods:{m.supported_generation_methods}\n")
Output
name: models/chat-bison-001
description: Chat-optimized generative language model.
generation methods:['generateMessage', 'countMessageTokens']
name: models/text-bison-001
description: Model targeted for text generation.
generation methods:['generateText', 'countTextTokens', 'createTunedTextModel']
name: models/embedding-gecko-001
description: Obtain a distributed representation of a text.
generation methods:['embedText']
Note: The model names are based on animal names the bigger the animal the bigger the model will be.
Filter models by their supported generation methods
generateText
is currently recommended for coding-related prompts.generateMessage
is optimized for multi-turn chats (dialogues) with an LLM.
models = [m for m in palm.list_models()
if 'generateText'
in m.supported_generation_methods]
print(models)
model_bison = models[0]
print(model_bison)
Helper function to generate text
- The
@retry
decorator helps you to retry the API call if it fails. - We set the temperature to 0.0 so that the model returns the same output (completion) if given the same input (the prompt).
from google.api_core import retry
@retry.Retry()
def generate_text(prompt,
model=model_bison,
temperature=0.0):
return palm.generate_text(prompt=prompt,
model=model,
temperature=temperature)
Ask the LLM how to write some code
prompt = "Show me how to iterate across a list in Python."
completion = generate_text(prompt)
print(completion.result)
Output
#To iterate across a list in Python, you can use the for loop. The syntax is as #follows:
for item in list:
# do something with item
# For example, the following code prints each item in the list my_list:
my_list = ["a", "b", "c"]
for item in my_list:
print(item)
Output:
a
b
c
# You can also use the enumerate() function to iterate over a list and get the
# index of each item. The syntax is as follows:
for index, item in enumerate(list):
# do something with index and item
# For example, the following code prints the index and value of each item in the # list my_list:
my_list = ["a", "b", "c"]
for index, item in enumerate(my_list):
print(index, item)
Output:
0 a
1 b
2 c
Tip: The words "show me" tends to encourage the PaLM LLM to give more details and explanations compared to if you were to ask "write code to ..."
Try out the code
- Try copy-pasting some of the generated code and running it in the notebook.
- Remember to test out the LLM-generated code and debug it make sure it works as intended.
Try asking your own coding question
# Modify the prompt with your own question
prompt = "Show me how to [...]"
completion = generate_text(prompt)
Using a String Template
Prompt template
- priming: getting the LLM ready for the type of task you'll ask it to do.
- question: the specific task.
- decorator: how to provide or format the output.
prompt_template = """
{priming}
{question}
{decorator}
Your solution:
"""
priming_text = "You are an expert at writing clear, concise, Python code."
question = "create a doubly linked list"
decorator = "Insert comments for each line of code."
Observe how the decorator affects the output
- In other non-coding prompt engineering tasks, it's common to use "chain-of-thought prompting" by asking the model to work through the task "step by step".
- For certain tasks like generating code, you may want to experiment with other wording that would make sense if you were asking a developer the same question.
prompt = prompt_template.format(priming=priming_text,
question=question,
decorator=decorator)
print(prompt)
Call the API to get the completion
completion = generate_text(prompt)
print(completion.result)
Pair Programming Scenarios
Scenario 1: Improve existing code
- An LLM can help you rewrite your code in the way that's recommended for that particular language.
- You can ask an LLM to rewrite your Python code in a way that is more 'Pythonic".
prompt_template = """
I don't think this code is the best way to do it in Python, can you help me?
{question}
Please explain, in detail, what you did to improve it.
"""
question = """
def func_x(array)
for i in range(len(array)):
print(array[i])
"""
completion = generate_text(
prompt = prompt_template.format(question=question)
)
print(completion.result)
Ask for multiple ways of rewriting your code
prompt_template = """
I don't think this code is the best way to do it in Python, can you help me?
{question}
Please explore multiple ways of solving the problem, and explain each.
"""
completion = generate_text(
prompt = prompt_template.format(question=question)
)
print(completion.result)
Ask the model to recommend one of the methods as most 'Pythonic'
prompt_template = """
I don't think this code is the best way to do it in Python, can you help me?
{question}
Please explore multiple ways of solving the problem, and explain each.
"""
completion = generate_text(
prompt = prompt_template.format(question=question)
)
print(completion.result)
Ask the model to recommend one of the methods as most 'Pythonic'
prompt_template = """
I don't think this code is the best way to do it in Python, can you help me?
{question}
Please explore multiple ways of solving the problem,
and tell me which is the most Pythonic
"""
completion = generate_text(
prompt = prompt_template.format(question=question)
)
print(completion.result)
Scenario 2: Simplify code
- Ask the LLM to perform a code review.
- Note that adding/removing newline characters may affect the LLM completion that gets output by the LLM.
# option 1
prompt_template = """
Can you please simplify this code for a linked list in Python?
{question}
Explain in detail what you did to modify it, and why.
"""
# option 2
prompt_template = """
Can you please simplify this code for a linked list in Python? \n
You are an expert in Pythonic code.
{question}
Please comment each line in detail, \n
and explain in detail what you did to modify it, and why.
"""
question = """
class Node:
def __init__(self, dataval=None):
self.dataval = dataval
self.nextval = None
class SLinkedList:
def __init__(self):
self.headval = None
list1 = SLinkedList()
list1.headval = Node("Mon")
e2 = Node("Tue")
e3 = Node("Wed")
list1.headval.nextval = e2
e2.nextval = e3
"""
completion = generate_text(
prompt = prompt_template.format(question=question)
)
print(completion.result)
Scenario 3: Write test cases
- It may help to specify that you want the LLM to output "in code" to encourage it to write unit tests instead of just returning test cases in English.
prompt_template = """
Can you please create test cases in code for this Python code?
{question}
Explain in detail what these test cases are designed to achieve.
"""
question = """
class Node:
def __init__(self, dataval=None):
self.dataval = dataval
self.nextval = None
class SLinkedList:
def __init__(self):
self.head = None
def create_linked_list(data):
head = Node(data[0])
for i in range(1, len(data)):
node = Node(data[i])
node.nextval = head
head = node
return head
list1 = create_linked_list(["Mon", "Tue", "Wed"])
"""
completion = generate_text(
prompt = prompt_template.format(question=question)
)
print(completion.result)
Scenario 4: Make code more efficient
- Improve runtime by potentially avoiding inefficient methods (such as ones that use recursion when not needed).
prompt_template = """
Can you please make this code more efficient?
{question}
Explain in detail what you changed and why.
"""
question = """
# Returns index of x in arr if present, else -1
def binary_search(arr, low, high, x):
# Check base case
if high >= low:
mid = (high + low) // 2
if arr[mid] == x:
return mid
elif arr[mid] > x:
return binary_search(arr, low, mid - 1, x)
else:
return binary_search(arr, mid + 1, high, x)
else:
return -1
# Test array
arr = [ 2, 3, 4, 10, 40 ]
x = 10
# Function call
result = binary_search(arr, 0, len(arr)-1, x)
if result != -1:
print("Element is present at index", str(result))
else:
print("Element is not present in array")
"""
completion = generate_text(
prompt = prompt_template.format(question=question)
)
print(completion.result)
Scenario 5: Debug your code
prompt_template = """
Can you please help me to debug this code?
{question}
Explain in detail what you found and why it was a bug.
"""
question = """
class Node:
def __init__(self, data):
self.data = data
self.next = None
self.prev = None
class doubly_linked_list:
def __init__(self):
self.head = None
# Adding data elements
def push(self, NewVal):
NewNode = Node(NewVal)
NewNode.next = self.head
if self.head is not None:
self.head.prev = NewNode
self.head = NewNode
# Print the Doubly Linked list in order
def listprint(self, node):
print(node.data),
last = node
node = node.next
dllist = doubly_linked_list()
dllist.push(12)
dllist.push(8)
dllist.push(62)
dllist.listprint(dllist.head)
"""
completion = generate_text(
prompt = prompt_template.format(question=question)
)
print(completion.result)
Technical Debt
Ask an LLM to explain a complex code base
CODE_BLOCK = """
YOUR CODE GOES HERE
"""
prompt_template = """
Can you please explain how this code works?
{question}
Use a lot of detail and make it as clear as possible.
"""
completion = generate_text(
prompt = prompt_template.format(question=CODE_BLOCK)
)
print(completion.result)
Ask an LLM to document a complex code base
prompt_template = """
Please write technical documentation for this code and \n
make it easy for a non swift developer to understand:
{question}
Output the results in markdown
"""
completion = generate_text(
prompt = prompt_template.format(question=CODE_BLOCK)
)
print(completion.result)
Conclusion
There is a lot of fear, insecurity and doubt when it comes to generative code, and there is a lot of hype saying LLM's will put developers out of work but LLM's can be great help to developers making them more efficient. In this blog we stepped through a number of ways in which you can use LLM's that go beyond just simple code generation and which can help you become a better software engineer. I hope that they inspired many use-cases in your mind about how you can be a better developer.