Search for answers or browse our knowledge base.
GenAI Agent Building Guide
0 out of 5 stars
5 Stars | 0% | |
4 Stars | 0% | |
3 Stars | 0% | |
2 Stars | 0% | |
1 Stars | 0% |
Introduction
GenAI Agents (hereafter simply Agents) are Services which combine application logic with the use of a large language model (LLM), either directly or via other resources such as Semantic Indexes. When it comes to their basic implementation including issues such as state management, Agents are just standard services. However, the use of LLMs and the nature of the functionality they typically provide, do present some unique issues. That is what we will be focusing on in this document.
Related Documentation
When it comes to leveraging an LLM you may be interested in the SubmitPrompt, AnswerQuestion, and GenAIFlow activity patterns in the Visual Event Handler Guide. For practice adding GenAI functionality to your services see the GenAI Builder Tutorial.
Conversations
LLM interactions are stateless. This means that for every request, the LLM only has access to its own “knowledge” and the information in the current request. If you want the LLM to know about previous requests and its responses to them, this information must be presented as part of the current request. Doing this is the role of a conversation.
The word “conversation” gets used in a variety of contexts when talking about GenAI applications. This isn’t surprising given that LLMs appear to “converse” with users and it is a convenient word to describe many application behaviors. However, in the Vantiq platform the term has a very specific meaning and anytime you see it in relation to Vantiq Agents and GenAI Applications, this is what we mean.
A conversation consists of an ordered sequence of messages which capture the history of an interaction between an Agent and an LLM. The messages in a conversation have a type and associated content. A message’s type tells the LLM how to interpret the content and must be one of the following:
- system – Instructions to the LLM about how to interpret the conversation or “behave” in general. Typically there is only a single system message which is added automatically by the application. Vantiq supports including a system message as part of an LLM definition to ensure that it is always present.
- human – Content provided by the user/client.
- ai – Content generated by the LLM in response to a request. Maybe a direct response or instructions for some further action (e.g. the invocation of an LLM “tool”).
- tool – Content produced by the execution of an LLM tool.
The structure of a message’s content depends on its type. See ChatMessage for more details.
Transient Conversations
Conversations are managed using the Conversation Memory service which supports creation and manipulation of conversations. The conversations managed by this service can be referenced when sending an LLM request via the built-in submitPrompt and answerQuestion procedures or when invoking a GenAI procedure. Doing so causes the conversation to be automatically updated based on the underlying LLM interactions. On the client side, there is the Conversation Widget to facilitate the user’s participation in a conversation (use the conversationId
property to refer to a specific conversation)
As its name implies, the resulting conversation state is stored in memory. This means that it has a limited lifetime and can be subject to loss in certain failure cases. We refer to these as “transient” conversations. Transient conversations are suitable for interactions that will last minutes to maybe an hour or so and which do not need to be saved for any reason (such as auditing).
Persistent Conversations
For cases where a conversation must be available over much longer time frames (days or even weeks) or when it needs to be recorded for some reason, conversations can be persisted as part of a collaboration managed by the Agent. This can be accomplished in a variety of ways. Using the SubmitPrompt, AnswerQuestion, or GenAIFlow activity patterns in a visual event handler will automatically bind a conversation to the current collaboration instance (or create one as needed). The Agent may also choose the manage its collaborations more explicitly. If the conversation is associated with some application “entity”, then the entity role procedures are a natural fit. Alternatively, the Agent can directly manage one or more persistent conversations using the collaboration management procedures.
In either case, once bound to a collaboration instance, persistent conversations are automatically saved along with their associated collaboration instance and loaded into memory when the collaboration instance is retrieved. Once loaded, they can be accessed through the Conversation Memory service as described above. This is all done using standard partitioned state and fully supports service replication for stricter reliability guarantees.
When using persistent conversations, clients should use
Client.setCollaborationContext
to bind the client to the active collaboration instance. This will trigger binding any conversation widgets to the appropriate conversation (including support for use of named conversations).
Agent to Human Interaction
The use of an LLM can make Agents very powerful, allowing them to make decisions much more dynamically instead of relying solely on predetermined pathways. To help mitigate against the Agent doing something not just unexpected, but inappropriate, it can be necessary to keep the “human in the loop”, requiring that it obtain permission prior to acting. This requires that the Agent be able to initiate an interaction with the user. This mechanism can also be used for other purposes, such as allowing the Agent to gather additional information it might need to complete its task. Vantiq supports two ways to accomplish this, direct communication and using notifications.
Direct Communication
The direct communication model requires that the agent and the user be actively engaged in a conversation via the Conversation Widget. Whenever the conversation widget loads a conversation (either directly or via an enclosing collaboration instance), it will register a “callback” with the Callback service. The id of the current conversation is used as the callbackId. This allows the Agent to contact the user using the io.vantiq.Callback.invoke
procedure like this:
var userPrompt = "I'm about to withdraw money from your account, is that OK?"
var userResponse = io.vantiq.Callback.invoke(conversationId, userPrompt, 5 minutes)
... do something with the response ...
The data sent will be displayed to the user in the conversation widget and then the user’s response will be returned as the result of the invocation (unless the user takes longer than 5 minutes to respond). The advantage of this approach is that the Agent’s communication will appear to the user where they are likely already engaged. This avoids the need to pop up additional UI elements or distract them from the current task. The disadvantage is that it won’t work if the user isn’t actively using a client with a conversation widget.
Notification
If the user cannot be reached directly, then the Agent must instead use a notification based approach to contact them. The Notify activity pattern already provides robust support for sending a notification to one or more users and then managing their responses. The primary limitation is that it works in the context of a visual event handler, which typically operate asynchronously and do not provide a means to produce a result. Rather than invent an alternate notification mechanism, we instead chose to address this limitation.
To do this we added the ability to “invoke” a service event handler. The VAIL PUBLISH
statement can obviously be used to trigger a handler, but it assumes a fully asynchronous execution model, so it cannot “wait” for a reply. Therefore, we have added the Event.request
procedure to the built-in event processing service. This procedure triggers the handler for a specified service event. It must be called from a service procedure belonging to the same service as the target event type. The behavior of the handler is unrestricted, but it is assumed that at some point it will provide a response using the Reply activity pattern. The net result is a request/response execution model which uses an event handler as its implementation.
For example, suppose we have the following event handler:
We can “invoke” it from the Agent using code like this:
var event = {collaborationId: collaborationId}
var userResponse = Event.request("NotifySessionEVT", event, 5 minutes)
... do something with the response ...
When run, the target user will receive the notification and be presented with the associated client. Once the user provided the requested input, the result from the client would be sent back to the Agent as the return from Event.request
and processing would continue from that point. The advantage of this approach is that it allows the agent to contact users on an “interrupt” basis, not just when they are actively in a conversation. The disadvantage is that the Vantiq Notify pattern is limited to use on a mobile device. So this approach isn’t appropriate for browser only applications.
0 out of 5 stars
5 Stars | 0% | |
4 Stars | 0% | |
3 Stars | 0% | |
2 Stars | 0% | |
1 Stars | 0% |
-
Getting Started
-
- Advanced Collaboration Tutorial
- Analytics Tutorial
- App Component Tutorial
- Application Deployment Tutorial
- Assembly Tutorial
- Autopsy Debugger Tutorial
- Catalogs Tutorial
- Client Builder Tutorial
- Client Component Tutorial
- Collaboration Tutorial
- Conversation Widget Tutorial
- Floor Plan
- GenAI Builder Tutorial
- Source Tutorial
- Stateful Services
- System Modeler Tutorial
- Testing the Debugging Tutorial
- Testing the Introductory Tutorial
- Testing the Source Tutorial
- User and Namespace Administration Tutorial
- Show Remaining Articles ( 5 ) Collapse Articles
-
Product Documentation
-
-
-
- Accessing Documents
- Automatic Document Caching
- Client Resources
- Client Startup
- Control Widgets in the "Views" Portion of Client Builder
- Controllers
- Creating A Client
- Data Objects
- Data Stream Widgets in the “Views” Portion of Client Builder
- Data Streams
- Debugging
- Field Validation
- Introduction
- Launching Clients from a browser
- Layout Widgets in the “Views” Portion of Client Builder
- Localizing Clients
- Navigation Between Pages
- Offline Operation
- On Start Events
- Public Clients
- Server Requests
- Terminating The Client
- The Client Builder Concepts
- The Client Builder's Canvas Section
- The Client Builder's Control Dock
- The Client Builder's Palette Area
- The Client Builder's Slideout Section
- Uploading data to the Server
- Show Remaining Articles ( 13 ) Collapse Articles
-
- ‘On Assets Loaded’ Event
- ‘On Change’ Event
- ‘On Click’ Event
- ‘On Client Start’ Event
- ‘On Context Menu’
- ‘On Data Arrived’ Event
- ‘On End’ Event
- ‘On End’ Event
- ‘On Network Status Changed’ Event
- ‘On Start’ Event
- ‘On Start’ Event
- ‘On Swipe’
- ‘On Validation’ Event
- abort()
- AccordionLayout
- addAPIRequestFor(responseObjectProperty:string):boolean
- addEventHandler()
- addRequestFor(widgetName:string):boolean
- addRequestForDataURL():void
- addRequestsForClient():boolean
- addRequestsForCurrentPage():boolean
- addRequestsForPage(pageName:string):boolean
- adjustPopupSizeAndPosition()
- AudioRecorder
- Basic Information
- cancelSpeaking()
- children
- clearInterval()
- clearTimeout()
- clearUpload()
- clearValidationErrors()
- clone()
- closeIcon:string
- closeIcon:string
- closePopup()
- confirmCustom()
- confirmCustomEx()
- copyMatchingData(obj:any):void
- createClientEventDataStream()
- createDataChangedDataStream()
- createOutboundServiceEventDataStream()
- createPagedQueryDataStream()
- createPublishEventDataStream()
- createResourceEventDataStream()
- createResponseObject()
- createSourceEventDataStream()
- createTimedQueryDataStream()
- data
- data
- DataObject
- DataStream
- defaultSubmit()
- deleteAll()
- deleteOne()
- deleteOne()
- documentGroupName:string
- documentName:string
- errorDialog()
- execute()
- execute()
- executePublic()
- executePublic()
- executeStreamed()
- executeStreamed()
- executeStreamedPublic()
- executeStreamedPublic()
- fontColor:string
- fontFace:string
- fontSize:number
- fontStyle:string
- fontWeight:string
- formatMsg()
- generateUUID()
- getCollaborationContext()
- getCurrentPage()
- getCurrentPopup()
- getDataStreamByName()
- getDataStreamByUUID()
- getDeviceId()
- getDeviceName()
- getDocumentAssetLabelList()
- getDocumentAssetList()
- getDocumentUrl()
- getGroupNames()
- getLocation()
- getName()
- getProfileNames()
- getRequestParameters()
- getStateObject()
- getUsername()
- getUserRecord()
- getWidget()
- goToPage()
- hideCancelButton()
- Http
- infoDialog()
- initializePropertyToDefaultValue(propertyName:string):void
- initializeToDefaultValues():void
- insert()
- insert()
- instance
- isExpanded:Boolean
- isNetworkActive
- isPaused:boolean
- isPublic
- localeCountryCode
- localeLanguageCode
- localeVariantCode
- logout()
- markupImage()
- maxDurationInSeconds:number
- maxSizeInK:number
- modifyClientEvent()
- modifyDataChanged()
- modifyPagedQuery()
- modifyPublishEvent()
- modifyResourceEvent()
- modifyServiceEvent()
- modifySourceEvent()
- modifyTimedQuery()
- name:string
- navBarBackgroundColor
- navBarForegroundColor
- navBarIcon
- navBarIconHeight
- navBarIconWidth
- navBarShowControls
- navBarTitle
- navBarTitleFontFamily
- navBarTitleFontSize
- navBarTitleFontWeight
- openIcon:string
- optional:boolean
- overrideLocale
- Page
- patch()
- placeholder:string
- playAudio()
- playVideo()
- popupPage()
- publish()
- publish()
- publishToServiceEvent()
- query()
- recordAudio()
- recordVideo()
- remove():void
- responseObject:any
- restart():void
- returnToCallingPage()
- scanBarcode()
- select()
- select()
- selectOne()
- selectOne()
- sendClientEvent()
- sendLocation()
- setInterval()
- setResponseObject(responseObject:any=null, responseResource:string=null, responseResourceId:string=null):void
- setResponseObjectValues(submitValue:number, responseObjectValues:any, responseResource:string=null, responseResourceId:string=null):void
- setTimeout()
- setVantiqHeaders()
- setVantiqUrlForResource()
- setVantiqUrlForSystemResource()
- showDocument()
- showHttpErrors()
- showMap()
- speakText()
- start(completedFunction:Function):boolean
- startBLEScan()
- stopGeofencing()
- takePhoto()
- terminate()
- terminateWithDialog()
- title:string
- titleForegroundColor:string
- update()
- update()
- uploadDataURL()
- uploadDocument()
- Uploader
- upsert()
- upsert()
- uuid:string
- validate()
- validate()
- Widget Hierarchy
- Show Remaining Articles ( 172 ) Collapse Articles
-
-
-
- Accessing Namespaces in the Organization
- Active Resource Control Center
- Adding a New User to an Organization
- Adding a New User to the Application Namespace
- Administrators' Concepts and Terminology
- Authorizing Users to Access the Application
- Creating a Developer Namespace for the Organization Administrator
- Creating a New Application Namespace
- Creating Resources for New Namespaces
- Custom User Invites
- Deploying the GenAI Flow Service Connector
- Developer Tasks
- Handling Administrators Leaving
- Related Configuration
- Removing Namespace Administrators
- Self-Administration Tasks
- System Administration Tasks
- Viewing Lists of Users
- Show Remaining Articles ( 3 ) Collapse Articles
-
- Deploy Results Tab
- Deploying the same application to different environments
- Deployment
- Deployment Tool - Introduction
- Environment
- Environment Tab
- Node
- Project Partitions
- Redeploy On A Failed Node
- Reliable Deployment
- Settings Tab
- The Graph View
- The Tree View
- Undeploy
- Update Partitions
- Verify Application After Deployment
- Show Remaining Articles ( 1 ) Collapse Articles
-
- CheckedInsert/CheckedUpsert Command
- Command Line Options
- Delete Command
- Execute Command
- Export Command
- Find Command
- Help Command
- Import Command
- Insert Command
- Installation - Prerequisites
- Installation - Profile
- List Command
- Load Command
- Recommend Command
- Run Command
- Select Command
- Stop Command
- The Vantiq Command Line Interface (CLI) - Overview
- Upsert Command
- Show Remaining Articles ( 4 ) Collapse Articles
-
- App Execution Dashboard
- App With Split Dashboard
- Dashboard Navigation Bar
- Deprecated Dashboards
- Event Processing Dashboard
- General Dashboard Behavior
- Getting Started with Grafana
- Grafana Usage
- Monitoring Namespaces with Grafana
- Most Commonly Used Dashboards
- Namespace Monitoring Dashboards
- Organization Level Behavior
- Procedure and Rule Execution Dashboards
- Profiling Dashboards
- Reliable Event Dashboard
- Resource Usage Dashboard
- Service Execution Dashboard
- Service Handler Dashboard
- Source Activity Dashboard
- Storage Manager Dashboard
- Tensorflow Model Dashboard
- Type Storage Dashboard
- Show Remaining Articles ( 7 ) Collapse Articles
-
- Access to a Kubernetes Cluster
- Creating a K8s Cluster
- Delayed Processing
- Deploying K8s Installations to a Kubernetes Cluster
- Deploying the K8s Worker
- External Lifecycle Management Guide - Overview
- K8s Worker
- Kubernetes Components of a K8s Installation
- Kubernetes Namespaces
- Loading Images into a Kubernetes Cluster
- Managing K8s Installations
- Other Configuration Options
- System View
- Use of the self Cluster
- Using a Kubernetes Cluster
- Using Templates to Deploy the K8s Worker
- Vantiq Namespaces
- Verify Installation
- Show Remaining Articles ( 3 ) Collapse Articles
-
- Changing the System Password
- Creating a GenAIFlowService Service Connector
- Creating a New Organization and Namespace
- Deployment Methods
- Docker Deployment
- Edge Installation Management
- Edge Vision Server
- Executable JAR Deployment
- MongoDB
- Requirements
- Running the Vantiq Executable
- Setting the default LLMs API key
- Setting Up Vantiq Edge
- Vantiq Edge Reference Guide - Overview
- Vantiq Edge Self Node
- Windows bat file
- Show Remaining Articles ( 1 ) Collapse Articles
-
- Additional Buffer Semantics
- Applicability
- auditFrequency Quota
- Background
- Default Quotas
- Detailed Credit Quotas
- errorBreaker Quota
- errorReportingFrequency Quota
- Execution Credit Quota
- Execution Credit Quota - Diagnostics
- Execution Credit Quota - Mitigation
- Execution Rate Quota
- Execution Rate Quota - Diagnostics
- Execution Rate Quota - Mitigations
- executionTime Quota
- k8sResources Quota
- Quota Interactions
- receiveMessage Quota
- receiveMessage Quota - Diagnostics
- receiveMessage Quota - Mitigation
- reservedGroups Quota
- stackDepth Quota
- Stream Quota
- Terminology
- Workload Management
- Workload Management Conceptual Model
- Show Remaining Articles ( 11 ) Collapse Articles
-
-
-
- Android Post-Installation Instructions
- Authentication Functions
- Database Functions
- Installation Instructions
- iOS Post-Installation Instructions
- Miscellaneous Functions
- Prerequisites
- Procedure Execution Functions
- Publishing Functions
- Sample iOS AppDelegate.m File
- User Creation Functions
- Vantiq Functionality for React Native Apps
-
-
- Accumulate State
- Analytics
- Answer Question
- App Activity Tasks
- App Builder Guide - Introduction
- App Builder Overview
- Assign
- Build and Predict Path
- Cached Enrich
- Chat
- Close Collaboration
- Collaborations in Apps
- Compute Statistics
- Convert Coordinates
- Creating an App
- DBScan
- Delay
- Dependency Management
- Dwell
- Enrich
- Error Handling
- Escalate
- EscalateState
- Establish Collaboration
- Event Redelivery
- Event Stream
- Filter
- GenAI Flow
- Get Collaboration
- Interpret Conversational Language
- Join
- K-Means Cluster
- Limit
- Linear Regression
- Log Stream
- Loop While
- Merge
- Notify
- Optional Imports
- Polynomial Fitter
- Predict Paths By Age
- Procedure
- Process Intent
- PublishToService
- PublishToSource
- PublishToTopic
- Rate
- Recommend
- RecordEvent
- Reliable Apps
- Run TensorFlow Model On Document
- Run TensorFlow Model On Image
- Run TensorFlow Model On Tensors
- Sample
- SaveToType
- Split By Group
- Submit Prompt
- Threshold
- Time Difference
- Track
- Track Motion
- Tracking Progress
- Transformation
- Unwind
- VAIL
- VisionScript
- Window
- Within Tracking Region
- YOLO From Images
- Show Remaining Articles ( 54 ) Collapse Articles
-
-
-
- Broker Service
- Catalog Operations
- Catalog Procedures
- Connect to Catalog
- Create Entry
- Create Entry
- Custom Operations
- Disconnect from Catalog
- Host Catalog
- Integrating Applications With the Catalog
- Managing Catalog
- Managing Event Types
- Publisher Service
- Register
- Remove Entry
- Repair Catalog
- Resolve
- Subscriber Service
- Unhost Catalog
- Unregister
- Utilities
- Show Remaining Articles ( 6 ) Collapse Articles
-
- AMQP Reference Guide
- CHATBOT Reference Guide
- Email Reference Guide
- Enterprise Connectors Reference Guide
- External Source Reference Guide
- Google Cloud Pub/Sub Reference Guide
- KAFKA Reference Guide
- MQTT Reference Guide
- Push Notification Reference Guide
- Remote Reference Guide
- SMS Reference Guide
- Video Reference Guide
-
-
- Advanced Use Cases
- Data Manipulation
- Defining Types
- Discovery from External Data Store
- Error Handling
- Installation and Use
- Native Language Implementation
- Restricting Capabilities
- Service Connectors
- Storage Manager Assembly Contents
- Storage Manager Service API
- Storage Manager Transactions
- Storage Managers - Introduction
- Transaction Support
-
-
-
- App Pane
- Autopsies
- Defining a Run Policy
- Defining a Test Suite - Properties
- Defining an Input
- Defining an Output
- Error Pane
- Integration Tests
- Populate Testing Namespace With Data
- Procedure Pane
- Rule Pane
- Running a Test in the IDE
- Running a Test through the REST Interface
- Source Mocking For Tests
- Unit Tests
- Vantiq Testing Reference Guide - Introduction
- Show Remaining Articles ( 1 ) Collapse Articles
-
-
-
- Articles coming soon
-
- AWS
- Azure OpenAI
- Bedrock
- Configuration
- Function Authorizer
- Gemini
- LLM Playground
- Main Chatting Area
- Navigation Panel
- NVIDIA NIM
- OpenAI
- SageMaker
- Settings Panel
- Testing Semantic Index
- Tool Authorizer
- Tools
- Show Remaining Articles ( 1 ) Collapse Articles
-
-
-
-
Articles
-
- Build Your Own Tools
- Cache Services
- Camel Assemblies
- Client to Component Conversaion
- Discovering Current Session Information
- Dynamic Client Content
- Dynamic Map View Widget
- Filters
- GenAI Builder Tools
- Generative AI Functions (Tools)
- Generative AI with Collaborations
- How To Video Shorts: Client Layouts
- How To Video Shorts: AI Functions
- How To Video Shorts: Analytics and ComputeStatistics
- How To Video Shorts: Calling Procedures by Properties
- How To Video Shorts: Client CSS
- How To Video Shorts: Invite Other Users to Your Namespace
- How To Video Shorts: SplitByGroup
- How To Video Shorts: The Vantiq API
- How To Video Shorts: The Vantiq IDE
- How To Video Shorts: The Vantiq Version Control System
- How To Video Shorts: Using Generative AI in Applications
- How-To Video Shorts: Managing AI Conversations
- How-To Videos: AI Design Model Assistant
- How-To Videos: AI Documentation Search
- Managing AI Conversation
- Production Applications Best Practices
- Public Clients
- Security Secrets
- Service Event Handlers
- Sharing Resources
- Streaming AI Output
- Transformations
- Using the Video Sources
- Web-Based APIs
- Show Remaining Articles ( 20 ) Collapse Articles