Skip to content

chore(wren-ai-service): add followup sql generation reasoning#1407

Merged
cyyeh merged 2 commits into
mainfrom
chore/ai-service/fix-followup-reasoning
Mar 14, 2025
Merged

chore(wren-ai-service): add followup sql generation reasoning#1407
cyyeh merged 2 commits into
mainfrom
chore/ai-service/fix-followup-reasoning

Conversation

@cyyeh
Copy link
Copy Markdown
Member

@cyyeh cyyeh commented Mar 13, 2025

Summary by CodeRabbit

  • New Features
    • Introduced a follow-up SQL generation capability that enhances query responses when historical context is provided.
    • Updated configurations across various environments to support the new follow-up SQL generation reasoning, enabling more contextually aware SQL query generation.
    • Added a new pipeline entry for followup_sql_generation_reasoning utilizing the litellm_llm.default model in multiple configuration files.

@cyyeh cyyeh added module/ai-service ai-service related ci/ai-service ai-service related labels Mar 13, 2025
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 13, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

This pull request integrates a new follow-up SQL generation reasoning capability across the system. It adds a new model entry (followup_sql_generation_reasoning with llm: litellm_llm.default) in multiple configuration files and introduces a corresponding pipeline implementation. The service container and ask service are updated to support conditional invocation of the new pipeline, ensuring the reasoning process adapts based on the provided historical data.

Changes

File(s) Change Summary
deployment/kustomizations/.../cm.yaml,
docker/config.example.yaml,
wren-ai-service/tools/config/config.example.yaml,
wren-ai-service/tools/config/config.full.yaml,
wren-ai-service/docs/config_examples/config.azure.yaml,
wren-ai-service/docs/config_examples/config.deepseek.yaml,
wren-ai-service/docs/config_examples/config.google_ai_studio.yaml,
wren-ai-service/docs/config_examples/config.groq.yaml,
wren-ai-service/docs/config_examples/config.ollama.yaml
Added new entries/pipes for followup_sql_generation_reasoning utilizing litellm_llm.default in configuration files.
wren-ai-service/src/globals.py Updated the create_service_container function to include a new service for followup_sql_generation_reasoning in the query_cache.
wren-ai-service/src/pipelines/generation/__init__.py Added import for FollowUpSQLGenerationReasoning and updated the __all__ list to expose it.
wren-ai-service/src/pipelines/generation/followup_sql_generation_reasoning.py Introduced a new file implementing the FollowUpSQLGenerationReasoning pipeline with methods for prompt building, asynchronous SQL reasoning generation, post-processing, and streaming result management.
wren-ai-service/src/web/v1/services/ask.py Modified the ask method to conditionally invoke the follow-up reasoning pipeline based on the presence of query histories.

Possibly related PRs

  • feat(wren-ai-service): change sql through reasoning #1273: The changes in the main PR are related to the modifications in the retrieved PR as both involve the addition of new pipeline entries for SQL generation reasoning, specifically focusing on enhancing the functionality of SQL processing within the same configuration files.
  • chore(wren-ai-service): minor-updates #1253: The changes in the main PR, which introduce a new model for follow-up SQL generation reasoning, are related to the retrieved PR as both involve modifications to the configuration settings for SQL generation reasoning, specifically the addition of the allow_sql_generation_reasoning parameter.
  • chore(wren-ai-service): improve text2sql process #1070: The changes in the main PR introduce a new pipeline for follow-up SQL generation reasoning, while the retrieved PR modifies the logic in the ask method to prioritize historical data for SQL generation, indicating a direct relationship in their focus on SQL generation processes.

Suggested reviewers

  • paopa

Poem

I'm a little rabbit on a code-filled spree,
Hopping through configs and pipelines with glee,
Follow-up SQL thoughts take a graceful leap,
Streaming results as secrets they keep,
Cheers to new code, where bugs now sleep! 🐰✨

Tip

⚡🧪 Multi-step agentic review comment chat (experimental)
  • We're introducing multi-step agentic chat in review comments. This experimental feature enhances review discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments.
    - To enable this feature, set early_access to true under in the settings.

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 90ef342 and 487ba07.

📒 Files selected for processing (5)
  • wren-ai-service/docs/config_examples/config.azure.yaml (1 hunks)
  • wren-ai-service/docs/config_examples/config.deepseek.yaml (1 hunks)
  • wren-ai-service/docs/config_examples/config.google_ai_studio.yaml (1 hunks)
  • wren-ai-service/docs/config_examples/config.groq.yaml (1 hunks)
  • wren-ai-service/docs/config_examples/config.ollama.yaml (1 hunks)

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (6)
wren-ai-service/src/web/v1/services/ask.py (2)

369-390: Validate branching logic for followup vs. standard reasoning.
When histories is nonempty, the code switches to the “followup_sql_generation_reasoning” pipeline. Otherwise, it uses “sql_generation_reasoning.” This approach is clear and maintains backward compatibility for queries without history. Make sure to test scenarios with extremely long histories or partial histories to confirm stable performance and correct reasoning output.


676-678: Minor refactoring for feedback pipeline.
This code re-indentation is fine, and storing a “correcting” status in _ask_feedback_results is consistent with the existing pattern. If the re-indentation was unintentional, consider placing it in a dedicated formatting commit to keep functional changes separate from style changes.

wren-ai-service/src/pipelines/generation/followup_sql_generation_reasoning.py (4)

19-35: Consider externalizing large system prompts.
This block defines a multi-line system prompt in the source code. To improve maintainability, consider extracting it into a dedicated file or configuration variable, which can make updates and translations easier.


37-67: Ensure no sensitive data is leaked in user prompt fields.
Building a large user prompt that includes database schemas, SQL samples, and user queries is powerful. Double-check logging configurations and potential debug statements to prevent unintentional exposure of sensitive content.


108-125: Initialize pipeline components with concurrency in mind.
Storing user queues in self._user_queues is suitable for handling streaming. However, confirm that concurrent usage (two calls from the same query_id) is either invalid or properly synchronized if it occurs.


140-164: Consider longer or configurable timeout in get_streaming_results.
Terminating after 120 seconds is reasonable as a default, but if processing large contexts or slow models, additional time may be needed. Providing a configurable timeout would be beneficial.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f419d82 and 9a727b6.

