Skip to content
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

Ollama giving issues with multiple Tools. #1612

Open
alaap001 opened this issue Dec 19, 2024 · 7 comments
Open

Ollama giving issues with multiple Tools. #1612

alaap001 opened this issue Dec 19, 2024 · 7 comments

Comments

@alaap001
Copy link

alaap001 commented Dec 19, 2024

Hey,
Thanks for the amazing work.

I am facing issue with Ollama in multiple tools, When using OpenAIChat everything works, but when I use Ollama with Agents I get errors as shown below.

I tried Using Agent with Ollama model with 2 different tools and both gave issues.

  1. WebAgent:
    Reproducable Code:
import json
from typing import Optional
from phi.model.openai import OpenAIChat
from textwrap import dedent
from pathlib import Path
from phi.vectordb.pgvector import PgVector
from phi.tools.duckduckgo import DuckDuckGo

from phi.agent import Agent
from phi.tools.postgres import PostgresTools
from phi.storage.agent.sqlite import SqlAgentStorage
from phi.playground import Playground, serve_playground_app
from phi.knowledge.csv import CSVKnowledgeBase
from reranker import BGEFlagReranker
from phi.embedder.openai import OpenAIEmbedder
# from phi.vectordb.chroma import ChromaDb
from dotenv import load_dotenv
from phi.model.ollama import Ollama
# from phi.llm.ollama import OllamaTools

load_dotenv()

cwd = Path(__file__).parent

storage_dir = cwd.joinpath("storage")
storage_dir.mkdir(parents=True, exist_ok=True)

# Storage setup
agent_storage = SqlAgentStorage(
    table_name="mygpt_sessions",
    db_file=str(storage_dir.joinpath("mygpt.db"))
)

# Initialize reranker
reranker = BGEFlagReranker(model_name="BAAI/bge-reranker-base")

web_instructions = 'Always include sources'
finance_instructions = 'Use tables to display data'

web_agent = Agent(
    name="Web Agent",
    role="Search the web for information",
    model=Ollama(id="qwen2.5:7b"),
    tools=[DuckDuckGo()],
    instructions=[web_instructions],
    show_tool_calls=True,
    markdown=True,
)

# Create the playground app
app = Playground(agents=[web_agent]).get_app()

if __name__ == "__main__":
    serve_playground_app("reproducable:app", reload=True)

No Errors reported but in UI I don't get any output:
<tool_call> {"name": "duckduckgo_news", "arguments": {"query": "today", "max_results": 5}} </tool_call>

image

  1. SQLAgent:

This is a bigger problem

Reproducable Code:

import json
from typing import Optional
from phi.model.openai import OpenAIChat
from textwrap import dedent
from pathlib import Path
from phi.vectordb.pgvector import PgVector
from phi.tools.duckduckgo import DuckDuckGo

from phi.agent import Agent
from phi.tools.postgres import PostgresTools
from phi.storage.agent.sqlite import SqlAgentStorage
from phi.playground import Playground, serve_playground_app
from phi.knowledge.csv import CSVKnowledgeBase
from reranker import BGEFlagReranker
from phi.embedder.openai import OpenAIEmbedder
# from phi.vectordb.chroma import ChromaDb
from dotenv import load_dotenv
from phi.model.ollama import Ollama
# from phi.llm.ollama import OllamaTools

load_dotenv()

## PG Vector
db_url = "postgresql+psycopg://ai:ai@localhost:5432/ai"

cwd = Path(__file__).parent

storage_dir = cwd.joinpath("storage")
storage_dir.mkdir(parents=True, exist_ok=True)

# Storage setup
agent_storage = SqlAgentStorage(
    table_name="mygpt_sessions",
    db_file=str(storage_dir.joinpath("mygpt.db"))
)

# Initialize reranker
reranker = BGEFlagReranker(model_name="BAAI/bge-reranker-base")

