DrupalEasy: Using the ECA module to replace a not-Drupal-10-ready contrib module (Termcase)

I've been a big fan of the Termcase module for a long time - it is my go-to module for sites that employ free-tagging taxonomies. Termcase allows site-builders to force consistency on tag names (all lowercase, all uppercase, first-letter uppercase, etc…) It's one of those modules that I was surprised that not everyone used (or had even heard of.) While working to update a Drupal 9 site that uses Termcase to Drupal 10, I became curious if free-tagging was still a commonly-used technique on modern Drupal sites.

In an effort to satisfy my curiosity, I performed a 100% not scientific poll recently on various social media platforms to see how prevalent the use of free-tagging vocabularies are; the results weren't very enlightening; of the 60 responses I received, the vote was about split.

Poll: do you have any free-tagging term reference fields on a modern Drupal (8/9/10) site you own/manage/built?

Image removed.

This didn't really satisfy my curiosity about why not everyone is/was using the Termcase module. Surely, I'm not the only person who is adamant about their free-tagging terms all having the same capitalization scheme… 🤨

Motivation

Officially, there's no Drupal 8 or 9 version of Termcase, but it has been limping along with a two patches that allowed me (and a few others) to keep using it in Drupal 8 and 9. While there is a Drupal 10 compatibility patch available, it seems pretty clear that the listed maintainers have no interest/bandwidth in updating the module, so I figured it was time to consider an alternative that would provide a solid solution in Drupal 9, 10, and beyond. 🚀

Again, I went to social media for answers (ChatGPT wasn't much help) and one of the maintainers of the ECA module, Jürgen Haas, quickly responded that ECA could help (I'm pretty sure that is Jürgen's default answer to most Drupal questions these days 😀). He pointed me toward the Convert case action of the ECA Tamper module. Excellent, now all I needed to do is learn how to use the ECA module 👍🏼

ECA module 101

The ECA module is the modern-day successor to the formerly widely-used Rules module that was a popular solution for pre-Drupal 8 sites.

Disclaimer: I did have a little bit of prior experience in experimenting with ECA, but this would be my first real implementation for a client using the module.

I'm not going to go into all the details of the basics of installing and using ECA, as the existing documentation is quite robust, if not yet completely geared toward beginners (more on that later.)

To get started, I used Composer and Drush to install ECA and the necessary modules:

$ composer require drupal/eca drupal/eca_tamper drupal/bpmn_io $ drush en bpmn_io eca_tamper eca_content

This results in the following modules being enabled: bpmn_io, eca_modeller_bpmn, eca_ui, eca_tamper, eca, and tamper.

Next, I had to create a new ECA model (for those of you familiar with the Rules module, an ECA model is similar to a rule).

One counter-intuitive aspect about the ECA module is its name and the nouns it uses in its interface. ECA is an acronym for the nouns Events, Conditions, and Actions. But, when using the BPMN.iO (Business Process Model and Notation standard) interface module, the nouns used are StartEvent, Sequence flow, Gateway, and Task. For folks new to this type of module, this can be confusing. I am confident that this is due to the design of the BPMN.iO interface, and not a purposeful decision by the ECA maintainers just to confuse us. StartEvent and Task map pretty cleanly to Event and Action. A Sequence flow is a connector between StartEvents, Gateways, and Actions. A Sequence flow can optionally have a condition. A Gateway can be added after a Sequence flow to allow for one or more Sequence flows with conditions to be evaluted. 

  • Event = StartEvent
  • Condition = Optionally attached to a SequenceFlow
  • Action = Task

For example, consider the model where a "Batman message" is displayed if an article node has a "Batman" term associated with it. 

Image removed.

In this model, the Gateway just provides a point where the two potential Sequence flows ("Batman?" and "No Batman") can be evaluated. The Gateway doesn't usually have any non-trivial properties - it is usually a branch point.

Replacing Termcase with an ECA model

For this model, in non-ECA speak, the goal is to lower-case all terms of the Tag vocabulary prior to each being saved. Therefore, our Event/StartEvent will be Presave content entity. Then we will need to perform the Convert Case action (from the ECA Tamper module) on the term name, and finally we will need to update the name value of the about-to-be-saved term to the updated (lowercased) term name. For good measure, when developing a new model (as well as a new rule back in the day) I generally also add a temporary Drupal message action (task) to confirm that things are working.

I'll get into the details of each of the aforementioned steps, but here's a quick preview of what the completed model looks like:

Image removed.

lowercase terms model details

Taking a not-quite comprehensive look at each aspect of the model:

Presave tag

After dragging a new StartEvent to the layout area, the first step is generally to select a Template. Now, this is not a theming template, but rather the event for which this model will be triggered on. In this case, the Presave content entity template was used (which is provided by the eca_content module.) Each StartEvent, Gateway and Task has both an ID and a Name - both customizable by the model author. I generally leave the ID at the default value, but populate the non-required Name field with something descriptive. In this case, I used Presave tag. Each template generally has a set of Custom properties. Not surprisingly, different templates generally have different Custom properties. In this case, it was pretty obvious that I needed to set the Type (and bundle) Custom property to Taxonomy term: Tags.

Image removed.

Lowercase

Next, I dragged a new Task to the layout area, named it Lowercase, and selected the Tamper: Convert case template. The list of available templates is quite impressive (IMHO), these are provided by the various installed ECA-related modules. Since the ECA Tamper module is installed, we have access to all of its templates.

Image removed.

Setting the Custom properties of the template (again, think of this like the configuration of the task/action) is a bit more tricky - especially for folks new to the ECA module. The ECA module utilizes Drupal's Token system extensively. In many cases, it also relies a bit on the model author's knowledge of Drupal data structures.

In this case, I used the following Custom properties (configuration):

  • Data: [term:name]
  • Token name: my-tag
  • How to convert case: Convert to lowercase

This is where I think the ECA module needs some DX (developer experience) tweaks. For the uninitiated, knowing that Data is the input and Token name is the output is not obvious, but that is exactly what is going on here. The Presave tag StartEvent provides the term to be saved as a Drupal token. Since we want to lowercase the term name, we need to set Data (incoming) to the [term:name] token.

The result of the Task (action) is then saved to a new custom token whose name we specify in the Token name field. The lowercased term name is not automatically saved back to the term name field which is why we need to save the result of this task as a new custom token. We will save the updated term name back to the Term entity in the next Task.  

Based on an online discussion with Jürgen regarding how this would probably be difficult for beginners to pick-up on quickly, he opened (and acted on) an issue

Set updated tag name

The final Task (action) is then to set the new (lowercased) value of the term name back to the about-to-be-saved term entity. This is done with the Entity: Set field value template. There are quite a few Custom properties for this template, but in this case, the only ones I set to non-default values were:

  • Field name: name
  • Field value: [my-tag]
  • Entity: taxonomy_term

This is where the DX of the ECA module could again be much improved (IMHO.) The Field name value requires a bit of knowledge that not all Drupal site-builders have - that is the machine name of the taxonomy term entity's Name/Label field. Granted, it is a pretty obvious value (name,) but it easily could also be label or title - it would be amazeballs if the user was presented with a select list of potential values instead of a text field in the UI, but I do appreciate the amount of effort that would entail.

The Field value field is a bit better, but again, not entirely intuitive. This is the input to the task - that is - the value to which the field will be set to. It is a bit tricky to know that in the Lowercase action only the token name is needed (my-tag), but in this task the full token (including square brackets) is required ([my-tag]).

The Entity field also requires knowledge that not all Drupal site-builders may have - the machine name of the entity type to which the field value is being set for. In this case, the proper value is taxonomy_term, but I'll admit I was a bit surprised that this isn't something that the Task can figure out on its own - or at least provide a select list for. Again, I suspect (and appreciate) that it has to do with how each Task is written completely independently (and without dependencies) on other aspects of the ECA model.

I've opened up a new issue in the ECA module's queue with these thoughts.

For me, one of the more significant challenges of using the ECA module is understanding what each Custom property is actually asking for and determining if it is input or output of the task. I think there is some room for improvement.

Something else that originally tripped me up in this task was the Save entity setting. It defaults to no, and I mistakenly thought to myself, "of course I want to save the entity" and set it to yes; which led to a fatal PHP error. Again, Jürgen was very responsive and set me straight by explaining that since the StartEvent is Presave content entity, there is no need to set Save entity to yes, the term is already on its way to being saved. By selecting yes, the model will effectively try to save the same term twice; leading to the fatal error. 

Temporary confirmation message

As mentioned previously, I often include a temporary task/action to output something that tells me that the model is actually running and achieving its goal. Once I am confident in the model, I often remove this task.

In this case, the Display a message to the user task template was used with the following Custom property:

  • Message: Tag updated: [my-tag]

Final "gotcha"

Maybe it is just me, but there's one thing that I keep doing in ECA's BPMN.iO's interface that can be very confusing at first - I often find myself not paying attention to what is selected in the layout area when looking at the "inspector" (I'm not really sure what else to call it) so that I get a bit confused with the configuration options. Somehow, I frequently have an arrow connector selected (a Sequence flow in BPMN.iO parlance) when I think I have a task selected (Sequence flows have properties as well!) So, my advice is to be methodical and pay attention to what is selected in the layout area when looking at configuration options.

Image removed.

I'm not sure there's anything that the ECA maintainers can do about this. I liken it to a similar habit I have of moving too quickly when configuring multi-display Views and overriding/not-overriding values incorrectly. My advice: Move slowly and methodically in the interface.

Summary

This was a good exercise and excuse for me to take a (slightly) deeper dive into the ECA module. Based on its documentation and videos about the module that I've seen, this article barely scratches the surface of what ECA can do. I look forward to finding more reasons to use it!

It is pretty clear that the maintainers are super-active and super-responsive to feedback and requests for support; take advantage of them. 😃

Oomph Insights: DrupalCon 2023: Recapping the Biggest Week in Web Dev

For digital ecosystem builders like us, DrupalCon is kind of like our Super Bowl: best-in-class web devs coming together to level up our Drupal prowess. Earlier this summer, we joined 1,800 other Drupal users in Pittsburgh, turning the David L. Lawrence Convention Center into a four-day meeting of the minds for anyone who builds with Drupal. Why DrupalCon? Well, we’re huge fans of the platform. We’ve been developing Drupal projects since 2008 and have served the Drupal community by sponsoring the annual New England Drupal Camp; hosting the monthly Providence Drupal Meetup; developing new…

Drupal.org blog: Ensuring a Fair Drupal Contribution Credit System

Drupal's contribution credit system plays an important role in fostering contribution. It is crucial that we protect the integrity of that system.

Because contribution credit can impact an organization's marketplace position, there is a financial incentive for contribution. This is by design, and helps promote sustainable contribution in Drupal. Unfortunately, whenever a financial incentive is created, there is a risk that some organizations will try to game the system by making superficial contributions in bulk, or using automation or AI to try and boost contribution numbers.

This gaming behavior undermines the true goal of the credit system, which is to grow meaningful and authentic contributions to the Drupal project and community.

What steps are we taking?

To help discourage the temptation of superficial contribution, we've implemented additional updates to our systems and policies:

  • The credit checkbox on issues is no longer 'pre-checked' for certain kinds of issue activity.
  • We have published a draft policy on the use of artificial intelligence on Drupal.org. AI is not banned, but must be used carefully:

    • Contributors must acknowledge that AI was used to assist the creation of the work in the same post or issue comment.
    • Any work that was created with the assistance of AI must be relevant to resolving the issue.
    • Work created with the assistance of AI must be edited and corrected as needed before being posted to any issue.
    • This policy is subject to significant revisions as the legal status of AI generated work and copyright evolves.
  • We have also updated our standards of conduct for the Drupal.org marketplace, including a warning and escalation policy for abuse of the credit system.
    • Consistent abuse despite repeated warnings can result in loss of marketplace position, partner status, or delisting.
  • Individual users engaging in this activity may receive temporary account suspensions, so that we can reach out with educational materials. Repeated infractions may result in a permanent account ban.

Why is this important?

Drupal remains unique in the open source world for the power of our contribution credit system. All kinds of contribution activity on Drupal.org can be attributed to individuals and organizations, giving us unprecedented insight into the ecosystem that drives contribution.

This system also plays an important role in promoting individuals, companies and organizations who give back to the project and community. We use an organization's contribution history to rank them in the Drupal.org marketplace, and an individual's contribution history is a powerful tool for organizations to find talent, and for Drupal contributors to find work.

Our credit system is designed so that only project maintainers can ultimately grant credit. This means that there is always an element of human review, but relying exclusively on human intervention to monitor large numbers of superficial contributions can lead to burn out.

Education first

Our first goal when we see contribution activity that isn't meaningful or authentic is always education. With the help of Drupal mentors, site moderators, and other community members, we focus on gentle intervention, education, and support wherever we can.

We've collected a series of resources to support this educational effort:

With these systems and policies in place, we can reduce the burden on maintainers and help ensure that the credit system serves its higher purpose: Growing meaningful contributions to Drupal, and providing recognition for those who give back to our project and community.

LN Webworks: Upgrading Your Drupal Site: 5 Key Challenges and How to Conquer Them?

Image removed.

Navigating the intricate process of Drupal migration poses a myriad of challenges for organizations. This complex endeavor demands meticulous planning and execution. However, unexpected issues can emerge, potentially leading to delays or complete migration disruptions.

In this blog, we will discuss the top five challenges in Drupal migration and provide practical solutions to overcome them. But before we discuss that, let’s understand in a snippet why migration is even needed. 

Why Drupal Migration Is Important? 

Drupal migration is the process of upgrading a website from an older version of Drupal to the latest version. It involves transferring data, content, functionalities, and design elements to the new version. Drupal migration is of paramount importance for organizations seeking to keep their digital presence relevant and robust. 

Drupal Association blog: Open Source Unity: Joint Concerns Over the Proposed Cyber Resilience Act in the EU

It should not come as a surprise that open source projects would act collaboratively.  But it’s somewhat of a first, in my understanding, that Open Source Matters, Inc. (Joomla), Typo3, WordPress, and the Drupal Association have issued a joint letter to the legislators of the European Union raising concerns with the proposed Cyber Resilience Act. And the concerns raised by our four organizations, whose communities collectively serve over 50% of the European websites, are significant enough to warrant such a first.

The impact of the regulation as proposed would undermine effective software practices in its ban on “unfinished software”, chill the contributions of tens of thousands of developers who make free contributions to open source software due to an expansive definition of “commercial activity”, and would impose one-size fits all compliance costs likely causing development to gravitate to large, for-profit firms that can absorb the costs.

Read the letter here

While the rule’s impact would be extremely negative, the opportunity we have before us is positive. This rule provides an opportunity for open source communities across Europe (and the globe!) to explain the unique role that FOSS plays in the software that underpins much of the web and to develop a model for how regulation should be applied to it. It is an opportunity for our communities to learn how to best work together in making this case, as the four signatories on this letter have begun to do. Finally, it’s an opportunity to educate legislators and policy-makers as to the shared values that open source communities have with the European Union.

The Drupal Association engaged in this issue because we recognized that the Cyber Resilience Act is the current issue at hand, but not the only one. The European Union’s parliament is considering proposed changes to the Product Liability Directive this Fall that could impose a strict liability standard. And beyond that lies A.I. and patent rules.

So we embrace this opportunity to collaborate with Joomla, Typo3, WordPress, and hopefully other open source initiatives to credential FOSS’ role in the E.U. regulatory landscape. As experts in the field, we embrace the responsibility to educate and provide support for our online ecosystem. We also look forward to engaging with and serving our Drupal community members in Europe.

LN Webworks: Challenges in Upgrading Drupal & Advance Solutions: A 2023 Mini-Guide

Image removed.

Upgrading Drupal can be quite a journey, and it's natural for organizations to encounter various challenges along the way. Despite our best efforts in planning and execution, the migration process might throw unexpected curveballs that could slow us down or temporarily stall progress. 

In this blog, we'll look at some of the common hurdles faced during a Drupal migration and offer helpful tips to navigate through them successfully. Let's dive in and explore how we can make this migration adventure.

Pierce Lamb: Improving GPT-4 Function Calling with an Explanation Parameter

Image removed.Prompt: “An AI that has automated the world”

I’ve been building ChatGPT-powered features since its release and have been absolutely amazed by what it can do. Even though I’ve been interacting with GPT every day for a while now, oftentimes its outputs still feel like magic. For months, creating inputs (prompts) for GPT was a fun new way to program this tool, but handling its output was a mess. In my prompting, I experimented with various ways to steer its output to give it structure and used basic string functions to slice and dice the results, but it never worked 100% of the time. I evaluated a number of tools that tried to fix this problem, but none of them quite fit our use case. All of this changed dramatically with the advent of Function Calling. For those that have been living in a cave, OpenAI fine-tuned GPT3.5-turbo and GPT-4 so that these models can accept a list of functions, defined using JSON schema, as input along with a prompt. The model(s) can then select a function and call it as output. That is, GPT will return an output that answers one’s prompt, but in the form of a function call with the function name and inputs for its parameters. Thus, a program accepting that output can choose to call that function with those inputs and return the output to GPT for further processing. This seemingly simple functionality was the basis for an entire ecosystem of ChatGPT “agents” that existed prior to OpenAI rolling out function calling; now a user can build a custom agent using just the OpenAI libraries.

I suspect, however, that, like me, a large majority of people using function calling are using it to get structured output out of GPT. For many, there are stomach-turning security issues with allowing a LLM to execute code in your program, but for receiving structured output, function calling is extremely useful. In this blog post I will demonstrate how to use function calling to receive structured output and that one small improvement — adding an explanation parameter — appears to improve the outputs of function calls and helps to debug the prompts that generate them significantly.

If you’re trying to solve a problem with ChatGPT, at some point in time you’ve googled the phrase “prompt engineering.” And, if you got lucky, you came across Lilian Weng’s post on the topic that saved you from having to read a bunch of verbose academic papers. Lilian does a fantastic job at explaining the technical side of prompt engineering and summarizing the results of academic papers; her work can immediately improve your prompting. However, I want to diverge for a second to explain how I often think about prompting LLMs that has recently helped me.

Imagine you’ve hired a high school or college graduate that excelled in all language or liberal arts classes. They possess an elite ability to apply language reasoning skills to any tasks that involve language. However, for your specific task, they lack any prior context on how to perform the task. Thus, for them to succeed at performing your task, you can either teach them all the context you’ve learned about the task, or you can give them a set of criteria to follow where all they need to perform the task is to apply the criteria and use their language reasoning skills.

Since you’ve hired this person with no background or context on what you do, one thing you might do to verify the results they produce is ask them to provide a chain of reasoning or rationale for why they arrived at the answer they did. For the new employee, being forced to write down a chain of reasoning will likely help them arrive at an accurate answer. For you, their manager, it will help you to understand if they’ve arrived at an accurate answer and if there are any gaps or issues in the criteria you provided them. Furthermore, for any third party you might show their work, it would reduce any confusion about the answer by seeing an explanation of how the answer was found.

Of course, in our example the employee is ChatGPT and this style of requesting a chain of reasoning is now a common technique for improving results. Chain-of-thought (CoT) prompting was introduced by Wei et al. 2022 as well as Kojima et al. 2022, Zhou et al. 2022 and later made very popular in the ReAct paper by Yao et al. 2023. In its most basic form, simply asking ChatGPT to think step-by-step before providing an answer fits this bill, though these papers introduce a much more nuanced perspective.

Prior to function calling, I was using chain-of-thought prompting not only to obtain more accurate answers, but also to debug edge cases in my prompts. When you’re providing ChatGPT criteria to follow to help create an answer, oftentimes there will be an edge case you have not considered and ChatGPT’s explanation will show the gap in your criteria. This explanation would be provided in the text blob that came back from ChatGPT. If you just stored the raw prompt and raw answer and examined these when your provided answer didn’t make much sense, this explanation would oftentimes elucidate the gap in your criteria. However, when you start using function calling, you likely will not be getting a text blob back.

Here are a few examples from my work with ChatGPT:

  • Return the top-k most similar questions to a given question,
  • Create a synthesized answer between two answers to the same question,
  • Find a specific column type in tabular data,
  • Answer a new question based on similar previous questions’ answers,
  • Answer a question using related documentation to find the answer.

In all of these examples, once you move to function calling, ChatGPT is going to start filling a parameter with its answer to these requests. However the explanation of how it arrived at that answer, which was regularly a feature of the old text blob, is lost. As a result of this, I started adding an explanation parameter to every single function call and modifying the prompt so ChatGPT knew to dump an explanation into this parameter. Not only did this subjectively seem to improve the answers overall (in the same way CoT is supposed to), it also provided me with a way to debug my prompts when answers went haywire. Let’s look at a more concrete example to better understand what I mean.

We will look at an example of answering a new question based on similar questions’ answers. Note that “similarity” is measured via an approximate nearest neighbors search over previous questions that have been embedded as vectors. Let’s take a look at the function call we are sending to GPT:

{
"name": "get_answer_and_explanation",
"description": "Returns the answer to the new question and an explanation of how the answer was created",
"parameters": {
"type": "object",
"properties": {
"answer": {
"type": "string",
"description": "The answer to the new question",
},
"explanation": {
"type": "string",
"description": "An explanation of how the answer was created",
},
},
"required": ["answer", "explanation"],
},
}

As you can see, this is pretty straight forward. We just add a second parameter to the function call called “explanation” and give it a succinct description. GPT will create an answer to our new question, fill it in the answer parameter and then explain how it arrived at that answer in the explanation parameter. Next, let’s see how we connect this function call back to the prompt.

Recall that the goal is to steer ChatGPT and provide a list of criteria it can follow to utilize its incredible reasoning abilities without providing it a mass of in-context examples (my main reason for avoiding the latter is because of token rate limits). Here is the beginning of the system prompt:

You are a helpful assistant that answers questions about a company based on
similar questions the company has responded to in the past. Below are 5
questions the company has responded to in the past. After those 5 questions,
there will be a new question for you to answer.

This provides the most basic steering on the task ChatGPT is to perform. Next, also in the system prompt, we provide the list of criteria that will help it understand how to apply its reasoning abilities and adjudicate edge cases.

Please think step-by-step when answering the new question and use the criteria
listed below as guidelines for answering the new question:
a.) Use the old 5 questions and their responses as context to answer the
new question.
b.) The old 5 questions are sorted by similarity to your new question.
However, the most similar questions may not have the best responses
to answer your new question. Analyze the old questions and their
answers and then pick one of the following strategies for answering
the new question based on your analysis:
b1.) Two or more old questions are similar to the new question and have
good responses. Synthesize these responses into an answer for the
new question.
b2.) Two or more old questions are similar to the new question,
but their responses disagree or contradict each other.
Pick the response that answers the new question the best.
b3.) One old question has the best response for answering the new question.
Discard the other old questions and use that response to answer
the new question.
b4.) The old questions are sufficiently dissimilar to the new question,
answer the new question with “cannot be answered”
c.) Additional criteria on how to evaluate a response:
c1.) A good response is usually sentence(s) of English. Note it can contain
grammatical and spelling mistakes.
c2.) A good response could be considered a response to it’s question.
c3.) The voice of a good response should be written as if it is a
human at a company responding to the question. Sometimes it’s as
simple as “Yes” or “No” and other times it includes additional
information.

Now, I didn’t come up with 10 criteria in a vacuum. This list was built up over successive requests to ChatGPT and analysis of its responses. And, like I’ve already argued at length, the explanation parameter was the single best method for understanding what ChatGPT was doing and thereby enhancing this list of criteria. Finally, also in the system prompt, we provide formatting instructions which is what will help ChatGPT correctly call the function:

Your answer should be the answer to the new question and an
explanation of how you arrived at that answer that includes
your step-by-step reasoning using the criteria above.
Use this format:

Answer: <your-answer>
Explanation: <your-explanation>

You can see here that the end of the system prompt is what connects the whole prompt back up to the function call. Now GPT can easily see how its response to the prompt can match the function’s input parameters.

Given what we know about the function call and prompt, what are some examples of these explanations? Here is one of the more simple examples where GPT-4’s explanation provides so much more detail on how GPT-4 created the answer:

"answer": "Yes, our company does have cyber insurance.",
"explanation": "The new question is 'does your company have cyber insurance?'
The most similar old questions are 'does your company have cyber insurance?'
and 'how much coverage do you have in cyber insurance?' The responses to
these old questions confirm that the company does have cyber insurance.
Therefore, the strategy b3 is used: One old question has the best response
for answering the new question. The response to the old question 'does your
company have cyber insurance?' is used to answer the new question."

I find it so cool when GPT-4 highlights which strategy it’s chosen to create an answer:

“explanation”: “The new question is asking about the amount of coverage
the company has in cyber insurance. Looking at the old questions, question
2 and question 3 are the most similar to the new question and both provide
a clear response about the amount of coverage the company has in cyber
insurance. The company maintains a Cyber Liability with a combined limit
of $5,000,000 each occurrence and $10,000,000 annual aggregate. Therefore,
I used strategy b1, synthesizing these responses into an answer for the new
question.”

Here is another where it synthesizes across many questions:

“explanation”: “The answer is synthesized from multiple previous questions
and their responses. Questions 2, 3, 6, 8, 9, 11, 14, 17, 18, 19, 20, and 21
all provide information about the various tools and infrastructure pieces
that the company monitors. These responses collectively provide a
comprehensive answer to the new question.”

How about an older one where the explanation helped me to improve the list of criteria?

“answer”: “Cannot be answered.”,
“explanation”: “I apologize, but I cannot provide an answer based on the
given responses. The two answers provided are contradictory, and it is
unclear which one accurately reflects the types of hygiene maintenance
required for the company. Therefore, I cannot answer the question with
certainty.”

Without this explanation, I would have had no idea why GPT-4 was choosing Cannot be answered as the answer and likely not have been able to debug what was happening. This is a situation that is typical with function calling and why I think the `explanation` parameter is so helpful. It is easy to see how this would guide one to engineer the prompt differently. I hope this blog has shown how this small change to one’s function calls can improve quality-of-life with respect to ChatGPT outputs.

Finally, I should also address the paper “The Unreliability of explanations in Few-shot prompting for Textual Reasoning” by Ye & Durrett 2022. Here, the authors provided few-shot prompts to GPT3.5 that included explanations and found that when GPT3.5 hallucinated an answer it would often hallucinate an explanation that entailed that answer (it was less likely to produce an explanation that did not entail the answer). Any regular user of ChatGPT should know that it is possible for GPT to hallucinate its answer and explanation and so it’s always good to check an entire prompt and make sure this is not happening. That said, it is reasonable to presume that GPT-4 has gotten better at this sort of thing. Further, my instinct from my usage of GPT models is that few-shot examples often cause GPT to try and fit its responses to these examples at the expense of hallucinations. That is, GPT would rather produce an explanation that more closely models the few-shot explanations and is a hallucination than one that does not model them and is factually accurate. I do not have any research to back up this instinct so take it with a grain of salt. At any rate, one key difference between the paper and what I’ve described above is that there are no few-shot examples on the explanation parameter; we only attempt to constrain it via the criteria list. My subjective take from repeated use of this setup is that GPT-4’s explanations appear to always entail the answer and almost always cite which criteria it has chosen to create the answer which raises confidence about factual accuracy. But any GPT user should always be checking answers and explanations regularly for hallucinations.

Image removed.

Matt Glaman: Speed up developer onboarding with DDEV snapshots from your CI

In my previous blog post, Using DDEV snapshots to speed up GitHub Actions workflows, I explained how DDEV snapshots can be used to speed up continuous integration workflows for end-to-end tests. A workflow runs on the main development branch to create a DDEV snapshot to be cached and reused by subsequent jobs. If that cache can speed up continuous integration workflows, why can't it also speed up developer onboarding?

It is actually pretty simple! You will need somewhere to upload the snapshot archive, such as AWS S3 or some other storage. I leverage S3 for database dumps that I re-use with Tugboat so that a sample database can be seeded. I just never put it all together: use your CI to populate the dump artifact and automatically upload it so it can be shared across your team!