-
Notifications
You must be signed in to change notification settings - Fork 4
feat: Add Chat and Judge supporting methods #64
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 17 commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
5f924ab
move dataclass into models
jsonbailey 951eda1
create new config types completion, agent, and judges
jsonbailey ae7516b
use inheritance for configs for consistency
jsonbailey 0d933d2
added deprecations for old types
jsonbailey 8271807
create the ai provider interface and factory
jsonbailey 6ee62b4
create a langchain implementation of the ai provider
jsonbailey 231ae2e
Add Judge and evaluation metric tracking
jsonbailey 445ab8c
Add Chat implementation
jsonbailey 5446222
Set a default for evaluation metircs
jsonbailey bc46608
add the logger
jsonbailey fd0aff4
adjust langchain import
jsonbailey c3c939f
fix structure response
jsonbailey 125bb66
judge respose should be async
jsonbailey 63b1d9e
fix test
edwinokonkwo cae7952
fix lint
edwinokonkwo 3ffb55d
fix deps
edwinokonkwo 64bb5f7
remove langchain and comment ref lines for now
edwinokonkwo 86acd6e
simplify
edwinokonkwo 11f7602
add judgeConfigKey
edwinokonkwo 06acc21
strongly type JudgeResponse
edwinokonkwo 84669d5
AIJudge to Judge
edwinokonkwo d57c4f7
add key to model
edwinokonkwo 351d4f1
fixes
edwinokonkwo 7a699ef
fix linting
edwinokonkwo 8d3bfbb
revert to sync
edwinokonkwo 5de380b
judge should set key for responses
jsonbailey 07c5454
use simplified Chat name
jsonbailey 3c77d76
re-order track_metrics_of params to be more intuitive
jsonbailey 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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,41 @@ | ||
| __version__ = "0.10.1" # x-release-please-version | ||
|
|
||
| # Export main client | ||
| # Export chat | ||
| from ldai.chat import TrackedChat | ||
| from ldai.client import LDAIClient | ||
| # Export judge | ||
| from ldai.judge import AIJudge | ||
| # Export models for convenience | ||
| from ldai.models import ( # Deprecated aliases for backward compatibility | ||
| AIAgentConfig, AIAgentConfigDefault, AIAgentConfigRequest, AIAgents, | ||
| AICompletionConfig, AICompletionConfigDefault, AIConfig, AIJudgeConfig, | ||
| AIJudgeConfigDefault, JudgeConfiguration, LDAIAgent, LDAIAgentConfig, | ||
| LDAIAgentDefaults, LDMessage, ModelConfig, ProviderConfig) | ||
| # Export judge types | ||
| from ldai.providers.types import EvalScore, JudgeResponse | ||
|
|
||
| __all__ = [ | ||
| 'LDAIClient', | ||
| 'AIAgentConfig', | ||
| 'AIAgentConfigDefault', | ||
| 'AIAgentConfigRequest', | ||
| 'AIAgents', | ||
| 'AICompletionConfig', | ||
| 'AICompletionConfigDefault', | ||
| 'AIJudgeConfig', | ||
| 'AIJudgeConfigDefault', | ||
| 'AIJudge', | ||
| 'TrackedChat', | ||
| 'EvalScore', | ||
| 'JudgeConfiguration', | ||
| 'JudgeResponse', | ||
| 'LDMessage', | ||
| 'ModelConfig', | ||
| 'ProviderConfig', | ||
| # Deprecated exports | ||
| 'AIConfig', | ||
| 'LDAIAgent', | ||
| 'LDAIAgentConfig', | ||
| 'LDAIAgentDefaults', | ||
| ] |
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,188 @@ | ||
| """TrackedChat implementation for managing AI chat conversations.""" | ||
|
|
||
| import asyncio | ||
| from typing import Any, Dict, List, Optional | ||
|
|
||
| from ldai.judge import AIJudge | ||
| from ldai.models import AICompletionConfig, LDMessage | ||
| from ldai.providers.ai_provider import AIProvider | ||
| from ldai.providers.types import ChatResponse, JudgeResponse | ||
| from ldai.tracker import LDAIConfigTracker | ||
|
|
||
|
|
||
| class TrackedChat: | ||
| """ | ||
| Concrete implementation of TrackedChat that provides chat functionality | ||
| by delegating to an AIProvider implementation. | ||
|
|
||
| This class handles conversation management and tracking, while delegating | ||
| the actual model invocation to the provider. | ||
| """ | ||
|
|
||
| def __init__( | ||
| self, | ||
| ai_config: AICompletionConfig, | ||
| tracker: LDAIConfigTracker, | ||
| provider: AIProvider, | ||
| judges: Optional[Dict[str, AIJudge]] = None, | ||
| logger: Optional[Any] = None, | ||
| ): | ||
| """ | ||
| Initialize the TrackedChat. | ||
|
|
||
| :param ai_config: The completion AI configuration | ||
| :param tracker: The tracker for the completion configuration | ||
| :param provider: The AI provider to use for chat | ||
| :param judges: Optional dictionary of judge instances keyed by their configuration keys | ||
| :param logger: Optional logger for logging | ||
| """ | ||
| self._ai_config = ai_config | ||
| self._tracker = tracker | ||
| self._provider = provider | ||
| self._judges = judges or {} | ||
| self._logger = logger | ||
| self._messages: List[LDMessage] = [] | ||
|
|
||
| async def invoke(self, prompt: str) -> ChatResponse: | ||
| """ | ||
| Invoke the chat model with a prompt string. | ||
|
|
||
| This method handles conversation management and tracking, delegating to the provider's invoke_model method. | ||
|
|
||
| :param prompt: The user prompt to send to the chat model | ||
| :return: ChatResponse containing the model's response and metrics | ||
| """ | ||
| # Convert prompt string to LDMessage with role 'user' and add to conversation history | ||
| user_message: LDMessage = LDMessage(role='user', content=prompt) | ||
| self._messages.append(user_message) | ||
|
|
||
| # Prepend config messages to conversation history for model invocation | ||
| config_messages = self._ai_config.messages or [] | ||
| all_messages = config_messages + self._messages | ||
|
|
||
| # Delegate to provider-specific implementation with tracking | ||
| response = await self._tracker.track_metrics_of( | ||
| lambda result: result.metrics, | ||
| lambda: self._provider.invoke_model(all_messages), | ||
| ) | ||
|
|
||
| # Start judge evaluations as async tasks (don't await them) | ||
| if ( | ||
| self._ai_config.judge_configuration | ||
| and self._ai_config.judge_configuration.judges | ||
| and len(self._ai_config.judge_configuration.judges) > 0 | ||
| ): | ||
| evaluation_tasks = self._start_judge_evaluations(self._messages, response) | ||
| response.evaluations = evaluation_tasks | ||
|
edwinokonkwo marked this conversation as resolved.
Outdated
|
||
|
|
||
| # Add the response message to conversation history | ||
| self._messages.append(response.message) | ||
| return response | ||
|
|
||
| def _start_judge_evaluations( | ||
| self, | ||
| messages: List[LDMessage], | ||
| response: ChatResponse, | ||
| ) -> List[asyncio.Task[Optional[JudgeResponse]]]: | ||
| """ | ||
| Start judge evaluations as async tasks without awaiting them. | ||
|
|
||
| Returns a list of async tasks that can be awaited later. | ||
|
|
||
| :param messages: Array of messages representing the conversation history | ||
| :param response: The AI response to be evaluated | ||
| :return: List of async tasks that will return judge evaluation results | ||
| """ | ||
| if not self._ai_config.judge_configuration or not self._ai_config.judge_configuration.judges: | ||
| return [] | ||
|
|
||
| judge_configs = self._ai_config.judge_configuration.judges | ||
|
|
||
| # Start all judge evaluations as tasks | ||
| async def evaluate_judge(judge_config): | ||
| judge = self._judges.get(judge_config.key) | ||
| if not judge: | ||
| if self._logger: | ||
| self._logger.warn( | ||
| f"Judge configuration is not enabled: {judge_config.key}", | ||
| ) | ||
| return None | ||
|
|
||
| eval_result = await judge.evaluate_messages( | ||
| messages, response, judge_config.sampling_rate | ||
| ) | ||
|
|
||
| if eval_result and eval_result.success: | ||
| self._tracker.track_eval_scores(eval_result.evals) | ||
|
edwinokonkwo marked this conversation as resolved.
Outdated
|
||
|
|
||
| return eval_result | ||
|
|
||
| # Create tasks for each judge evaluation | ||
| tasks = [ | ||
| asyncio.create_task(evaluate_judge(judge_config)) | ||
| for judge_config in judge_configs | ||
| ] | ||
|
|
||
| return tasks | ||
|
|
||
| def get_config(self) -> AICompletionConfig: | ||
| """ | ||
| Get the underlying AI configuration used to initialize this TrackedChat. | ||
|
|
||
| :return: The AI completion configuration | ||
| """ | ||
| return self._ai_config | ||
|
|
||
| def get_tracker(self) -> LDAIConfigTracker: | ||
| """ | ||
| Get the underlying AI configuration tracker used to initialize this TrackedChat. | ||
|
|
||
| :return: The tracker instance | ||
| """ | ||
| return self._tracker | ||
|
|
||
| def get_provider(self) -> AIProvider: | ||
| """ | ||
| Get the underlying AI provider instance. | ||
|
|
||
| This provides direct access to the provider for advanced use cases. | ||
|
|
||
| :return: The AI provider instance | ||
| """ | ||
| return self._provider | ||
|
|
||
| def get_judges(self) -> Dict[str, AIJudge]: | ||
| """ | ||
| Get the judges associated with this TrackedChat. | ||
|
|
||
| Returns a dictionary of judge instances keyed by their configuration keys. | ||
|
|
||
| :return: Dictionary of judge instances | ||
| """ | ||
| return self._judges | ||
|
|
||
| def append_messages(self, messages: List[LDMessage]) -> None: | ||
| """ | ||
| Append messages to the conversation history. | ||
|
|
||
| Adds messages to the conversation history without invoking the model, | ||
| which is useful for managing multi-turn conversations or injecting context. | ||
|
|
||
| :param messages: Array of messages to append to the conversation history | ||
| """ | ||
| self._messages.extend(messages) | ||
|
|
||
| def get_messages(self, include_config_messages: bool = False) -> List[LDMessage]: | ||
| """ | ||
| Get all messages in the conversation history. | ||
|
|
||
| :param include_config_messages: Whether to include the config messages from the AIConfig. | ||
| Defaults to False. | ||
| :return: Array of messages. When include_config_messages is True, returns both config | ||
| messages and conversation history with config messages prepended. When False, | ||
| returns only the conversation history messages. | ||
| """ | ||
| if include_config_messages: | ||
| config_messages = self._ai_config.messages or [] | ||
| return config_messages + self._messages | ||
| return list(self._messages) | ||
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.