-
Notifications
You must be signed in to change notification settings - Fork 30
feat!: Add invokeStructuredModel method to support new Judge online evals #970
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
Open
jsonbailey
wants to merge
4
commits into
main
Choose a base branch
from
jb/sdk-1522/structed-model-provider-langchain
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+156
−32
Open
Changes from 3 commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
4b71d80
feat!: Support invoke with structured output
jsonbailey 99ea7bd
catch exceptions in langchain provider
jsonbailey 4c38dcc
fix version in langchain ai package
jsonbailey 24d7520
Merge branch 'main' into jb/sdk-1522/structed-model-provider-langchain
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,7 @@ import type { | |
| LDLogger, | ||
| LDMessage, | ||
| LDTokenUsage, | ||
| StructuredResponse, | ||
| } from '@launchdarkly/server-sdk-ai'; | ||
|
|
||
| /** | ||
|
|
@@ -44,39 +45,102 @@ export class LangChainProvider extends AIProvider { | |
| * Invoke the LangChain model with an array of messages. | ||
| */ | ||
| async invokeModel(messages: LDMessage[]): Promise<ChatResponse> { | ||
| // Convert LDMessage[] to LangChain messages | ||
| const langchainMessages = LangChainProvider.convertMessagesToLangChain(messages); | ||
|
|
||
| // Get the LangChain response | ||
| const response: AIMessage = await this._llm.invoke(langchainMessages); | ||
|
|
||
| // Generate metrics early (assumes success by default) | ||
| const metrics = LangChainProvider.createAIMetrics(response); | ||
|
|
||
| // Extract text content from the response | ||
| let content: string = ''; | ||
| if (typeof response.content === 'string') { | ||
| content = response.content; | ||
| } else { | ||
| // Log warning for non-string content (likely multimodal) | ||
| this.logger?.warn( | ||
| `Multimodal response not supported, expecting a string. Content type: ${typeof response.content}, Content:`, | ||
| JSON.stringify(response.content, null, 2), | ||
| ); | ||
| // Update metrics to reflect content loss | ||
| metrics.success = false; | ||
| try { | ||
| // Convert LDMessage[] to LangChain messages | ||
| const langchainMessages = LangChainProvider.convertMessagesToLangChain(messages); | ||
|
|
||
| // Get the LangChain response | ||
| const response: AIMessage = await this._llm.invoke(langchainMessages); | ||
|
|
||
| // Generate metrics early (assumes success by default) | ||
| const metrics = LangChainProvider.createAIMetrics(response); | ||
|
|
||
| // Extract text content from the response | ||
| let content: string = ''; | ||
| if (typeof response.content === 'string') { | ||
| content = response.content; | ||
| } else { | ||
| // Log warning for non-string content (likely multimodal) | ||
| this.logger?.warn( | ||
| `Multimodal response not supported, expecting a string. Content type: ${typeof response.content}, Content:`, | ||
| JSON.stringify(response.content, null, 2), | ||
| ); | ||
| // Update metrics to reflect content loss | ||
| metrics.success = false; | ||
| } | ||
|
|
||
| // Create the assistant message | ||
| const assistantMessage: LDMessage = { | ||
| role: 'assistant', | ||
| content, | ||
| }; | ||
|
|
||
| return { | ||
| message: assistantMessage, | ||
| metrics, | ||
| }; | ||
| } catch (error) { | ||
| this.logger?.warn('LangChain model invocation failed:', error); | ||
|
|
||
| return { | ||
| message: { | ||
| role: 'assistant', | ||
| content: '', | ||
| }, | ||
| metrics: { | ||
| success: false, | ||
| }, | ||
| }; | ||
| } | ||
| } | ||
|
|
||
| // Create the assistant message | ||
| const assistantMessage: LDMessage = { | ||
| role: 'assistant', | ||
| content, | ||
| }; | ||
| /** | ||
| * Invoke the LangChain model with structured output support. | ||
| */ | ||
| async invokeStructuredModel( | ||
| messages: LDMessage[], | ||
| responseStructure: Record<string, unknown>, | ||
| ): Promise<StructuredResponse> { | ||
| try { | ||
| // Convert LDMessage[] to LangChain messages | ||
| const langchainMessages = LangChainProvider.convertMessagesToLangChain(messages); | ||
|
|
||
| // Get the LangChain response | ||
| const response = await this._llm | ||
| .withStructuredOutput(responseStructure) | ||
| .invoke(langchainMessages); | ||
|
|
||
| // Using structured output doesn't support metrics | ||
| const metrics = { | ||
| success: true, | ||
| usage: { | ||
| total: 0, | ||
| input: 0, | ||
| output: 0, | ||
| }, | ||
| }; | ||
|
|
||
| return { | ||
| message: assistantMessage, | ||
| metrics, | ||
| }; | ||
| return { | ||
| data: response, | ||
| rawResponse: JSON.stringify(response), | ||
| metrics, | ||
| }; | ||
| } catch (error) { | ||
| this.logger?.warn('LangChain structured model invocation failed:', error); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: Mismatch: log level for model invocation failures should be errorThe Additional Locations (2) |
||
|
|
||
| return { | ||
| data: {}, | ||
| rawResponse: '', | ||
| metrics: { | ||
| success: false, | ||
| usage: { | ||
| total: 0, | ||
| input: 0, | ||
| output: 0, | ||
| }, | ||
| }, | ||
| }; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
|
|
||
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.
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.
Bug: Mismatched Logging Levels for Model Invocation Errors
The
invokeModelandinvokeStructuredModelmethods inLangChainProvider.tslog caught errors usinglogger.warn(), but their corresponding tests expectlogger.error(). This mismatch causes test failures and suggests an incorrect severity classification for these error conditions.Additional Locations (3)
packages/ai-providers/server-ai-langchain/src/LangChainProvider.ts#L82-L83packages/ai-providers/server-ai-langchain/src/LangChainProvider.ts#L128-L129packages/ai-providers/server-ai-langchain/__tests__/LangChainProvider.test.ts#L168-L169