📒 Files selected for processing (8)
  • deployment/kustomizations/base/cm.yaml (1 hunks)
  • docker/config.example.yaml (1 hunks)
  • wren-ai-service/src/globals.py (1 hunks)
  • wren-ai-service/src/pipelines/generation/__init__.py (2 hunks)
  • wren-ai-service/src/pipelines/generation/followup_sql_generation_reasoning.py (1 hunks)
  • wren-ai-service/src/web/v1/services/ask.py (3 hunks)
  • wren-ai-service/tools/config/config.example.yaml (1 hunks)
  • wren-ai-service/tools/config/config.full.yaml (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: pytest
  • GitHub Check: pytest
  • GitHub Check: Analyze (go)
🔇 Additional comments (13)
docker/config.example.yaml (1)

129-130: Implementation of new followup SQL generation reasoning pipeline looks good.

The addition of the followup_sql_generation_reasoning pipeline with the default LLM is consistent with other pipeline configurations and properly positioned after the related sql_generation_reasoning pipeline.

wren-ai-service/tools/config/config.example.yaml (1)

143-144: Configuration consistency maintained across environments.

The addition of the followup_sql_generation_reasoning pipeline in this example config matches the implementation in the Docker configuration, ensuring consistent behavior across different environments.

wren-ai-service/src/pipelines/generation/__init__.py (2)

5-5: New module import for FollowUpSQLGenerationReasoning looks good.

The import statement follows the same pattern as other pipeline imports in this file.


38-38: Public API correctly updated to include the new pipeline.

The new pipeline class has been appropriately added to the __all__ list, making it available to importers of this module.

wren-ai-service/tools/config/config.full.yaml (1)

143-144: Full configuration properly updated with new pipeline.

The addition of the followup_sql_generation_reasoning pipeline in the full configuration is consistent with the other config files and properly positioned in the pipeline sequence.

deployment/kustomizations/base/cm.yaml (1)

177-178: Confirm model alignment and configurations.
The addition of the “followup_sql_generation_reasoning” pipeline with the same LLM provider is consistent with the other pipelines. Verify that all references—particularly in production and test configuration files—point to this correct model name and that no environment variables or settings are inadvertently overridden.

wren-ai-service/src/web/v1/services/ask.py (1)

753-755: Graceful handling for stopping feedback requests.
Marking the status as “stopped” in _ask_feedback_results is suitable. If multiple parallel requests might alter this state, confirm that you handle concurrency or repeated calls to avoid race conditions.

wren-ai-service/src/pipelines/generation/followup_sql_generation_reasoning.py (6)

1-18: Imports and logging look good.
Imports and logger usage are straightforward and appropriate for async pipeline handling.


70-88: Prompt function flow is clear.
The code merges multiple data points into a single prompt. This is concise and logical. No immediate issues noticed.


90-93: Check generator’s timeout or error handling.
Currently, you await the generator call without additional timeout or fallback logic. If the downstream LLM takes too long or returns empty data, consider handling or at least logging that scenario.


130-139: Streaming callback approach looks correct.
Placing message chunks into a per-user asyncio.Queue is a robust pattern for real-time streaming. This is well-designed.


166-188: Run logic is straightforward.
The pipeline flow is clear. If any step fails within execute(), ensure the exception is captured upstream. Everything else is well structured.


190-200: Local testing block is beneficial.
Having a dry_run_pipeline call for quick tests or demos is commendable, and it won’t affect production.

Comment thread wren-ai-service/src/globals.py
@paopa paopa self-requested a review March 14, 2025 02:24
@cyyeh cyyeh force-pushed the chore/ai-service/fix-followup-reasoning branch from c676edb to 90ef342 Compare March 14, 2025 03:12
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
wren-ai-service/src/pipelines/generation/followup_sql_generation_reasoning.py (1)

95-100: ⚠️ Potential issue

Add defensive check for empty replies.

The current implementation could trigger an index error if "replies" is missing or empty. Add safeguards to avoid runtime errors.

@observe()
def post_process(
    generate_sql_reasoning: dict,
) -> dict:
-    return generate_sql_reasoning.get("replies")[0]
+    replies = generate_sql_reasoning.get("replies", [])
+    if not replies:
+        return {}
+    return replies[0]
🧹 Nitpick comments (6)
wren-ai-service/src/pipelines/generation/followup_sql_generation_reasoning.py (6)

140-164: Implement proper error handling in the streaming results method.

The current implementation has a basic timeout handling, but there's no detailed error logging or recovery strategy for other potential exceptions during streaming. Consider adding more comprehensive error handling.

async def get_streaming_results(self, query_id):
    async def _get_streaming_results(query_id):
        return await self._user_queues[query_id].get()

    if query_id not in self._user_queues:
        self._user_queues[
            query_id
        ] = asyncio.Queue()  # Ensure the user's queue exists
    while True:
        try:
            # Wait for an item from the user's queue
            self._streaming_results = await asyncio.wait_for(
                _get_streaming_results(query_id), timeout=120
            )
            if (
                self._streaming_results == "<DONE>"
            ):  # Check for end-of-stream signal
                del self._user_queues[query_id]
                break
            if self._streaming_results:  # Check if there are results to yield
                yield self._streaming_results
                self._streaming_results = ""  # Clear after yielding
        except TimeoutError:
+            logger.warning(f"Timeout while waiting for streaming results for query_id: {query_id}")
+            break
+        except Exception as e:
+            logger.error(f"Error in get_streaming_results for query_id {query_id}: {str(e)}")
             break

130-139: Ensure proper error handling in the streaming callback.

The streaming callback doesn't have any error handling, which could potentially lead to unhandled exceptions and affect the application's stability.

def _streaming_callback(self, chunk, query_id):
-    if query_id not in self._user_queues:
-        self._user_queues[
-            query_id
-        ] = asyncio.Queue()  # Create a new queue for the user if it doesn't exist
-    # Put the chunk content into the user's queue
-    asyncio.create_task(self._user_queues[query_id].put(chunk.content))
-    if chunk.meta.get("finish_reason"):
-        asyncio.create_task(self._user_queues[query_id].put("<DONE>"))
+    try:
+        if query_id not in self._user_queues:
+            self._user_queues[
+                query_id
+            ] = asyncio.Queue()  # Create a new queue for the user if it doesn't exist
+        # Put the chunk content into the user's queue
+        asyncio.create_task(self._user_queues[query_id].put(chunk.content))
+        if chunk.meta.get("finish_reason"):
+            asyncio.create_task(self._user_queues[query_id].put("<DONE>"))
+    except Exception as e:
+        logger.error(f"Error in streaming callback for query_id {query_id}: {str(e)}")

166-187: Add docstring to the run method.

The run method lacks a docstring that explains its purpose, parameters, and return values. Adding a comprehensive docstring would improve code maintainability.

@observe(name="FollowupSQL Generation Reasoning")
async def run(
    self,
    query: str,
    contexts: List[str],
    histories: List[AskHistory],
    sql_samples: Optional[List[str]] = None,
    configuration: Configuration = Configuration(),
    query_id: Optional[str] = None,
):
+    """
+    Runs the followup SQL generation reasoning pipeline.
+
+    Args:
+        query (str): The user's query to process
+        contexts (List[str]): Database schema contexts
+        histories (List[AskHistory]): Previous questions and SQL queries
+        sql_samples (Optional[List[str]], optional): Example SQL queries. Defaults to None.
+        configuration (Configuration, optional): Configuration settings. Defaults to Configuration().
+        query_id (Optional[str], optional): Unique identifier for the query. Defaults to None.
+
+    Returns:
+        dict: The processed reasoning for SQL generation
+    """
    logger.info("Followup SQL Generation Reasoning pipeline is running...")
    return await self._pipe.execute(
        ["post_process"],
        inputs={
            "query": query,
            "documents": contexts,
            "histories": histories,
            "sql_samples": sql_samples or [],
            "configuration": configuration,
            "query_id": query_id,
            **self._components,
        },
    )

71-87: Add type hints for the prompt function return value.

The prompt function is missing proper type hinting for its return value. It returns a dict, but the specific structure of this dict isn't documented, which would be helpful for maintainers.

@observe(capture_input=False)
def prompt(
    query: str,
    documents: List[str],
    histories: List[AskHistory],
    sql_samples: List[str],
    prompt_builder: PromptBuilder,
    configuration: Configuration | None = Configuration(),
-) -> dict:
+) -> dict[str, Any]:
    """
+    Creates a prompt for SQL reasoning generation.
+
+    Returns:
+        dict[str, Any]: A dictionary containing the generated prompt
+    """
    return prompt_builder.run(
        query=query,
        documents=documents,
        histories=histories,
        sql_samples=sql_samples,
        current_time=configuration.show_current_time(),
        language=configuration.language,
    )

190-199: Add error handling to the main block.

The main block for testing should include proper error handling to catch and log exceptions during pipeline execution.

if __name__ == "__main__":
    from src.pipelines.common import dry_run_pipeline
+    import logging
+    
+    # Set up basic logging configuration for the test run
+    logging.basicConfig(level=logging.INFO)
+    
+    try:
+        dry_run_pipeline(
+            FollowUpSQLGenerationReasoning,
+            "followup_sql_generation_reasoning",
+            query="this is a test query",
+            histories=[],
+            contexts=[],
+        )
+    except Exception as e:
+        logging.error(f"Error during dry run: {str(e)}")
-    dry_run_pipeline(
-        FollowUpSQLGenerationReasoning,
-        "followup_sql_generation_reasoning",
-        query="this is a test query",
-        histories=[],
-        contexts=[],
-    )

151-153: Consider making the timeout configurable.

The timeout value of 120 seconds is hardcoded. It would be better to make this configurable, either through a class parameter or as part of the configuration object.

class FollowUpSQLGenerationReasoning(BasicPipeline):
    def __init__(
        self,
        llm_provider: LLMProvider,
+       streaming_timeout: int = 120,
        **kwargs,
    ):
+       self._streaming_timeout = streaming_timeout
        self._user_queues = {}
        # ...rest of the method

    async def get_streaming_results(self, query_id):
        # ...existing code
                # Wait for an item from the user's queue
                self._streaming_results = await asyncio.wait_for(
-                   _get_streaming_results(query_id), timeout=120
+                   _get_streaming_results(query_id), timeout=self._streaming_timeout
                )
                # ...rest of the method
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c676edb and 90ef342.

📒 Files selected for processing (8)
  • deployment/kustomizations/base/cm.yaml (1 hunks)
  • docker/config.example.yaml (1 hunks)
  • wren-ai-service/src/globals.py (1 hunks)
  • wren-ai-service/src/pipelines/generation/__init__.py (2 hunks)
  • wren-ai-service/src/pipelines/generation/followup_sql_generation_reasoning.py (1 hunks)
  • wren-ai-service/src/web/v1/services/ask.py (1 hunks)
  • wren-ai-service/tools/config/config.example.yaml (1 hunks)
  • wren-ai-service/tools/config/config.full.yaml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • docker/config.example.yaml
  • wren-ai-service/tools/config/config.full.yaml
  • wren-ai-service/src/pipelines/generation/init.py
  • wren-ai-service/src/globals.py
  • wren-ai-service/tools/config/config.example.yaml
  • deployment/kustomizations/base/cm.yaml
  • wren-ai-service/src/web/v1/services/ask.py
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: pytest
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (go)

Copy link
Copy Markdown
Contributor

@paopa paopa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall lgtm. Can you also add the pipeline setup into other example configs like Ollama, Groq, etc.?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/ai-service ai-service related module/ai-service ai-service related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants