How can I orchestrate multiple semantic skills with chain-of-thought planning(Azure AI Search as DataSource) #11462
Replies: 3 comments 1 reply
-
This is my implementation of RAG using Semantic Kernel and samples. I let llm first retrieve the question, then plan, view the samples, examine the code implementation of Semantic Kernel, and finally answer the question. Is it very effective? Based on the analysis of the Semantic Kernel architecture and functionality, here are the answers to your questions: 1. Recommended Method for Structuring Semantic Skills and Loading Them into the KernelIn the context of Chain-of-Thought (CoT) reasoning, the following method is recommended for structuring semantic skills:
# Create and register your domain plugins
nsp_plugin = kernel.add_plugin(NSPPlugin(search_endpoint, admin_key, embedding_model), "NSP")
capacity_plugin = kernel.add_plugin(CapacityPlugin(search_endpoint, admin_key, embedding_model), "Capacity")
property_plugin = kernel.add_plugin(PropertyPlugin(search_endpoint, admin_key, embedding_model), "Property") 2. Best Approach to Designing the Chain-of-Thought PlannerThe best approach to designing a Chain-of-Thought planner in Semantic Kernel to dynamically decide which skills to invoke:
from semantic_kernel.planners import FunctionCallingStepwisePlanner, FunctionCallingStepwisePlannerOptions
# 1. Create custom planner configuration
planner_options = FunctionCallingStepwisePlannerOptions(
get_initial_plan=lambda: custom_plan_yaml,
get_step_prompt=lambda: custom_step_prompt,
max_iterations=10,
max_completion_tokens=2000
)
# 2. Instantiate the planner
stepwise_planner = FunctionCallingStepwisePlanner(
service_id="chat-completion-service",
options=planner_options
)
# 3. Use the planner to handle user queries
result = await stepwise_planner.invoke(
kernel=kernel,
question=composite_prompt, # Composite prompt containing history and current query
arguments=arguments
) 3. Best Practices for Aggregating Outputs from Multiple SkillsBest practices for aggregating outputs from multiple skills and synthesizing a coherent final answer using Azure OpenAI Chat Completion service:
# 1. Execute the planner to get the Chain-of-Thought result
planner_result = await stepwise_planner.invoke(kernel, user_query)
# 2. Extract information from the result (already includes all skill results)
chat_history = planner_result.chat_history
# 3. Build the final synthesis prompt
final_prompt = f"""
Based on the following skill execution results, generate a comprehensive and helpful response:
Conversation History:
{chat_history}
The final answer should:
1. Integrate all relevant information
2. Respond in the tone of a sales assistant
3. Provide specific, actionable advice
"""
# 4. Call the model for final synthesis
final_response = await chat_completion.complete(final_prompt) Overall Architecture RecommendationThe following high-level architecture is recommended for implementing your conversational sales assistant:
This architecture provides a modular, scalable approach to handling complex sales advisor interactions while fully leveraging the planning and reasoning capabilities of Semantic Kernel. |
Beta Was this translation helpful? Give feedback.
-
I'll help you set up a conversational sales assistant using Semantic Kernel with multiple semantic skills backed by Azure Cognitive Search. Let me explore the best approach for your architecture. Search files... Search files... Search files... Search files... 1. Setting Up Semantic Skills with Azure Cognitive SearchEach semantic skill will be implemented as a plugin that wraps an Azure Cognitive Search index. Here's a recommended structure: import asyncio
from semantic_kernel import Kernel
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion, AzureTextEmbedding
from semantic_kernel.connectors.memory.azure_cognitive_search import AzureCognitiveSearchMemoryStore
from semantic_kernel.memory import SemanticTextMemory
from semantic_kernel.core_plugins import TextMemoryPlugin
# Initialize Kernel with Azure OpenAI services
kernel = Kernel()
kernel.add_service(
AzureChatCompletion(
service_id="chat",
deployment_name="your-gpt-deployment",
endpoint="your-azure-endpoint",
api_key="your-azure-api-key"
)
)
kernel.add_service(
AzureTextEmbedding(
service_id="embedding",
deployment_name="your-embedding-deployment",
endpoint="your-azure-endpoint",
api_key="your-azure-api-key"
)
)
# Create memory stores for each domain (NSP, Capacity, Property)
async def setup_memory_stores():
# Network Service Provider memory
nsp_memory_store = await AzureCognitiveSearchMemoryStore(
vector_size=1536, # Size depends on your embedding model
search_endpoint="your-search-endpoint",
admin_key="your-search-api-key"
).acreate()
nsp_memory = SemanticTextMemory(storage=nsp_memory_store)
# Capacity memory
capacity_memory_store = await AzureCognitiveSearchMemoryStore(
vector_size=1536,
search_endpoint="your-search-endpoint",
admin_key="your-search-api-key"
).acreate()
capacity_memory = SemanticTextMemory(storage=capacity_memory_store)
# Property memory
property_memory_store = await AzureCognitiveSearchMemoryStore(
vector_size=1536,
search_endpoint="your-search-endpoint",
admin_key="your-search-api-key"
).acreate()
property_memory = SemanticTextMemory(storage=property_memory_store)
return nsp_memory, capacity_memory, property_memory 2. Implementing Domain-Specific SkillsCreate each semantic skill as a plugin that wraps a specific search index: class NSPSkill:
def __init__(self, memory: SemanticTextMemory, collection_name: str = "nsp"):
self.memory = memory
self.collection_name = collection_name
@kernel_function(
description="Searches for information about network service providers",
name="search_nsp"
)
async def search_nsp(self, query: str, relevance: float = 0.7, limit: int = 5) -> str:
results = await self.memory.search(
collection=self.collection_name,
query=query,
limit=limit,
min_relevance_score=relevance
)
# Format results into a coherent response
if not results:
return "No information found about network service providers for this query."
response = "Here's information about network service providers:\n\n"
for match, score in results:
response += f"• {match.text} (relevance: {score:.2f})\n"
return response
# Similarly create CapacitySkill and PropertySkill classes 3. Composite Prompt ConstructionCreate a function to build the composite prompt from instructions, tool descriptions, and conversation history: async def build_composite_prompt(kernel: Kernel, user_query: str, conversation_history: list):
# System instructions that describe the assistant's role
system_instructions = """
You are a sales assistant specialized in telecommunications services.
You have access to several tools that can search for information:
- NSP tool: Searches for network service provider information
- Capacity tool: Searches for capacity and bandwidth information
- Property tool: Searches for property details and locations
Analyze each user query carefully. Consider which tools are needed to provide a complete response.
Always use a step-by-step approach to determine the most relevant tools to use based on the query content.
"""
# Format conversation history
formatted_history = ""
for message in conversation_history:
role = "User" if message["role"] == "user" else "Assistant"
formatted_history += f"{role}: {message['content']}\n"
# Create the composite prompt
composite_prompt = f"""
{system_instructions}
### Conversation History:
{formatted_history}
### Current User Query:
{user_query}
### Think step by step:
1. What information is the user looking for?
2. Which tools would be most relevant to answer this query?
3. What specific aspects of the query should I search for with each tool?
"""
return composite_prompt 4. Chain-of-Thought PlannerImplement the CoT planner that determines which skills to invoke: from semantic_kernel.planners.function_calling_stepwise_planner import FunctionCallingStepwisePlanner, FunctionCallingStepwisePlannerOptions
async def create_cot_planner(kernel: Kernel):
# Configure options for the planner
options = FunctionCallingStepwisePlannerOptions()
options.max_iterations = 15
options.max_completion_tokens = 2000
# Create the planner
planner = FunctionCallingStepwisePlanner(service_id="chat", options=options)
return planner
async def execute_cot_plan(kernel: Kernel, planner, user_query: str, conversation_history: list):
# Register all semantic skills to the kernel
nsp_memory, capacity_memory, property_memory = await setup_memory_stores()
# Register the semantic skills as plugins
kernel.add_plugin(NSPSkill(nsp_memory), "NSPSkill")
kernel.add_plugin(CapacitySkill(capacity_memory), "CapacitySkill")
kernel.add_plugin(PropertySkill(property_memory), "PropertySkill")
# Create arguments with conversation history
arguments = {"history": conversation_history, "input": user_query}
# Execute the plan
plan_result = await planner.invoke(kernel=kernel, question=user_query, arguments=arguments)
return plan_result 5. Final SynthesisImplement the final answer synthesis: async def synthesize_final_answer(kernel: Kernel, plan_result, user_query: str):
# Extract relevant information from plan execution
skill_outputs = plan_result.skill_outputs
# Prepare a prompt for final synthesis
synthesis_prompt = f"""
The user asked: "{user_query}"
Based on the information retrieved from various sources:
{skill_outputs}
Please synthesize a comprehensive, coherent answer that addresses the user's query.
The answer should be conversational, helpful, and concise.
"""
# Use the chat service to generate the final response
chat_service = kernel.get_service("chat")
chat_history = ChatHistory()
chat_history.add_system_message("You are a telecommunications sales assistant. Synthesize a comprehensive answer based on the information provided.")
chat_history.add_user_message(synthesis_prompt)
response = await chat_service.complete_chat(chat_history)
return response.content 6. Complete Workflow IntegrationNow, put everything together: async def handle_user_query(kernel: Kernel, user_query: str, conversation_history: list):
# 1. Create the CoT planner
planner = await create_cot_planner(kernel)
# 2. Execute the plan to determine and call relevant skills
plan_result = await execute_cot_plan(kernel, planner, user_query, conversation_history)
# 3. Synthesize the final answer from all skill outputs
final_answer = await synthesize_final_answer(kernel, plan_result, user_query)
# 4. Update conversation history
conversation_history.append({"role": "user", "content": user_query})
conversation_history.append({"role": "assistant", "content": final_answer})
return final_answer, conversation_history Best Practices
This architecture leverages Semantic Kernel's ability to seamlessly integrate Azure Cognitive Search indices as searchable knowledge bases and provides a structured approach to dynamically select and combine information from multiple sources based on the user's query. |
Beta Was this translation helpful? Give feedback.
-
Tagging @alliscode |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
I’m working on a project where I need to build a conversational sales assistant using Semantic Kernel. My goal is to integrate multiple semantic skills—each wrapping an Azure Cognitive Search index (for example, one for network service providers, another for capacity-related queries, and a third for property details).
The high-level workflow I’m aiming for is as follows:
Composite Prompt Construction:
I want to merge a predefined set of instructions, tool descriptions, and conversation history (e.g., from Cosmos DB), along with the current user query, into a single composite prompt.
Chain-of-Thought Planner:
I’d like to use the Azure OpenAI chat completion service to generate a chain-of-thought (CoT) reasoning on the composite prompt. The CoT should decide which semantic skills to invoke based on the query’s requirements.
Semantic Skills Execution:
Each semantic skill is implemented as a function (or plugin) for a specific search index (e.g., NSP, Capacity, Property) and registered into the Semantic Kernel instance so that they’re callable via SK function invocation.
Final Synthesis:
After executing the selected skills, I plan to aggregate their outputs and send the combined result back to the Azure OpenAI service for the final answer synthesis.
Question
What is the recommended way to structure and load these semantic skills into the kernel so that they are easily invoked based on the CoT reasoning?
How can I best design the chain-of-thought planner within Semantic Kernel to decide dynamically which skills to invoke?
Are there any best practices for aggregating outputs from multiple skills and synthesizing a coherent final answer via the Azure OpenAI chat completion service?
Beta Was this translation helpful? Give feedback.
All reactions