-
Notifications
You must be signed in to change notification settings - Fork 1.5k
feat: RAG Layered Optimization #448
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
base: main
Are you sure you want to change the base?
Conversation
Summary of ChangesHello @jorschac, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a significant overhaul to the wiki page generation system, focusing on improving the quality, efficiency, and robustness of the process. By adopting a layered RAG approach, modularizing the codebase, and enabling parallel generation, the system can now produce more comprehensive and contextually rich wiki content faster. The changes also enhance error handling and resource management, making the generation process more reliable and maintainable. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces a significant and well-structured refactoring of the wiki page generation logic, moving it into modular components with a layered RAG query strategy. The use of dependency injection, context managers for resource management, and dedicated modules for validation and exceptions are excellent architectural choices that improve maintainability and testability. My review focuses on enhancing robustness, configurability, and code clarity. Key suggestions include removing hardcoded model parameters, improving error handling with more specific exception catches, simplifying complex resource cleanup logic, and increasing code consistency. Overall, this is a strong contribution, and the suggested changes aim to further polish the implementation.
| "model_name": "gpt-4.1", | ||
| "temperature": 0.2, | ||
| "max_tokens": 65535 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The model_name and max_tokens are hardcoded. This reduces flexibility and requires code changes to use a different model or adjust token limits. These values should be configurable, for example by adding them to the WikiPageGenerationRequest model or loading them from a configuration file. This would allow callers to specify the desired model and parameters.
| except: | ||
| pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using a bare except is discouraged as it can suppress all errors, including system-exiting ones like SystemExit or KeyboardInterrupt, making debugging difficult. It's better to catch a specific exception, such as Exception, and log the error to provide visibility into what went wrong during the error handling process.
| except: | |
| pass | |
| except Exception as send_error: | |
| logger.warning(f"Failed to send final error to websocket: {send_error}") |
| prompt = f"""Generate comprehensive wiki page content for "{page['title']}" in the repository {request.repo_url}. | ||
|
|
||
| This page should focus on the following files: | ||
| {chr(10).join(f"- {path}" for path in page.get('filePaths', []))} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using chr(10) for a newline character is less common and less readable than the standard \n escape sequence. For better code clarity and adherence to Python conventions, it's recommended to use \n.
| {chr(10).join(f"- {path}" for path in page.get('filePaths', []))} | |
| {'\n'.join(f"- {path}" for path in page.get('filePaths', []))} |
| if 'results' in locals() and results: | ||
| logger.warning(f"Partial failure in parallel generation. Processing {len(results)} results despite error: {str(e)}") | ||
| return results |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Checking for a local variable's existence using 'results' in locals() is fragile and not a standard practice. A more robust and readable approach is to initialize results to None at the beginning of the try block (e.g., on line 354) and then simply check if results: in the except block. This makes the code's intent clearer and avoids relying on the locals() dictionary.
| if 'results' in locals() and results: | |
| logger.warning(f"Partial failure in parallel generation. Processing {len(results)} results despite error: {str(e)}") | |
| return results | |
| if results: | |
| logger.warning(f"Partial failure in parallel generation. Processing {len(results)} results despite error: {str(e)}") | |
| return results |
| logger.info(f" - Total requested: {total_requested}") | ||
| logger.info(f" - Successfully generated: {total_successful}") | ||
| logger.info(f" - Failed: {total_failed}") | ||
| logger.info(f" - Success rate: {total_successful/total_requested*100:.1f}%") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a potential for a ZeroDivisionError here if total_requested is 0. Although other checks in the code make this scenario unlikely, it's a good practice to guard against division by zero to make the code more robust. A similar issue exists on line 638. You could handle this with a conditional check, for example: success_rate_str = f'{(total_successful/total_requested*100):.1f}%' if total_requested > 0 else 'N/A'.
| "message": f"正在重试 {total_failed} 个失败页面..." | ||
| })) | ||
|
|
||
| await asyncio.sleep(5) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This hardcoded sleep(5) is a "magic number". Its purpose isn't immediately clear from the code. To improve maintainability, it's best to add a comment explaining why the delay is necessary (e.g., to avoid hitting API rate limits).
| await asyncio.sleep(5) | |
| # Wait for a few seconds before retrying to avoid hitting API rate limits. | |
| await asyncio.sleep(5) |
| if hasattr(self.rag, 'cleanup'): | ||
| if hasattr(self.rag.cleanup, '__call__'): | ||
| # Check if it's an async method | ||
| if hasattr(self.rag.cleanup, '__code__'): | ||
| import inspect | ||
| if inspect.iscoroutinefunction(self.rag.cleanup): | ||
| await self.rag.cleanup() | ||
| else: | ||
| self.rag.cleanup() | ||
| else: | ||
| await self.rag.cleanup() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic to determine if self.rag.cleanup is an awaitable coroutine is overly complex and contains a potential bug. The else block on line 42 unconditionally awaits self.rag.cleanup, which will raise a TypeError if it's a regular synchronous function that doesn't have a __code__ attribute. A simpler and more reliable approach is to use inspect.iscoroutinefunction to check if the method is async.
if hasattr(self.rag, 'cleanup') and callable(self.rag.cleanup):
import inspect
if inspect.iscoroutinefunction(self.rag.cleanup):
await self.rag.cleanup()
else:
self.rag.cleanup()| """验证 wiki 结构的有效性""" | ||
|
|
||
| @staticmethod | ||
| def validate_wiki_structure(structure: Dict[str, Any]) -> None: | ||
| """ | ||
| 验证 wiki 结构,失败时抛出 ValidationError | ||
|
|
||
| Args: | ||
| structure: Wiki 结构字典 | ||
|
|
||
| Raises: | ||
| ValidationError: 如果结构无效 | ||
| """ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The docstrings in this file are in Chinese, while the file-level docstring and the rest of the codebase are in English. To maintain consistency and improve readability for all contributors, it's best to use a single language throughout the project. Please consider translating these docstrings to English.
class WikiStructureValidator:
"""Validates the wiki structure.
Ensures that the input wiki structure conforms to the required format
before processing begins.
"""
@staticmethod
def validate_wiki_structure(structure: Dict[str, Any]) -> None:
"""
Validates the wiki structure, raising a ValidationError on failure.
Args:
structure: The wiki structure dictionary.
Raises:
ValidationError: If the structure is invalid.
"""| else: | ||
| print(f"⚠️ Warning: .env file not found at {env_path}") | ||
| print(" Please create a .env file with OPENAI_API_KEYS and OPENAI_BASE_URL") | ||
| sys.exit(1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using sys.exit(1) when a .env file is not found is too aggressive for a test suite. This will halt the entire test run, preventing other tests that might not depend on environment variables from executing. It's better to print a warning and allow the specific tests that require these variables to fail gracefully. This makes the test suite more resilient and provides more complete feedback.
| else: | |
| print(f"⚠️ Warning: .env file not found at {env_path}") | |
| print(" Please create a .env file with OPENAI_API_KEYS and OPENAI_BASE_URL") | |
| sys.exit(1) | |
| else: | |
| print(f"⚠️ Warning: .env file not found at {env_path}") | |
| print(" Please create a .env file with OPENAI_API_KEYS and OPENAI_BASE_URL for integration tests.") |
Description
Implemented layered RAG query strategy for wiki page generation as mentioned in #447. Refactored wiki generation logic from
api/websocket_wiki.pyinto modular components with improved error handling and resource management.Files Changed:
api/tools/rag_layers.py,api/tools/wiki_exceptions.py,api/tools/wiki_validator.py,api/tools/wiki_resources.pyapi/websocket_wiki.pytests/unit/test_wiki_generator.pyType of Change
Testing
Checklist