<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: livw</title>
    <description>The latest articles on DEV Community by livw (@livw).</description>
    <link>https://dev.to/livw</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1406342%2F3b20a6eb-5636-4ffb-849a-1062cbdca3c6.jpg</url>
      <title>DEV Community: livw</title>
      <link>https://dev.to/livw</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/livw"/>
    <language>en</language>
    <item>
      <title>Automating Insurance Claims Processing with AI and Conductor</title>
      <dc:creator>livw</dc:creator>
      <pubDate>Fri, 25 Apr 2025 10:12:22 +0000</pubDate>
      <link>https://dev.to/orkes/automating-insurance-claims-processing-with-ai-and-conductor-3nlp</link>
      <guid>https://dev.to/orkes/automating-insurance-claims-processing-with-ai-and-conductor-3nlp</guid>
      <description>&lt;p&gt;One of the biggest bottlenecks for the insurance industry is the sheer number of claims to process. The manual approach is expensive and time-consuming, requiring human operations to verify the documents, cross-check against the insurance policy, and follow up with the claimant, before the claim can be approved. &lt;/p&gt;

&lt;p&gt;These process inefficiencies translate to a poor claims experience for customers, &lt;a href="https://newsroom.accenture.com/news/2022/poor-claims-experiences-could-put-up-to-170b-of-global-insurance-premiums-at-risk-by-2027-according-to-new-accenture-research" rel="noopener noreferrer"&gt;leading to dissatisfaction and ultimately driving customers to switch insurers&lt;/a&gt;. What if there were a way to effectively automate all that work so that claims processing can be completed in mere days or hours, reducing customer churn?&lt;/p&gt;

&lt;p&gt;In this guide, we will explore how to wield LLMs (large language models) and orchestration to streamline manual business processes like insurance claims. Read on to learn the benefits, technical implementation details, and a demo example that you can try out in Orkes Conductor. &lt;/p&gt;

&lt;h2&gt;
  
  
  The solution: AI meets orchestration
&lt;/h2&gt;

&lt;p&gt;The insurance industry is not new to automation. Rules-based automation approaches like RPA involved tons of pre-planning and data preparation, which meant that once the process was set in place, new changes could not be easily made. These early automation approaches were more rigid and limited, and could not easily scale to handle complex cases or exceptions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automating complexity&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By leveraging the natural language capabilities of LLMs, the claims processing pipeline can be more effortlessly automated without having to predefine hundreds of rules across different policy wordings. Using &lt;a href="https://dev.to/orkes/guide-to-prompt-engineering-pof"&gt;prompt engineering&lt;/a&gt;, an LLM can act as an insurance representative to evaluate whether a claim can be approved. Here is an LLM-generated evaluation, which correctly identifies potential issues without any explicit business rules set:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The claim description mentions leukemia, which is a type of cancer. The 
doctor's report indicates tumors detected in blood, which is consistent 
with leukemia. However, the stage of cancer is not explicitly mentioned, 
and the policy covers only stage 3 and 4 cancer. The required documents 
(medical bill and doctor's report) are present, but the stage information 
is missing, which creates some uncertainty. The probability [of approval] 
is relatively high but not certain due to the lack of specific staging 
information.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Automating distributed systems&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Reviewing the claim details is just one step in the insurance processing pipeline. This is where &lt;a href="https://orkes.io/blog/what-is-orchestration" rel="noopener noreferrer"&gt;orchestration&lt;/a&gt; comes into play. Orkes Conductor is a fully-managed orchestration platform that coordinates disparate components and systems into an automated workflow or business process. Even if the supporting documents are uploaded on a system separate from customer details, or if the payment processing service resides on a different platform from the claims portal, an orchestration engine transforms these friction points into a well-oiled flow. &lt;/p&gt;

&lt;p&gt;These are some key highlights of Orkes Conductor: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Integration&lt;/strong&gt;—Connect different services and data sources, including legacy systems, through a cloud-based middleware platform.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visibility&lt;/strong&gt;—Track the status of your processes, easily recover from failures, and gain in-depth metrics on performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI capabilities&lt;/strong&gt;—Use in-built features to natively add LLM-powered components to your processes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let’s walk through an example insurance claims flow built in Orkes Conductor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Insurance claims processing flow
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fklzwnnahqe8gxo1efuy2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fklzwnnahqe8gxo1efuy2.png" alt="Infographic of insurance claims processing flow: Data extraction from multiple sources, Claims assessment, Outcome processing." width="800" height="420"&gt;&lt;/a&gt;Orkes Conductor can automate any claims processing flow with stateful process orchestration and seamless AI integrations.&lt;/p&gt;

&lt;p&gt;The claims processing flow can be distilled into three main steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Data extraction from multiple sources&lt;/strong&gt;—capture the claim details, supporting documents, and relevant policy documents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claims assessment&lt;/strong&gt;—review the data to determine if the claim meets the criteria for approval, using AI or human reviewers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Outcome processing&lt;/strong&gt;—execute the approval decision, like kicking off a payments flow and notifying the claimant.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As the orchestrator unit, Orkes Conductor acts as the execution engine that drives all the core components of the insurance claims process.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fryqtt2te45kauwbmqujz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fryqtt2te45kauwbmqujz.png" alt="Architecture diagram of how Conductor integrates with existing systems to orchestrate an insurance claims processing workflow." width="800" height="573"&gt;&lt;/a&gt;Conductor is the central orchestrator that coordinates between distributed services and systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Data extraction from multiple sources
&lt;/h3&gt;

&lt;p&gt;With a suite of over 20 &lt;a href="https://orkes.io/content/category/reference-docs/system-tasks" rel="noopener noreferrer"&gt;system tasks&lt;/a&gt;, Orkes Conductor supports retrieving data from many sources: through API endpoints, from data lakes, SQL databases, vector databases in a &lt;a href="https://dev.to/orkes/rag-explained-using-retrieval-augmented-generation-to-build-semantic-search-1i32"&gt;RAG system&lt;/a&gt;, and more. This enables you to automatically plug disparate data sources into business processes without any manual imports. &lt;/p&gt;

&lt;h3&gt;
  
  
  2. AI-powered claim assessment
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The claim description mentions leukemia, which is a type of cancer. The 
doctor's report indicates tumors detected in blood, which is consistent 
with leukemia. However, the stage of cancer is not explicitly mentioned, 
and the policy covers only stage 3 and 4 cancer. The required documents 
(medical bill and doctor's report) are present, but the stage information 
is missing, which creates some uncertainty. The probability [of approval] 
is relatively high but not certain due to the lack of specific staging 
information.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As previously demonstrated, LLMs possess the capability to naturally parse text without requiring deep technical work. Leveraging &lt;a href="https://dev.to/orkes/guide-to-prompt-engineering-pof"&gt;prompt engineering&lt;/a&gt;, the LLM can be easily tuned to output accurate claim assessments. Even if the insurance policy changes, an LLM-powered solution will intelligently reason through any claims scenario. Here is a simplified prompt template that produced the claims assessment above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are an insurance claims assessor who needs to calculate the probability of approving a claim. 

This is the policy statement: "${policy-statement}".

These are the supporting docs: "${docs}".

This is the claims description: "${claims-description}".
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Orkes Conductor makes it easy to scale LLM-driven processes with its &lt;a href="https://orkes.io/content/developer-guides/creating-and-managing-gen-ai-prompt-templates" rel="noopener noreferrer"&gt;&lt;strong&gt;AI Prompt Studio&lt;/strong&gt;&lt;/a&gt; and code-free &lt;strong&gt;AI/LLM integrations and tasks&lt;/strong&gt;. With the Orkes’ AI Prompt Studio, you can securely craft and test reusable prompts for the claims assessment workflow. By replacing the prompt variables like &lt;code&gt;${policy-statement}&lt;/code&gt; with the required information extracted in step 1, the LLM can predictably handle complex or edge cases—combining the strengths of AI-powered flexibility with guardrails.&lt;/p&gt;

&lt;p&gt;Orkes’ suite of LLM integrations provides access to the latest AI models from all major LLM providers, like OpenAI, &lt;a href="https://aws.amazon.com/blogs/apn/build-production-ready-generative-ai-applications-with-orkes-and-amazon-bedrock/" rel="noopener noreferrer"&gt;Amazon Bedrock&lt;/a&gt;, and Anthropic. With all these choices at your fingertips, Orkes’ modular workflow approach makes it easy to test and switch between any AI model to find the most effective one for your use case — in this case, an insurance claims flow.&lt;/p&gt;

&lt;p&gt;Bring all of these together by using Orkes’ built-in LLM tasks, which provides chat completions, embedding retrievals, and more without needing to add extra code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fouhfego7twg8zv95xjlr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fouhfego7twg8zv95xjlr.png" alt="Infographic showcasing Orkes AI Prompt Studio, AI Integrations, and AI Tasks." width="800" height="1133"&gt;&lt;/a&gt;Orkes' suite of AI features empowers rapid development.&lt;/p&gt;

&lt;h4&gt;
  
  
  Human-in-the-loop
&lt;/h4&gt;

&lt;p&gt;Even with guardrails for AI models, adding human review checkpoints further mitigates the risks of AI miscalculation. After the AI-driven claims assessment is completed, the process can then trigger a human review for final approval of the insurance payout. The AI-generated assessment provides a detailed summary for the human assessor to investigate, speeding up the process.&lt;/p&gt;

&lt;p&gt;In Orkes, our human-in-the-loop features allow you to seamlessly integrate these human touchpoints with both your backend process and your frontend claims review portal. This ensures an audit trail of all actions taken, while guaranteeing that businesses don’t have to migrate to different portal just to enjoy these benefits.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Business decision post-actions
&lt;/h3&gt;

&lt;p&gt;Finally, once the decision has been made, the workflow can route either to an early termination in the case of rejection, or to a post-processing sequence like a payout initiation and outcome notification. Orkes’ orchestration engine facilitates coordination across different microservices, internal services, and other third-party integrations like Stripe and Sendgrid.&lt;/p&gt;

&lt;h3&gt;
  
  
  Integration with your tech stack
&lt;/h3&gt;

&lt;p&gt;Integrate the workflow into your existing portal for claims processing. Run it as a server job. Trigger the claims process from an event-driven system. Whatever your system architecture requires, Orkes Conductor brings the flexibility to fit with your existing processes rather than force you to migrate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it out in Conductor
&lt;/h2&gt;

&lt;p&gt;Now, here’s how you can try out a working AI-powered insurance claims processing workflow for yourself in Conductor. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz2cjcq0otmc79w6i4ihl.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz2cjcq0otmc79w6i4ihl.jpg" alt="High-level diagram versus the actual Conductor workflow for insurance claims processing." width="800" height="965"&gt;&lt;/a&gt;Orkes’ visual workflow editor makes it intuitive to transition from a napkin-top or whiteboard-sketch idea to a production-ready workflow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create an account in our free &lt;a href="https://developer.orkescloud.com/?utm_campaign=insurance-claims-blog&amp;amp;utm_source=devto-blog&amp;amp;utm_medium=web" rel="noopener noreferrer"&gt;Developer Playground&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Create the insurance claim workflow&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Log in to &lt;a href="https://developer.orkescloud.com/?utm_campaign=insurance-claims-blog&amp;amp;utm_source=devto-blog&amp;amp;utm_medium=web" rel="noopener noreferrer"&gt;Developer Playground&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;In &lt;strong&gt;Definitions&lt;/strong&gt; &amp;gt; &lt;strong&gt;Workflow&lt;/strong&gt;, select &lt;strong&gt;+ Define workflow&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Paste the following workflow JSON into the &lt;strong&gt;Code&lt;/strong&gt; tab on the right-side panel:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"createTime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1744263984129&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"updateTime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1744871696379&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"insurance-claim"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Insurance claim workflow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tasks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"collate-details"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"taskReferenceName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"collate-details_ref"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"inputParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FORK_JOIN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"decisionCases"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"defaultCase"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"forkTasks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"get-customer-details"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"taskReferenceName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"get-customer-details_ref"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"inputParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"uri"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://orkes-api-tester.orkesconductor.com/api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"connectionTimeOut"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"readTimeOut"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"accept"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"contentType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application/json"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HTTP"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"get-claims-details"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"taskReferenceName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"get-claims-details_ref"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"inputParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"expression"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"// Function to randomly pick an item from the array&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;(function getRandomItem(arr) {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  const items = [&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    { id: 1, name: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Jane&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;, claims: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;stage 3 stomach cancer&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    { id: 2, name: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Jen&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;, claims: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;stage 0 breast cancer&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    { id: 3, name: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;John&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;, claims: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;stage 4 leukemia&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    { id: 4, name: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Jim&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;, claims: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;hyperthyroidism &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    { id: 4, name: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Jeff&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;, claims: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;leukemia &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    { id: 4, name: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;June&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;, claims: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;stage 4 flu &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; }&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  ];&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;  const randomIndex = Math.floor(Math.random() * items.length);&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  return items[randomIndex];&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;)();"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"evaluatorType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"graaljs"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"INLINE"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"get-policy-details"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"taskReferenceName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"get-policy-details_ref"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"inputParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"uri"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://orkes-api-tester.orkesconductor.com/api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"connectionTimeOut"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"readTimeOut"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"accept"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"contentType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application/json"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HTTP"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"get-coverage-statement"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"taskReferenceName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"get-coverage-statement_ref"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"inputParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"coverageStatement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Critical illness cover of USD 200,000.00 for stage 3 and 4 cancer. To make a successful claim, the following documents are required: (1) medical bill and (2) doctor's report. If any documents are missing, the claim cannot be processed."&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SET_VARIABLE"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"get-supporting-docs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"taskReferenceName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"get-supporting-docs_ref"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"inputParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"expression"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"// Function to randomly pick an item from the array&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;(function getRandomItem(arr) {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  const items = [&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    { receipt: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;x-ray scan - USD 4000 consult USD 7000 total USD 11000&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;, report: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Doctor Lee 15/03/25 Tumours detected in blood. Suspected stage 4 cancer. Patient is referred for further treatment.&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    { receipt: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;x-ray scan - USD 4000 consult USD 7000 total USD 11000&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;, report: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Doctor Lee 15/03/25 Tumours detected in blood. Suspected stage 1 cancer. Patient is referred for further treatment.&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    { receipt: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;x-ray scan - USD 4000 consult USD 7000 total USD 11000&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;, report: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Doctor Lee 15/03/25 Tumours detected in blood. Patient is referred for follow-up.&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; },&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    { receipt: &lt;/span&gt;&lt;span class="se"&gt;\"\"&lt;/span&gt;&lt;span class="s2"&gt;, report: &lt;/span&gt;&lt;span class="se"&gt;\"\"&lt;/span&gt;&lt;span class="s2"&gt; }&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  ];&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;  const randomIndex = Math.floor(Math.random() * items.length);&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  return items[randomIndex];&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;)();"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"evaluatorType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"graaljs"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"INLINE"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"startDelay"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"joinOn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"join_on_collate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"taskReferenceName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"join_on_collate_ref"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"inputParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"JOIN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"forkTasks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"joinOn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"get-customer-details_ref"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"get-policy-details_ref"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"optional"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"get-approval-probability"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"taskReferenceName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"get-approval-probability_ref"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"inputParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"llmProvider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AnthropicClaude"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"claude-3-5-sonnet-20240620"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"promptName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"determine-insurance-claim-probability"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"promptVariables"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"claims-description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${get-claims-details_ref.output.result.claims}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"policy-statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${workflow.variables.coverageStatement}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"docs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${get-supporting-docs_ref.output.result}"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"LLM_TEXT_COMPLETE"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ai-decider"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"taskReferenceName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ai-decider_ref"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"inputParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"probabilityValue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${get-approval-probability_ref.output.result.probability}"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SWITCH"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"decisionCases"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"0.0"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"send-refile-claim-notification"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"taskReferenceName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"send-refile-claim-notification_ref"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"inputParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"uri"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://orkes-api-tester.orkesconductor.com/api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"accept"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"contentType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"encode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HTTP"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"terminate_2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"taskReferenceName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"terminate_ref_2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"inputParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"terminationStatus"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"COMPLETED"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"terminationReason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Claim did not pass LLM validation check. Need to refile for claims processing."&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"TERMINATE"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"defaultCase"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"approve-claim-payout"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"taskReferenceName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"approve-claim-payout_ref"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"inputParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"__humanTaskDefinition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"assignmentCompletionStrategy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"LEAVE_OPEN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"displayName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Approve Claim"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"userFormTemplate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"InsuranceClaims"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"assignments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"assignee"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ACME"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"userType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EXTERNAL_GROUP"&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"slaMinutes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"taskTriggers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"claimDescription"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${get-claims-details_ref.output.result.claims}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"coverageStatement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${workflow.variables.coverageStatement}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"probability"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${get-approval-probability_ref.output.result.probability}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"aiSummary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${get-approval-probability_ref.output.result.reason}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"approval"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HUMAN"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"approved"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"taskReferenceName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"approved_ref"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"inputParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"approval"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${approve-claim-payout_ref.output.approval}"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SWITCH"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"decisionCases"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"true"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"process-payment"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"taskReferenceName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"process-payment_ref"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"inputParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"uri"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://orkes-api-tester.orkesconductor.com/api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"connectionTimeOut"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"readTimeOut"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"accept"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"contentType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application/json"&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HTTP"&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"send-success-notification"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"taskReferenceName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"send-success-notification_ref"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"inputParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"uri"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://orkes-api-tester.orkesconductor.com/api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"connectionTimeOut"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"readTimeOut"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"accept"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"contentType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application/json"&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HTTP"&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"defaultCase"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"send-not-approved-notification"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"taskReferenceName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"send-not-approved-notification_ref"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"inputParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"uri"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://orkes-api-tester.orkesconductor.com/api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"connectionTimeOut"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"readTimeOut"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"accept"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"contentType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application/json"&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HTTP"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"terminate_1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"taskReferenceName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"terminate_ref_1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"inputParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"terminationStatus"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"COMPLETED"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"terminationReason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Claim has not been approved by human agent."&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"TERMINATE"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"evaluatorType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"value-param"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"expression"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"approval"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"evaluatorType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"value-param"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"expression"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"probabilityValue"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"inputParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"policyNumber"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"customerId"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"supportingDocs"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"outputParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"failureWorkflow"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"schemaVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"restartable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timeoutPolicy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ALERT_ONLY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timeoutSeconds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"variables"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"inputTemplate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"enforceSchema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Save the workflow. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Add LLM integrations and models&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;Integrations&lt;/strong&gt; and select &lt;strong&gt;+ New integration&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;AI/LLM&lt;/strong&gt; section, add your desired LLM provider.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: In the workflow that you’ve just created, the &lt;code&gt;get-approval-probability&lt;/code&gt; task makes use of **Anthropic Claude’s Sonnet 3.5&lt;/em&gt;&lt;em&gt;, but you can choose any LLM provider and simply modify the workflow task later.&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Return to &lt;strong&gt;Integrations&lt;/strong&gt; and add your LLM models to your newly-added integration.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For detailed steps on adding LLM integrations, refer to the &lt;a href="https://orkes.io/content/category/integrations/ai-llm" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Add the AI prompt&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;Definitions&lt;/strong&gt; &amp;gt; &lt;strong&gt;AI Prompts&lt;/strong&gt; and select &lt;strong&gt;+ Add AI prompt&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;Code&lt;/strong&gt; tab, paste the following JSON:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"createTime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1744715996941&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"updateTime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1744906103023&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"determine-insurance-claim-probability"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"template"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"You are an insurance claims assessor who needs to calculate the probability of approving a claim.&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;This is the policy statement: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;${policy-statement}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;These are the supporting docs: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;${docs}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;This is the claims description: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;${claims-description}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;Format your response ONLY as a JSON object with the following structure:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;valid&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;{&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;probability&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;A numerical probability between 0.0 - 1.0. &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;reason&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;A reason for the probability.&lt;/span&gt;&lt;span class="se"&gt;\"\n&lt;/span&gt;&lt;span class="s2"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/valid&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;Do not wrap the JSON object in markdown. Do use quotation marks in the JSON object.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;invalid&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;{probability=0.0, reason=The claim description mentions 'stage 5 cancer', which does not match the policy coverage for stage 3 and 4 cancer. Additionally, the provided documents confirm stage 3 cancer, further disqualifying the claim from approval.}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/invalid&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;invalid&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;```

json&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;{&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;probability&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: 0.0,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;reason&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;The claim description mentions 'stage 5 cancer', which does not match the policy coverage for stage 3 and 4 cancer. Additionally, the provided documents confirm stage 3 cancer, further disqualifying the claim from approval.&lt;/span&gt;&lt;span class="se"&gt;\"\n&lt;/span&gt;&lt;span class="s2"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;

```&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/invalid&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Determine the probability of approving a claim based on a policy statement and a claim description"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"variables"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"docs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"claims-description"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"policy-statement"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"integrations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Return to the &lt;strong&gt;Form&lt;/strong&gt; tab, and add any AI models you wish to use with this prompt.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: In the workflow that you’ve just created, the &lt;code&gt;get-approval-probability&lt;/code&gt; task makes use of **Anthropic Claude’s Sonnet 3.5&lt;/em&gt;&lt;em&gt;, but you can add any LLM provider here and simply modify the workflow task later.&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Save the AI prompt.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Optional: Modify the AI prompt&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The prompt should look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are an insurance claims assessor who needs to calculate the probability of approving a claim.

This is the policy statement: "${policy-statement}".

These are the supporting docs: "${docs}".

This is the claims description: "${claims-description}".

Format your response ONLY as a JSON object with the following structure:
&amp;lt;valid&amp;gt;
{
  "probability": "A numerical probability between 0.0 - 1.0. ",
  "reason": "A reason for the probability."
}
&amp;lt;/valid&amp;gt;

Do not wrap the JSON object in markdown. Do use quotation marks in the JSON object.
&amp;lt;invalid&amp;gt;
{probability=0.0, reason=The claim description mentions 'stage 5 cancer', which does not match the policy coverage for stage 3 and 4 cancer. Additionally, the provided documents confirm stage 3 cancer, further disqualifying the claim from approval.}
&amp;lt;/invalid&amp;gt;

&amp;lt;invalid&amp;gt;
\`\`\`json
{
  "probability": 0.0,
  "reason": "The claim description mentions 'stage 5 cancer', which does not match the policy coverage for stage 3 and 4 cancer. Additionally, the provided documents confirm stage 3 cancer, further disqualifying the claim from approval."
}
\`\`\`
&amp;lt;/invalid&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To modify the prompt, here are some guidelines to steer the LLM to respond with a well-structured JSON output:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unambiguously establish the role of the LLM as an insurance claims assessor.&lt;/li&gt;
&lt;li&gt;Precisely describe the expected input and output formats.

&lt;ul&gt;
&lt;li&gt;Make sure the output has the exact fields expected by the subsequent tasks in the workflow.&lt;/li&gt;
&lt;li&gt;Provide clear examples of the output.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Emphasize fairness and adherence to the provided policies.&lt;/li&gt;

&lt;li&gt;Make sure that missing inputs are properly handled.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Optional: Modify the workflow&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you wish to use other LLM providers than Anthropic Claude, make sure to modify the &lt;code&gt;get-approval-probability&lt;/code&gt; task.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Return to your insurance claim workflow and select the &lt;strong&gt;get-approval-probability&lt;/strong&gt; task in the visual diagram.&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;Task&lt;/strong&gt; tab, modify the &lt;strong&gt;LLM provider&lt;/strong&gt; and &lt;strong&gt;Model&lt;/strong&gt; fields.&lt;/li&gt;
&lt;li&gt;Save the workflow.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Add the user form for the Human task&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The user form serves as the interface for human assessors to evaluate and approve the payout. Orkes Conductor makes it easy to integrate and deploy these user forms on your own user portals through our extensive suite of &lt;a href="https://orkes.io/content/developer-guides/orchestrating-human-tasks#step-4-display-the-form-on-an-external-ui" rel="noopener noreferrer"&gt;APIs and SDKs&lt;/a&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;Definitions&lt;/strong&gt; &amp;gt; &lt;strong&gt;User Forms&lt;/strong&gt; and select &lt;strong&gt;+ New form&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;Code&lt;/strong&gt; tab, paste the following JSON:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"createTime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1744816361848&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"updateTime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1744816643214&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"InsuranceClaims"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"jsonSchema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"$schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://json-schema.org/draft-07/schema"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"claimDescription"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"coverageStatement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"probability"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"aiSummary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"approval"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"boolean"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"templateUI"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"VerticalLayout"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"elements"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Control"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"scope"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#/properties/claimDescription"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Claim Description"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"readonly"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Control"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"scope"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#/properties/coverageStatement"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Coverage Statement"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"readonly"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Control"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"scope"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#/properties/probability"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Probability"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"readonly"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Control"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"scope"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#/properties/aiSummary"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AI Summary"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"readonly"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Control"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"scope"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#/properties/approval"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Approve?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Save the user form.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Running the workflow
&lt;/h3&gt;

&lt;p&gt;Now that all your Conductor resources are ready, let’s run the workflow to experience the power of AI in automating claims processing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To run the workflow:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In &lt;strong&gt;Definitions&lt;/strong&gt; &amp;gt; &lt;strong&gt;Workflow&lt;/strong&gt;, select your insurance claim workflow.&lt;/li&gt;
&lt;li&gt;Select the &lt;strong&gt;Run&lt;/strong&gt; tab in the right-side panel and select &lt;strong&gt;Run Workflow&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Upon running the workflow, you will be redirected to the workflow execution details page. Use the visual diagram to follow the workflow progression.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmdakhmhrzxku49lh0335.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmdakhmhrzxku49lh0335.jpg" alt="Screenshot of the workflow execution in Conductor." width="800" height="679"&gt;&lt;/a&gt;In Conductor, easily track workflows as they progress through different stages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Intelligent automation in action
&lt;/h2&gt;

&lt;p&gt;In the workflow execution details page, select the &lt;code&gt;get-approval-probability&lt;/code&gt; task and then its &lt;strong&gt;Output&lt;/strong&gt; tab. The LLM will provide an approval probability along with its reasoning.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flinldqst0azv0gvhbqcg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flinldqst0azv0gvhbqcg.png" alt="Screenshot of the LLM get-approval-probability task output, where the probability is 0." width="800" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this instance, the probability of approval is 0, since the required supporting documents are missing. With workflow orchestration, the process then automatically progresses to notify the claimant to supplement the missing documents without needing additional human review.&lt;/p&gt;

&lt;p&gt;Let’s trigger another execution to examine how a different scenario might play out.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnpt9btpnsp04t3vdauen.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnpt9btpnsp04t3vdauen.png" alt="Screenshot of the LLM get-approval-probability task output, where the probability is 0.7." width="800" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this instance, the probability is non-zero since all the supporting documents are present. However, the supporting evidence is a little vague and may require further follow-up. &lt;strong&gt;This is where the workflow benefits greatly from human oversight.&lt;/strong&gt; Since there is a chance for approval, the workflow routes to a human-in-the-loop task, where a human assessor can review the AI-generated assessment summary to make the final decision.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsgnzfy7wbmke0i3e11j0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsgnzfy7wbmke0i3e11j0.jpg" alt="Screenshot of the user form on the Conductor interface." width="800" height="556"&gt;&lt;/a&gt;Through Conductor's Human Task APIs, these user forms can be integrated into existing portals.&lt;/p&gt;

&lt;p&gt;Try it out yourself by going to &lt;strong&gt;Executions&lt;/strong&gt; &amp;gt; &lt;strong&gt;Human Tasks&lt;/strong&gt; and selecting the pending execution. You can claim the task, check the approve button to approve it (or leave it unchecked to reject it), and complete the task.&lt;/p&gt;

&lt;p&gt;When you return to the workflow executions details page (in &lt;strong&gt;Executions&lt;/strong&gt; &amp;gt; &lt;strong&gt;Workflow&lt;/strong&gt;), the workflow will have progressed to the next steps depending on your choice. This is the power of Orkes Conductor, combining both orchestration and AI capabilities to build automated processes that scale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Extending the workflow&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While the data extraction, payment processing, and notification steps are mock tasks, they can be easily replaced with real data sources and services. Go a step further by switching out the mock tasks with real tasks for your own needs, or request a demo for &lt;a href="https://orkes.io/platform?utm_campaign=insurance-claims-blog&amp;amp;utm_source=devto-blog&amp;amp;utm_medium=web" rel="noopener noreferrer"&gt;Orkes Conductor&lt;/a&gt; to learn more about how orchestration can accelerate your business processes. &lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Slow, outdated insurance claims processes can be modernized by investing in the latest technology for AI and orchestration. Using Orkes Conductor to scale AI-automated processes offers a multitude of benefits:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;AI automation and agility&lt;/strong&gt;—Easily add and upgrade AI-driven components to your processes for intelligent automation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration with existing systems&lt;/strong&gt;—Use Orkes as the middleware platform to integrate legacy systems, third-party applications, and other components in your business ecosystem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced governance and monitoring&lt;/strong&gt;—Built-in monitoring and state tracking dashboards to get global visibility and auditability into processes and performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human-in-the-loop oversight&lt;/strong&gt;—Seamlessly add human oversight to processes and integrate them with frontend interfaces for your intended users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fast, scalable performance&lt;/strong&gt;—Build and run processes on a performant orchestration engine that powers the biggest players across industries, like Netflix, Tesla, and American Express.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;a href="https://orkes.io/platform?utm_campaign=insurance-claims-blog&amp;amp;utm_source=devto-blog&amp;amp;utm_medium=web" rel="noopener noreferrer"&gt;Conductor&lt;/a&gt; is an enterprise-grade Unified Application Platform for process automation, API and microservices orchestration, agentic workflows, and more. Check out the &lt;a href="https://orkes.io/pricing" rel="noopener noreferrer"&gt;full set of features&lt;/a&gt;, or try it yourself using our free &lt;a href="https://developer.orkescloud.com/?utm_campaign=insurance-claims-blog&amp;amp;utm_source=devto-blog&amp;amp;utm_medium=web" rel="noopener noreferrer"&gt;Developer Playground&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>orchestration</category>
      <category>ai</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Orchestrating Asynchronous Workflows (How Are They Different from Synchronous?)</title>
      <dc:creator>livw</dc:creator>
      <pubDate>Thu, 27 Mar 2025 04:38:48 +0000</pubDate>
      <link>https://dev.to/orkes/orchestrating-asynchronous-workflows-how-are-they-different-from-synchronous-26gc</link>
      <guid>https://dev.to/orkes/orchestrating-asynchronous-workflows-how-are-they-different-from-synchronous-26gc</guid>
      <description>&lt;p&gt;Asynchronous workflows have become a cornerstone of modern software development, enabling applications to handle complex operations without blocking the main execution thread. This approach is how we can design responsive, scalable, and efficient systems involving distributed components. In this blog, let’s explore what asynchronous workflows are, their use cases, challenges, and best practices for implementing them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use asynchronous workflows?
&lt;/h2&gt;

&lt;p&gt;The modern tech stack is inherently distributed. Your SuperAwesome program might call on a LongProcessing endpoint, receive SuperImportant events streamed from a legacy system, or require SomeRelevant input from a human user. When these processes or events take a long or indefinite time to complete, in a synchronous paradigm, your main execution program is forced to wait, which blocks it from completing anything else. &lt;/p&gt;

&lt;p&gt;An asynchronous workflow approach uses design patterns where indefinite or long-running processes are non-blocking yet durable. In other words, &lt;strong&gt;asynchronous workflows enable responsive and resilient systems even in the face of uncertainty&lt;/strong&gt;, like an unscheduled event message or unknown processing time. &lt;/p&gt;

&lt;p&gt;One of the biggest benefits of asynchronous workflows is the ability to combine both event-driven and &lt;a href="https://orkes.io/blog/what-is-orchestration" rel="noopener noreferrer"&gt;orchestration&lt;/a&gt; patterns into a unified system for &lt;strong&gt;event-driven workflows&lt;/strong&gt;. When workflow orchestration is used in conjunction with event-driven architecture, this flexibility unlocks the best of both worlds: real-time responsivity to events while coordinating complex sequences of interactions. &lt;/p&gt;

&lt;p&gt;But what exactly does asynchronous mean? What even is an asynchronous workflow? You may already be familiar with these concepts, but let’s have a quick recap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Synchronous vs asynchronous programming
&lt;/h2&gt;

&lt;p&gt;In software, &lt;em&gt;synchronous&lt;/em&gt; and &lt;em&gt;asynchronous&lt;/em&gt; are broad concepts that apply across all levels of software architecture. At its core, synchronous tasks or processes are executed in a fashion where the &lt;strong&gt;server actively awaits the response before moving on to the next task&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In contrast, asynchronous tasks or processes are executed &lt;strong&gt;without the server actively waiting for the required response&lt;/strong&gt;. In an asynchronous paradigm, the task is executed in a way that doesn’t block the main thread, such as by being completed on a separate thread, worker, or program.  The execution is typically a &lt;strong&gt;fire-and-forget&lt;/strong&gt; pattern, where the main thread initiates the task without waiting for the response — a simple implementation could be a function that starts the operation and returns immediately to the main thread, with a callback to return the computed result later. The server can then process another task that isn’t dependent on this pending task.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Area&lt;/th&gt;
&lt;th&gt;Synchronous Programming&lt;/th&gt;
&lt;th&gt;Asynchronous Programming&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Code execution&lt;/td&gt;
&lt;td&gt;Tasks are executed one after the other only after completion (blocking).&lt;/td&gt;
&lt;td&gt;Tasks are executed in a fire-and-forget fashion (can be non-blocking).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Implementation&lt;/td&gt;
&lt;td&gt;Easier to implement.&lt;/td&gt;
&lt;td&gt;More challenging to implement.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Program flow&lt;/td&gt;
&lt;td&gt;Deterministic, easier to reason about and debug.&lt;/td&gt;
&lt;td&gt;Non-deterministic, harder to reason about and debug; potential for race conditions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scalability&lt;/td&gt;
&lt;td&gt;Limited scalability under high concurrency.&lt;/td&gt;
&lt;td&gt;Higher scalability under high concurrency due to more efficient resource usage.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Uses&lt;/td&gt;
&lt;td&gt;Ideal for straightforward projects without unpredictable interactions.&lt;/td&gt;
&lt;td&gt;Ideal for complex projects involving real-time interactions with multiple distributed components.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Challenges of asynchronous implementation
&lt;/h2&gt;

&lt;p&gt;At the program-level, asynchronous programming can be implemented in several ways: callbacks, promises, or async/await. When it comes to communicating between different services, it starts to look more like webhooks, event handlers, or stream processing. For modern-day applications, event-driven architecture has multiple advantages: real-time processing, loose coupling of services, and resilient messaging. &lt;/p&gt;

&lt;p&gt;However, an event-driven approach runs into many complications when services inadvertently still need to be executed in a specific order, resulting in implicit dependencies that are &lt;a href="https://dev.to/orkes/debugging-distributed-systems-52ln"&gt;difficult to trace and debug&lt;/a&gt;. Issues like data consistency, handling &lt;a href="https://dev.to/orkes/compensation-transaction-patterns-the-key-to-handling-failures-in-distributed-applications-nh9"&gt;transaction rollbacks&lt;/a&gt;, and mitigating race conditions end up much more difficult to deal with in a distributed, decoupled event-based architecture. &lt;strong&gt;Without careful implementation, the state of your application becomes impossible to maintain or track&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Another related challenge is ensuring the &lt;a href="https://dev.to/orkes/why-your-applications-need-durable-execution-and-best-practices-to-achieve-it-5ham"&gt;&lt;strong&gt;durability of your program flow&lt;/strong&gt;&lt;/a&gt;. If an asynchronous process is in progress but crashes mid-flight, the work may get lost without retries or retried with duplicate side effects. Getting visibility for troubleshooting and handling failures gracefully becomes even more complicated, taking away precious time from developing the main program flow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using asynchronous workflows
&lt;/h2&gt;

&lt;p&gt;Enter asynchronous workflows.&lt;/p&gt;

&lt;p&gt;A workflow is a sequence of tasks that must be completed in a specific order to achieve a particular goal. On the surface, an “asynchronous workflow” seems oxymoronic: an ordered sequence of tasks can’t possibly be asynchronous. But let’s return to the core of asynchronicity: completing tasks without blocking the program flow. In an asynchronous workflow, asynchronous tasks are triggered and returned immediately, with the actual response returned later on. This is what makes for an asynchronous workflow, even if the tasks are executed in sequential order. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkh2dicdea0oqub2bh128.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkh2dicdea0oqub2bh128.jpg" alt="Diagram of async workflows." width="800" height="418"&gt;&lt;/a&gt;Asynchronous workflows contain asynchronous tasks.&lt;/p&gt;

&lt;p&gt;By orchestrating asynchronous workflows, &lt;strong&gt;we can easily overcome the issue of state management and durable execution when tracking various asynchronous tasks or processes.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  State management with asynchronous workflows
&lt;/h3&gt;

&lt;p&gt;Workflows can be orchestrated and managed using unified platforms like Orkes Conductor. Using &lt;a href="https://orkes.io/blog/what-is-orchestration" rel="noopener noreferrer"&gt;workflow orchestration&lt;/a&gt;, a central orchestrator manages the execution of a series of tasks pre-determined or dynamically ordered at runtime. The platform tracks each task’s status, so you get a global view of the application state (scheduled, in progress, completed, failed), even when the tasks occur independently of the main flow.&lt;/p&gt;

&lt;p&gt;State management ensures application consistency, facilitates graceful recovery, and enables rapid debugging in case of terminal failure. Using orchestration, developers no longer need to spend time building plumbing code to get visibility into the execution flow of distributed components.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to use asynchronous workflows?
&lt;/h2&gt;

&lt;p&gt;The choice to use a synchronous or asynchronous workflow depends on your project requirements. Asynchronous workflows are often advantageous in the following situations where there is uncertainty in time-bound conditions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;User-facing applications where responsiveness is critical&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An asynchronous workflow enables the application to process long jobs, like file uploads, in the background while the user continues using the application.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Data processing and analytics pipelines&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since ingesting, transforming, and analyzing large datasets can take a long time, asynchronous orchestration helps manage the flow between various processing stages, ensuring data integrity and handling errors appropriately.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Long-running business processes that span hours or days&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Asynchronous orchestration provides a way to manage the state of &lt;a href="https://orkes.io/blog/business-process-orchestration-best-practices/" rel="noopener noreferrer"&gt;business processes&lt;/a&gt;, like order fulfillment, approval flows, and claims processing, over an indefinite period.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj4j0wd83tfpxwdwjo4x4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj4j0wd83tfpxwdwjo4x4.jpg" alt="Use cases for asynchronous workflows: User-facing applications where responsiveness is critical; Data processing and analytics pipelines; and Long-running business processes that span hours or days." width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In these cases where processes take a long or unknown time to complete, using an asynchronous workflow ensures that the process remains durable and persists despite interruptions or failures. &lt;/p&gt;

&lt;h2&gt;
  
  
  Best practices for asynchronous workflows
&lt;/h2&gt;

&lt;p&gt;When using asynchronous workflows for your applications, keep in mind the following practices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Design for resilience.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Configure proper retry mechanisms and design with the expectation that services may fail temporarily. Use compensation flows to handle terminal failures or the &lt;a href="https://dev.to/orkes/saga-pattern-in-distributed-systems-5bm0"&gt;saga pattern&lt;/a&gt; to safely track reversals or termination in a workflow.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Make sure to use the appropriate error-handling measures.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An asynchronous workflow that takes a long time to complete will require different timeout, rate limit, or retry strategies compared to fast, synchronous workflows. For example, to avoid unnecessary timeouts, use an appropriate timeout duration based on the recovery requirements.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Embed observability into your workflows.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Get comprehensive tracing, logging, and monitoring across your asynchronous workflows. This is crucial for diagnosing issues and maintaining overall system health.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Building an asynchronous workflow using Orkes Conductor
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://orkes.io/platform" rel="noopener noreferrer"&gt;Orkes Conductor&lt;/a&gt; is an enterprise-grade Unified Application Platform for &lt;a href="https://orkes.io/use-cases/process-orchestration" rel="noopener noreferrer"&gt;process automation&lt;/a&gt;, API and microservices orchestration, &lt;a href="https://orkes.io/use-cases/agentic-workflows" rel="noopener noreferrer"&gt;agentic workflows&lt;/a&gt;, and more. With global state tracking, Orkes Conductor’s &lt;strong&gt;core platform architecture makes it easy to build asynchronous and event-driven workflows&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Easily add asynchronous tasks like &lt;a href="https://orkes.io/content/reference-docs/operators/wait" rel="noopener noreferrer"&gt;Wait&lt;/a&gt; tasks and &lt;a href="https://orkes.io/content/reference-docs/operators/human" rel="noopener noreferrer"&gt;Human&lt;/a&gt; tasks.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;These tasks enable you to durably pause the workflow for an extended period while waiting on an external signal, such as a form completion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Seamlessly consume and publish events with other event-driven systems.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With in-built integrations with dozens of event systems and the ease of creating and monitoring event handlers, you can quickly build and extend your system’s event-driven architecture.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F84fu8lckm5wkays2y4vi.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F84fu8lckm5wkays2y4vi.jpg" alt="List of event broker integrations in Orkes Conductor: AMQP, AWS SQS, Confluent Kafka, Apache Kafka, NATS Messaging, Amazon MSK, Azure Service Bus, GCP Pub Sub, IBM MQ." width="800" height="480"&gt;&lt;/a&gt;Current message broker integrations available in Orkes Conductor.&lt;/p&gt;

&lt;p&gt;Trigger workflows from an event, publish events from a workflow, or create &lt;a href="https://dev.to/orkes/change-data-capture-cdc-in-event-driven-microservices-13m3"&gt;event-driven CDC systems&lt;/a&gt;—the flexibility is yours to decide.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Get webhook integrations with external systems to send or receive webhook events.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use webhooks from enterprise systems like Slack, Teams, GitHub, or any custom system you need for asynchronous design patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Trigger workflows asynchronously in response to tasks, signals, events, and webhooks.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Unlike synchronous workflows, all asynchronous workflows must be invoked asynchronously in a fire-and-forget pattern due to their unknown completion time. Use Conductor’s SDKs or APIs to start workflows asynchronously.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Fully native error-handling and observability mechanisms.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Set custom retries, timeouts, rate limits, and more for every task and workflow based on individual needs. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What an asynchronous workflow looks like&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An example could look like kicking off a subtitling workflow whenever an UploadSuccess message is registered in the video processing pipeline. An event handler can be easily created in Conductor to start the subtitling workflow from an external trigger. Since the subtitling workflow involves processing time and perhaps a step for human review, it may take some time to complete – making it an asynchronous workflow. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo7spcmg2rgfjbk8m0bm2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo7spcmg2rgfjbk8m0bm2.jpg" alt="Example async workflows." width="800" height="571"&gt;&lt;/a&gt;Asynchronous workflows in Orkes Conductor.&lt;/p&gt;

&lt;p&gt;With a fire-and-forget invocation, listeners must be implemented to get notified of an asynchronous workflow completion. In Conductor, a workflow status listener enables you to detect and capture workflow state changes in real-time. These updates can be further transmitted to other systems, such as a message broker, to trigger downstream services or processes. For example, once the subtitling workflow is completed, this change can be captured to make the subtitled video available on the video platform for the end user.&lt;/p&gt;

&lt;p&gt;This is how asynchronous workflows in Conductor can be used to manage the complex interactions between multiple processes.&lt;/p&gt;




&lt;p&gt;Explore more use cases with our &lt;a href="https://orkes.io/content/category/templates" rel="noopener noreferrer"&gt;Template Library&lt;/a&gt; or try building asynchronous workflows using our online &lt;a href="https://developer.orkescloud.com/?utm_campaign=async-workflows-blog&amp;amp;utm_source=devto-blog&amp;amp;utm_medium=web" rel="noopener noreferrer"&gt;Developer Playground&lt;/a&gt; sandbox.&lt;/p&gt;

</description>
      <category>orchestration</category>
      <category>asynchronous</category>
      <category>distributedsystems</category>
      <category>eventdriven</category>
    </item>
    <item>
      <title>Best Practices for Production-Scale RAG Systems — An Implementation Guide</title>
      <dc:creator>livw</dc:creator>
      <pubDate>Fri, 21 Feb 2025 05:11:59 +0000</pubDate>
      <link>https://dev.to/orkes/best-practices-for-production-scale-rag-systems-an-implementation-guide-13eh</link>
      <guid>https://dev.to/orkes/best-practices-for-production-scale-rag-systems-an-implementation-guide-13eh</guid>
      <description>&lt;p&gt;Knowledge bases can augment AI model responses by providing additional background information. For instance, a financial analyst bot would need access to reports, market prices, and industry news; while a policy advisor bot would need access to hundreds of policy documents. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RAG (retrieval-augmented generation)&lt;/strong&gt; is a popular method for providing AI models access to such background knowledge. At a high level, such knowledge gets chunked and stored in a database, which is later used to retrieve the most relevant information based on the user query. The retrieved information gets appended to the prompt sent to the AI model, thus improving its final response to the user query.&lt;/p&gt;

&lt;p&gt;In theory, it sounds straightforward enough. But to implement a production-ready RAG system, we would need to consider factors like retrieval quality, search speed, and response quality to meet user satisfaction. Let’s explore some common issues in implementing RAG systems and best practices for resolving them. Afterward, we will demonstrate an implementation example built using an orchestration platform like Orkes Conductor.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://dev.to/orkes/rag-explained-using-retrieval-augmented-generation-to-build-semantic-search-1i32"&gt;RAG Explained — Learn the ins and outs of how RAG works, its use cases, and how to build one for yourself&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Common issues in implementing RAG
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Documents lose context when chunked&lt;/strong&gt;, which affects the retrieval quality and subsequent response quality. &lt;/p&gt;

&lt;p&gt;For example, chunks in a financial knowledge base may contain revenue data without specifying the company:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;“Dollars in millions, except per share data  FISCAL 2024  FISCAL 2023 % CHANGE

Revenues    $   38,343      $   38,584      0   %”. 
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Without the proper context, a search query like “What was the revenue for Acme Inc in 2024?” could pull up dozens of incorrect revenue data for the AI model to process and reference. The model could just as well respond with revenue from Nakatomi Trading Corp or Sirius Cybernetics rather than from Acme Inc. &lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The vector embedding approach to storing and retrieving information is &lt;strong&gt;inherently lossy and may miss out on retrieving chunks with exact lexical matches&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Vector embeddings capture semantic meaning, like lexical relationships (e.g., actor/actress are closely related), intent (e.g., positive/negative), and contextual significance. This approach works well for capturing meaningful information, such that two completely different sentences, “I love cats” and “Cats are the best”, are marked as highly similar due to their conceptual similarity.&lt;/p&gt;

&lt;p&gt;On the flip side, this means that precise and specific wording gets lost in the vectorization process. As such, a typical vector-based RAG approach can sometimes fail to pick up on exact lexical matches. &lt;/p&gt;

&lt;p&gt;For example, if you are trying to search for information about the Cornish Rex, a chunk like:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;“The appearance of the German Rex is reminiscent of the European Shorthair. Both cat breeds are of medium size and rather stocky build. The German Rex is a strong, muscular cat with a round head and a broad forehead, pronounced cheeks and large round eyes. It strolls through its territory on medium-long legs. The German Rex is not a graceful, Oriental-looking cat like its Cornish Rex and Devon Rex counterparts. It has a robust and grounded appearance.” - [Source](https://www.catsbest.eu/cat-breed/german-rex/)
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;could be overlooked by the RAG system because it is primarily about the German Rex, and thus stored further away from chunks about the Cornish Rex in the vector space.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Best practices for RAG
&lt;/h2&gt;

&lt;p&gt;Now, let’s explore some best practices to mitigate the common issues outlined above.&lt;/p&gt;

&lt;h3&gt;
  
  
  Re-introduce context
&lt;/h3&gt;

&lt;p&gt;First: &lt;strong&gt;introduce context back into the chunks&lt;/strong&gt;. This can be as simple as prepending chunks with the document and section titles, a method sometimes known as contextual chunk headers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Document title: Acme Inc Annual Fiscal Report
Section title: Results of Operation

“Dollars in millions, except per share data  FISCAL 2024  FISCAL 2023 % CHANGE

Revenues    $   38,343      $   37,584      0   %”
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or it can be as elaborate as &lt;a href="https://www.anthropic.com/news/contextual-retrieval" rel="noopener noreferrer"&gt;Anthropic’s context retrieval method&lt;/a&gt;​​, where a summary of the chunk’s relation to the entire document is added to the chunk. In this approach, the contextual summaries are generated by an AI model using a prompt like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;document&amp;gt; 
{{WHOLE_DOCUMENT}} 
&amp;lt;/document&amp;gt; 

Here is the chunk we want to situate within the whole document 
&amp;lt;chunk&amp;gt; 
{{CHUNK_CONTENT}} 
&amp;lt;/chunk&amp;gt; 

Please give a short succinct context to situate this chunk within the overall document for the purposes of improving search retrieval of the chunk. Answer only with the succinct context and nothing else. 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Use semantic chunking
&lt;/h3&gt;

&lt;p&gt;Semantic chunking can also help preserve each chunk's context. Rather than fixed-sized chunking, semantic chunking takes meaning and context into account when dividing the text.&lt;/p&gt;

&lt;p&gt;In this approach, the text is split into individual sentences that are then indexed as embeddings. These sentence-level embeddings enable us to compare the semantic similarity of each sentence with neighboring sentences and split the chunks based on a breakpoint threshold value. This is useful for maintaining each chunk’s semantic integrity, which is essential for more accurate retrieval.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fny9jlx7cjduxubmvd5uf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fny9jlx7cjduxubmvd5uf.png" alt="Graph showing the cosine distance between subsequent chunks of text generated by the RecursiveCharacterTextSplitter. Relatively high cosine distances are marked in red, which can serve as breakpoints." width="800" height="380"&gt;&lt;/a&gt;Measuring the cosine similarity of adjacent sentences for semantic chunking. Source: &lt;a href="https://towardsdatascience.com/a-visual-exploration-of-semantic-text-chunking-6bb46f728e30/" rel="noopener noreferrer"&gt;towards data science&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Use hybrid search
&lt;/h3&gt;

&lt;p&gt;Next: use multiple search techniques at once to capitalize on each of their strengths. A hybrid search approach leverages both keyword-based search and vector search techniques, then combines the search results from both methods to provide a final search result.&lt;/p&gt;

&lt;p&gt;BM25 (Best Matching 25) is one of the most popular ranking functions, used across major search engines. It’s a bag-of-words retrieval function that ranks documents based on the frequency of the search query appearing in its contents. BM25F is a variant that enables you to modify the weights of different fields, such as making the document body more important than the title.&lt;/p&gt;

&lt;p&gt;These keyword-based functions remediate the lossy nature of vector searches, and using both types of search methods at once will cover the major bases in retrieving relevant information.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rerank retrieved chunks
&lt;/h3&gt;

&lt;p&gt;Reranking can also help to surface more relevant information from the set of retrieved documents. Rerankers are more accurate than embedding models in analyzing and comparing the query against the knowledge base, but are also much slower in processing compared to embedding models.&lt;/p&gt;

&lt;p&gt;The best of both worlds (accuracy and speed) means using a two-stage retrieval process, where an embedding model is used to retrieve a subset of information from the entire knowledge base, and a reranker is used to further pare down and refine the search results.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3y0h5nfp2oyinm6rgqdl.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3y0h5nfp2oyinm6rgqdl.jpg" alt="Diagram of the retrieval step: relevant chunks are retrieved by the embedding model and are reranked before they are passed to an LLM to generate the answer." width="800" height="384"&gt;&lt;/a&gt;Two-step retrieval process involving the embedding model and reranker.&lt;/p&gt;

&lt;h2&gt;
  
  
  A RAG implementation walkthrough
&lt;/h2&gt;

&lt;p&gt;How can these best practices be implemented? Let’s look at an example of a production-grade RAG system that is efficiently implemented and monitored using an orchestration platform like Orkes Conductor. Using &lt;a href="https://orkes.io/blog/what-is-orchestration" rel="noopener noreferrer"&gt;orchestration&lt;/a&gt;, developers can build and monitor complex flows across distributed components, frameworks, and languages. In our case, there are two key workflows required to build a RAG system:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An &lt;code&gt;index&lt;/code&gt; workflow&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;search&lt;/code&gt; workflow&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Tip: If you’d like to try building a RAG system yourself, sign up for our free developer sandbox at &lt;a href="https://developer.orkescloud.com/?utm_campaign=rag-best-practices-blog&amp;amp;utm_source=devto-blog&amp;amp;utm_medium=web" rel="noopener noreferrer"&gt;Developer Playground&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Building the index workflow
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;index&lt;/code&gt; workflow consists of several parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Load a document from a source&lt;/li&gt;
&lt;li&gt;Chunk your data&lt;/li&gt;
&lt;li&gt;Store the data in your vector and BM25 indexes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fke806la8z10mrymr39zv.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fke806la8z10mrymr39zv.jpg" alt="The indexing process, which involves loading a document from a source, chunking the documente, and storing the chunks into both vector and BM25 indexes." width="800" height="342"&gt;&lt;/a&gt;The index workflow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 1: Load a document from a source&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As an orchestration engine, Conductor facilitates all sorts of implementation choices with its wide variety of tasks. In this example, we’ve used a pre-made &lt;a href="https://orkes.io/content/reference-docs/ai-tasks/llm-get-document" rel="noopener noreferrer"&gt;Get Document&lt;/a&gt; task to retrieve a private policy document stored on an internal URL. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6dz2mppgxwv15uzocth3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6dz2mppgxwv15uzocth3.jpg" alt="Screenshot of the Get Document task in a Conductor workflow." width="800" height="454"&gt;&lt;/a&gt;Get Document task.&lt;/p&gt;

&lt;p&gt;You could also use an &lt;a href="https://orkes.io/content/reference-docs/system-tasks/http" rel="noopener noreferrer"&gt;HTTP&lt;/a&gt; task to get a document through an API call, or create a custom task for whatever custom implementation. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 2: Chunk the data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The chunking task can be implemented using an &lt;a href="https://orkes.io/content/reference-docs/system-tasks/inline" rel="noopener noreferrer"&gt;Inline&lt;/a&gt; task or custom worker task. Here’s a sample Inline task code that utilizes a straightforward fixed-size chunking method with some overlap to reduce context loss:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;policy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Policy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;This chunk is from the policy: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;policy&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;. &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;paragraphs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;currentChunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;paragraph&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;paragraphs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentChunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;paragraph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;currentChunk&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentChunk&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;paragraph&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentChunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;currentChunk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lastChunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;overlapText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lastChunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;currentChunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;overlapText&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;paragraph&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentChunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;currentChunk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The contextual chunk headers can be created within the same chunking task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;This chunk is from the policy: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;policy&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;. &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// … code omitted&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentChunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;currentChunk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The more elaborate situated context approach (à la Anthropic) can be completed in a separate task during the final indexing part.&lt;/p&gt;

&lt;p&gt;One major benefit of using Conductor to orchestrate these distributed components is the ease of switching up tasks and managing workflow versions. If we wanted to test whether semantic chunking will be worth the computational cost, it’s as simple as switching out the fixed-size chunking task with a new worker task that runs a different piece of code.&lt;/p&gt;

&lt;p&gt;Using Conductor’s SDKs, you can easily write a worker that carries out semantic splitting with your framework of choice (LlamaIndex, Langchain, and so on).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 3: Store the data into your vector and BM25 indexes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The final part of the &lt;code&gt;index&lt;/code&gt; workflow involves storing the data chunks into indexes. &lt;/p&gt;

&lt;p&gt;Before indexing the chunks, you can create and prepend situated contextual summaries for each chunk. These summaries can be created using generative AI models, paired with prompt caching to reduce the cost of creating these contextual summaries.&lt;/p&gt;

&lt;p&gt;Again, we can use a custom task worker to generate these contextual summaries using your preferred LLM provider. This sample worker code example leverages Conductor’s SDK with Anthropic’s prompt caching feature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;conductor.client.worker.worker_task&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;worker_task&lt;/span&gt;

&lt;span class="n"&gt;DOCUMENT_CONTEXT_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
&amp;lt;document&amp;gt;
{doc_content}
&amp;lt;/document&amp;gt;
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="n"&gt;CHUNK_CONTEXT_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
Here is the chunk we want to situate within the whole document
&amp;lt;chunk&amp;gt;
{chunk_content}
&amp;lt;/chunk&amp;gt;

Please give a short succinct context to situate this chunk within the overall document for the purposes of improving search retrieval of the chunk.
Answer only with the succinct context and nothing else.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="nd"&gt;@worker_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task_definition_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;get-context&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;situate_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;beta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prompt_caching&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;claude-3-haiku-20240307&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;max_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DOCUMENT_CONTEXT_PROMPT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doc_content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cache_control&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ephemeral&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;#we will make use of prompt caching for the full documents
&lt;/span&gt;                    &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CHUNK_CONTEXT_PROMPT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk_content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;extra_headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;anthropic-beta&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt-caching-2024-07-31&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once processed, we can finally index these chunks. Using a hybrid search approach means that the chunks must be indexed in a (i) vector database and (ii) BM25 index. With Orkes Conductor, we can easily use a &lt;a href="https://orkes.io/content/reference-docs/operators/fork-join" rel="noopener noreferrer"&gt;Fork-Join&lt;/a&gt; operator to index the same chunk into both indexes simultaneously, speeding up the process.&lt;/p&gt;

&lt;p&gt;Here, a pre-made &lt;a href="https://orkes.io/content/reference-docs/ai-tasks/llm-index-text" rel="noopener noreferrer"&gt;Index Text&lt;/a&gt; task is used to store the chunks into a vector database, while an internal API is used to store the chunks into a BM25 database.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcdos3xeeenfbj80c43dj.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcdos3xeeenfbj80c43dj.jpg" alt="Screenshot of the indexing tasks in a Conductor Workflow." width="800" height="454"&gt;&lt;/a&gt;The data are indexed into a vector database and BM25 index in parallel.&lt;/p&gt;

&lt;p&gt;With that, the &lt;code&gt;index&lt;/code&gt; workflow is completed. To build out your knowledge base, run the workflow to index your policy documents.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building the search workflow
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;search&lt;/code&gt; workflow retrieves relevant documents from the knowledge base and answers the user query. In production, a &lt;code&gt;search&lt;/code&gt; workflow would include the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Retrieve relevant chunks using a hybrid search approach&lt;/li&gt;
&lt;li&gt;Rerank the search results based on the user query&lt;/li&gt;
&lt;li&gt;Generate the answer to the user query based on the most relevant results&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frt5u4jb6elo5znvnm21v.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frt5u4jb6elo5znvnm21v.jpg" alt="Diagram of the search workflow, which involces retrieving relevant data from both vector and BM25 indexes, reranking the search results, and generate the answer using an LLM." width="800" height="397"&gt;&lt;/a&gt;The search workflow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 1: Hybrid search&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since we are using a hybrid search approach, another &lt;a href="https://orkes.io/content/reference-docs/operators/fork-join" rel="noopener noreferrer"&gt;Fork-Join&lt;/a&gt; operator is used to retrieve information from both indexes at once. Here, a pre-made &lt;a href="https://orkes.io/content/reference-docs/ai-tasks/llm-search-index" rel="noopener noreferrer"&gt;Search Index&lt;/a&gt; task is used to retrieve from the vector database, while an &lt;a href="https://orkes.io/content/reference-docs/system-tasks/http" rel="noopener noreferrer"&gt;HTTP&lt;/a&gt; task is used to call an internal API to the BM25 database.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fso2tmalbya3j987okrbt.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fso2tmalbya3j987okrbt.jpg" alt="Screenshot of the search tasks in a Conductor workflow." width="800" height="454"&gt;&lt;/a&gt;Both vector database and BM25 indexes are searched in parallel based on the user query.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 2: Rerank&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once the retrieval stage is completed, we can use a custom worker task to rerank the search results, by leveraging rerankers from providers like Cohere or Voyage AI. Here’s a sample code that uses Cohere’s reranker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;conductor.client.worker.worker_task&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;worker_task&lt;/span&gt;

&lt;span class="nd"&gt;@worker_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task_definition_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;reranker&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rerank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RerankInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;co&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cohere&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;COHERE_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;co&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rerank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rerank-english-v3.0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;top_n&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Part 3: Generate answer&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Finally, a built-in &lt;a href="https://orkes.io/content/reference-docs/ai-tasks/llm-text-complete" rel="noopener noreferrer"&gt;Text Complete&lt;/a&gt; task is used to interact with an LLM, which will generate the answer based on the top reranked information. Using Orkes Conductor to orchestrate the flow, you can easily integrate and interact with any LLM provider, from OpenAI and Anthropic to open-source models on HuggingFace. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhzhbtmr68g0yq8roriqo.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhzhbtmr68g0yq8roriqo.jpg" alt="Screenshot of the Text Complete task in a Conductor workflow." width="800" height="454"&gt;&lt;/a&gt;Generate the answer to the user query using a templatized prompt.&lt;/p&gt;

&lt;p&gt;The Text Complete task sends the LLM a prompt template that is injected with the user query and the RAG-retrieved background knowledge. Orkes’ AI Prompt Studio feature makes it easy for developers to create, manage, and test these prompts, facilitating &lt;a href="https://dev.to/orkes/guide-to-prompt-engineering-pof"&gt;the prompt engineering process&lt;/a&gt; to enhance the LLM output.&lt;/p&gt;

&lt;p&gt;Using some of the common prompt engineering tactics, here is an example prompt used in the RAG system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Answer the question directly based on the context provided.
Do not repeat the question.
Do not mention the existence of any context provided.

&amp;lt;context&amp;gt;
${context}
&amp;lt;/context&amp;gt;

&amp;lt;question&amp;gt;
${question}
&amp;lt;/question&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Done! The &lt;code&gt;search&lt;/code&gt; workflow is completed. Unlike the &lt;code&gt;index&lt;/code&gt; workflow, the &lt;code&gt;search&lt;/code&gt; workflow is used for your system runtime, when your users interact with your application to make queries.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd1gf1197ulix7neb90yn.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd1gf1197ulix7neb90yn.jpg" alt="Screenshot of the full search workflow in Conductor." width="800" height="1277"&gt;&lt;/a&gt;Search Workflow in Conductor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use orchestration to build AI systems?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://orkes.io/blog/what-is-orchestration" rel="noopener noreferrer"&gt;Orchestration&lt;/a&gt; is an ideal design pattern to follow when it comes to building distributed systems that are &lt;strong&gt;composable, governable, and durable&lt;/strong&gt;. As demonstrated in the RAG example above, the workflows can be easily composed from multiple services, packages, frameworks, and languages. As systems evolve and refine, developers can switch out tasks, use new frameworks, test different AI models, and implement best practices frictionlessly.&lt;/p&gt;

&lt;p&gt;Furthermore, an orchestration platform like &lt;a href="https://orkes.io/platform" rel="noopener noreferrer"&gt;Orkes Conductor&lt;/a&gt; unlocks complete visibility into each step of the workflow, from its task status to its inputs/outputs and even completion duration. For complex AI-driven systems, where multiple layers of AI interactions take place under the hood, the ease of monitoring becomes even more vital for troubleshooting and optimizing these interactions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffgo8nma86lt5uhna0s6z.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffgo8nma86lt5uhna0s6z.jpg" alt="Compilation of screenshots of the Orkes Conductor interface, with various features for monitoring and visbility." width="800" height="533"&gt;&lt;/a&gt;Unlock complete visibility into each step of the workflow, from its task status to its inputs/outputs and even completion duration.&lt;/p&gt;

&lt;p&gt;Most importantly, Conductor is hardened for failures, with comprehensive mechanisms for timeout, retry, idempotency, compensation flows, rate limits, and more. Such orchestration engines ensure the &lt;a href="https://dev.to/orkes/durable-execution-explained-how-conductor-delivers-resilient-systems-out-of-the-box-3i1p"&gt;durable execution&lt;/a&gt; of any workflow, long-running or otherwise.&lt;/p&gt;

&lt;p&gt;—&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/conductor-oss/conductor" rel="noopener noreferrer"&gt;Conductor&lt;/a&gt; is an open-source orchestration platform used widely in mission-critical applications such as &lt;a href="https://orkes.io/use-cases/ai-and-llm-chaining" rel="noopener noreferrer"&gt;AI/LLM systems&lt;/a&gt;, &lt;a href="https://orkes.io/use-cases/event-driven-architecture" rel="noopener noreferrer"&gt;event-driven systems&lt;/a&gt;, and &lt;a href="https://orkes.io/use-cases/microservices-and-api-orchestration" rel="noopener noreferrer"&gt;microservice or API-first systems&lt;/a&gt;. Try it out using our free &lt;a href="https://developer.orkescloud.com/?utm_campaign=rag-best-practices-blog&amp;amp;utm_source=devto-blog&amp;amp;utm_medium=web" rel="noopener noreferrer"&gt;Developer Playground&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rag</category>
      <category>aiops</category>
      <category>orchestration</category>
    </item>
    <item>
      <title>Lowering Latency with Realtime API Orchestration</title>
      <dc:creator>livw</dc:creator>
      <pubDate>Tue, 07 Jan 2025 15:59:00 +0000</pubDate>
      <link>https://dev.to/orkes/lowering-latency-with-realtime-api-orchestration-28l0</link>
      <guid>https://dev.to/orkes/lowering-latency-with-realtime-api-orchestration-28l0</guid>
      <description>&lt;p&gt;Today’s software applications run on the big three: cloud, microservices, and APIs. Although APIs are a lightweight, flexible, and easy-to-consume means of interconnecting multiple services and data sources, the complexity of orchestrating multiple API calls adds up quickly. In production, APIs come with a myriad of implementation concerns: how to route traffic, handle request spikes, eliminate cascading failures, and manage execution flow all at once.&lt;/p&gt;

&lt;p&gt;Enter stage right: realtime API orchestration.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is API orchestration?
&lt;/h2&gt;

&lt;p&gt;API orchestration streamlines complex application flows by coordinating multiple API requests and responses to produce a concerted response for the end client, such as a web browser. This approach is indispensable for building responsive, user-first web applications, as it accelerates loading speeds and safeguards against failure scenarios.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhceacl5xnv9x1evlq2sf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhceacl5xnv9x1evlq2sf.jpg" alt="Diagram of the API Orchestration layer that interfaces between the client and the backend APIs." width="800" height="496"&gt;&lt;/a&gt;The API orchestration layer enables the centralized flow of multiple APIs, standardized failure handling, granular workflow observability, and more.&lt;/p&gt;



&lt;h3&gt;
  
  
  The need for speed
&lt;/h3&gt;

&lt;p&gt;Consider loading a website application—your preferred investment platform or streaming service. A single page typically fetches data across multiple services, which must be aggregated before it is delivered to the end user.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx2gsq08ob6xw0brar5he.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx2gsq08ob6xw0brar5he.jpg" alt="Screen mockup of a booking user interface and the underlying APIs needed." width="800" height="418"&gt;&lt;/a&gt;A single page fetches data across multiple services, which must be aggregated before it is delivered to the end user.&lt;/p&gt;



&lt;p&gt;These API requests add up, and a longer load time translates into substantial business costs. According to recent surveys, &lt;a href="https://blog.hubspot.com/marketing/page-load-time-conversion-rates" rel="noopener noreferrer"&gt;a B2B site that loads in 1 second has a 3x conversion rate compared to a site that loads in 5 seconds and 5x compared to a site that loads in 10 seconds&lt;/a&gt;. Speed could be the make-or-break criterion for high-intent web pages, like log-in screens, transaction/checkout pages, or demo interfaces.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvczrihyitioago3of85t.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvczrihyitioago3of85t.jpg" alt="Bar chart showing decreasing conversion rate as load time increases." width="800" height="418"&gt;&lt;/a&gt;Source: Portent&lt;/p&gt;



&lt;h2&gt;
  
  
  Strategies for realtime speed in API calls
&lt;/h2&gt;

&lt;p&gt;What are some of the strategies you can use to improve your API performance?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Taming the tail latency&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Your aggregate API is only as fast (or slow) as the slowest API call. One well-known way to handle tail latency is to hedge your API requests (making multiple requests) and use the request that completes the fastest. This ensures that the tail latencies don’t impact your overall API performance.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Parallel API requests&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Send requests in parallel wherever possible to improve the throughput of your request volume.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Caching&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A cache serves as a temporary, high-speed data storage layer for previously retrieved data, so that repeated requests do not need to be attempted again. Caching cuts precious processing time for the most frequent API calls, providing speed at scale. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Circuit breakers&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The circuit breaker pattern blocks applications from sending traffic to services that are down until the service has recovered. This enables faulty services to recover and stabilize without being inundated with requests, shortening the downtime.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;API orchestration&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;API orchestration provides a high-speed switchboard that executes, monitors, and governs multiple API calls simultaneously. An orchestration platform comes optimized for low latencies and equipped with features that enable teams to easily implement the various design patterns for realtime speeds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of API orchestration
&lt;/h2&gt;

&lt;p&gt;API orchestration is a full-scale solution for scaling API performance alongside an application’s growth. As the application complexity grows, the dependency graph of the APIs that need to work together also grows. And as that grows, it becomes harder to debug, detect failures, and gain insights into latencies. &lt;/p&gt;

&lt;p&gt;More than just executing an intricate graph of API calls, API orchestration empowers teams to track, debug, and detect failures and performance issues.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance at every level&lt;/strong&gt;—Complex API execution at realtime speed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Increased reliability&lt;/strong&gt;—Automated failure handling and fallback mechanisms.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Governance&lt;/strong&gt;—Visibility into execution graphs for debugging and performance metrics for monitoring.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Developer productivity&lt;/strong&gt;—Build and debug more quickly with version control, reusable configs, payload introspection.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  API orchestration in practice: Orkes Conductor
&lt;/h2&gt;

&lt;p&gt;Orkes Conductor—originally built at Netflix—is a well-known platform for orchestrating microservices. It lets you build distributed applications that are resilient and easily scale with both the volume and complexity of the services.&lt;/p&gt;

&lt;p&gt;Let’s explore an example application flow that relies on complex API orchestration, built using Orkes Conductor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fommvtl8wx17f4zfohjs1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fommvtl8wx17f4zfohjs1.jpg" alt="Screenshot of example Conductor workflow that loads a list of financial assets to be added to a watchlist." width="800" height="986"&gt;&lt;/a&gt;Example Conductor workflow.&lt;/p&gt;



&lt;p&gt;In this example, we are loading a list of financial assets that can be added to a watchlist. This means retrieving the user data, the list of assets, and the current watchlist; followed by posting additional data when new assets are added to the watchlist.&lt;/p&gt;

&lt;p&gt;Using Orkes Conductor, &lt;strong&gt;&lt;a href="https://orkes.io/content/faqs/task-cache-output" rel="noopener noreferrer"&gt;caching behavior can be easily implemented&lt;/a&gt;&lt;/strong&gt;, which cuts the request time from mere milliseconds (10-40ms) to near-zero.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faghp0m3s7mw3hg3z1nv7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faghp0m3s7mw3hg3z1nv7.jpg" alt="Diagram demonstrating how caching behavior works in Orkes Conductor." width="800" height="418"&gt;&lt;/a&gt;With caching enabled, subsequent requests for commonly-used APIs take almost no time to execute.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;&lt;a href="https://orkes.io/content/error-handling" rel="noopener noreferrer"&gt;Rate limits, retries, and timeouts can be natively configured&lt;/a&gt;&lt;/strong&gt; on Conductor as well, ensuring that transient failures are automatically handled for every single execution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftzce68er8cjyjviyptj9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftzce68er8cjyjviyptj9.jpg" alt="Diagram demonstrating how failure handling works in Orkes Conductor." width="800" height="418"&gt;&lt;/a&gt;The orchestration layer will retry failed task executions based on the failure handling configuration.&lt;/p&gt;



&lt;p&gt;Last but not least, Conductor supports &lt;strong&gt;parallel requests&lt;/strong&gt;, enabling non-blocking API calls to execute simultaneously. &lt;strong&gt;&lt;a href="https://orkes.io/content/reference-docs/operators/fork-join" rel="noopener noreferrer"&gt;Static fork-joins&lt;/a&gt;&lt;/strong&gt; are useful when the number of API calls is predetermined ahead of runtime, while &lt;strong&gt;&lt;a href="https://orkes.io/content/reference-docs/operators/dynamic-fork" rel="noopener noreferrer"&gt;dynamic fork-joins&lt;/a&gt;&lt;/strong&gt; are especially handy when the number of calls is determined at runtime. For example, a dynamic fork is used when a user adds a number of assets to the watchlist, and all the PUT requests are executed in parallel, even if two or twenty assets are added.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fazknojrkhxvrvupefx8c.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fazknojrkhxvrvupefx8c.jpg" alt="Diagram demonstrating how parallel execution works in Orkes Conductor." width="800" height="418"&gt;&lt;/a&gt;With parallel execution, the total execution time only takes as long as the longest request.&lt;/p&gt;



&lt;p&gt;In this demonstration, we have seen how API orchestration works in practice. As shown, API orchestrators yield low latencies through a variety of features and capabilities beyond just coordinating requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core capabilities of realtime API orchestrators
&lt;/h2&gt;

&lt;p&gt;When deciding on an API orchestration platform, here are some key requirements to look out for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Near-zero response time&lt;/li&gt;
&lt;li&gt;High throughput&lt;/li&gt;
&lt;li&gt;Customizable caching&lt;/li&gt;
&lt;li&gt;Payload enforcement&lt;/li&gt;
&lt;li&gt;Integration with event streams&lt;/li&gt;
&lt;li&gt;Support for various API protocols and specifications (REST, gRPC, GraphQL)&lt;/li&gt;
&lt;li&gt;Comprehensive failure handling implementation (circuit breakers, request hedging, rate limits, retries)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrap up
&lt;/h2&gt;

&lt;p&gt;With the right tool for API orchestration, developers no longer have to spend time writing code for common API design patterns from scratch. This means more time to focus on the core recipe of your business capabilities while ensuring top-notch execution, speed, and reliability. &lt;/p&gt;




&lt;p&gt;&lt;a href="https://github.com/conductor-oss/conductor" rel="noopener noreferrer"&gt;Conductor&lt;/a&gt; is an open-source orchestration platform for executing durable long-running flows, lightning-speed API calls, or any case in between. Check out &lt;a href="https://orkes.io/pricing?utm_campaign=api-orchestration-blog&amp;amp;utm_source=devto-blog&amp;amp;utm_medium=web" rel="noopener noreferrer"&gt;the full list of features&lt;/a&gt; or start building for free with our &lt;a&gt;Developer Playground&lt;/a&gt; today.&lt;/p&gt;

</description>
      <category>api</category>
      <category>orchestration</category>
      <category>architecture</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Experimenting and Putting Prompt Engineering Tactics into Practice</title>
      <dc:creator>livw</dc:creator>
      <pubDate>Thu, 28 Nov 2024 07:55:22 +0000</pubDate>
      <link>https://dev.to/orkes/experimenting-and-putting-prompt-engineering-tactics-into-practice-2aii</link>
      <guid>https://dev.to/orkes/experimenting-and-putting-prompt-engineering-tactics-into-practice-2aii</guid>
      <description>&lt;p&gt;&lt;em&gt;This is Part 2 of the Prompt Engineering series, which will put prompt engineering tactics into practice, including model choice and LLM parameters like temperature. Check out &lt;a href="https://dev.to/orkes/guide-to-prompt-engineering-pof"&gt;Part 1 on the importance of creating effective prompts.&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Prompt engineering is the practice of enhancing LLM responses by writing optimized prompts and tuning parameters like temperature or topP. There are many strategies and tactics for creating effective prompts, but how do these translate into real-life situations? Which tactics are the most effective? How should I combine prompt writing and parameter tuning? Let’s explore some real examples of prompt engineering put into practice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Engineering better LLM responses
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://platform.openai.com/docs/guides/prompt-engineering" rel="noopener noreferrer"&gt;OpenAI documentation&lt;/a&gt; provides six main strategies for prompt engineering:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write clear instructions&lt;/li&gt;
&lt;li&gt;Provide reference text&lt;/li&gt;
&lt;li&gt;Split complex tasks into simpler subtasks&lt;/li&gt;
&lt;li&gt;Give the model time to "think"&lt;/li&gt;
&lt;li&gt;Use external tools&lt;/li&gt;
&lt;li&gt;Test changes systematically&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These strategies point to the overarching principle of prompt engineering: &lt;strong&gt;providing clear, specific, well-structured instructions&lt;/strong&gt;. There are many ways to split hairs about how exactly to do that, with numerous guides available online (including our previous &lt;a href="https://dev.to/orkes/guide-to-prompt-engineering-pof"&gt;Guide to Prompt Engineering&lt;/a&gt;, where we introduced the basics of creating clear and effective prompts). What we want to do is to dig deeper into how &lt;strong&gt;model choice, prompt writing tactics, and parameter tuning&lt;/strong&gt; interact and interplay to produce the ideal responses.&lt;/p&gt;

&lt;p&gt;In the following sections, we will explore each facet in turn and finally put it all together, so you have a concrete idea of what to focus on when implementing prompt engineering in your AI projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Model choice
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Without any prompt engineering, your choice of LLM serves as the ringfence determining the base quality of the response output.&lt;/strong&gt; To illustrate, here is the response by &lt;a href="https://docs.cohere.com/v2/docs/command-beta" rel="noopener noreferrer"&gt;Cohere’s &lt;code&gt;command&lt;/code&gt; model&lt;/a&gt; compared to &lt;a href="https://docs.mistral.ai/getting-started/models/models_overview/" rel="noopener noreferrer"&gt;Mistral’s &lt;code&gt;mistral-small&lt;/code&gt; model&lt;/a&gt;. Both models were asked to summarize an article about NASA’s Europa Clipper mission:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Summarize ${text}
// Assume that ${text} is a dynamic variable that is injected with the 
relevant content at runtime
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While both models provide a relatively accurate summary of the article, Mistral offers a well-structured response out of the box without additional prompting.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbjk0xkcarqmca85n89kj.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbjk0xkcarqmca85n89kj.jpg" alt="Diagram of Cohere’s command model’s output vs Mistral’s mistral-small-latest’s output, in response to the user query “Summarize text”." width="800" height="442"&gt;&lt;/a&gt;Various LLM models differ in their instinctual, un-engineered responses.&lt;/p&gt;

&lt;p&gt;Depending on your use cases and system requirements, Mistral’s responses could be overly-engineered or the more optimal response. Nevertheless, using prompt engineering tactics, you can get &lt;code&gt;command&lt;/code&gt; to respond just like &lt;code&gt;mistral-small&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tactics for effective prompts
&lt;/h3&gt;

&lt;p&gt;To provide clear, specific, well-structured instructions, these are some of the tactics employed in the prompts shown below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Break up the instructions for clarity.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of combining the article and the instructions in a single sentence, the prompt is now divided into distinct sections: one for the content and another for the instructions on how to evaluate the content.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Demarcate your prompt with special characters or tags where appropriate.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The article content is now enclosed in quotation marks to explicitly mark the text that should be summarized. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Include details about the desired output. Quantify where possible.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In one variation, the prompt now asks for the response to be “clear and concise” and even specifies the desired format of using bullet points. In another, it explicitly states the desired length of the output.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy33bxr9wjz4t27tbpv2f.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy33bxr9wjz4t27tbpv2f.jpg" alt="Diagram showing three different LLM prompts, with relevant phrases highlighted to demonstrate the prompt tactics." width="800" height="418"&gt;&lt;/a&gt;There are numerous ways to implement prompt engineering tactics depending on what output you need.&lt;/p&gt;

&lt;p&gt;Check out how the responses have improved in each of these prompts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Prompt: Here is the text from an article: "${text}". Provide a summary 
of this text in a clear and concise manner.

Response: NASA has launched the Europa Clipper mission, a $5.2 billion 
robotic spacecraft, to explore Jupiter's moon, Europa, which is believed 
to have a global ocean of liquid water beneath its icy crust and could 
potentially support extraterrestrial life. The mission aims to determine 
if Europa has the necessary ingredients for life, including water, 
organic compounds, and an energy source. The spacecraft, the largest 
and most expensive planetary science mission in NASA's history, will 
conduct 49 close encounters with Europa, studying its ocean, atmosphere, 
and surface features. Scientists are particularly interested in the 
possibility of hydrothermal vents on Europa's ocean floor, which could 
support simple life forms. The mission also aims to find potential 
landing sites for future lander missions. Europa Clipper's findings will 
shape future exploration of Europa and the search for life beyond Earth.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Prompt: Here is the text from an article: "${text}". Provide a summary 
of this text in a clear and concise manner, starting with the title 
**Summary**, and including the following bullet points:
- **Mission:**
- **Objective:**
- **Spacecraft:**
- **Journey:**
- **Scientific Goals:**
- **Future Missions:**

Response: Summary

- **Mission:** NASA's Europa Clipper mission aims to explore Jupiter's 
moon, Europa, a promising location for finding extraterrestrial life.
- **Objective:** The primary goal is to determine if Europa has the 
necessary ingredients for life, particularly simple, single-celled 
organisms.
- **Spacecraft:** Europa Clipper is the largest and most expensive 
planetary science spacecraft NASA has ever launched. It carries a 
sophisticated suite of nine instruments to study Europa's ocean, 
surface, and atmosphere.
- **Journey:** The spacecraft was launched on a SpaceX Falcon Heavy 
rocket and will take a 5.5-year journey to Jupiter. It will fly by Mars 
and Earth for gravity assists, reaching Jupiter in 2030.
- **Scientific Goals:** Europa Clipper will study Europa's ocean, ice 
shell, atmosphere, and potential plumes to understand its habitability. 
It will search for water, organic compounds, and energy sources 
necessary for life.
- **Future Missions:** A Europa lander is a challenging prospect, but 
a compelling discovery could prompt a follow-up mission. Other high-
priority missions include a Uranus orbiter and a mission to Saturn's 
moon Enceladus.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Prompt: Here is the text from an article: "${text}". Summarize the text 
clearly in 280 characters using this format "Article summary: &amp;lt;your_
summary_here&amp;gt;".

Response: Article summary: NASA's Europa Clipper mission launched on a 
SpaceX Falcon Heavy rocket to explore Jupiter's moon Europa, which may 
harbor life. The spacecraft will study Europa's ocean, atmosphere, and 
surface, seeking signs of habitability and potential life.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Temperature
&lt;/h3&gt;

&lt;p&gt;In some cases, it is also useful to tune the temperature of the responses. This LLM parameter affects how creative or deterministic the output will be — the higher the temperature, the more random and creative the output will be.&lt;/p&gt;

&lt;p&gt;While temperature is associated with creative tasks like generating a poem or a story, it can also apply to factual writing, like summaries. Take a look at this response below, where the temperature is set to 0.1. The text output reuses similar words or phrasing, and this repetitiveness makes the summary rather stale and unengaging.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz9y968rx3xz0jiixqyzp.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz9y968rx3xz0jiixqyzp.jpg" alt="Diagram of Cohere’s response to the prompt “Here is the text from an article: " width="800" height="418"&gt;&lt;/a&gt;A low temperature favors more frequent words or phrases, which can make the output repetitive.&lt;/p&gt;

&lt;p&gt;In contrast, a temperature of 1 leads to more dynamic and lively text, but tends to exaggerate or include less important information. This would mean that the summarizer is prone to creating misleading snapshots of the articles.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmkykp0ol7a9neu7td9jn.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmkykp0ol7a9neu7td9jn.jpg" alt="Diagram of Cohere’s response to the prompt “Here is the text from an article: " width="800" height="418"&gt;&lt;/a&gt;A high temperature produces rarer words or phrases, which can lead to a focus on less important information.&lt;/p&gt;

&lt;p&gt;A more moderate temperature of 0.4 could be the sweet spot for an article summarizer, providing relevant information with livelier language.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ppzkuo6fcq6hq3bblcw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ppzkuo6fcq6hq3bblcw.jpg" alt="Diagram of Cohere’s response to the prompt “Here is the text from an article: " width="800" height="418"&gt;&lt;/a&gt;Tune your temperature to a more moderate value to avoid repetitiveness and steer clear of overly-exaggerated information at the same time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evaluating your LLM responses
&lt;/h2&gt;

&lt;p&gt;We’ve seen individually how model choice, prompt writing tactics, and LLM parameters can affect your desired output. But how do these factors stack together to get optimized results at scale? While prompt writing tactics get you the biggest mileage in obtaining a particular result, LLM parameter tuning and model choice could be the distinguishing factor between an average response and a stellar one.&lt;/p&gt;

&lt;p&gt;Using the following prompt with different models and temperature values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Here is the text from an article: "${text}". Summarize the text clearly 
in 280 characters using this format "Article summary: &amp;lt;your_summary_
here&amp;gt;".
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We get the following responses:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbbgage1x3zsn6voaa7rp.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbbgage1x3zsn6voaa7rp.jpg" alt="Diagram of different model responses at different temperatures for the prompt “Here is the text from an article: " width="800" height="346"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;At a small sample size, it is easy to pick which answer is more desirable. But in a production setting, it is best practice to systematically test changes using a larger sample size to ascertain between randomness and true improvement.&lt;/p&gt;

&lt;p&gt;One way to systematically track changes would be to evaluate the LLM responses against a benchmark — using relevant criteria or gold-standard answers. In this case, we want summaries that are concise yet comprehensive — answering the 5W1H (what, who, where, when, why, and how).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fys1li76tcskos9gderke.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fys1li76tcskos9gderke.jpg" alt="Annotated diagram of different model responses at different temperatures for the prompt “Here is the text from an article: " width="800" height="402"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;These evaluations can be manually done by humans or AI-assisted. Whichever route you choose, ensure that you can evaluate a large sample set with sufficient variety to cover all the edge cases in your use scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimizing LLM responses for AI app development
&lt;/h2&gt;

&lt;p&gt;In practice, an application that leverages generative AI is likely far more complex than using a simple one-shot prompt. Multiple prompts can be used across different tasks in a process, or AI techniques like retrieval-augmented generated (RAG), computer vision, and other data pre-processing tasks may come into play.&lt;/p&gt;

&lt;p&gt;An &lt;a href="https://orkes.io/blog/ai-orchestration-explained/" rel="noopener noreferrer"&gt;AI orchestration&lt;/a&gt; engine like Orkes Conductor can streamline such developmental efforts with its built-in AI tasks and feature-rich AI prompt builder, where you can test various prompt engineering strategies. With one-step integrations for a dozen LLM providers (including OpenAI, HuggingFace, and more), Orkes’ AI prompt builder unlocks the convenience of plugging, testing, and playing with prompts across models. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff1hzzfatkpbekvnpbcdv.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff1hzzfatkpbekvnpbcdv.jpg" alt="Testing Interface for prompts in Orkes Conductor." width="800" height="453"&gt;&lt;/a&gt;Orkes Conductor AI prompt builder, as part of its AI Orchestration capabilities.&lt;/p&gt;

&lt;p&gt;Besides testing, these prompts can be templatized, saved, and safely used in a production setting for AI-driven workflows and applications, such as document classification, RAG-based search retrieval, approval journeys, and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap up
&lt;/h2&gt;

&lt;p&gt;By implementing various prompt engineering tactics, we have explored effective ways to combine model choice, prompt writing, and parameter tuning and systematically test these changes.&lt;/p&gt;

&lt;p&gt;Beyond what we have explored here, there are many other ways to improve model outputs, such as model fine-tuning or &lt;a href="https://dev.to/orkes/rag-explained-using-retrieval-augmented-generation-to-build-semantic-search-1i32"&gt;retrieval-augmented generation (RAG)&lt;/a&gt;. A strategic combination of these different techniques and methods will unleash the full potential of generative AI in automating creative, complex, or human-involved tasks.&lt;/p&gt;




&lt;p&gt;Using Orkes Conductor, you can &lt;a href="https://orkes.io/content/developer-guides/quickstart-ai-orchestration" rel="noopener noreferrer"&gt;rapidly build, optimize, and test AI-enabled applications&lt;/a&gt; in a distributed environment. &lt;a href="https://github.com/conductor-oss/conductor" rel="noopener noreferrer"&gt;Conductor&lt;/a&gt; is an open-source orchestration platform used widely in many mission-critical applications for orchestrating microservices, AI services, event handling, and more. Try out a fully-managed and hosted Conductor service with the free &lt;a href="https://developer.orkescloud.com/?utm_campaign=prompt-eng-blog-2&amp;amp;utm_source=devto-blog&amp;amp;utm_medium=web" rel="noopener noreferrer"&gt;Developer Playground&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>promptengineering</category>
      <category>ai</category>
      <category>llm</category>
      <category>genai</category>
    </item>
    <item>
      <title>How to Develop an AI Application: Step-by-Step using Orkes Conductor</title>
      <dc:creator>livw</dc:creator>
      <pubDate>Thu, 21 Nov 2024 05:30:43 +0000</pubDate>
      <link>https://dev.to/orkes/how-to-develop-an-ai-application-step-by-step-using-orkes-conductor-106d</link>
      <guid>https://dev.to/orkes/how-to-develop-an-ai-application-step-by-step-using-orkes-conductor-106d</guid>
      <description>&lt;p&gt;&lt;em&gt;This is Part 1 of the AI App Development series, which will demonstrate how to build a simple AI application using Conductor. Check out Part 2 for an &lt;a href="https://dev.to/orkes/build-an-ai-application-for-document-classification-a-step-by-step-guide-3fcg"&gt;AI-powered document classifier&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;The potential of using AI for enterprise use cases is vast, but building an AI-powered application from scratch involves a deeply technical tech stack. By leveraging an orchestration platform like Orkes Conductor, you can easily govern these moving parts into a well-coordinated flow, be it during development, testing, or production phases.&lt;/p&gt;

&lt;p&gt;This introductory tutorial will demonstrate how to develop enterprise-ready AI applications using Conductor. Let's start with a simple &lt;strong&gt;article summarizer&lt;/strong&gt;. While straightforward, the workflow can be abstracted and adapted for practical use cases across industries, such as generating movie synopses for a streaming platform or extracting key highlights from quarterly earnings reports.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building an AI application with Conductor
&lt;/h2&gt;

&lt;p&gt;As an orchestration engine, Conductor powers code-based flows like cloud infrastructure management, shipping and order tracking, media delivery pipelines, LLM chains, and so on. Conductor oversees the workflow execution and manages the plumbing matters of a distributed environment, such as data flow, timeouts, retries, and compensation flows, so that applications can be more quickly brought to an enterprise-ready state. These capabilities are instrumental for building AI-enabled applications, where velocity and agility are paramount to success.&lt;/p&gt;

&lt;p&gt;At a high level, building with Conductor involves three simple steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Get access to Conductor.&lt;/strong&gt; This is where you will build the application flow.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Build the AI-powered application flow.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write the application frontend and backend.&lt;/strong&gt; Conductor can easily be integrated with any programming language, allowing you to trigger Conductor flows in your backend using our SDKs.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Get access to Conductor
&lt;/h3&gt;

&lt;p&gt;To begin, create an account in an Orkes Conductor cluster. For this tutorial, you can use the free &lt;a href="https://play.orkes.io/?utm_campaign=build-ai-app-blog&amp;amp;utm_source=devto-blog&amp;amp;utm_medium=web" rel="noopener noreferrer"&gt;Orkes Playground&lt;/a&gt; to follow along.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create the LLM-enabled application flow
&lt;/h3&gt;

&lt;p&gt;Conductor provides an &lt;a href="https://orkes.io/content/category/reference-docs/ai-tasks" rel="noopener noreferrer"&gt;out-of-the-box suite of LLM system tasks&lt;/a&gt; that are convenient to use in most cases. For more complex AI tasks, developers can opt to &lt;a href="https://orkes.io/content/category/sdks" rel="noopener noreferrer"&gt;create their own task workers in any language&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1: Create your application flow using Orkes’ visual workflow editor
&lt;/h4&gt;

&lt;p&gt;In a straightforward article summarizer, the application flow involves two tasks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Retrieve the article from a given URL.&lt;/li&gt;
&lt;li&gt;Prompt an LLM to provide a summary of the article.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9wpopvi9vnkx1gchuj0u.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9wpopvi9vnkx1gchuj0u.jpg" alt="Diagram of user calling an application frontend that runs on a Conductor backend, which orchestrates the two tasks." width="800" height="276"&gt;&lt;/a&gt;Application flow using Conductor as the orchestration engine.&lt;/p&gt;

&lt;p&gt;For Task 1, we can use the &lt;a href="https://orkes.io/content/reference-docs/ai-tasks/llm-get-document" rel="noopener noreferrer"&gt;Get Document task&lt;/a&gt;, which can retrieve text from various content types. In this case, text from an HTML file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdj0riwgf7yxyd21vyhs7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdj0riwgf7yxyd21vyhs7.png" alt="Screenshot of Conductor UI, showing the Get Document task configuration." width="800" height="311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For Task 2, we can use the &lt;a href="https://orkes.io/content/reference-docs/ai-tasks/llm-text-complete" rel="noopener noreferrer"&gt;Text Complete task&lt;/a&gt; to call an LLM with a prompt. Both tasks are system tasks that eliminate the need to write custom code to integrate with LLM providers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4yzj3g604ikevorljvgh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4yzj3g604ikevorljvgh.png" alt="Screenshot of Conductor UI, showing the Text Complete task configuration." width="800" height="357"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To create the article summarizer flow:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://play.orkes.io/?utm_campaign=build-ai-app-blog&amp;amp;utm_source=devto-blog&amp;amp;utm_medium=web" rel="noopener noreferrer"&gt;Orkes Playground&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;In the left navigation menu, go to &lt;strong&gt;Definitions&lt;/strong&gt; &amp;gt; &lt;strong&gt;Workflow&lt;/strong&gt;.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2o0pfzmdehdod7ord83a.jpg" alt="Screenshot of Conductor UI, showing the left navigation menu for Definitions &amp;gt; Workflow." width="800" height="418"&gt;
&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Define Workflow&lt;/strong&gt; in the top right. The visual workflow editor appears.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select the &lt;strong&gt;Code&lt;/strong&gt; tab on the right and paste the following JSON code:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"studyPartner"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AI application that summarizes an article"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"tasks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"get_article"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"taskReferenceName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"get_article_ref"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"inputParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;{workflow.input.url}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"mediaType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text/html"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET_DOCUMENT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"cacheConfig"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;{url}-&lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;{mediaType}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"ttlInSecond"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;360&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"summarize_article"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"taskReferenceName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"summarize_article_ref"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"inputParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"promptVariables"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;{get_article_ref.output.result}"&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"llmProvider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"providerNameHere"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"modelNameHere"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"promptName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"promptNameHere"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"temperature"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;{workflow.input.temperature}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"topP"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;{workflow.input.topP}"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"LLM_TEXT_COMPLETE"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"inputParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="s2"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="s2"&gt;"temperature"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="s2"&gt;"topP"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"schemaVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"timeoutPolicy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ALERT_ONLY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"timeoutSeconds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Change the workflow &lt;strong&gt;Name&lt;/strong&gt; to something unique.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select &lt;strong&gt;Save&lt;/strong&gt; &amp;gt; &lt;strong&gt;Confirm&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Your workflow should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpb5o80gf7xpr0ia8crka.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpb5o80gf7xpr0ia8crka.jpg" alt="Screenshot of article summarizer workflow, containing the Get Document and Text Complete tasks." width="800" height="1124"&gt;&lt;/a&gt;Article summarizer workflow.&lt;/p&gt;

&lt;p&gt;Now that your workflow is ready, it’s time to get it up and running by adding your LLM integration.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2: Add your preferred LLM integration
&lt;/h4&gt;

&lt;p&gt;Orkes offers dozens of integrations with all major LLM providers—OpenAI, Anthropic, Google, Amazon, Cohere, Mistral, Hugging Face, and so on.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ikms6hiaieojtwebniv.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ikms6hiaieojtwebniv.jpg" alt="List of AI/LLM and vector database integrations in Orkes Conductor: Azure Open AI, Open AI, Cohere, Google Vertex AI, Google Gemini AI, Anthropic Claude, Hugging Face, AWS Bedrock Anthropic, AWS Bedrock Cohere, AWS Bedrock Llama2, AWS Bedrock Titan, Mistral, Pinecone, Weaviate, Postgres Vector Database, MongoDB." width="800" height="453"&gt;&lt;/a&gt;AI-related integrations in Orkes Conductor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To add an integration:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Grab your API key from your LLM provider.&lt;/li&gt;
&lt;li&gt;In the left navigation menu of Orkes Playground, go to &lt;strong&gt;Integrations&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;New Integration&lt;/strong&gt; and select your preferred LLM provider.&lt;/li&gt;
&lt;li&gt;Enter the required fields, such as the Integration Name, Description, Access Credentials, and API Endpoint. The required fields differ by LLM provider, so you can refer to the &lt;a href="https://orkes.io/content/category/integrations/ai-llm" rel="noopener noreferrer"&gt;Integration Docs&lt;/a&gt; for guidance.&lt;/li&gt;
&lt;li&gt;Make sure to enter a unique value for the Integration Name, such as “OpenAI_yourNameHere”.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Save&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With the LLM integration added, you can start adding the specific models offered by the LLM provider.&lt;/p&gt;

&lt;p&gt;Each model has different capabilities or is tuned for a different use case. Which model you choose depends on your use case — for our article summarizer, a general conversational model with text capabilities will suffice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To add a model:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the &lt;strong&gt;Integrations&lt;/strong&gt; page, select the &lt;strong&gt;+&lt;/strong&gt; button next to your newly-added integration.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;New model&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Enter the &lt;strong&gt;Model name&lt;/strong&gt; and &lt;strong&gt;Description&lt;/strong&gt;. Ensure that the &lt;strong&gt;Active&lt;/strong&gt; toggle is switched on.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Save&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Done! With the right prompt, you can now start using the LLMs in your workflows. In the next few steps, you will add the LLMs to the prompt template and workflow before using it.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3: Create a prompt template using Orkes’ AI prompt builder
&lt;/h4&gt;

&lt;p&gt;A prompt is necessary to get the model to summarize an article. Since we are building an AI article summarizer and not a general-purpose chatbot, the prompts can be templatized and automatically fire with the necessary context. Orkes’ AI prompt builder allows you to do exactly that: create and test prompt templates with multiple models.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frvbgugjdqw49lr4k70ty.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frvbgugjdqw49lr4k70ty.jpg" alt="Screenshot of Orkes' Conductor Ai Prompt Builder screen." width="800" height="418"&gt;&lt;/a&gt;Create and test prompt templates with any LLM in Orkes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To create a prompt template:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In Orkes Playground, go to &lt;strong&gt;Definitions&lt;/strong&gt; &amp;gt; &lt;strong&gt;AI Prompts&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Add AI prompt&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Enter a unique &lt;strong&gt;Prompt Name&lt;/strong&gt;, such as “summarizeText_yourNameHere”.&lt;/li&gt;
&lt;li&gt;In &lt;strong&gt;Model(s)&lt;/strong&gt;, select the models which the prompt can be used with.&lt;/li&gt;
&lt;li&gt;Enter a &lt;strong&gt;Description&lt;/strong&gt; of what the prompt does. For example, “Takes an article content and summarizes it.”&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enter your &lt;strong&gt;Prompt Template&lt;/strong&gt;, which can be as simple as the following:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Summarize ${text}.
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Here, &lt;code&gt;${text}&lt;/code&gt; is a variable input. At runtime, this variable will be replaced with the article content — for example, “Summarize NASA's Europa Clipper spacecraft lifted off Monday from Kennedy Space Center in Florida aboard a SpaceX Falcon Heavy rocket, [...]”.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once done, select &lt;strong&gt;Save&lt;/strong&gt; &amp;gt; &lt;strong&gt;Confirm save&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, you can start testing your prompt. To do that, pick a specific model to test and tune the LLM parameters, like temperature, stop words, and topP. Then paste in the variable substitute for &lt;code&gt;${text}&lt;/code&gt; and run the prompt to get the LLM response.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgf71w2bbqq6wjmnbg7lw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgf71w2bbqq6wjmnbg7lw.jpg" alt="Screenshot of Orkes' Conductor AI Prompt Builder, with the steps for testing prompts highlighted" width="800" height="418"&gt;&lt;/a&gt;Test your prompts with your chosen model, text variables, and prompt variables.&lt;/p&gt;

&lt;p&gt;We’ll explore more methods for engineering better responses in an upcoming blog post. For now, let’s put together the finishing touches for your article summarizer flow.  &lt;/p&gt;

&lt;h4&gt;
  
  
  Step 4: Put it all together
&lt;/h4&gt;

&lt;p&gt;Recall the JSON code that you copied to create your workflow? Now that you have added your LLM models and created your prompt, it’s time to put these resources into the JSON code (ie your workflow definition).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To put it all together:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In Orkes Playground, go to &lt;strong&gt;Definitions&lt;/strong&gt; &amp;gt; &lt;strong&gt;Workflow&lt;/strong&gt; and select the workflow you have created previously.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;summarize_article&lt;/strong&gt; task, replace the following values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replace &lt;code&gt;providerNameHere&lt;/code&gt; with your chosen LLM provider.&lt;/li&gt;
&lt;li&gt;Replace &lt;code&gt;modelNameHere&lt;/code&gt; with your chosen model.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Replace &lt;code&gt;promptNameHere&lt;/code&gt; with your prompt template name. Make sure to add back the following variable for the prompt:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${get_article_ref.output.result}"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select &lt;strong&gt;Save&lt;/strong&gt; &amp;gt; &lt;strong&gt;Confirm&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Done! &lt;strong&gt;Give your workflow a test run:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;From the visual workflow editor, select the &lt;strong&gt;Run&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enter the &lt;strong&gt;Input params&lt;/strong&gt; and select &lt;strong&gt;Run workflow&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;example&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;input&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;params&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://arstechnica.com/space/2024/10/nasa-launches-mission-to-explore-the-frozen-frontier-of-jupiters-moon-europa/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"temperature"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"topP"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Upon running the workflow, you will be directed to the workflow execution page, where you can track the progress of your application flow. If you select the &lt;strong&gt;Workflow Input/Output&lt;/strong&gt; tab, you should see the summary of the article you requested.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbo2qm7i7uof2y3nprk9i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbo2qm7i7uof2y3nprk9i.png" alt="Screenshot of the Workflow Input/Output tab in the workflow execution screen in Conductor." width="800" height="373"&gt;&lt;/a&gt;The article summarizer returns the requested summary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Write the application frontend and backend
&lt;/h3&gt;

&lt;p&gt;With the application flow created, the next step is to build the application itself. Use any framework (React, Next.js, Angular, and so on) to build the frontend and backend. For the backend, you will also use &lt;a href="https://orkes.io/content/category/sdks" rel="noopener noreferrer"&gt;Conductor’s SDKs&lt;/a&gt; to execute and track workflows. Here is an example snippet of a React-based backend that uses the JavaScript SDK to execute the &lt;code&gt;studyPartner&lt;/code&gt; summarizer workflow created earlier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;orkesConductorClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;WorkflowExecutor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;TaskType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@io-orkes/conductor-javascript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;getConfig&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/config&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;publicRuntimeConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getConfig&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getSummary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;articleUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;topP&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;clientPromise&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;executor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WorkflowExecutor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Create the executor instance&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;executionId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;executor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startWorkflow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="c1"&gt;// Start the workflow&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;publicRuntimeConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;workflows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;studyPartner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;articleUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;topP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;correlationId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;setExecutionId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;executionId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Persist executionId in state&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Connecting your application with Conductor
&lt;/h4&gt;

&lt;p&gt;While writing your backend, make sure to get authorized access to Conductor so that your backend can fire the workflow without any issues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Get access tokens for your application&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the Conductor UI, go to &lt;strong&gt;Applications&lt;/strong&gt; in the left navigation menu to &lt;a href="https://orkes.io/content/access-control-and-security/applications" rel="noopener noreferrer"&gt;create your application abstraction layer&lt;/a&gt; and &lt;a href="https://www.youtube.com/watch?v=f1b5vZRKn2Q" rel="noopener noreferrer"&gt;generate the access tokens&lt;/a&gt;. To do so,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In &lt;strong&gt;Applications&lt;/strong&gt;, select &lt;strong&gt;(+) Create application&lt;/strong&gt; and enter a name for your application.&lt;/li&gt;
&lt;li&gt;In the Access Keys section, select &lt;strong&gt;(+) Create access key&lt;/strong&gt; to generate a unique Key Id and Key Secret, and note it down.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Important: The Key Secret is shown only once, so make sure to copy and store your credentials securely for future reference.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Configure access&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Set the Key Id and Secret in your project environment and point to the appropriate Conductor server. If you are using Orkes Playground, the server should be &lt;a href="https://play.orkes.io/api" rel="noopener noreferrer"&gt;https://play.orkes.io/api&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CONDUCTOR_SERVER_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;SERVER_URL&amp;gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CONDUCTOR_AUTH_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;KEY_ID&amp;gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CONDUCTOR_AUTH_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;KEY_SECRET&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Configure permissions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Finally, configure the permissions for the application layer you have previously created so that your application project can access the necessary resources. To set the required permissions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In &lt;strong&gt;Application&lt;/strong&gt; in the Conductor UI, select your application.&lt;/li&gt;
&lt;li&gt;In the Permissions section, select &lt;strong&gt;+ Add Permission&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Add Execute and Read permissions to the following resources:

&lt;ul&gt;
&lt;li&gt;Your article summarizer workflow&lt;/li&gt;
&lt;li&gt;The LLM models used in your workflow&lt;/li&gt;
&lt;li&gt;The prompts used in your workflow&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Congratulations! You have successfully created an AI article summarizer. Using Orkes’ AI prompt builder, you can optimize the LLM responses to fit your needs by implementing &lt;a href="https://dev.to/orkes/guide-to-prompt-engineering-pof"&gt;prompt engineering techniques&lt;/a&gt; and testing your prompts to improve the LLM responses. &lt;/p&gt;

&lt;h2&gt;
  
  
  Going beyond
&lt;/h2&gt;

&lt;p&gt;With Orkes Conductor, you have created an AI application in no time at all. Now that you have the basics down, you can try your hand at creating more complex workflows, like a &lt;a href="https://orkes.io/content/templates/document-classifier" rel="noopener noreferrer"&gt;document classifier&lt;/a&gt; or &lt;a href="https://orkes.io/content/templates/automatic-subtitle-generator" rel="noopener noreferrer"&gt;automatic subtitle generator&lt;/a&gt;, or leveling up your summarizer workflow for more advanced uses, like summarizing video or audio content. Custom task workers can be easily built for advanced AI tasks using &lt;a href="https://orkes.io/content/category/sdks" rel="noopener noreferrer"&gt;Conductor’s SDKs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Using Orkes Conductor to build applications spells faster time-to-market, enterprise-grade durability and security, and full governance in a distributed program. From pre-built tasks to fully custom business logic, developers get the best of both worlds: speed and flexibility. Simply brainstorm the high-level flow, pinpoint which tasks are needed, and start building. &lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap up
&lt;/h2&gt;

&lt;p&gt;As an open-source orchestration platform, Conductor can be used in diverse cases beyond AI orchestration, such as infrastructure automation, data transformation pipelines, digital user journeys, microservice coordination, and more.&lt;/p&gt;

&lt;p&gt;Want detailed examples? Check out other tutorials and use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://dev.to/orkes/guide-to-backend-for-frontend-bff-pattern-an-approach-using-orchestration-k5j"&gt;Guide to Backend for Frontend (BFF) Pattern&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/orkes/building-checkout-app-using-nextjs-and-conductor-4fdj"&gt;Building Checkout App using Next.js and Conductor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/orkes/automating-slack-greetings-to-community-with-orkes-conductor-5gap"&gt;Automating Slack Greetings to Community with Orkes Conductor&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/orkes/upgrade-eks-clusters-across-multiple-versions-in-less-than-a-day-using-automated-workflows-2nj0"&gt;Upgrade EKS Clusters across Multiple Versions in Less Than A Day - using Automated Workflows&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stay tuned for more AI-based tutorials coming soon.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://orkes.io/cloud" rel="noopener noreferrer"&gt;Orkes Cloud&lt;/a&gt; is a fully managed and hosted Conductor service that can scale seamlessly to meet your needs. When you use Conductor via Orkes Cloud, your engineers don’t need to worry about setting up, tuning, patching, and managing high-performance Conductor clusters. Try it out with our free &lt;a href="https://developer.orkescloud.com/?utm_campaign=build-ai-app-blog&amp;amp;utm_source=devto-blog&amp;amp;utm_medium=web" rel="noopener noreferrer"&gt;Developer Playground&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>development</category>
      <category>ai</category>
      <category>orchestration</category>
      <category>aiops</category>
    </item>
    <item>
      <title>Monolith to Microservices: Should I Migrate and How?</title>
      <dc:creator>livw</dc:creator>
      <pubDate>Thu, 03 Oct 2024 09:50:35 +0000</pubDate>
      <link>https://dev.to/orkes/monolith-to-microservices-should-i-migrate-and-how-gkj</link>
      <guid>https://dev.to/orkes/monolith-to-microservices-should-i-migrate-and-how-gkj</guid>
      <description>&lt;p&gt;Microservices have dominated software development in the past decade as the most popular system design. Over 70% of organizations surveyed by &lt;a href="https://static.pulse.qa/omirs/pulse/microservices-architecture-have-engineering-organizations-found-success-u6b.pdf" rel="noopener noreferrer"&gt;Gartner in 2023&lt;/a&gt; use microservices, with 22% having migrated over within the past 12 months. While there has been buzz about microservices being over-hyped, the trend towards microservices remains a steady force, with more than 20% of surveyed organizations planning to make the shift to microservices.&lt;/p&gt;

&lt;p&gt;Just like any system design, microservices is not a one-size-fits-all approach. What are the benefits and challenges of using microservices? Should my organization switch to a microservice-based design? How can I migrate from a monolith to microservices? Let’s explore these considerations below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monoliths vs Microservices
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;In a monolith design, the entire system is built and deployed as a single unit.&lt;/strong&gt; In other words, the user interface, application methods and services, and database are stored in a single codebase and these modules are tightly coupled, typically with a shared context.&lt;/p&gt;

&lt;p&gt;In contrast, &lt;strong&gt;a microservices-based design consists of separate services that can be individually deployed&lt;/strong&gt;. These services each have its own database and bounded context, and are loosely coupled. Communication between each service occurs over a network protocol, typically through API, gPRC, message brokers, or an orchestration layer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F52d19avwu5glxwaswb2j.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F52d19avwu5glxwaswb2j.jpg" alt="Diagram of monolithic architecture versus microservices architecture." width="800" height="400"&gt;&lt;/a&gt;Architecture of a monolithic application vs a microservices-based application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits of monolithic architecture
&lt;/h3&gt;

&lt;p&gt;Because monoliths are designed as a single consolidated system, it is typically the preferred approach in the early stages of development. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity&lt;/strong&gt;: Monolith systems are more straightforward to build, test, deploy, and debug—developers don’t have to worry about coordinating and tracing across distributed components.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lower infrastructure overhead:&lt;/strong&gt; With only one application to monitor and maintain and fewer moving parts, the costs and infrastructure requirements are easier to manage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lower latency:&lt;/strong&gt; Different services in a monolith are tightly coupled, with a shared memory and no need to communicate over a network. This set-up provides better performance and faster response times at a given load.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Limitations of monolithic architecture
&lt;/h3&gt;

&lt;p&gt;However, as an application grows with new features, the limitations of a monolith architecture become apparent: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Slower development cycles&lt;/strong&gt;: Multiple teams working on the same codebase can lead to conflicts or breaking changes, requiring careful coordination and resulting in slower releases. Small changes or bug fixes become too effortful to make in light of long build times.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limited scalability:&lt;/strong&gt; Horizontal scaling across multiple machines calls for the entire application to be scaled, even if only certain modules require more resources. It’s not just harder to optimize specific components in a monolith but also more inefficient at resource utilization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Risky to innovate:&lt;/strong&gt; A tightly-coupled system means that new features or changes to the tech stack can result in unintended cascading consequences elsewhere, making it harder and harder to implement changes over time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At some point, the monolith system becomes too complex to maintain at a performant level. Without proper code discipline and organization, you run the risk of creating a &lt;a href="https://deviq.com/antipatterns/big-ball-of-mud" rel="noopener noreferrer"&gt;big ball of mud&lt;/a&gt; or &lt;a href="https://deviq.com/antipatterns/spaghetti-code" rel="noopener noreferrer"&gt;spaghetti code&lt;/a&gt;. This is when the shift towards microservices becomes relevant.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits of microservices
&lt;/h3&gt;

&lt;p&gt;When implemented carefully, microservices offer numerous benefits that overcome the limitations of monoliths.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reliability:&lt;/strong&gt; Unlike a monolith where one unresponsive component brings down the entire system, a microservice-based architecture reduces the blast radius. Orchestration patterns like retries and compensation workflows also help to handle partial failures gracefully.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed:&lt;/strong&gt; Likewise with independently-deployed services, teams can iterate features and fix bugs more quickly, using automated CI/CD pipelines to test and deploy releases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability:&lt;/strong&gt; Since each service has its own dedicated resources, they can be scaled independently based on demand, maintaining service performance while minimizing resource wastage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility:&lt;/strong&gt; Each service can use the tools, technologies, and language best suited to its functionality, and critical services can be reused across multiple domains.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Challenges of microservices
&lt;/h3&gt;

&lt;p&gt;The benefits of loosely-coupled, independently-deployed services with a bounded context come with some trade-offs. Distributed systems tend to be more complex, which introduces additional challenges for inter-service communication, resource management, data persistence, and testing and debugging.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Failure&lt;/strong&gt;: The more components a system has, the more points of failure get introduced. Distributed systems, like microservices, face a greater risk of &lt;a href="https://robertovitillo.com/how-distributed-systems-fail/" rel="noopener noreferrer"&gt;single points of failure, cascading failures, resource leaks, and network failures&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure&lt;/strong&gt;: Microservices require more infrastructure overhead, like a dedicated DevOps team, tools for service discovery, load balancing, networking, message queues, orchestration, and so on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data&lt;/strong&gt;: Maintaining data consistency across services, especially for distributed transactions, also poses more challenges compared to a single, unified database, and requires more careful planning.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testing&lt;/strong&gt;: It is much more difficult to design end-to-end tests with production environments for distributed systems, and likewise, debugging poses challenges with &lt;a href="https://dev.to/orkes/debugging-distributed-systems-52ln"&gt;global observability and reproducibility&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Microservices: To migrate or not to migrate
&lt;/h2&gt;

&lt;p&gt;As organizations and systems scale, the question of migrating from a monolith to microservices inevitably emerges. Microservices have provided businesses like Netflix, Uber, Amazon, and SoundCloud a way to move and innovate rapidly, even in large teams.&lt;/p&gt;

&lt;p&gt;A successful migration involves many technical hurdles but is a worthy investment when there is a solid business case to create a clear separation between services. You should migrate to microservices when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple teams working on the same codebase create blockers in development speed.&lt;/li&gt;
&lt;li&gt;A single service needs to be reused or shared across multiple programs or domains.&lt;/li&gt;
&lt;li&gt;Significantly more computing resources are required for a particular feature but not others.&lt;/li&gt;
&lt;li&gt;A specific functionality becomes a unique business capability that requires more innovation and a dedicated team.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to migrate to microservices
&lt;/h2&gt;

&lt;p&gt;If microservices prove to be the path forward, next comes the dreaded project of overhauling, refactoring, and migrating your code. Here are some best practices you can follow when migrating from monolith to microservice:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Plan the migration using domain-driven design
&lt;/h3&gt;

&lt;p&gt;One of the biggest challenges in migrating a monolith to a microservice-based system is ensuring proper separation of services. If not carefully implemented, it is easy to end up with a distributed monolith, where the services communicate over a network protocol, but are still tightly-coupled and dependent on each other. A distributed monolith should be avoided, as it introduces all the challenges of a microservice-based architecture without any of its advantages.&lt;/p&gt;

&lt;p&gt;Before migrating, inventorize the monolithic codebase and identify areas where services can be decoupled from each other. Despite what its name suggests, microservices do not need to be &lt;em&gt;micro&lt;/em&gt;: as long as there is a bounded context, data model, and independent deployment, the service can be as encompassing as your system demands it to be.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.domainlanguage.com/ddd/" rel="noopener noreferrer"&gt;Domain-driven design&lt;/a&gt; is a handy set of principles for deciding how to split up your monolith. The core idea is to model your services based on the business domain—an insurance app entails concepts like claims, plan tiers, or renewals, while a shopping app should model concepts like customers, products, or discounts. Using these standard terminology, you map out the services required in your system—a shopping app would have a product inventory, checkout, and order tracking. These are the bounded contexts that have emerged from the monolith, allowing you to design the scope and function of your microservices grounded in business sense.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fll9flp0cncp1ttwp7vz3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fll9flp0cncp1ttwp7vz3.jpg" alt="Diagram of the bounded contexts in a core order workflow: product inventory, cart, and payment." width="800" height="418"&gt;&lt;/a&gt;Example of the bounded contexts in an order application and how they are linked to one another.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Gradually decouple your monolith services using a strangler pattern
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjtnkhmfg8phyxwgwo7l6.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjtnkhmfg8phyxwgwo7l6.jpg" alt="Diagram illustrating how the strangler pattern works, by pulling out services from the monolith over time." width="800" height="466"&gt;&lt;/a&gt;Strangler pattern. &lt;a href="https://microservices.io/refactoring/" rel="noopener noreferrer"&gt;Reference&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you have identified the candidates for microservice refactoring, gradually pull them out of the monolith by setting up a separate microservice. During this process, any new feature or service should be implemented as a separate microservice instead of being added to the monolith. These microservices, extracted or new, should have their own database. Integration code, or glue code, is added to bridge between the microservice and the monolith in the interim.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl89gvwj1bj75srcss6sj.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl89gvwj1bj75srcss6sj.jpg" alt="Diagram illustrating how the microservice integrates with the monolith." width="800" height="418"&gt;&lt;/a&gt;Glue code is used to bridge between the extracted services and the remaining monolith during the migration process.&lt;/p&gt;

&lt;p&gt;Once the microservice is ready to be used as a standalone service, use blue/green or canary deployments to gradually transition your user traffic from the monolith and roll back if necessary.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fui27yi3icajhqy8z090z.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fui27yi3icajhqy8z090z.jpg" alt="Diagram of traffic being routed to the microservice instead of the monolith." width="800" height="418"&gt;&lt;/a&gt;Use blue/green or canary deployments to gradually transition your user traffic from the monolith to the newly-extracted microservice.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Set up robust testing for your microservices
&lt;/h3&gt;

&lt;p&gt;Finally, when deploying your microservices, testing is crucial to ensuring that there are no code regressions. Since microservices can be tested and deployed individually, the approach should fundamentally differ from testing monoliths.&lt;/p&gt;

&lt;p&gt;While it is easier to test your microservices independently, it is more challenging to visualize and trace the entire process from end to end. Here are some tips for testing microservices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When doing unit tests, the microservice’s inputs/outputs should be treated as one of the critical functionalities to test, avoiding overreliance on test doubles or mocks.&lt;/li&gt;
&lt;li&gt;Instead of having developers spin up an end-to-end application instance, use a shared test environment to reduce test coupling and &lt;a href="https://eng.lyft.com/scaling-productivity-on-microservices-at-lyft-part-3-extending-our-envoy-mesh-with-staging-fdaafafca82f" rel="noopener noreferrer"&gt;isolate the test request&lt;/a&gt; to minimize its impact.&lt;/li&gt;
&lt;li&gt;Use context propagation tools like OpenTracing or OpenTelemetry to get a view of your distributed system.&lt;/li&gt;
&lt;li&gt;Implement chaos engineering to test the resilience of your system.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Managing inter-service coordination using orchestration
&lt;/h2&gt;

&lt;p&gt;One key challenge of using microservice: what about the plumbing code that manages the communication between all your microservices? &lt;a href="https://orkes.io/blog/what-is-orchestration" rel="noopener noreferrer"&gt;Orchestration&lt;/a&gt; is a powerful way to coordinate services and components in a distributed system, providing both &lt;a href="https://dev.to/orkes/durable-execution-explained-how-conductor-delivers-resilient-systems-out-of-the-box-3i1p"&gt;state tracking and durable execution&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Orchestration simplifies the added complexity and infrastructure overhead of microservices by providing a centralized platform to model, manage, and route your application flows and implementation details, abstracted away from the business logic encoded in each microservice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Microservice orchestration with Conductor
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/conductor-oss/conductor" rel="noopener noreferrer"&gt;Conductor&lt;/a&gt; is an open-source orchestration platform used widely in many mission-critical applications for microservice orchestration, LLM chaining, and event handling. Using orchestration with Conductor, teams can build multi-language microservice-based systems that are even more fault-tolerant, highly observable, and performant.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Resilience parameters:&lt;/strong&gt; Conductor allows you to specify resilience parameters like the number of retries, rate limits, compensation flows, and timeouts, decoupled from your microservice logic, and provides in-built tools to recover from failures gracefully.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data flow:&lt;/strong&gt; Be it inputs/outputs, secrets, or environment variables, Conductor securely stores and passes these parameters across microservices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Centralized monitoring and logging:&lt;/strong&gt; Conductor provides a centralized platform to inspect your workflow execution and logs for troubleshooting, as well as to monitor your workflow performance and cluster health.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Load balancing:&lt;/strong&gt; Conductor runs on a worker-task queue architecture that round-robins tasks across a pool of workers that can be dynamically scaled based on demand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lifecycle management:&lt;/strong&gt; From development and testing to deployment, Conductor facilitates version control and rolling updates without disrupting your production runs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Migrating to microservices with Conductor
&lt;/h3&gt;

&lt;p&gt;When you migrate from a monolith to microservices with Conductor as your platform, refactoring is as straightforward as injecting Conductor’s SDK into your application and annotating your endpoints with @WorkerTask. This prepares individual tasks for eventual refactoring into a microservice without disrupting the overall application functionality. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6aplfioaea3mesvrzxou.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6aplfioaea3mesvrzxou.jpg" alt="Screenshots of a monolith codebase vs an annotated monolith codebase." width="800" height="950"&gt;&lt;/a&gt;Annotate your functions to turn it into a task worker.&lt;/p&gt;

&lt;p&gt;From there, you can gradually remove each task from the monolith and set it up as an individual microservice. Using Conductor’s &lt;a href="https://orkes.io/content/developer-guides/task-to-domain" rel="noopener noreferrer"&gt;task-to-domain&lt;/a&gt;, differentiate the worker pools and slowly transition traffic from the monolith to microservices. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq2qnfs7lufxjkuqu0woq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq2qnfs7lufxjkuqu0woq.jpg" alt="Screenshots of a monolith codebase versus a microservice codebase." width="800" height="740"&gt;&lt;/a&gt;Use different domains to split the worker pools.&lt;/p&gt;

&lt;p&gt;Conductor SDKs are available in &lt;a href="https://github.com/orkes-io/orkes-conductor-client" rel="noopener noreferrer"&gt;Java&lt;/a&gt;, &lt;a href="https://github.com/conductor-sdk/conductor-python" rel="noopener noreferrer"&gt;Python&lt;/a&gt;, &lt;a href="https://github.com/conductor-sdk/conductor-javascript" rel="noopener noreferrer"&gt;JavaScript&lt;/a&gt;, &lt;a href="https://github.com/conductor-sdk/conductor-go" rel="noopener noreferrer"&gt;Go&lt;/a&gt;, &lt;a href="https://github.com/conductor-sdk/conductor-csharp" rel="noopener noreferrer"&gt;CSharp&lt;/a&gt;, and &lt;a href="https://github.com/conductor-sdk/conductor-clojure" rel="noopener noreferrer"&gt;Clojure&lt;/a&gt;, allowing you to write services in your preferred language. &lt;/p&gt;

&lt;p&gt;With a platform like Orkes Conductor, you can streamline microservices development and rise above any challenges associated with it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simplify migration:&lt;/strong&gt; Gradually transition monolithic applications to microservices without disrupting operations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safeguard from failures:&lt;/strong&gt; Ensure robust execution of distributed processes with built-in fault tolerance, failure flows, and retry mechanisms.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gain full visibility:&lt;/strong&gt; Debug in minutes rather than days, with comprehensive monitoring and tracing capabilities. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By choosing Conductor, you're investing in a battle-tested solution that tackles the complexities of microservice-based applications.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://orkes.io/cloud" rel="noopener noreferrer"&gt;Orkes Cloud&lt;/a&gt; is a fully managed and hosted Conductor service that can scale seamlessly to meet your needs. When you use Conductor via Orkes Cloud, your engineers don’t need to worry about setting up, tuning, patching, and managing high-performance Conductor clusters. Try it out with our free &lt;a href="https://developer.orkescloud.com/?utm_campaign=monolith-to-microservices-blog&amp;amp;utm_source=devto-blog&amp;amp;utm_medium=web" rel="noopener noreferrer"&gt;Developer Playground&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>distributedsystems</category>
      <category>development</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Debugging Distributed Systems</title>
      <dc:creator>livw</dc:creator>
      <pubDate>Mon, 09 Sep 2024 10:43:17 +0000</pubDate>
      <link>https://dev.to/orkes/debugging-distributed-systems-52ln</link>
      <guid>https://dev.to/orkes/debugging-distributed-systems-52ln</guid>
      <description>&lt;p&gt;Distributed systems have many advantages: horizontal scalability, increased fault tolerance, and modular design, to name a few. On the flip side, distributed systems are also much harder to debug compared to centralized systems. In this article, let’s explore the challenges of debugging distributed systems and some strategies to make it easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three tiers of complexity in debugging
&lt;/h2&gt;

&lt;p&gt;Bugs are errors in the program that cause unexpected behavior. This can stem from unit-level errors in syntax, logic, or calculation, or system-level issues like integration errors or compatibility issues. In general, there are &lt;a href="https://maximilianmichels.com/2020/debugging-distributed-systems/" rel="noopener noreferrer"&gt;three tiers of complexity in debugging&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Debugging non-concurrent programs.&lt;/li&gt;
&lt;li&gt;Debugging concurrent programs.&lt;/li&gt;
&lt;li&gt;Debugging distributed programs.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4rk6z3kdn5l0p9udzdds.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4rk6z3kdn5l0p9udzdds.jpg" alt="Diagram of a non-concurrent program, which is a single-threaded process, versus a concurrent program, which is a multi-threaded process." width="800" height="418"&gt;&lt;/a&gt;Concurrent programs are more complex to debug than non-concurrent one, as there are multiple threads of execution to account for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Non-concurrent programs&lt;/strong&gt; run a single thread of execution, which makes debugging relatively straightforward. At a basic level, most bugs can be caught by attaching a debugger to the program and enlisting fundamental debugging methods like breakpoints and stepping through code, print statements and inspecting the variables during program execution, and examining the call stack and memory at runtime.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Concurrent programs&lt;/strong&gt; run multiple threads of execution using shared resources. In a concurrent program for example, one thread could be used to display content, another to load animations, and yet another for copying content, and so on. These threads do not have a guaranteed order of execution, yet some threads may depend on another thread’s output before it can execute. &lt;/p&gt;

&lt;p&gt;Because the behavior of one thread can affect other threads, concurrency introduces an additional layer of complexity. Bugs can arise due to race conditions, deadlocks, or other synchronization issues. Such issues are more difficult to detect and reproduce as they are non-deterministic and occur based on specific real-time conditions like execution order and timing.&lt;/p&gt;

&lt;p&gt;To debug a concurrent program, execution logs, thread dumps, and stack traces play a vital role in figuring out the behavior and interactions between threads. You can leverage a debugger to identify and reproduce bugs by recording and replaying the program execution. However, with concurrent programs, strategies like using breakpoints and logging should be implemented carefully to avoid interfering with the timing and synchronization of multiple threads.&lt;/p&gt;

&lt;h3&gt;
  
  
  Challenges of debugging distributed programs
&lt;/h3&gt;

&lt;p&gt;Distributed programs consist of multiple connected nodes that communicate with each other over a network to complete a goal, like file storage, streaming, user management, or payment processing. Each node runs its own thread or threads of execution, and each node has its own memory, resources, and execution context. As such, for distributed programs, even if every node is non-concurrent, the entire system is ultimately concurrent.&lt;/p&gt;

&lt;p&gt;At this level of complexity, debugging becomes much trickier. More than just debugging code, developers must also understand and account for interactions, timing, and emergent behaviors in order to identify the root cause. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Limited observability&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One key constraint for debugging distributed systems is limited observability at a global scale. Many traditional debugging strategies are typically confined to one node or machine at the execution level: using a debugger, inspecting the logs, or profiling the execution. Given that the entire system’s state is distributed across multiple nodes, these strategies often only provide a partial view of what is happening. Without a global view of the entire system, it is difficult to piece together the interactions and circumstances that have led to the error and to test your hypotheses.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Reproducibility&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Concurrency bugs or bugs arising from the interactions between nodes are also much harder to reproduce and test due to their non-deterministic nature. The same input can lead to different behavior due to timing, network conditions, or load distribution. Such bugs are often timing-dependent or related to race conditions and may not replicate if the circumstances are altered. And when a system’s behavior also depends on environmental factors like the network set-up, the underlying infrastructure, or the scale of data load, bugs encountered in a distributed system become much harder to replicate in a local environment.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The observer effect&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Finally, if not used prudently, many debugging strategies or tools can alter the behavior of the distributed system, masking the bug that you’re hunting down or creating new errors in the process. Debuggers also often slow down your program, which may impact time-sensitive or asynchronous interactions. This observer effect may make it harder to identify and isolate the root causes of the problem.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Strategies for debugging distributed programs
&lt;/h2&gt;

&lt;p&gt;Given its tricky nature, what strategies can we use to debug a distributed program? It boils down to three key aspects of debugging: understanding what your code is trying to do, the execution, and how the code resulted in the execution.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Understanding the code:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For distributed programs in particular, rather than just understanding the code, it is vital to also &lt;strong&gt;develop an understanding of the overall flow of your distributed system and its interlocking dependencies&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;What is the execution path in a success scenario? And what are the areas where errors can arise? For example, in a payment flow, how should the system handle a duplicate transaction, or what happens if the payment is authorized seconds before the card get frozen by the bank? Often, good design and thinking through the program flow are one of the first safeguards against bugs both pre-production and in production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Understanding the execution:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since distributed programs have logs distributed across different nodes, it would take much more time to pinpoint the relevant logs for debugging. To cut down the time taken to locate the logs, it would be useful to know the program execution flow and which nodes are involved in the error ahead of time. &lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;distributed tracing comes in handy for distributed debugging&lt;/strong&gt;. These tracers follow a request as it moves across different nodes and services, capturing context about the interactions, behaviors, and errors encountered along the way, including where the errors originated and how they propagate through the system. Tools such as OpenTracing or OpenTelemetry go a long way for context propagation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Understanding how the code resulted in the execution:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When using debuggers for distributed systems, you should take care to use them on the appropriate node to avoid masking the bug or creating other unwanted errors and timeouts. Remote debuggers can be used for remote nodes, and time-travel debugging can be used to reproduce hard-to-find bugs.&lt;/p&gt;

&lt;p&gt;In cases where a debugger creates more problems than it solves, &lt;strong&gt;bisecting is a powerful alternative for locating the source of the error&lt;/strong&gt;. Bisecting is a technique that uses binary search to quickly pinpoint the commit that introduced a bug to your code repository. At each point of the binary search, you will test the build for the bug before marking the commit as good or bad. While testing at high volumes may be time-consuming, with some automation, bisecting becomes a productive way to locate the source of the bug.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting it in practice: How to debug a distributed system
&lt;/h2&gt;

&lt;p&gt;Let’s hear from our Orkes developers, the team behind the open-source orchestration engine Conductor (also a distributed system), on how we debug errors in a distributed system.&lt;/p&gt;

&lt;p&gt;Even though distributed systems are highly complex with tons of moving parts involved, debugging such systems does not have to be too complicated. The key lies in narrowing the debugging scope: the vast majority of the bugs we deal with usually can be reduced to a single component, with a limited amount of context needed for the bug to occur.&lt;/p&gt;

&lt;p&gt;Context propagation lays the groundwork for reducing the debugging scope. This can be as simple as carrying a unique ID across logs during executions, or using tools like OpenTracing or OpenTelemetry. With the information, we can find the exact section where the problem occurred and then isolate it.&lt;/p&gt;

&lt;p&gt;Whenever Conductor users reach out about a bug, the first thing we do is to get the exact setup they have. This step is critical for confirming where exactly the bug is coming from, given that different version builds may have different code, and the code containing the bug may have already been changed.&lt;/p&gt;

&lt;p&gt;To try to reproduce the bug, we get more details such as the logs, the workflow execution JSON, or any SDK code that the user ran. If successfully reproduced, we bisect across Conductor releases to find the exact change that caused the bug. From there, it’s an iteration of a discussion, a fix, and integration tests to prevent future regressions. &lt;/p&gt;

&lt;p&gt;If there are difficulties reproducing the bug even with all the available context, we go back to the basics: analyzing the source code areas which could negatively impact execution. Sometimes, the bug is related to concurrency and multithreading, which requires careful analysis of the code and double-checking your own assumptions. As one of our developers says: "If you have a seemingly impossible bug that you cannot reproduce consistently, then it is almost always a race condition."&lt;/p&gt;

&lt;p&gt;There is no silver bullet to debugging. When it comes to a thorny bug that relates to concurrency, we run through the same process of reproducing the bug but at larger volumes, and carefully thinking through the code. Ultimately, the best debugging tools are those that facilitate the process of thinking through the code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging with Orkes Conductor
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/conductor-oss/conductor" rel="noopener noreferrer"&gt;Conductor&lt;/a&gt; is an open-source orchestration platform used widely in many mission-critical applications for &lt;a href="https://orkes.io/use-cases/ai-and-llm-chaining" rel="noopener noreferrer"&gt;LLM chaining&lt;/a&gt;, &lt;a href="https://orkes.io/use-cases/event-driven-architecture" rel="noopener noreferrer"&gt;event handling&lt;/a&gt;, and &lt;a href="https://orkes.io/use-cases/microservices-and-api-orchestration" rel="noopener noreferrer"&gt;microservice orchestration&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Orchestration is a powerful way to coordinate services and components in a distributed system. Beyond simplifying distributed development, orchestration tools like Conductor provide system observability for troubleshooting and debugging. In other words, it cuts out all the time spent on tracking down the source of the error so that developers get straight to thinking through the code and flow, slashing debugging time from hours or days to mere minutes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trace with ease&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With Orkes Conductor’s workflow visualization and ID tracking, developers can look up the state of their workflows and tasks, instantly identify the source of failure, and inspect the execution details for execution time, input/output values, or worker logs. No need to spend time tracking down where the error occurred, manually printing variables, or hunting down logs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgheco2ac6cjozq64mwyo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgheco2ac6cjozq64mwyo.png" alt="Diagram of Orkes Platform screenshots showing the workflow visualization, task summary, task input/output, and logs." width="800" height="509"&gt;&lt;/a&gt;Orkes Conductor is an orchestration platform with in-built capabilities for debugging.&lt;/p&gt;

&lt;p&gt;Let’s take a look at an example distributed program flow of a data indexer. This program loops through a series of tasks, namely: a task that retrieves data from a third-party API, and a task that indexes the data into a vector database using an embedding model. &lt;/p&gt;

&lt;p&gt;When a workflow fails, developers can use Conductor to retrieve or visualize the exact task where the error occurred, which instantly reduces the debugging scope. Conductor tracks the task execution details, which means you can then look up the source of the failure. In the case of the data indexer, the workflow failed during the data retrieval task due to a 429 (Too Many Requests) error. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fajifcrx4i3mezbmvfcto.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fajifcrx4i3mezbmvfcto.png" alt="Screenshot of the workflow execution screen in Orkes Platform." width="800" height="472"&gt;&lt;/a&gt;Introspecting the execution details of a failed data indexer workflow.&lt;/p&gt;

&lt;p&gt;With the bug easily identified, you can spend your time coming up with the solution instead—in this case, retrying the task again later or upgrading the third-party API limits. Since the data indexer workflow loops through its tasks iteratively to retrieve as much data as possible in a single run, you can also retrieve the execution details for each iteration. Here, you get to see that the flow terminated on the 17th iteration. These information help with making an informed decision on how to best resolve the problem.&lt;/p&gt;

&lt;p&gt;Once resolved, Conductor enables developers to quickly recover from failure with programmatic calls to rerun, retry, or upgrade workflows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Monitor at scale&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Orkes Conductor also provides a rich metrics dashboard to &lt;a href="https://dev.to/orkes/monitoring-microservices-using-prometheus-grafana-42cj"&gt;monitor your executions&lt;/a&gt;. Developers can get aggregated analytics for workflow execution volume and rate, system health, or latencies; configure alerts for critical thresholds; or export the data to a central metrics repository like Datadog or Prometheus. These metrics can help in making informed decisions on scaling workers, optimizing workflow speeds, and so on.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft4ezv03w8k8man5kmr3k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft4ezv03w8k8man5kmr3k.png" alt="Screenshot of the metrics dashboard in Orkes Platform." width="800" height="507"&gt;&lt;/a&gt;Orkes Conductor metrics dashboard.&lt;/p&gt;

&lt;p&gt;—--&lt;/p&gt;

&lt;p&gt;&lt;a href="https://orkes.io/cloud" rel="noopener noreferrer"&gt;Orkes Cloud&lt;/a&gt; is a fully managed and hosted Conductor service that can scale seamlessly to meet your needs. When you use Conductor via Orkes Cloud, your engineers don’t need to worry about setting up, tuning, patching, and managing high-performance Conductor clusters. Try it out with our free &lt;a href="https://developer.orkescloud.com/?utm_campaign=debug-distrib-systems-blog&amp;amp;utm_source=devto-blog&amp;amp;utm_medium=web" rel="noopener noreferrer"&gt;Developer Playground&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>debugging</category>
      <category>distributedsystems</category>
      <category>development</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Evolution of Software Architecture: From Mainframes and Monoliths to Distributed Computing</title>
      <dc:creator>livw</dc:creator>
      <pubDate>Tue, 06 Aug 2024 10:36:13 +0000</pubDate>
      <link>https://dev.to/orkes/evolution-of-software-architecture-from-mainframes-and-monoliths-to-distributed-computing-3g7a</link>
      <guid>https://dev.to/orkes/evolution-of-software-architecture-from-mainframes-and-monoliths-to-distributed-computing-3g7a</guid>
      <description>&lt;p&gt;&lt;strong&gt;Software architecture—the blueprint of our digital world—has evolved tremendously since the dawn of the computer age in the mid-20th century.&lt;/strong&gt; The early 1960s and 70s were dominated by mainframes and monolithic software. Today, the digital landscape looks entirely different, running on a distributed web of cloud computing, API connectivity, AI algorithms, microservices, and orchestration platforming.&lt;/p&gt;

&lt;p&gt;How has software architecture evolved over the years? As we revisit the technological progress through the decades, we will see how changes in business needs, market trends, and engineering practices have impacted software architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mainframes and monoliths: ~1940s
&lt;/h2&gt;

&lt;p&gt;The first computers were mainframe computers—large, powerful hardware machines that took up an entire room. &lt;strong&gt;Mainframes originated as standalone machines that could run complex computing tasks&lt;/strong&gt;. Prior to the 1970s, instructions to mainframe computers were sent via punchcards or magnetic tape, and the output received via printers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpwvy15odlty8ujdyg2mv.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpwvy15odlty8ujdyg2mv.jpg" alt="Annotated illustration of data centers in the 1950s, which contained the central processor, magnetic tape units, tape controller, input/output controller, control console, card punch, card reader, disk storage, and high-speed printers." width="612" height="329"&gt;&lt;/a&gt;Prior to the 1970s, data centers held mainframes that accepted instructions through punchcards or magnetic tape. Credit: unknown.&lt;/p&gt;

&lt;p&gt;The first mainframes, Harvard Mark I and ENIAC, were developed for military and research purposes in the 1930s-1940s. In 1948, the first commercial mainframe was introduced to the world: UNIVAC. The following decades saw widespread adoption by banking, financial, and airline sectors for the mainframe’s outstanding ability in batch processing transactional data. Many of these systems still remain in operation today.&lt;/p&gt;

&lt;p&gt;Mainframe applications were programmed in COBOL (Common Business-Oriented Language), which remains popular amongst mainframers even today. &lt;strong&gt;The software architecture for these applications was monolithic&lt;/strong&gt;, which meant a single, unified codebase that contained the data schema, application methods, database connections, presentation logic, and so on without modularization. To update any of these components, developers would have to access the entire codebase and redeploy it in a single package.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fydh98vseqh4mykhtqgus.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fydh98vseqh4mykhtqgus.jpg" alt="Diagram of a monolithic architecture, where the user interface, application logic, and database are store on a single codebase and deployed together." width="800" height="418"&gt;&lt;/a&gt;Monolithic architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Networks and client-server: ~1950s
&lt;/h2&gt;

&lt;p&gt;Networks connect and facilitate communication between computers—mainframe to terminal, mainframe to mainframe, and later client to server. &lt;strong&gt;The development of network technology from 1958 onwards enabled mainframes to be connected electronically&lt;/strong&gt;, transforming them into multi-user computers that were connected to multiple terminals. Instead of punchcards and printers, people could use a monitor, keyboard, and a command-line interface (CLI) to send and receive data.&lt;/p&gt;

&lt;p&gt;Technological limitations restricted the first few connected computer systems. Multiplex mainframes, for example, could only be used locally as the cable length meant that the terminals had to be positioned very close to the mainframe. These early data centers contained not just computers, but dozens of humans sending jobs to the mainframe.&lt;/p&gt;

&lt;p&gt;ARPANET was the first public, wide-area computer network, going live in 1969. It communicated data using packet switching, which went on to serve as the foundation for modern-day Internet as we know it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Network technology popularized the client-server structure in the 1980s&lt;/strong&gt;, where an application is divided into a server software and a client software that communicates over a computer network. This structure is familiar to us today: a client, typically a desktop computer, remotely makes a request to a server, which returns a response. With the distribution of computing resources, the server handled data processing and retrieval while the client dealt with the presentation of the data. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fndsot069tcwar9le9tx6.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fndsot069tcwar9le9tx6.jpg" alt="Diagram of a client-server architecture, where the client side, comprising of the user interface, sends a request to the server side, where the application logic and database resides." width="800" height="418"&gt;&lt;/a&gt;Client-server architecture.&lt;/p&gt;

&lt;p&gt;The first client-server applications were mail services, web servers, and other desktop applications with online capabilities. Today, client-server has become the standard paradigm for most applications, and more broadly encompasses a general model of a service requester and a service provider.&lt;/p&gt;

&lt;p&gt;Despite the two-tier separation, many such applications were still built in a monolithic fashion. All application features resided in a single codebase, tightly coupled, and shared access to a single database.&lt;/p&gt;

&lt;h2&gt;
  
  
  WWW, websites, and webapps: ~1980s
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1983 marked the year of the Internet.&lt;/strong&gt; The Internet was a global system of computer networks that used the TCP/IP protocol to facilitate communication between devices and applications. This was the backbone for FTP programs, SSH systems, and of course, the World Wide Web (WWW).&lt;/p&gt;

&lt;p&gt;Although the Internet and WWW are used interchangeably today, the WWW was invented almost a decade later, in 1990. The WWW is an information system—a web of HTML content connected by links—shared and organized over the Internet using the HTTP protocol. It was a revolutionary way of storing information such that it could be accessed globally, paving the road for the era of websites and web programming.&lt;/p&gt;

&lt;p&gt;In the early days, websites were static pages that displayed data from the web server. The introduction of the Common Gateway Interface (CGI) in 1993 brought web interactivity to the fore, kickstarting the prospects of web applications. &lt;/p&gt;

&lt;p&gt;Fledging web interactivity took off with the invention of JavaScript in 1995, which brought scripting logic onto the client side. JavaScript quickly became the new standard for web programming, and web servers could more easily deliver dynamic, interactive content. These were the early forums, bulletin boards, and web forms.&lt;/p&gt;

&lt;p&gt;The invention of the web and its latent possibilities soon kicked off the next wave of application development. Instead of building a dedicated client for your application, you could simply build a website to be hosted on the web.&lt;/p&gt;

&lt;h2&gt;
  
  
  Service-oriented architecture and web services: ~1990s
&lt;/h2&gt;

&lt;p&gt;As application development grew, a monolithic codebase became more unwieldy to manage, and it became clear that capabilities or data housed in one system could be reused in another.&lt;/p&gt;

&lt;p&gt;To address these challenges, modularization became a topic of discussion. In the 1990s, the server side was further split into two tiers: the application server and the database. The application server stored all the application and business logic, while the database server stored the data records, which reduced latency at high processing volumes.&lt;/p&gt;

&lt;p&gt;Around the same time, &lt;strong&gt;service-oriented architecture (SOA) emerged as an architectural pattern where software capabilities are designed as individual services that can be used with any system as long as the system followed its usage specification&lt;/strong&gt;. SOA encouraged a move towards developing enterprise applications as loosely coupled services that interact through a communication protocol over a network, a pattern that has remained dominant today. &lt;/p&gt;

&lt;p&gt;Under SOA, a shopping app would contain multiple services: one for inventory tracking, another for order processing, and yet another for user authentication. Unlike a microservice-based application, services in an SOA pattern still share the same database, through the application layer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffpao8r8numv7fvf5rx1w.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffpao8r8numv7fvf5rx1w.jpg" alt="Diagram of service-oriented architecture (SOA), where the application logic is split into individual services, although the services share a single database." width="800" height="418"&gt;&lt;/a&gt;Service-oriented architecture (SOA).&lt;/p&gt;

&lt;p&gt;With SOA, came the need to define set standards and protocols for how these services interacted with all sorts of clients. DCOM and CORBA were some non-web-based standards soon overshadowed by &lt;strong&gt;web-based ones like SOAP and REST APIs&lt;/strong&gt;. SOA offered a way for services from different providers to be integrated into one application or for the same services to be utilized on different clients, like a web portal or a dedicated desktop interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Virtual machines and cloud computing: ~2000s
&lt;/h2&gt;

&lt;p&gt;SOA set the stage for the move from traditional desktop applications to a new mode of software applications—SaaS—but it was the invention of virtual machines and cloud computing that further spurred the explosion of SaaS products in the coming decades.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Virtual machines, enabled by the hypervisor, are computer systems that exist on the software layer instead of as a physical machine.&lt;/strong&gt; Using virtual machines, it became much easier to create, update, and destroy multiple machines that run different operating systems on a single computer, maximizing resource allocation and utilization for application development.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd1smegauj3xpkcfdjz4g.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd1smegauj3xpkcfdjz4g.jpg" alt="Diagram of virtual machines, which are abstract machines residing on the same physical machine due to the hypervisor." width="800" height="418"&gt;&lt;/a&gt;Virtual machine infrastructure.&lt;/p&gt;

&lt;p&gt;Although machine virtualization has existed since the 1960s, it only came into mainstream use in the 2ooos with the rapid succession of releases by Linux, Microsoft, and VMware. This was the period when companies like Amazon identified the lucrative opportunity that virtualization offered: managed cloud computing services. Physical bare metal machines are expensive and difficult to manage, a limiting factor when companies want to scale. With cloud computing services like Amazon EC2, companies could rent virtual machines for processing power and scale as required.&lt;/p&gt;

&lt;p&gt;Growing companies like Facebook and Netflix could truly focus on building out their software capabilities without needing to maintain the underlying hardware of bare metal machines and data centers. The technical overhead to get started became much lower, accelerating the next wave of startups and digital-native businesses in the coming decades. In turn, this unlocked the next step in distributed computing and software architecture: microservices.&lt;/p&gt;

&lt;h2&gt;
  
  
  APIs, containers, and the rise of microservices: ~2010s
&lt;/h2&gt;

&lt;p&gt;The 2010s were the culmination of multiple trends towards distributed computing. Fueled by the need for third-party access to their services, the first few commercial APIs were launched in 2000 by Salesforce and eBay, enabling their partners or customers to integrate features onto their own sites or applications. From Twitter and Google Maps to Stripe, Twilio, and now OpenAI, &lt;a href="https://dev.to/orkes/emerging-tech-trends-2024-the-latest-developments-in-ai-api-and-automation-1omj"&gt;the API economy has ballooned since&lt;/a&gt;, powering integrated features across the web.&lt;/p&gt;

&lt;p&gt;In the same vein, microservices took off when scaling companies like Amazon and Netflix needed to speed up and streamline the development cycle, which was slowed down by a monolithic codebase. By splitting up an application into individual microservices, each with its own database, teams could independently update and deploy them, leading to faster releases and improvements.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Futkx50feq7e58li4raz3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Futkx50feq7e58li4raz3.jpg" alt="Diagram of microservice-based architecture, which are individual services connected to individual databases and can be deployed separately." width="800" height="418"&gt;&lt;/a&gt;Microservice-based infrastructure.&lt;/p&gt;

&lt;p&gt;While there are many ways to package and deploy microservices—on a physical or virtual machine—the growth in microservice-based architecture was supported by the emergence of containers. Like virtual machines, containers were an abstraction layer conceptualized in the 1970s, but only launched into enterprise recognition after 2013 when Docker was made open-source.&lt;/p&gt;

&lt;p&gt;Compared to virtual machines, containers provide a greater level of compartmentalization, so multiple instances and versions of the same application can run on the same operating system. All the components needed to run an application—code, run time, libraries, dependencies, and system tools—are stored within the container, offering greater portability and scalability for deploying applications or microservices.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgo0nxzeqoics8x3zk5d1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgo0nxzeqoics8x3zk5d1.jpg" alt="Diagram of containers, which are abstract layers that enable compartmentalization of applications or microservices." width="800" height="418"&gt;&lt;/a&gt;Containers.&lt;/p&gt;

&lt;p&gt;With a patchwork of native or third-party services, databases, and so on, modern application development now requires a robust way to architect and integrate these different components. This brings us to the software architecture of today: orchestration and event systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Orchestration, eventing systems, and solving for distributed interdependency: today
&lt;/h2&gt;

&lt;p&gt;With a distributed model of computing—microservices, APIs, and SOA to a degree—comes a pertinent problem in software architecture: &lt;strong&gt;how will these separate services, databases, and components communicate and interact with each other to flow cohesively?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are two main approaches to resolving the issue of interdependency between distributed services: event-driven architecture and orchestration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Event-driven architecture
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;In an event-driven architecture, services push data into a service bus or event pipeline for any other connected service to read and execute if necessary.&lt;/strong&gt; The overall system responds to events or state changes without keeping track of the impact of individual events on other events, thus reducing interdependency between each service.&lt;/p&gt;

&lt;p&gt;While the concept of a service bus has been around since the emergence of SOA, the trend towards microservices has brought it even further to the fore, with the likes of Kafka and Amazon SQS. An event-driven system enables real-time updates and improved system responsiveness while unlocking increased throughput in parallel processing. This has powered systems with fast-changing updates, such as ride-hailing or airline transactions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa3g4xt133pflfqzgeftx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa3g4xt133pflfqzgeftx.jpg" alt="Diagram of event-driven architecture, where services (producers) push data (known as events) into an event stream for other services (consumers) to subscribe to and receive." width="800" height="418"&gt;&lt;/a&gt;Event-driven architecture.&lt;/p&gt;

&lt;p&gt;However, event streams do not provide insight into the overall state of the system and the progress of a process across distributed services. The lack of state tracking and visibility poses significant challenges when it comes to debugging and troubleshooting, as well as implementing error handling and resilience mechanisms. Designing an event stream that can properly handle sequential processes when there is no in-built chronology may end up overly complicated, requiring careful consideration of the event flow, routing, and handling.&lt;/p&gt;

&lt;h3&gt;
  
  
  Orchestration
&lt;/h3&gt;

&lt;p&gt;Orchestration offers another viable solution to resolving the problem of microservice interdependency and even the issues encountered in event-driven architecture. &lt;strong&gt;In orchestration, a central orchestrator schedules each task or microservice based on a predefined flow, only proceeding to the next task in sequence when the previous one has been completed successfully.&lt;/strong&gt; Unlike event streams, the orchestrator tracks the overall progress across each service, empowering developers to easily trace and debug errors and implement failure compensation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Focl51ixgi6dolay58wjg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Focl51ixgi6dolay58wjg.jpg" alt="Diagram of orchestration, where services, databases, event streams, and so on connect to a central orchestrator that coordinate all the different components into a directed workflow." width="800" height="418"&gt;&lt;/a&gt;Orchestration.&lt;/p&gt;

&lt;p&gt;The orchestration layer forms an integral level of abstraction that coordinates separate services, databases, event streams, LLMs, and other components into a concerted process. From ease of integration to ease of tracking and troubleshooting, orchestration empowers developers to architect applications across the entire development lifecycle, seizing the world of software development with the likes of Orkes Conductor and Airflow. The durability of orchestration has streamlined many complex workflows, such as automating infrastructure upgrades or processing shipment orders over long periods of time.&lt;/p&gt;

&lt;p&gt;We leave the history of software architecture at this juncture: orchestration as an architectural layer that unlocks the next step in distributed computing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Throughout the past century, technology has advanced in leaps and bounds from mainframes and networks to virtual machines, containers, and genAI capabilities today.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9lw2h68susnsudceq31g.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9lw2h68susnsudceq31g.jpg" alt="Diagram of the technology stack over the years." width="800" height="418"&gt;&lt;/a&gt;The tech stack over the years.&lt;/p&gt;

&lt;p&gt;Looking ahead, software architecture will continue to evolve, shaped by advances in technology and the changing needs of businesses. For software architects and developers, it is more important than ever to adopt and adapt to better paradigms without losing sight of the core principles of good design. Ultimately, the best software architecture is one that best suits your business and product requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Orkes Conductor
&lt;/h2&gt;

&lt;p&gt;Leveraging advanced workflow orchestration platforms like Orkes Conductor unlocks developer productivity in the world of distributed computing. Used widely in many mission-critical applications for &lt;a href="https://orkes.io/use-cases/microservices-and-api-orchestration" rel="noopener noreferrer"&gt;microservice orchestration&lt;/a&gt;, &lt;a href="https://orkes.io/use-cases/event-driven-architecture" rel="noopener noreferrer"&gt;event handling&lt;/a&gt;, and &lt;a href="https://orkes.io/use-cases/ai-and-llm-chaining" rel="noopener noreferrer"&gt;LLM chaining&lt;/a&gt;, Orkes Conductor empowers teams to build resilient, scalable systems with ease:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Visual workflow editor&lt;/strong&gt;— Build and edit workflows visually, using dozens of integrations, custom tasks, and in-built system tasks and operators for APIs, webhooks, databases, and LLMs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Elastic capacity&lt;/strong&gt;—Run millions of concurrent workflows with minimal latency atop Conductor’s resilient infrastructure, created for durability, speed, and redundancy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failure handling&lt;/strong&gt;—Get native support for rate limits, retry policies, timeouts, and more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Versioning&lt;/strong&gt;—Safely version your workflows with no disruption to production runs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Introspection and metrics&lt;/strong&gt;—Inspect workflow performance and logs for testing and debugging, and get aggregated insights into throughput and other metrics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise-grade security&lt;/strong&gt;—Secure access with SSO, RBAC, and secret variables.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;a href="https://orkes.io/cloud" rel="noopener noreferrer"&gt;Orkes Cloud&lt;/a&gt; is a fully managed and hosted Conductor service that can scale seamlessly to meet your needs. When you use Conductor via Orkes Cloud, your engineers don’t need to worry about setting up, tuning, patching, and managing high-performance Conductor clusters. Try it out with our free &lt;a href="https://developer.orkescloud.com/?utm_campaign=software-archi-evol-blog&amp;amp;utm_source=devto-blog&amp;amp;utm_medium=web" rel="noopener noreferrer"&gt;Developer Playground&lt;/a&gt; for Orkes Cloud.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>microservices</category>
      <category>orchestration</category>
      <category>eventdriven</category>
    </item>
    <item>
      <title>RAG Explained | Using Retrieval-Augmented Generation to Build Semantic Search</title>
      <dc:creator>livw</dc:creator>
      <pubDate>Thu, 13 Jun 2024 08:59:48 +0000</pubDate>
      <link>https://dev.to/orkes/rag-explained-using-retrieval-augmented-generation-to-build-semantic-search-1i32</link>
      <guid>https://dev.to/orkes/rag-explained-using-retrieval-augmented-generation-to-build-semantic-search-1i32</guid>
      <description>&lt;p&gt;Large language models (LLMs) have captured the public sphere of imagination in the past few years since OpenAI first launched ChatGPT to the world in late 2022. After the initial fascination amongst the public, businesses followed suit to find use cases where they could potentially deploy LLMs.&lt;/p&gt;

&lt;p&gt;With more and more LLMs released as open source and deployable as on-premise private models, it became possible for organizations to train, fine-tune, or supplement models with private data. &lt;strong&gt;RAG (retrieval-augmented generation)&lt;/strong&gt; is one such technique for customizing an LLM, serving as a viable approach for businesses to use LLMs without the high costs and specialized skills involved in building a custom model from scratch.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is retrieval-augmented generation?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;RAG (retrieval-augmented generation) is a technique that improves the accuracy of an LLM (large language model) output with pre-fetched data from external sources.&lt;/strong&gt; With RAG, the model references a separate database from its training data in real-time before generating a response.&lt;/p&gt;

&lt;p&gt;RAG extends the general capabilities of LLMs into a specific domain without the need to train a custom model from scratch. This approach enables general-purpose LLMs to provide more useful, relevant, and accurate answers in highly-specialized or private contexts, such as an organization’s internal knowledge base. For most use cases, RAG provides a similar result as training custom models but at a fraction of the required cost and resources. &lt;/p&gt;

&lt;h2&gt;
  
  
  How does retrieval-augmented generation work?
&lt;/h2&gt;

&lt;p&gt;RAG involves using general-purpose LLMs as-is without special training or fine-tuning to serve answers based on domain-specific knowledge. This is achieved using a two-part process. &lt;/p&gt;

&lt;p&gt;First, the data is chunked and transformed into embeddings, which are vector representations of the data. These embeddings are then indexed into a vector database with the help of an AI algorithm known as embedding models. &lt;/p&gt;

&lt;p&gt;Once the data is populated in the index, natural language queries can be performed on the index using the same embedding model to yield relevant chunks of information. These chunks then get passed to the LLM as context, along with guardrails and prompts on how to respond given the context.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq9v92zteyvwwno7wjvb8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq9v92zteyvwwno7wjvb8.jpg" alt="Diagram of how retrieval-augmented generation works. Part 1 is indexing, which involves accessing the data from a source, transforming the data into embeddings, and storing the embeddings into a vector database index. Part 2 is searching, which involves searching the indexing to yield context and calling the LLM with a prompt containing the context." width="800" height="501"&gt;&lt;/a&gt;&lt;/p&gt;
RAG (retrieval-augmented generation) is a two-part AI technique that involves indexing data into a vector database and searching the database to retrieve relevant information. 



&lt;h2&gt;
  
  
  Why use retrieval-augmented generation?
&lt;/h2&gt;

&lt;p&gt;RAG offers several strategic advantages when implementing generative AI capabilities:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Minimize inaccuracies&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Using a RAG-based LLM can help reduce hallucinations (plausible yet completely false information) or inaccuracies in the model’s answers. By providing access to additional information, RAG enables relevant context to be added to the LLM prompt, thus leveraging the power of in-context learning (ICL) to improve the reliability of the model’s answers. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Access to latest information&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With access to a continuously updated external database, the LLM can provide the latest information in news, social media, research, and other sources. RAG ensures that the LLM responses are up-to-date, relevant, and credible, even if the model’s training data does not contain the latest information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost-effective, scalable, and flexible&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;RAG requires much less time and specialized skills, tooling, or infrastructure to obtain a production-ready LLM. Furthermore, by changing the data source or updating the database, the LLM can be efficiently modified without any retraining, making RAG an ideal approach at scale.&lt;/p&gt;

&lt;p&gt;Since RAG makes use of general-purpose LLMs, the model is decoupled from the domain, enabling developers to switch up the model at will. Compared to a custom pre-trained model, RAG provides instant, low-cost upgrades from one LLM to another.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Highly inspectable architecture&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;RAG offers a highly inspectable architecture, so developers can examine the user input, the retrieved context, and the LLM response to identify any discrepancies. With this ease of visibility, RAG-powered LLMs can also be instructed to provide sources in their responses, establishing more credibility and transparency with users.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use retrieval-augmented generation?
&lt;/h2&gt;

&lt;p&gt;RAG can be used for various knowledge-intensive tasks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Question-answering systems&lt;/li&gt;
&lt;li&gt;Knowledge base search engine&lt;/li&gt;
&lt;li&gt;Document retrieval for research&lt;/li&gt;
&lt;li&gt;Recommendation systems&lt;/li&gt;
&lt;li&gt;Chatbots with real-time data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzfiocs9tgznzyrrx7w7v.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzfiocs9tgznzyrrx7w7v.jpg" alt="Diagram of 5 RAG use cases: question-answering systems, knowledge base search engine, document retrieval for research, recommendation systems, chatbots with real-time data." width="800" height="465"&gt;&lt;/a&gt;&lt;/p&gt;
RAG (retrieval-augmented generation) is useful for many knowledge-retrieval processes.



&lt;h2&gt;
  
  
  Building a retrieval-augmented generation system
&lt;/h2&gt;

&lt;p&gt;While the barriers to entry into RAG are much lower, it still requires an understanding of LLM concepts, as well as trained developers and engineers who can build data pipelines and integrate the query toolchain into the required services for consumption. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using workflow orchestration as a means to build RAG-based applications levels the playing field to that of anyone who can string together API calls to form a business process.&lt;/strong&gt; The two-part process described above can be built as two workflows to create a RAG-based application. Let's build a financial news analysis platform in this example.&lt;/p&gt;

&lt;h3&gt;
  
  
  Orchestrating RAG using Orkes Conductor
&lt;/h3&gt;

&lt;p&gt;Orkes Conductor streamlines the process of building LLM-powered applications by orchestrating the interaction between distributed components so that you don’t have to write the plumbing or infrastructure code for it. In this case, a RAG system requires orchestration between four key components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Aggregating data from a &lt;strong&gt;data source&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;Indexing and retrieving the data in a &lt;strong&gt;vector database&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Using an &lt;strong&gt;embedding model&lt;/strong&gt;; and&lt;/li&gt;
&lt;li&gt;Integrating and calling the &lt;strong&gt;LLM&lt;/strong&gt; to respond to a search query.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's build out the workflows to orchestrate the interaction between these components.&lt;/p&gt;

&lt;h4&gt;
  
  
  Part 1: Indexing the data
&lt;/h4&gt;

&lt;p&gt;The first part of creating a RAG system is to load, clean, and index the data. This process can be accomplished with a Conductor workflow. Let’s build a &lt;code&gt;data-indexer&lt;/code&gt; workflow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Get the data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Choose a data source for your RAG system. The data can come from anywhere — a document repository, database, or API — and Conductor offers a variety of tasks that can pull data from any source.&lt;/p&gt;

&lt;p&gt;For our financial news analysis platform, the &lt;a href="https://site.financialmodelingprep.com/developer/docs/fmp-articles-api" rel="noopener noreferrer"&gt;FMP Articles API&lt;/a&gt; will serve as the data source. To call the API, get the API access keys and create an HTTP task in your Conductor workflow. Configure the endpoint method, URL, and other settings, and the task will retrieve data through the API whenever the workflow is executed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fidglh2y0pyt8dab24m02.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fidglh2y0pyt8dab24m02.jpg" alt="Screenshot of the HTTP task in Orkes Conductor." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
Use the HTTP task in Orkes Conductor to call an API.



&lt;p&gt;&lt;strong&gt;Step 2: Transform the data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before the data gets indexed to the vector database, the API payload should be transformed, cleaned, and chunked so that the embedding model can ingest it.&lt;/p&gt;

&lt;p&gt;Developers can write Conductor workers to transform the data to create chunks.  Conductor workers are powerful, language-agnostic functions that can be written in any language and use well-known libraries such as NumPy, pandas, and so on for advanced data transformation and cleaning.&lt;/p&gt;

&lt;p&gt;In our example, we will use a JSON JQ Transform Task as a simple demonstration of how to transform the data. We only need the article title and content from the FMP Articles API for our financial news analysis platform. Each article must be stored in separate chunks in the required payload format for indexing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3erqysqpp6x1y8li016s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3erqysqpp6x1y8li016s.png" alt="Diagram of the original data payload versus the transformed data." width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;
API payload vs the transformed data. Only the relevant data are retained.



&lt;p&gt;&lt;strong&gt;Step 3: Index the data into a vector database&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The cleaned data is now ready to be indexed into a vector database, such as Pinecone, Weaviate, MongoDB, and more. Use the LLM Index Text Task in your Conductor workflow to add one data chunk into the vector space. A dynamic fork can be used to execute multiple LLM Index Text Tasks in parallel so that multiple chunks can be added at once.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvwn6gk3mfitrbwkzdj81.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvwn6gk3mfitrbwkzdj81.jpg" alt="Screenshot of the LLM Index Text task in Orkes Conductor." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;
Use the LLM Index Text task in Orkes Conductor to store data into a vector database.



&lt;p&gt;The LLM Index Test Task is one of the many LLM tasks provided in Orkes Conductor to simplify building LLM-powered applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repeat&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To build out the vector database, iterate through the three steps — extract, transform, load — until the desired dataset size is reached. The iterative loop can be built using a Do While operator task in Conductor.&lt;/p&gt;

&lt;p&gt;Here is the full &lt;code&gt;data-indexer&lt;/code&gt; workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6v2luenpq3q5js3fewxh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6v2luenpq3q5js3fewxh.png" alt="Diagram of the data-indexer workflow." width="800" height="900"&gt;&lt;/a&gt;&lt;/p&gt;
data-indexer workflow in Orkes Conductor.



&lt;h4&gt;
  
  
  Part 2: Retrieving data for semantic search
&lt;/h4&gt;

&lt;p&gt;Once the vector database is ready, it can be deployed for production — in this case, for financial news analysis. This is where data is retrieved from the vector database to serve as context for the LLM, so that it can formulate a more accurate response. For this second part, let’s build a &lt;code&gt;semantic-search&lt;/code&gt; workflow that can be used in an application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Retrieve relevant data from vector database&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In a new workflow, add the LLM Search Index Task — one of the many LLM tasks provided in Orkes Conductor to simplify building LLM-powered applications. This task takes in a user query and returns the relevant context chunks that match the most closely.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe6tz306x8f1y32x33f8a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe6tz306x8f1y32x33f8a.png" alt="Diagram of the input, containing the user query versus the output, containing the relevant data from the vector database." width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;
The LLM Search Index Text takes in a user query and returns the relevant context chunks from the vector database.



&lt;p&gt;&lt;strong&gt;Step 2: Formulate an answer&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With the retrieved context, call an LLM of your choice to generate the response to the user query. Use the LLM Text Complete Task in Orkes Conductor to accomplish this step. The LLM will ingest the user query along with the context.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7rtqzxaek52s3qbar4rx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7rtqzxaek52s3qbar4rx.jpg" alt="Screenshot of the LLM Text Complete task in Orkes Conductor." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
Use the  LLM Text Complete task in Orkes Conductor to prompt a selected LLM for a response.



&lt;p&gt;Guardrails can be set up in Orkes Conductor to optimize and constrain the LLM response, such as by adjusting the temperature, topP, or maxTokens. &lt;/p&gt;

&lt;p&gt;Use Orkes Conductor’s AI Prompt studio to create a prompt template for the LLM to follow in the LLM Text Complete Task.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example prompt template&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Answer the question based on the context provided.

Context: "${context}"

Question: "${question}"

Provide just the answer without repeating the question or mentioning the context.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the full &lt;code&gt;semantic-search&lt;/code&gt; workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhzwcclw82coilx6y9eae.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhzwcclw82coilx6y9eae.jpg" alt="Diagram of the semantic-search workflow." width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;
semantic-search workflow in Orkes Conductor.



&lt;p&gt;&lt;strong&gt;Use the workflow in your application&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once the &lt;code&gt;semantic-search&lt;/code&gt; workflow is ready, you can use it in your application project to build a semantic search engine or chatbot. To build your application, leverage the Conductor SDKs, available in popular languages like Python, Java, and Golang, and call our APIs to trigger the workflow in your application.&lt;/p&gt;

&lt;p&gt;The RAG-based financial news analysis platform looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkym09h6ovotcan1b2bnu.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkym09h6ovotcan1b2bnu.jpg" alt="Screenshot of the example RAG-based financial news analysis platform." width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;
The RAG-based financial news analysis platform in action, with a Conductor workflow powering it.



&lt;p&gt;Whenever a user enters a query, a &lt;code&gt;semantic-search&lt;/code&gt; workflow runs in the background to provide the answer. &lt;/p&gt;

&lt;p&gt;If the vector database needs to be updated on the backend, the &lt;code&gt;data-indexer&lt;/code&gt; workflow can be triggered, or even scheduled at regular intervals for automatic updates.&lt;/p&gt;

&lt;p&gt;While the financial news analysis platform is a simple variant of a RAG system, developers can use Orkes Conductor to quickly develop and debug their own RAG systems of varying complexities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Building semantic search using RAG can be much more achievable than most people think. By applying orchestration using a platform like Orkes Conductor, the development and operational effort need not involve complicated tooling, infrastructure, skill sets and other resources. This translates to a highly efficient go-to-market process that can be rapidly iterated over time to optimize the results and value derived from such AI capabilities in any modern business.&lt;/p&gt;

&lt;p&gt;—&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/conductor-oss/conductor" rel="noopener noreferrer"&gt;Conductor&lt;/a&gt; is an open-source orchestration platform used widely in many mission-critical applications. Orkes Cloud is a fully managed and hosted Conductor service that can scale seamlessly according to your needs. Try it out with our free &lt;a href="https://developer.orkescloud.com/?utm_campaign=rag-explained-blog&amp;amp;utm_source=devto-blog&amp;amp;utm_medium=web" rel="noopener noreferrer"&gt;Developer Playground&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>rag</category>
      <category>ai</category>
      <category>orchestration</category>
      <category>llm</category>
    </item>
    <item>
      <title>Emerging Tech Trends 2024: The Latest Developments in AI, API, and Automation</title>
      <dc:creator>livw</dc:creator>
      <pubDate>Fri, 17 May 2024 11:05:28 +0000</pubDate>
      <link>https://dev.to/orkes/emerging-tech-trends-2024-the-latest-developments-in-ai-api-and-automation-1omj</link>
      <guid>https://dev.to/orkes/emerging-tech-trends-2024-the-latest-developments-in-ai-api-and-automation-1omj</guid>
      <description>&lt;p&gt;Technology has always been the lynchpin in driving progress — from the first ships built to the first industrial revolution to the computer age. The time between each successive technological wave has been shortening, and in the past few years, we have seen explosive growth in Artificial Intelligence (AI) and its capabilities.&lt;/p&gt;

&lt;p&gt;While AI has been the epicenter of most tech buzz, it is just one tailwind in the wider trajectory toward greater automation in computer-based industries. In this article, we will explore the latest tech trends in AI, APIs, and automation that can impact your business. Find out how AI serves as the frontrunner and API as the technical bedrock that accelerates ongoing tech trends, with automation as the overarching motivation for the latest developments in the tech and business landscape.&lt;/p&gt;

&lt;h2&gt;
  
  
  GenAI has unlocked new ways to work
&lt;/h2&gt;

&lt;p&gt;The viral release of OpenAI’s ChatGPT3.5 in 2022 sparked a huge wave of excitement, as millions of people experimented with what it could do and what it meant for the future of work. Chatbots like ChatGPT are a form of intelligence known as Generative AI (GenAI), which is capable of producing naturalistic images, text, or even videos based on a given prompt.&lt;/p&gt;

&lt;p&gt;At the core of GenAI are AI programs known as large language models (LLMs), which consume large amounts of training data in order to produce real-like data. Now, in 2024, ChatGPT is just one of the few thousand LLMs available for use. From enterprise offerings like Google Gemini, Amazon Bedrock, and Anthropic Claude to the 650K open-source models hosted on Hugging Face (as of May 2024), there is no shortage of choice when it comes to using GenAI as a copilot for work.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI-augmented code
&lt;/h3&gt;

&lt;p&gt;Unsurprisingly, the tech sector has been one of the first few to adopt GenAI in work. Many companies, big and small, have been using LLM chatbots like ChatGPT to produce, rewrite, and debug code, accelerating developer productivity. A survey by GitHub found that &lt;a href="https://github.blog/2023-06-13-survey-reveals-ais-impact-on-the-developer-experience/" rel="noopener noreferrer"&gt;92% of US-based developers are using AI coding tools for work, and 70% feel the benefits of using such tools&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Some early entrants to code completion tools are Tabnine, and more recently, GitHub Copilot and Google’s CodeGemma.&lt;/p&gt;

&lt;p&gt;But beyond using GenAI for writing code, there are many more possibilities for AI-powered software development. At the keynote for the 2024 Apidays Singapore conference, Manjunath Bhat (VP Analyst - Gartner) remarked that AI could also play a role in other high-impact avenues, like suggesting what should be built or explaining legacy or indecipherable code.&lt;/p&gt;

&lt;p&gt;Thus far, there is a fast-expanding array of AI tools for automating software tests, generating documentation, and answering developer questions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgxsay5t4b7urkqen1ait.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgxsay5t4b7urkqen1ait.jpg" alt="Infographic of 10 ways to use AI in software development: code generation, code completion, code conversion, code review and refactoring, code debugging, explaining code in codebase, AI documentation generation, AI-powered search in codebase or documentation, AI testing, and developer-focused chatbots." width="800" height="800"&gt;&lt;/a&gt;A wide variety of use cases for AI in software development.&lt;/p&gt;

&lt;h3&gt;
  
  
  Specialized models, plug-ins, and more
&lt;/h3&gt;

&lt;p&gt;Today, the average person may ask ChatGPT to summarize an essay, provide travel itineraries, or solve logic puzzles. Such chatbots are based on general-purpose models that can handle a gamut of tasks across domains.&lt;/p&gt;

&lt;p&gt;While generic models have the advantage of being able to handle — with varying success — any task right away with no training required, they often fall short when the user requires a more accurate or complex response. Issues like hallucination, bias, or inaccuracies are some of the biggest challenges to implementing and scaling AI in a highly specialized business context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Domain-specific models&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A variety of domain-specific and multilingual models have entered the scene to address the limitations of generic models. These specialized models are trained with domain-specific datasets, allowing the model to learn and perform far better on specialized tasks.&lt;/p&gt;

&lt;p&gt;Google’s Med-PaLM 2 model was trained with curated medical databases, becoming the &lt;a href="https://cloud.google.com/blog/topics/healthcare-life-sciences/sharing-google-med-palm-2-medical-large-language-model" rel="noopener noreferrer"&gt;first LLM to perform at 85% accuracy on medical examinations&lt;/a&gt;. Such domain-specific LLMs are the first crest in the next wave of AI development, where LLMs can be safely deployed in real-world contexts like assisting with tuberculosis diagnoses or analyzing past legal cases.&lt;/p&gt;

&lt;p&gt;Already, there are LLMs like BloombergGPT and FinGPT for finance, ChatLAW for law, and ClimateBERT for climate and environment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Plug-ins, API connectivity&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Besides specialized models, another way to power up general models is through plug-ins or connectivity with APIs.&lt;/p&gt;

&lt;p&gt;LLM plug-ins extend the model’s capabilities. Through API calls, these plugins can provide access to external databases or execute third-party tasks like making a hotel reservation. That’s how plug-ins enable LLMs to handle more complex requests like acting as a personal shopper or creating a financial report based on the latest data.&lt;/p&gt;

&lt;p&gt;While OpenAI has rolled back ChatGPT’s plug-ins after a year of service, the game is still on to get LLMs hooked up with APIs. Ongoing projects like Gorilla (UC Berkeley) and RestGPT (Peking University) are working to build LLM-powered systems that can carry out real-world actions based on a command, like “create a Spotify playlist” or “book a flight to Paris”.&lt;/p&gt;

&lt;p&gt;In these frameworks, LLMs act as a switchboard operator who knows the right APIs to call when prompted, then formulates the API request and parses the response for the user. API connectivity promises a new breakthrough for LLMs: beyond just a conversational partner, LLMs can act and carry out tasks in the real world, bringing us one step closer to natural language interfaces.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F28qrqhghcpzd2oxsvdfy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F28qrqhghcpzd2oxsvdfy.jpg" alt="Diagram of user interacting with the world through an LLM as the intermediary interface." width="800" height="418"&gt;&lt;/a&gt;API connectivity can allow LLMs to act on the world, unlocking new avenues in natural language interfaces.&lt;/p&gt;

&lt;h2&gt;
  
  
  API as a Product, API as tech accelerant
&lt;/h2&gt;

&lt;p&gt;If the 2010s were the decade for the rise of the software-as-a-service (SaaS) model, then the 2020s are all about API as a Product (AaaP). Under a SaaS model, businesses offer their unique services and strengths through web-based applications, like Gmail for mail services or Zoom for video conferencing.&lt;/p&gt;

&lt;p&gt;However, in recent years, applications are gradually becoming more modular and built using a microservice-based infrastructure. This means that application functionalities like payment, notifications, or even login credentials are added using APIs. Because APIs expose the capabilities of a service in a programmatic manner, it is much easier for developers to build products without having to code everything from scratch.&lt;/p&gt;

&lt;p&gt;This change in software development heralds an API-based economy, where products and services are offered and accessed through APIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  API as a Product
&lt;/h3&gt;

&lt;p&gt;Stripe, Sendgrid, and Twilio—these are companies that have grown tremendously by selling third-party API functionalities to other enterprises. More and more API offerings are expected to crop up in the coming decade, especially for industry-specific APIs like payroll, open banking, government, and so on.&lt;/p&gt;

&lt;p&gt;As the API market grows, Kong's 2023 API Impact Report estimates that &lt;a href="https://konghq.com/blog/enterprise/the-economic-impact-of-apis" rel="noopener noreferrer"&gt;APIs will contribute $14.2 trillion to the global economy by 2027, up from $10.9 trillion in 2023&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fye5tu3zya3kdib6gxh94.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fye5tu3zya3kdib6gxh94.jpg" alt="Graph of API’s global economic impact in 2023 and 2027, provided by Kong 2023 API Impact Report." width="800" height="800"&gt;&lt;/a&gt;Economic impact of APIs is expected to jump $3.3 trillion dollars by 2027.&lt;/p&gt;

&lt;p&gt;Along with the economic boom, there has been an explosion of tooling, standards, and platforms to support the growth of API as a Product. With so many APIs entering the market, it has become more difficult to discover and integrate each and every API into a given application. Two key trends stand out:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;API portals and marketplaces&lt;/strong&gt;—Provide a single point of collaboration where consumers can easily try, observe, use, and subscribe to API products.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unified APIs&lt;/strong&gt;—Provide a single point of access to multiple APIs, so users only need to integrate one API to obtain the capabilities of multiple APIs.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  API as tech accelerant
&lt;/h3&gt;

&lt;p&gt;An API-first economy espouses an interface-first approach, which means exposing capabilities and hiding complexities. This hallmark of APIs has made it the foundation for the rapid growth of many tech trends, the most prominent of which is AI.&lt;/p&gt;

&lt;p&gt;Since most LLMs have only been commercially available in recent years, many have been built with an API-first approach. Many LLMs can be programmatically accessed via APIs, making it super convenient for developers to integrate AI capabilities into their applications. In other words, API access has precipitated the rapid availability of AI-powered tools and features on the market within just the past two years.&lt;/p&gt;

&lt;p&gt;APIs have also served as the backbone for the recent proliferation of no- and low-code application builders like Bubble and Xano. With APIs, users can create applications without having to know a programming language. These tools have also led to the rise of citizen developers, enabling businesses to quickly build applications and dashboards without a large developer team.&lt;/p&gt;

&lt;p&gt;All these emerging trends in AI and API point to the same undercurrent of opportunity: lower barriers of entry to and automation of computer-based work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automation in computer-based industries
&lt;/h2&gt;

&lt;p&gt;Much like how the steam engine had automated blue-collar work in energy, manufacturing, and logistics, we are now entering a whole new era of automation across sectors, especially in computer-based industries.&lt;/p&gt;

&lt;p&gt;Needless to say, AI is one of the key factors towards greater automation. Research by Goldman Sachs suggests that &lt;a href="https://www.gspublishing.com/content/research/en/reports/2023/03/27/d64e052b-0f6e-45d7-967b-d7be35fabd16.html" rel="noopener noreferrer"&gt;18% of global work could be automated by AI&lt;/a&gt;, with the biggest impact felt in white-collar jobs like administration and business operations.&lt;/p&gt;

&lt;p&gt;It is important to note that AI is unlikely to make entire job functions redundant. Rather, repetitive or low-impact tasks can be delegated to AI automation, allowing more time for high-impact or more complex work. For example, in customer support, GenAI-enabled chatbots can interact autonomously with customers to provide basic support and handle common inquiries, while human agents can handle more demanding cases.&lt;/p&gt;

&lt;p&gt;Another key catalyst is the growing availability of automation tools, such as RPA (robotic process automation) software and orchestration platforms.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;RPA (robotic process automation)&lt;/strong&gt;—Automates high-volume, time-consuming, repetitive tasks using a bot. The bot replicates human actions on computer applications, like entering data from PDFs into a spreadsheet and emailing it, which eliminates such high-effort yet low-stakes tasks found in many business processes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orchestration&lt;/strong&gt;—Automates the coordination of multiple systems, applications, and services through a &lt;a href="https://dev.to/orkes/durable-execution-explained-how-conductor-delivers-resilient-systems-out-of-the-box-3i1p"&gt;centralized coordinating service&lt;/a&gt;. Based on a predefined workflow, the orchestrator runs through a series of tasks in order to achieve a complex or &lt;a href="https://dev.to/orkes/long-running-workflows-5aii"&gt;long-running business process&lt;/a&gt;, such as managing shipment orders, upgrading cloud infrastructure, or even deploying LLM-powered applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From AI to API to automation tools, we have yet again entered an age where computer-based technology will revolutionize how businesses are run. These trends promise greater productivity and connectivity across systems, allowing people to focus on high-impact work. In 2024, it is more important than ever for businesses to leverage new technology to drive value.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scale with Conductor
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/conductor-oss/conductor" rel="noopener noreferrer"&gt;Conductor&lt;/a&gt; is an open-source orchestration platform that automates complex or long-running processes, such as AI integration flows, microservice application flows, DevOps processes, transactional flows, and more. With Conductor, developers can build and update durable workflows without the complexities of managing system failures, dependencies, or scalability.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://orkes.io/" rel="noopener noreferrer"&gt;Orkes Cloud&lt;/a&gt; is a fully managed and hosted Conductor service that can scale seamlessly according to your needs. When you use Conductor via Orkes Cloud, your engineers don’t need to worry about set-up, tuning, patching, and managing high-performance Conductor clusters. Try it out with our free &lt;a href="https://developer.orkescloud.com/?utm_campaign=tech-trends-2024&amp;amp;utm_source=devto-blog&amp;amp;utm_medium=web" rel="noopener noreferrer"&gt;Developer Playground&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>automation</category>
      <category>devops</category>
    </item>
    <item>
      <title>Durable Execution Explained — How Conductor Delivers Resilient Systems Out Of The Box</title>
      <dc:creator>livw</dc:creator>
      <pubDate>Thu, 09 May 2024 16:00:00 +0000</pubDate>
      <link>https://dev.to/orkes/durable-execution-explained-how-conductor-delivers-resilient-systems-out-of-the-box-3i1p</link>
      <guid>https://dev.to/orkes/durable-execution-explained-how-conductor-delivers-resilient-systems-out-of-the-box-3i1p</guid>
      <description>&lt;p&gt;&lt;em&gt;&lt;p&gt;This is part 2 of a two-part series on durable execution, what it is, why it is important, and how to pull it off. Part 2 shows how Conductor, a workflow orchestration engine, seamlessly integrates durable execution into applications. Check out &lt;a href="https://dev.to/orkes/why-your-applications-need-durable-execution-and-best-practices-to-achieve-it-5ham"&gt;part 1 for more about what durable execution is&lt;/a&gt;.&lt;/p&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;In the ever-evolving landscape of application architecture, durable execution and platform engineering have been gaining traction in recent years, driven by the need for resilient, scalable, and efficient systems. &lt;/p&gt;

&lt;p&gt;Durable execution refers to a system’s ability to persist execution even in face of interruption or failure. This characteristic is especially important in distributed and/or long-running systems, where the chances of disruptions or failure increase drastically. While there are &lt;a href="https://dev.to/orkes/why-your-applications-need-durable-execution-and-best-practices-to-achieve-it-5ham"&gt;several best practices for building durable applications and systems&lt;/a&gt;, one of the most effective ways is to leverage stateful platforms like Orkes Conductor.&lt;/p&gt;

&lt;p&gt;Conductor is a &lt;strong&gt;workflow orchestration platform that abstracts away the complexities of underlying infrastructure&lt;/strong&gt;, enabling developers to focus on building applications. True to its name, Conductor directs and orchestrates the performance of distributed services into a dynamic application flow. Each individual player – or task – does not need to care what the other players are doing, because Conductor keeps track of what is supposed to happen at every juncture.&lt;/p&gt;

&lt;p&gt;Its in-built state management allows for reliable recovery in case of failure or interruption. Just like a musical conductor, it &lt;strong&gt;empowers applications to adapt to ever-changing conditions without going offline&lt;/strong&gt; — whether it is automatically retrying tasks, scaling up to meet traffic spikes, or integrating new services.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzytqem0ovwsfyywkt8h1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzytqem0ovwsfyywkt8h1.png" alt="Infographic of 6 key features in Conductor: a resilient engine, elastic capacity, failure handling, introspection, versioning, and metrics." width="800" height="689"&gt;&lt;/a&gt;6 key Conductor features for durable execution.&lt;/p&gt;

&lt;p&gt;How does Conductor enable you to build resilient, efficient, and scalable systems? Let’s take a look at what happens in the backend when you build your applications with Conductor as the main orchestration engine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conductor guarantees durable execution under the hood
&lt;/h2&gt;

&lt;p&gt;Conductor’s secret sauce for fortifying systems with durable execution is &lt;strong&gt;decoupled infrastructure and redundancy&lt;/strong&gt;. Let’s set the scene for an example workflow.&lt;/p&gt;

&lt;p&gt;Say you have an online shop that makes and ships custom violins worldwide. The order process can take months to fulfill, from pre-ordering the violin to customizing and shipping it. &lt;/p&gt;

&lt;p&gt;Enter the four key actors in our order workflow.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Order App&lt;/strong&gt;—the interface where customers can pre-order violins and make payment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conductor Server&lt;/strong&gt;—the central orchestration engine that directs and tracks the workflow. Conductor’s workflow execution service (WES) runs on this server and manages the task queues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Task Workers&lt;/strong&gt;—code units that run and complete queued tasks. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conductor Stores&lt;/strong&gt;—storage units that contain all workflow information, including metadata, task queues, and history.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvvoxknm1h5snv62uyxft.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvvoxknm1h5snv62uyxft.png" alt="Diagram stack of the Order App, Conductor Server, Task Workers, and Conductor Stores." width="800" height="646"&gt;&lt;/a&gt;The tech stack for how Conductor powers applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Typical success scenario
&lt;/h3&gt;

&lt;p&gt;In the Order App, when the user clicks the Order button during the checkout procedure, a Conductor workflow for &lt;code&gt;order_processing&lt;/code&gt; is triggered. The Order App passes the workflow input parameters, such as the order details, shipping address, and user email to the Conductor Server. In return, the Server passes back the workflow instance ID, which can be used to track the workflow progress and manage its execution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3d3zw682t7a71h3dewcb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3d3zw682t7a71h3dewcb.png" alt="Diagram of workflow getting triggered by a signal." width="800" height="418"&gt;&lt;/a&gt;Workflow begins upon a signal.&lt;/p&gt;

&lt;p&gt;Based on predefined signals and parameters, the &lt;code&gt;order_processing&lt;/code&gt; workflow will run through a series of tasks, such as a HTTP call to a payment processor, or a piece of custom functionality for invoice calculation.&lt;/p&gt;

&lt;p&gt;In Conductor, workflows are executed on a worker-task queue architecture, where each task type – HTTP call, webhook, and so on – has its own task queue. When the workflow execution for &lt;code&gt;order_processing&lt;/code&gt; begins, the workflow execution service (WES) begins to add the workflow’s tasks to the relevant queues. A HTTP task that calls a third-party payment processor, &lt;code&gt;capture_payment&lt;/code&gt;, is added to the HTTP task queue. Meanwhile, &lt;code&gt;calculate_invoice&lt;/code&gt;, a custom function, is added to a custom task queue, while &lt;code&gt;notify_invoice&lt;/code&gt;, another third-party email service, is added to the HTTP task queue.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1etx04cwdttp6hhkprse.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1etx04cwdttp6hhkprse.png" alt="Diagram of tasks getting sorted into queues based on task type." width="800" height="418"&gt;&lt;/a&gt;Based on the predefined workflow, Conductor Server adds tasks to the appropriate task queues.&lt;/p&gt;

&lt;p&gt;While Conductor’s WES is directing and scheduling tasks to the right queue, the available Task Workers are busy polling for tasks to do. Although there are three tasks queued, the first task, &lt;code&gt;capture_payment&lt;/code&gt;, has to be completed first, before the next task can begin. So, when Worker A polls for a task, the Conductor Server sends &lt;code&gt;capture_payment&lt;/code&gt; to Worker A for completion. Once Worker A has completed the task, it updates the Server about the task completion status.&lt;/p&gt;

&lt;p&gt;The Server registers and keeps track of each task’s status. So when it receives the update from Worker A that &lt;code&gt;capture_payment&lt;/code&gt; has been completed, it will send the next scheduled task to the next available worker.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn8aq37bvjrrhv8k9lm0u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn8aq37bvjrrhv8k9lm0u.png" alt="Diagram of workers polling for tasks, completing tasks, and sending the task status back to the server." width="800" height="418"&gt;&lt;/a&gt;Worker-task queue architecture, where workers poll the server for tasks to do, and the server assigns tasks based on the defined workflow schedule.&lt;/p&gt;

&lt;p&gt;This set-up is how Conductor keeps track of the workflow state as one task gets completed one after another based on the predefined workflow schedule. And voilà, with Conductor’s state management, developers need not spend time building complicated infrastructure for state management. Remember the workflow instance ID that was sent when the workflow was initiated? The Order App can simply use the ID to query the Server about the workflow status at any time.&lt;/p&gt;

&lt;h3&gt;
  
  
  State persistence and durability
&lt;/h3&gt;

&lt;p&gt;Crucially, Conductor goes beyond just state visibility. It’s built to withstand and recover from failures no matter how long the workflow runs. Cue the Conductor Stores. At every point, data gets stored on distributed, high-availability clusters so that the workflow can always pick up and resume from where it last stopped – whether from a restart in a failed run or from an idle state in a long-running flow. &lt;/p&gt;

&lt;p&gt;For example, after &lt;code&gt;capture_payment&lt;/code&gt;, the WES reads the next task, &lt;code&gt;wait_customization&lt;/code&gt;, and pauses the workflow to wait for the luthier to finish crafting the instrument. The process may take several months, but with the workflow execution history, pending task queues, and predefined flow of tasks, the system can easily recover from this state of idling. Once Conductor receives a signal – perhaps the luthier clicked a confirmation button on the Order App – that the violin has been made, it will send the next scheduled task in the queue to the next available worker.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7stvjmx5t0xhoepm8nbb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7stvjmx5t0xhoepm8nbb.png" alt="Diagram of Conductor Server receiving a signal to continue and assigning the next task to a worker." width="800" height="418"&gt;&lt;/a&gt;Conductor resumes the workflow upon receiving a signal to proceed to the next task.&lt;/p&gt;

&lt;h3&gt;
  
  
  Handling failures in all shapes and sizes
&lt;/h3&gt;

&lt;p&gt;Whether it’s transient failures, like services going offline briefly, or execution failures, like buggy code, or even deliberate termination, like a customer canceling an order, Conductor is equipped to handle it all.&lt;/p&gt;

&lt;p&gt;We’ve seen a glimpse of how Conductor’s decoupled infrastructure and redundancy enable applications to run smoothly with guaranteed state visibility and persistence. But failure scenarios are where these characteristics for durability really shine through.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;App server goes offline&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s continue with the custom violin order processing workflow. With the violin ready, the workflow proceeds to &lt;code&gt;calculate_invoice&lt;/code&gt;, a custom functionality on the Order App. Perhaps at this moment, a blackout causes the Order App’s server to go down temporarily, which takes all the Task Workers for the &lt;code&gt;calculate_invoice&lt;/code&gt; task offline as well. When the Conductor Server dispatches this task to be completed, there are no Workers available to complete it.&lt;/p&gt;

&lt;p&gt;Based on the task’s retry and timeout policies,  Conductor will automatically reschedule the task until the Order App’s server comes back online or until timeout occurs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjxe6odtvkz0xvk8qyc19.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjxe6odtvkz0xvk8qyc19.png" alt="Diagram of Conductor Server attempting to reach task workers on a different server." width="800" height="418"&gt;&lt;/a&gt;Conductor Server will automatically handle transient failures based on predefined parameters for retries, timeout, and so on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Service hits rate limit&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once the &lt;code&gt;calculate_invoice&lt;/code&gt; task has been completed, the next task – a HTTP call for &lt;code&gt;notify_invoice&lt;/code&gt; – is invoked. At this point, we hit another roadblock: the HTTP service for this task has reached its rate limit. As before, Conductor automatically retries the task with exponential backoff, so that the task is guaranteed to be completed successfully.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conductor goes offline&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Conductor can be deployed in high-availability clusters to guarantee maximum uptime. Even so, in the off-chance where its workflow execution service (WES) goes down, Conductor’s decoupled infrastructure ensures that task runs are not affected. Since the task queues reside on high-availability clusters, separate from the WES, workers can continue running the tasks until completion and update the Conductor Server once it comes back online.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Introspecting workflows for debugging&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once in a while, workflows may still fail despite these automated safeguards and policies for guaranteed execution. However, Conductor makes it easy to remedy these situations. With Conductor Stores that preserve all execution history, developers can inspect what happened under the hood to troubleshoot and rectify errors before restarting the failed workflows.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyql48ogydrc2rpfdhs57.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyql48ogydrc2rpfdhs57.png" alt="Diagram of workflow failure and Conductor’s introspection feature where developers can inspect the execution from various screens." width="800" height="418"&gt;&lt;/a&gt;Conductor enables you to look under the hood and find out where exactly your workflow failed and why it happened.&lt;/p&gt;

&lt;p&gt;For example, say the number of custom violin orders have increased over time, and a number of &lt;code&gt;order_processing&lt;/code&gt; workflow executions are taking too long or have timed out. With the ability to introspect, we can quickly pinpoint the problem. Perhaps the HTTP URL is outdated, or there are insufficient workers servicing a task. Armed with these logs, application developers can quickly troubleshoot and resolve these issues so that the workflows can restart without any roadblocks.&lt;/p&gt;

&lt;p&gt;Importantly, because Conductor keeps state management and infrastructure separate from the Order App’s business logic, the developers can easily scale or upgrade the underlying infrastructure without any downtime.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Analyzing metrics to optimize performance&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Over time, sufficient data will be collected to analyze the workflow performance in aggregate. Conductor comes equipped with a &lt;a href="https://dev.to/orkes/monitoring-microservices-using-prometheus-grafana-42cj"&gt;metrics dashboard&lt;/a&gt; that showcases key insights about latency, completion rate, failure rate, number of concurrent workflows, and so on. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ipbzup3rc96fgps4emw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ipbzup3rc96fgps4emw.png" alt="Diagram of a metrics dashboard." width="800" height="418"&gt;&lt;/a&gt;Conductor provides a metrics dashboard for aggregate workflow performance.&lt;/p&gt;

&lt;p&gt;These metrics can further inform decisions to optimize Conductor workflows for better performance, such as refactoring code or scaling up the infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Refactoring workflows with no downtime&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With in-built support for workflow versioning, application developers can refactor the workflow code anytime without impacting existing workflows. Once the workflow definition has been updated, new executions will run based on the latest definitions while existing workflows can be restarted to run the latest definitions. All of this, made possible with Conductor’s decoupled architecture.&lt;/p&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flv5a5bprilcjw6oiv7ve.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flv5a5bprilcjw6oiv7ve.jpg" alt="Diagram of different versions for the same workflow." width="800" height="400"&gt;&lt;/a&gt;Conductor has in-built versioning capabilities to allow for workflow changes without impacting existing runs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key features for durable execution
&lt;/h2&gt;

&lt;p&gt;In summary, Conductor bolsters your application durability with these key features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Resilient Engine&lt;/strong&gt;—build atop decoupled infrastructure, created for durability, speed, and redundancy&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Elastic Capacity&lt;/strong&gt;—run &lt;a href="https://dev.to/orkes/running-a-billion-workflows-a-month-with-netflix-conductor-45fb"&gt;millions of concurrent workflows&lt;/a&gt; with minimal latency&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failure Handling&lt;/strong&gt;—get native support for rate limits, retry policies, timeouts, and more&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Introspection&lt;/strong&gt;—inspect your workflow performance for troubleshooting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Versioning&lt;/strong&gt;—safely and cleanly version your workflows with no disruption to production runs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metrics&lt;/strong&gt;—get aggregated insights into workflow performance&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Durability for any use case
&lt;/h3&gt;

&lt;p&gt;As a general-purpose orchestration engine, Conductor is versatile enough for any possible use case — compliance checks in banking and finance, media encoding in entertainment, or shipping automation in logistics. Check out our &lt;a href="https://orkes.io/customers" rel="noopener noreferrer"&gt;case studies&lt;/a&gt; to discover how organizations across industries use Conductor or the following tutorials:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/orkes/how-to-create-standup-bot-using-conductor-slack-integration-5287"&gt;How to Create Standup Bot Using Conductor-Slack Integration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/orkes/automating-wildcard-certificate-management-across-multiple-kubernetes-clusters-with-orkes-conductor-21mh"&gt;Automating Wildcard Certificate Management Across Multiple Kubernetes Clusters with Orkes Conductor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/orkes/upgrade-eks-clusters-across-multiple-versions-in-less-than-a-day-using-automated-workflows-2nj0"&gt;Upgrade EKS Clusters across Multiple Versions in Less Than A Day - using Automated Workflows&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Orkes Cloud is a fully managed and hosted Conductor service that can scale seamlessly according to your needs. When you use Conductor via Orkes Cloud, your engineers don’t need to worry about set-up, tuning, patching, and managing high-performance Conductor clusters. Try it out with our free &lt;a href="https://developer.orkescloud.com/?utm_campaign=durable-execution-blog-2&amp;amp;utm_source=devto-blog&amp;amp;utm_medium=web" rel="noopener noreferrer"&gt;Developer Playground&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>durableexecution</category>
      <category>statemanagement</category>
      <category>distributedsystems</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