def get_sql_agent() -> Agent:
    """Create an agent for database operations"""
    postgres_tools = PostgresTools(
        db_name=TARGET_DB_CONFIG["dbname"],
        user=TARGET_DB_CONFIG["user"],
        password=TARGET_DB_CONFIG["password"],
        host=TARGET_DB_CONFIG["host"],
        port=TARGET_DB_CONFIG["port"],
        run_queries=True,
        inspect_queries=True,
        summarize_tables=True,
    )

    return Agent(
        name="SQL Assistant",
        agent_id="sql_assistant",
        role="Database Expert",
        # model=OpenAIChat(id="gpt-4o-mini"),
        model=Ollama(id="qwen2.5:7b"),
        storage=agent_storage,
        show_tool_calls=True,
        tools=[postgres_tools],
        use_tools=True,
        debug_mode=True,
        markdown=True,
        description="I execute SQL queries and analyze results.",
        instructions=[
            "When handling queries:",
            "1. Execute the appropriate SQL query immediately",
            "2. Show the query and its results",
            "3. Analyze the actual data returned",
            "4. Present findings based only on the data",
            
            "Important rules:",
            "- Never suggest what queries to run",
            "- Don't ask for clarification",
            "- Always execute a query",
            "- Base analysis only on returned data",
            "- Never end with questions or suggestions",
        ],
    )

# Create the team
sqlAgent = get_sql_agent()

# sqlAgent.print_response("What are all the tables?", stream=True)

# # Create the playground app
app = Playground(agents=[sqlAgent]).get_app()

if __name__ == "__main__":
    serve_playground_app("reproducable:app", reload=True)

Error:

DEBUG    *********** Session ID: 6eadf4df-dbe5-4405-b4f7-afdf3a7c488d ***********                                                                                                                                                                       
DEBUG    Debug logs enabled                                                                                                                                                                                                                             
INFO:     Started server process [254177]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     127.0.0.1:58778 - "OPTIONS /v1/playground/status HTTP/1.1" 200 OK
INFO:     127.0.0.1:58778 - "GET /v1/playground/status HTTP/1.1" 200 OK
INFO:     127.0.0.1:58778 - "OPTIONS /v1/playground/agent/sessions/8aac5756-6221-4bee-8a67-0e08513b2205 HTTP/1.1" 200 OK
DEBUG    AgentSessionsRequest: agent_id='5625f52e-186d-4362-a500-4cbc53fd9113' user_id=None                                                                                                                                                             
INFO:     127.0.0.1:58778 - "POST /v1/playground/agent/sessions/8aac5756-6221-4bee-8a67-0e08513b2205 HTTP/1.1" 404 Not Found
INFO:     127.0.0.1:58778 - "GET /v1/playground/agent/get HTTP/1.1" 200 OK
DEBUG    AgentRunRequest: message='What are all my tables?' agent_id='sql_assistant' stream=True monitor=False session_id=None user_id='alaapdhall79_743d' image=None                                                                                   
DEBUG    Creating new session                                                                                                                                                                                                                           
DEBUG    *********** Agent ID: sql_assistant ***********                                                                                                                                                                                                
DEBUG    *********** Session ID: ea436cf4-07ec-4678-80d5-3dfc9183ddca ***********                                                                                                                                                                       
DEBUG    Debug logs enabled                                                                                                                                                                                                                             
DEBUG    Created new Agent: agent_id: sql_assistant | session_id: ea436cf4-07ec-4678-80d5-3dfc9183ddca                                                                                                                                                  
INFO:     127.0.0.1:42514 - "POST /v1/playground/agent/run HTTP/1.1" 200 OK
DEBUG    *********** Async Agent Run Start: 00caf82d-bf27-4ab2-8433-f8e2e90c7f18 ***********                                                                                                                                                            
DEBUG    Function show_tables from postgres_tools added to model.                                                                                                                                                                                       
DEBUG    Function describe_table from postgres_tools added to model.                                                                                                                                                                                    
DEBUG    Function inspect_query from postgres_tools added to model.                                                                                                                                                                                     
DEBUG    Function run_query from postgres_tools added to model.                                                                                                                                                                                         
DEBUG    Function summarize_table from postgres_tools added to model.                                                                                                                                                                                   
DEBUG    ---------- Ollama Async Response Start ----------                                                                                                                                                                                              
DEBUG    ============== system ==============                                                                                                                                                                                                           
DEBUG    I execute SQL queries and analyze results.                                                                                                                                                                                                     
                                                                                                                                                                                                                                                        
         Your role is: Database Expert                                                                                                                                                                                                                  
                                                                                                                                                                                                                                                        
         ## Instructions                                                                                                                                                                                                                                
         - When handling queries:                                                                                                                                                                                                                       
         - 1. Execute the appropriate SQL query immediately                                                                                                                                                                                             
         - 2. Show the query and its results                                                                                                                                                                                                            
         - 3. Analyze the actual data returned                                                                                                                                                                                                          
         - 4. Present findings based only on the data                                                                                                                                                                                                   
         - Important rules:                                                                                                                                                                                                                             
         - - Never suggest what queries to run                                                                                                                                                                                                          
         - - Don't ask for clarification                                                                                                                                                                                                                
         - - Always execute a query                                                                                                                                                                                                                     
         - - Base analysis only on returned data                                                                                                                                                                                                        
         - - Never end with questions or suggestions                                                                                                                                                                                                    
         - Use markdown to format your answers.                                                                                                                                                                                                         
DEBUG    ============== user ==============                                                                                                                                                                                                             
DEBUG    What are all my tables?                                                                                                                                                                                                                        
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/starlette/responses.py", line 259, in __call__
    await wrap(partial(self.listen_for_disconnect, receive))
  File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/starlette/responses.py", line 255, in wrap
    await func()
  File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/starlette/responses.py", line 232, in listen_for_disconnect
    message = await receive()
  File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/uvicorn/protocols/http/httptools_impl.py", line 555, in receive
    await self.message_event.wait()
  File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/asyncio/locks.py", line 214, in wait
    await fut
asyncio.exceptions.CancelledError: Cancelled by cancel scope 77c528696080

During handling of the above exception, another exception occurred:

  + Exception Group Traceback (most recent call last):
  |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/uvicorn/protocols/http/httptools_impl.py", line 401, in run_asgi
  |     result = await app(  # type: ignore[func-returns-value]
  |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/uvicorn/middleware/proxy_headers.py", line 60, in __call__
  |     return await self.app(scope, receive, send)
  |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/fastapi/applications.py", line 1054, in __call__
  |     await super().__call__(scope, receive, send)
  |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/starlette/applications.py", line 113, in __call__
  |     await self.middleware_stack(scope, receive, send)
  |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/starlette/middleware/errors.py", line 187, in __call__
  |     raise exc
  |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/starlette/middleware/errors.py", line 165, in __call__
  |     await self.app(scope, receive, _send)
  |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/starlette/middleware/cors.py", line 93, in __call__
  |     await self.simple_response(scope, receive, send, request_headers=headers)
  |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/starlette/middleware/cors.py", line 144, in simple_response
  |     await self.app(scope, receive, send)
  |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/starlette/middleware/exceptions.py", line 62, in __call__
  |     await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
  |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
  |     raise exc
  |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app
  |     await app(scope, receive, sender)
  |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/starlette/routing.py", line 715, in __call__
  |     await self.middleware_stack(scope, receive, send)
  |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/starlette/routing.py", line 735, in app
  |     await route.handle(scope, receive, send)
  |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/starlette/routing.py", line 288, in handle
  |     await self.app(scope, receive, send)
  |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/starlette/routing.py", line 76, in app
  |     await wrap_app_handling_exceptions(app, request)(scope, receive, send)
  |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
  |     raise exc
  |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app
  |     await app(scope, receive, sender)
  |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/starlette/routing.py", line 74, in app
  |     await response(scope, receive, send)
  |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/starlette/responses.py", line 252, in __call__
  |     async with anyio.create_task_group() as task_group:
  |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/anyio/_backends/_asyncio.py", line 736, in __aexit__
  |     raise BaseExceptionGroup(
  | exceptiongroup.ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
  +-+---------------- 1 ----------------
    | Traceback (most recent call last):
    |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/starlette/responses.py", line 255, in wrap
    |     await func()
    |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/starlette/responses.py", line 244, in stream_response
    |     async for chunk in self.body_iterator:
    |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/phi/playground/router.py", line 400, in chat_response_streamer
    |     async for run_response_chunk in run_response:
    |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/phi/agent/agent.py", line 2134, in _arun
    |     async for model_response_chunk in model_response_stream:  # type: ignore
    |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/phi/model/ollama/chat.py", line 667, in aresponse_stream
    |     async for response in self.ainvoke_stream(messages=messages):
    |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/phi/model/ollama/chat.py", line 253, in ainvoke_stream
    |     async_stream = await self.get_async_client().chat(
    |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/ollama/_client.py", line 841, in chat
    |     tools=[tool for tool in _copy_tools(tools)],
    |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/ollama/_client.py", line 841, in <listcomp>
    |     tools=[tool for tool in _copy_tools(tools)],
    |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/ollama/_client.py", line 1133, in _copy_tools
    |     yield convert_function_to_tool(unprocessed_tool) if callable(unprocessed_tool) else Tool.model_validate(unprocessed_tool)
    |   File "/home/alaap/miniconda3/envs/envPy310/lib/python3.10/site-packages/pydantic/main.py", line 596, in model_validate
    |     return cls.__pydantic_validator__.validate_python(
    | pydantic_core._pydantic_core.ValidationError: 1 validation error for Tool
    | function.parameters.properties.table_schema.type
    |   Input should be a valid string [type=string_type, input_value=['string', 'null'], input_type=list]
    |     For further information visit https://errors.pydantic.dev/2.9/v/string_type
    +------------------------------------

Is it a bug that needs to be fixed causing this? or am I doing something wrong?

Please review the code also and suggest me if I used it wrong, I just got started with phiData 2 days back.

Any help would be appreciated, thanks.

@ysolanky
Copy link
Contributor

Hello @alaap001 ! Thank you for the kind words!

Ollama recently made an update to tool call streaming. Can you please verify that your Ollama app, Ollama python sdk and phidata are all updated to the latest version?

@alaap001 alaap001 reopened this Dec 20, 2024
@alaap001
Copy link
Author

alaap001 commented Dec 20, 2024

It worked by updating but now getting this on a simple query like "What are all the tables I have?"

ERROR    Function show_tables not found                                                                                                                                                                                                                 
ERROR    Function show_tables not found                                                                                                                                                                                                                 
ERROR    Function show_tables not found                                                                                                                                                                                                                 
ERROR    Function show_tables not found                                                                                                                                                                                                                 
WARNING  Could not run function transfer_task_to_sql_assistant(expected_output=A list of table names., task_description=List all the tables available in the database.)                                                                                 
ERROR    1 validation error for Agent.get_transfer_function.<locals>._transfer_task_to_agent                                                                                                                                                            
         additional_information                                                                                                                                                                                                                         
           Missing required argument [type=missing_argument, input_value=ArgsKwargs((), {'expected...able in the database.'}), input_type=ArgsKwargs]                                                                                                   
             For further information visit https://errors.pydantic.dev/2.10/v/missing_argument                                                                                                                                                          
         Traceback (most recent call last):                                                                                                                                                                                                             
           File "/home/alaap/anaconda3/envs/env-py310/lib/python3.10/site-packages/phi/tools/function.py", line 312, in execute                                                                                                                     
             self.result = self.function.entrypoint(**entrypoint_args, **self.arguments)                                                                                                                                                                
           File "/home/alaap/anaconda3/envs/env-py310/lib/python3.10/site-packages/pydantic/_internal/_validate_call.py", line 38, in wrapper_function                                                                                              
             return wrapper(*args, **kwargs)                                                                                                                                                                                                            
           File "/home/alaap/anaconda3/envs/env-py310/lib/python3.10/site-packages/pydantic/_internal/_validate_call.py", line 111, in __call__                                                                                                     
             res = self.__pydantic_validator__.validate_python(pydantic_core.ArgsKwargs(args, kwargs))                                                                                                                                                  
         pydantic_core._pydantic_core.ValidationError: 1 validation error for Agent.get_transfer_function.<locals>._transfer_task_to_agent                                                                                                              
         additional_information                                                                                                                                                                                                                         
           Missing required argument [type=missing_argument, input_value=ArgsKwargs((), {'expected...able in the database.'}), input_type=ArgsKwargs]                                                                                                   
             For further information visit https://errors.pydantic.dev/2.10/v/missing_argument      

Sometimes I randomly get:

ERROR    Function describe_table not found                                                                                                                                                                                                              
ERROR    Function describe_table not found                                                                                                                                                                                                              
ERROR    Function describe_table not found                                                                                                                                                                                                              

OR with Knowledge Assistant

WARNING  Could not run function transfer_task_to_knowledge_assistant(expected_output=Table names, schema, and relevant columns for determining operator efficiency., task_description=Provide context on tables that contain data about operators and   
         their tasks.)                                                                                                                                                                                                                                  
ERROR    1 validation error for Agent.get_transfer_function.<locals>._transfer_task_to_agent                                                                                                                                                            
         additional_information                                                                                                                                                                                                                         
           Missing required argument [type=missing_argument, input_value=ArgsKwargs((), {'expected...tors and their tasks.'}), input_type=ArgsKwargs]                                                                                                   
             For further information visit https://errors.pydantic.dev/2.10/v/missing_argument                                                                                                                                                          
         Traceback (most recent call last):                                                                                                                                                                                                             
           File "/home/alaap/anaconda3/envs/env-py310/lib/python3.10/site-packages/phi/tools/function.py", line 312, in execute                                                                                                                     
             self.result = self.function.entrypoint(**entrypoint_args, **self.arguments)                                                                                                                                                                
           File "/home/alaap/anaconda3/envs/env-py310/lib/python3.10/site-packages/pydantic/_internal/_validate_call.py", line 38, in wrapper_function                                                                                              
             return wrapper(*args, **kwargs)                                                                                                                                                                                                            
           File "/home/alaap/anaconda3/envs/env-py310/lib/python3.10/site-packages/pydantic/_internal/_validate_call.py", line 111, in __call__                                                                                                     
             res = self.__pydantic_validator__.validate_python(pydantic_core.ArgsKwargs(args, kwargs))                                                                                                                                                  
         pydantic_core._pydantic_core.ValidationError: 1 validation error for Agent.get_transfer_function.<locals>._transfer_task_to_agent                                                                                                              
         additional_information                                                                                                                                                                                                                         
           Missing required argument [type=missing_argument, input_value=ArgsKwargs((), {'expected...tors and their tasks.'}), input_type=ArgsKwargs]                                                                                                   
             For further information visit https://errors.pydantic.dev/2.10/v/missing_argument                                                                                                                                                          

@manthanguptaa
Copy link
Contributor

@alaap001 If it happens randomly, the model is most likely hallucinating. I think you are using qwen2.5 7b model which is a small model and will not give you 100% accuracy

@alaap001
Copy link
Author

alaap001 commented Dec 26, 2024

Let me try with Qwen2.5 32B, I hope that is good enough, Will report back if I face this.
On the same note, any advice on getting a high-quality DB agent that can generate SQL query, execute, and provide analysis? Am I doing anything wrong in my code that leads to this error?

@manthanguptaa
Copy link
Contributor

manthanguptaa commented Dec 27, 2024

@alaap001 for a high-quality DB agent that can generate SQL query you will have to use a self evaluation loop and do it via workflow. Here is an example that I made yesterday as a reference for you https://github.com/phidatahq/phidata/pull/1638/files

There will be an agent that generates the SQL query, another that checks for the validity of the query, and another one to run the query..

@alaap001
Copy link
Author

alaap001 commented Dec 29, 2024

@manthanguptaa Hey, Thanks for the help. I did made some changes and converted the application to workflow, however, I still see a major difference when using tools with Ollama and OpenAI.

For reference, I am using Ollama Qwen 72B instruct and Open AI's gpt 4o mini.

When using OpenAI gpt4o mini I get proper tool calls which can later help in generation of correct query

DEBUG    *********** Agent ID: 551956f9-0b21-4f9f-b8b0-14458a67513f ***********                                                                                                                                                                         
DEBUG    *********** Session ID: 64a823e5-1890-4815-a112-e3e389ffecbb ***********                                                                                                                                                                       
DEBUG    Debug logs enabled                                                                                                                                                                                                                             
DEBUG    *********** Agent ID: 4e6920ad-0f53-476d-bc10-2c471ce6fb68 ***********                                                                                                                                                                         
DEBUG    *********** Session ID: 00c140b0-8678-4ca1-9901-17e539c4f83c ***********                                                                                                                                                                       
DEBUG    Debug logs enabled                                                                                                                                                                                                                             
Enter your SQL analysis question                                                                                                                                                                                                                        
✨ (Who are my most efficient operators based on average case setup time?):                                                                                                                                                                             
DEBUG    *********** Worfklow ID: ef8fad70-9e27-4fe8-bf4b-f575798a404d ***********                                                                                                                                                                      
DEBUG    *********** Worflow Session ID: 14509a06-09b8-43e7-a5fc-e64173c1cd5f ***********                                                                                                                                                               
INFO     Running: SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'                                                                                                                                                        
INFO     Running: SELECT column_name, data_type, character_maximum_length FROM information_schema.columns WHERE table_name = 'c_activity'                                                                                                            
INFO     Running: SELECT column_name, data_type, character_maximum_length FROM information_schema.columns WHERE table_name = 's_activity'                                                                                                         
INFO     Running: SELECT column_name, data_type, character_maximum_length FROM information_schema.columns WHERE table_name = 'b_activity'                                                                                                           
INFO     Running: SELECT column_name, data_type, character_maximum_length FROM information_schema.columns WHERE table_name = 'b_event'                                                                                                           
                                                                                                                                                                                                                                                        
Attempt 1 - Executing query:                                                                                                                                                                                                                            
sql_query='Correct Query'                                                                             
INFO     Running: Correct query                                                                                                                                                                                                                                      

When using Qwen 72B instruct I don't see any calls to tools, which naturally leads to incorrect query generation.

DEBUG    Debug logs enabled                                                                                                                                                                                                                             
DEBUG    *********** Agent ID: ab64376b-5b37-438d-bf76-f068023d2826 ***********                                                                                                                                                                         
DEBUG    *********** Session ID: e1d3e708-56d9-4c55-bcff-626e26c9be1c ***********                                                                                                                                                                       
DEBUG    Debug logs enabled                                                                                                                                                                                                                             
DEBUG    *********** Agent ID: 18c05769-ed46-48b8-b56b-8e5c42674297 ***********                                                                                                                                                                         
DEBUG    *********** Session ID: 08685e09-164e-40d8-9f6b-1b69b81f2aea ***********
DEBUG    *********** Worfklow ID: 54064e30-2807-41f7-b84a-65b3265b76a3 ***********                                                                                                                                                                      
DEBUG    *********** Worflow Session ID: a012f790-87f3-4319-b4dc-15ccbc37f23e ***********                                                                                                                                                                        
DEBUG    Debug logs enabled                                                                                                                                                                                                                             
Enter your SQL analysis question
✨ (Who are my most efficient operators based on average case setup time?): DEBUG                                                                                                                                                                  


Attempt 1 - Executing query:
sql_query='Incorrect query'
INFO     Running: 'Incorrect query'

Error: relation "cases" does not exist
LINE 1: ...erator_id, AVG(setup_time) AS avg_setup_time FROM cases GROU...
                                                             ^


Attempt 2 - Executing query:
sql_query='Incorrect query'
INFO     Running: 'Incorrect query'

As you can see no call to tools happened, while OpenAI used the relevant tool calls to understand schema and generate correct query.

My code example is as shown:

"""SQL Analysis Workflow that uses a team of agents to analyze database queries."""

from typing import List, Dict, Any, Optional, ClassVar
from pydantic import BaseModel, Field
from phi.agent import Agent
from phi.model.openai import OpenAIChat
from phi.workflow.workflow import Workflow
from phi.tools.postgres import PostgresTools
from phi.run.response import RunResponse
from phi.utils.pprint import pprint_run_response
from phi.knowledge.csv import CSVKnowledgeBase
from phi.vectordb.pgvector import PgVector
from phi.vectordb.search import SearchType
from phi.embedder.openai import OpenAIEmbedder
import json
from phi.model.groq import Groq
from reranker import BGEFlagReranker
from phi.model.ollama import Ollama
from dotenv import load_dotenv
from phi.embedder.ollama import OllamaEmbedder

load_dotenv()


class SQLQuery(BaseModel):
    query: str = Field(description="The SQL query to execute")


class SQLAnalysisResult(BaseModel):
    sql: str = Field(description="The SQL query that was executed")
    data: str = Field(description="Data returned from query")
    analysis: str = Field(description="Analysis considering the question and returned data")


class SQLAnalysisWorkflow(Workflow):
    description: str = "SQL Analysis Workflow"

    reranker: ClassVar[BGEFlagReranker] = BGEFlagReranker(model_name="BAAI/bge-reranker-large")

    # Initialize knowledge base
    knowledge_base: CSVKnowledgeBase = CSVKnowledgeBase(
        path="knowledge",
        num_documents=10,
        reranker=reranker,
        vector_db=PgVector(
            table_name="sql_knowledge",
            db_url="postgresql+psycopg://ai:ai@localhost:5432/ai",
            search_type=SearchType.hybrid,
            embedder=OllamaEmbedder(model="mxbai-embed-large",dimensions=1024)
        )
    )

    # knowledge_base.load(recreate=True, upsert=True)

    # Initialize PostgresTools
    target_db: PostgresTools = PostgresTools(
        {detalis}
        run_queries=True,
        inspect_queries=True,
        summarize_tables=True
    )

    # Define agents as class attributes
    query_generator: Agent = Agent(
        name="SQL Query Generator",
        description="Generate SQL queries based on natural language questions",
       
        instructions=[
            "You are an expert SQL query generator.",
            # "search the knowledge base for similar questions and their SQL queries.",
            
            "Key Rules:",
            "1. Use show_tables and describe_table tools to understand the schema.",
            "2. Generate complete, executable SQL queries",
            "3. Use proper SQL syntax with SELECT, FROM, WHERE, etc.",
            "4. Use meaningful column aliases",
            "5. Add LIMIT based on question intent:",
            "- If question asks for specific number (top 5, best 3, etc.), use that number",
            "- If no specific limit is needed by question, add LIMIT 30 to avoid large results",
            "- Some questions may not need LIMIT if aggregating/grouping data",

            "Important:",
           
            "1. Output only the SQL query, no explanations",
            "2. Make sure query is complete and executable",
        ],
        tools=[target_db],
        debug_mode=True,
        show_tool_calls=True,
        model=Ollama(id="qwen2.5:72b-instruct"),
        # model=OpenAIChat(model="gpt-4o-mini"),
        response_model=SQLQuery,
        structured_outputs=True,
    )

    data_analyzer: Agent = Agent(
        name="Data Analyst",
        description="Analyze query results and provide insights",
        system_prompt="""You are an expert data analyst. Your role is to analyze SQL query results and provide meaningful insights from the data and question asked.""",
        instructions=[
            "You are an expert data analyst.",
            "Use the knowledge base to understand:",
            "1. Business metrics and their significance",
            "2. Business context for analysis",
            "Analyze the query results in context of the original question.",
            "Provide clear insights and explanations.",
            "Use markdown formatting for better readability.",
            "Include relevant statistics and patterns found in the data.",
        ],
        knowledge=knowledge_base,
        search_knowledge=True,
        debug_mode=True,
        show_tool_calls=True,
        model=Ollama(id="qwen2.5:72b-instruct"),
        markdown=True,
    )

    def is_error_message(self, result: str) -> bool:
        """Check if the result is an error message"""
        error_indicators = [
            "syntax error",
            "does not exist",
            "column",
            "relation",
            "ERROR:",
            "error",
            "invalid",
            "cannot"
        ]
        return any(indicator.lower() in result.lower() for indicator in error_indicators)

    def run(self, question: str) -> RunResponse:
        # Generate SQL Query
        query_response = self.query_generator.run(question)
        sql_query = query_response.content.query

        # Try executing with error handling and fixing
        max_tries = 3
        attempt = 1
        
        while attempt <= max_tries:
            print(f"\nAttempt {attempt} - Executing query:")
            print(f"{sql_query=}")
            
            # Execute query
            results = self.target_db.run_query(sql_query)
            
            # Check if results contain an error message
            if not self.is_error_message(results):
                # Query succeeded
                analysis_input = f"""
                Original Question: {question}
                
                Query Used:
                {sql_query}
                
                Query Results:
                {results}
                
                Please analyze these results in context of the original question.
                Focus on key insights and patterns in the data.
                """
                analysis = self.data_analyzer.run(analysis_input)
                
                result = SQLAnalysisResult(
                    sql=sql_query,
                    data=results,
                    analysis=analysis.content
                )
                return RunResponse(content=json.dumps(result.dict(), indent=2))
            
            # Query failed, try to fix it
            if attempt < max_tries:
                print(f"Error: {results}")
                
                
            else:
                # All attempts failed
                result = SQLAnalysisResult(
                    sql=sql_query,
                    data="",
                    analysis=f"Failed to execute query after {max_tries} attempts. Last error: {results}"
                )
                return RunResponse(content=json.dumps(result.model_dump(), indent=2))


if __name__ == "__main__":
    from rich.prompt import Prompt

    # Get question from user
    question = Prompt.ask(
        "[bold]Enter your SQL analysis question[/bold]\n✨",
        default="Who are my most efficient operators based on average case setup time?"
    )
    
    # Initialize workflow
    workflow = SQLAnalysisWorkflow()
    
    # Run workflow and get results
    response = workflow.run(question)
    result = json.loads(response.content)
    
    # Print formatted results using pprint_run_response
    markdown_content = (
        f"## SQL Query\n"
        f"```sql\n{result['sql']}\n```\n\n"
        f"## Data\n"
        f"```\n{result['data']}\n```\n\n"
        f"## Analysis\n"
        f"{result['analysis']}"
    )
    pprint_run_response(RunResponse(content=markdown_content), markdown=True)

Am I doing something wrong? or is it that Ollama isn't good enough for tool calls?

@alaap001
Copy link
Author

Also @manthanguptaa there wasn't a proper doc on workflow so I only used available cookbooks to understand and build something, please let me know if you find anything in the code that isn't a good workflow practice or something that can be improved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants