-
Notifications
You must be signed in to change notification settings - Fork 3
Examples: text to sql, multi consensus #50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
046d250
Create 13_templated_instructions.py
3dc3793
rename to example 14
1da3335
Create 15_text_to_sql.py
77a2461
Create 16_multi_model_consensus.py
a7556a7
Update 15_text_to_sql.py
d11741d
Update 16_multi_model_consensus.py
491d592
Update README.md
2f82445
Create 17_multi_model_consensus_with_tools.py
9a400f0
Update 17_multi_model_consensus_with_tools.py
4865804
Update README.md
b410381
remove additional fields "*, model:" from agent
6328cf5
Merge branch 'main' into pierre-examples-text-to-sql-multi-consensus
guillaq c60577d
fix: linter issues
guillaq b7cafb6
Merge remote-tracking branch 'origin/main' into pierre-examples-text-…
guillaq 81d03ee
Merge branch 'main' into pierre-examples-text-to-sql-multi-consensus
e05ed01
chore: remove templated instructions example
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,162 @@ | ||
| """ | ||
| This example demonstrates how to convert natural language questions to SQL queries. | ||
| It uses a sample e-commerce database schema and shows how to generate safe and efficient SQL queries. | ||
|
|
||
| Like example 14 (templated instructions), this example shows how to use variables in the agent's | ||
| instructions. The template variables ({{ db_schema }} and {{ question }}) are automatically populated | ||
| from the input model's fields, allowing the instructions to adapt based on the input. | ||
|
|
||
| The example includes: | ||
| 1. Simple SELECT query with conditions | ||
| 2. JOIN query with aggregation | ||
| 3. Complex query with multiple JOINs, grouping, and ordering | ||
| """ | ||
|
|
||
| import asyncio | ||
|
|
||
| from pydantic import BaseModel, Field | ||
|
|
||
| import workflowai | ||
| from workflowai import Model, Run | ||
|
|
||
|
|
||
| class SQLGenerationInput(BaseModel): | ||
| """Input model for the SQL generation agent.""" | ||
|
|
||
| db_schema: str = Field( | ||
| description="The complete SQL schema with CREATE TABLE statements", | ||
| ) | ||
| question: str = Field( | ||
| description="The natural language question to convert to SQL", | ||
| ) | ||
|
|
||
|
|
||
| class SQLGenerationOutput(BaseModel): | ||
| """Output model containing the generated SQL query and explanation.""" | ||
|
|
||
| sql_query: str = Field( | ||
| description="The generated SQL query", | ||
| ) | ||
| explanation: str = Field( | ||
| description="Explanation of what the query does and why certain choices were made", | ||
| ) | ||
| tables_used: list[str] = Field( | ||
| description="List of tables referenced in the query", | ||
| ) | ||
|
|
||
|
|
||
| @workflowai.agent( | ||
| id="text-to-sql", | ||
| model=Model.CLAUDE_3_5_SONNET_LATEST, | ||
| ) | ||
| async def generate_sql(review_input: SQLGenerationInput) -> Run[SQLGenerationOutput]: | ||
| """ | ||
| Convert natural language questions to SQL queries based on the provided schema. | ||
|
|
||
| You are a SQL expert that converts natural language questions into safe and efficient SQL queries. | ||
| The queries should be compatible with standard SQL databases. | ||
|
|
||
| Important guidelines: | ||
| 1. NEVER trust user input directly in queries to prevent SQL injection | ||
| 2. Use proper quoting and escaping for string values | ||
| 3. Use meaningful table aliases for better readability | ||
| 4. Format queries with proper indentation and line breaks | ||
| 5. Use explicit JOIN conditions (no implicit joins) | ||
| 6. Include column names in GROUP BY rather than positions | ||
|
|
||
| Schema: | ||
| {{ db_schema }} | ||
|
|
||
| Question to convert to SQL: | ||
| {{ question }} | ||
|
|
||
| Please provide: | ||
| 1. A safe and efficient SQL query | ||
| 2. An explanation of the query and any important considerations | ||
| 3. List of tables used in the query | ||
| """ | ||
| ... | ||
|
|
||
|
|
||
| async def main(): | ||
| # Example schema for an e-commerce database | ||
| schema = """ | ||
| CREATE TABLE customers ( | ||
| id INTEGER PRIMARY KEY, | ||
| name TEXT NOT NULL, | ||
| email TEXT UNIQUE NOT NULL, | ||
| created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP | ||
| ); | ||
|
|
||
| CREATE TABLE products ( | ||
| id INTEGER PRIMARY KEY, | ||
| name TEXT NOT NULL, | ||
| description TEXT, | ||
| price DECIMAL(10,2) NOT NULL, | ||
| category TEXT NOT NULL, | ||
| stock_quantity INTEGER NOT NULL DEFAULT 0, | ||
| created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP | ||
| ); | ||
|
|
||
| CREATE TABLE orders ( | ||
| id INTEGER PRIMARY KEY, | ||
| customer_id INTEGER NOT NULL, | ||
| order_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| status TEXT NOT NULL DEFAULT 'pending', | ||
| total_amount DECIMAL(10,2) NOT NULL, | ||
| FOREIGN KEY (customer_id) REFERENCES customers(id) | ||
| ); | ||
|
|
||
| CREATE TABLE order_items ( | ||
| id INTEGER PRIMARY KEY, | ||
| order_id INTEGER NOT NULL, | ||
| product_id INTEGER NOT NULL, | ||
| quantity INTEGER NOT NULL, | ||
| unit_price DECIMAL(10,2) NOT NULL, | ||
| FOREIGN KEY (order_id) REFERENCES orders(id), | ||
| FOREIGN KEY (product_id) REFERENCES products(id) | ||
| ); | ||
| """ | ||
|
|
||
| # Example 1: Simple SELECT with conditions | ||
| print("\nExample 1: Find expensive products") | ||
| print("-" * 50) | ||
| run = await generate_sql( | ||
| SQLGenerationInput( | ||
| db_schema=schema, | ||
| question="Show me all products that cost more than $100, ordered by price descending", | ||
| ), | ||
| ) | ||
| print(run) | ||
|
|
||
| # Example 2: JOIN with aggregation | ||
| print("\nExample 2: Customer order summary") | ||
| print("-" * 50) | ||
| run = await generate_sql( | ||
| SQLGenerationInput( | ||
| db_schema=schema, | ||
| question=( | ||
| "List all customers with their total number of orders and total spend, " | ||
| "only showing customers who have made at least 2 orders" | ||
| ), | ||
| ), | ||
| ) | ||
| print(run) | ||
|
|
||
| # Example 3: Complex query | ||
| print("\nExample 3: Product category analysis") | ||
| print("-" * 50) | ||
| run = await generate_sql( | ||
| SQLGenerationInput( | ||
| db_schema=schema, | ||
| question=( | ||
| "What are the top 3 product categories by revenue in the last 30 days, " | ||
| "including the number of unique customers who bought from each category?" | ||
| ), | ||
| ), | ||
| ) | ||
| print(run) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| asyncio.run(main()) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,118 @@ | ||
| """ | ||
| This example demonstrates how to ask the same question to multiple different LLMs | ||
| and then combine their responses into a single coherent answer using another LLM. | ||
|
|
||
| The example uses three different models for answering: | ||
| - GPT-4O Mini | ||
| - Gemini 2.0 Flash | ||
| - Llama 3.3 70B | ||
|
|
||
| Then uses O3 Mini (with medium reasoning effort) to analyze and combine their responses. | ||
| """ | ||
|
|
||
| import asyncio | ||
|
|
||
| from pydantic import BaseModel, Field | ||
|
|
||
| import workflowai | ||
| from workflowai import Model, Run | ||
|
|
||
|
|
||
| class MultiModelInput(BaseModel): | ||
| """Input model containing the question to ask all models.""" | ||
|
|
||
| question: str = Field( | ||
| description="The question to ask all models", | ||
| ) | ||
| model_name: str = Field( | ||
| description="Name of the model providing the response", | ||
| ) | ||
|
|
||
|
|
||
| class ModelResponse(BaseModel): | ||
| """Response from an individual model.""" | ||
|
|
||
| model_name: str = Field(description="Name of the model that provided this response") | ||
| response: str = Field(description="The model's response to the question") | ||
|
|
||
|
|
||
| class CombinerInput(BaseModel): | ||
| """Input for the response combiner.""" | ||
|
|
||
| responses: list[ModelResponse] = Field(description="List of responses to combine") | ||
|
|
||
|
|
||
| class CombinedOutput(BaseModel): | ||
| """Final output combining responses from all models.""" | ||
|
|
||
| combined_answer: str = Field( | ||
| description="Synthesized answer combining insights from all models", | ||
| ) | ||
| explanation: str = Field( | ||
| description="Explanation of how the responses were combined and why", | ||
| ) | ||
|
|
||
|
|
||
| @workflowai.agent( | ||
| id="question-answerer", | ||
| ) | ||
| async def get_model_response(query: MultiModelInput) -> Run[ModelResponse]: | ||
| """Get response from the specified model.""" | ||
| ... | ||
|
|
||
|
|
||
| @workflowai.agent( | ||
| id="response-combiner", | ||
| model=Model.O3_MINI_2025_01_31_MEDIUM_REASONING_EFFORT, | ||
| ) | ||
| async def combine_responses(responses_input: CombinerInput) -> Run[CombinedOutput]: | ||
| """ | ||
| Analyze and combine responses from multiple models into a single coherent answer. | ||
|
|
||
| You are an expert at analyzing and synthesizing information from multiple sources. | ||
| Your task is to: | ||
| 1. Review the responses from different models | ||
| 2. Identify key insights and unique perspectives from each | ||
| 3. Create a comprehensive answer that combines the best elements | ||
| 4. Explain your synthesis process | ||
|
|
||
| Please ensure the combined answer is: | ||
| - Accurate and well-reasoned | ||
| - Incorporates unique insights from each model | ||
| - Clear and coherent | ||
| - Properly attributed when using specific insights | ||
| """ | ||
| ... | ||
|
|
||
|
|
||
| async def main(): | ||
| # Example: Scientific explanation | ||
| print("\nExample: Scientific Concept") | ||
| print("-" * 50) | ||
| question = "What is dark matter and why is it important for our understanding of the universe?" | ||
|
|
||
| # Get responses from all models | ||
| models = [ | ||
| (Model.GPT_4O_MINI_LATEST, "GPT-4O Mini"), | ||
| (Model.GEMINI_2_0_FLASH_LATEST, "Gemini 2.0 Flash"), | ||
| (Model.LLAMA_3_3_70B, "Llama 3.3 70B"), | ||
| ] | ||
|
|
||
| responses = [] | ||
| for model, model_name in models: | ||
| run = await get_model_response( | ||
| MultiModelInput( | ||
| question=question, | ||
| model_name=model_name, | ||
| ), | ||
| model=model, | ||
| ) | ||
| responses.append(run.output) | ||
|
|
||
| # Combine responses | ||
| combined = await combine_responses(CombinerInput(responses=responses)) | ||
| print(combined) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| asyncio.run(main()) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.