Skip to content

Commit d99a37c

Browse files
Qardclaude
andauthored
Add models configuration object to init() (#164)
Introduces a new `models` parameter to init() that allows configuring default models for different evaluation types: ```typescript init({ models: { completion: 'claude-3-5-sonnet-20241022', embedding: 'text-embedding-3-large', } }) ``` Changes: - Added `models` parameter to init() in both JS and Python - Models object supports: - `completion`: Default model for LLM-as-a-judge evaluations - `embedding`: Default model for embedding-based evaluations - `models.completion` takes precedence over deprecated `defaultModel` - All embedding scorers now use configured default embedding model - Added getDefaultEmbeddingModel() function - Maintains backward compatibility with existing `defaultModel` parameter - Added comprehensive tests for both languages Default values: - Completion: "gpt-4o" (unchanged) - Embedding: "text-embedding-ada-002" --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent d78f4ab commit d99a37c

9 files changed

Lines changed: 365 additions & 37 deletions

File tree

js/init-models.test.ts

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import { expect, test, describe, beforeEach } from "vitest";
2+
import { init, getDefaultModel, getDefaultEmbeddingModel } from "./oai";
3+
import { OpenAI } from "openai";
4+
5+
describe("init with defaultModel parameter", () => {
6+
beforeEach(() => {
7+
// Reset to defaults
8+
init();
9+
});
10+
11+
test("string form sets completion model (backward compatible)", () => {
12+
init({
13+
defaultModel: "gpt-4-turbo",
14+
});
15+
16+
expect(getDefaultModel()).toBe("gpt-4-turbo");
17+
expect(getDefaultEmbeddingModel()).toBe("text-embedding-ada-002"); // Default
18+
});
19+
20+
test("object form can set completion model only", () => {
21+
init({
22+
defaultModel: {
23+
completion: "gpt-4-turbo",
24+
},
25+
});
26+
27+
expect(getDefaultModel()).toBe("gpt-4-turbo");
28+
});
29+
30+
test("object form can set embedding model only", () => {
31+
init({
32+
defaultModel: {
33+
embedding: "text-embedding-3-large",
34+
},
35+
});
36+
37+
expect(getDefaultEmbeddingModel()).toBe("text-embedding-3-large");
38+
// Completion model should remain at default since we didn't update it
39+
expect(getDefaultModel()).toBe("gpt-4o");
40+
});
41+
42+
test("object form can set both models", () => {
43+
init({
44+
defaultModel: {
45+
completion: "claude-3-5-sonnet-20241022",
46+
embedding: "text-embedding-3-large",
47+
},
48+
});
49+
50+
expect(getDefaultModel()).toBe("claude-3-5-sonnet-20241022");
51+
expect(getDefaultEmbeddingModel()).toBe("text-embedding-3-large");
52+
});
53+
54+
test("partial updates preserve unspecified models", () => {
55+
// First set completion model
56+
init({
57+
defaultModel: {
58+
completion: "gpt-4-turbo",
59+
},
60+
});
61+
62+
expect(getDefaultModel()).toBe("gpt-4-turbo");
63+
expect(getDefaultEmbeddingModel()).toBe("text-embedding-ada-002");
64+
65+
// Then set only embedding model - completion should remain unchanged
66+
init({
67+
defaultModel: {
68+
embedding: "text-embedding-3-large",
69+
},
70+
});
71+
72+
expect(getDefaultModel()).toBe("gpt-4-turbo"); // Should still be gpt-4-turbo
73+
expect(getDefaultEmbeddingModel()).toBe("text-embedding-3-large");
74+
});
75+
76+
test("falls back to defaults when not set", () => {
77+
init();
78+
79+
expect(getDefaultModel()).toBe("gpt-4o");
80+
expect(getDefaultEmbeddingModel()).toBe("text-embedding-ada-002");
81+
});
82+
83+
test("string form resets embedding model to default", () => {
84+
// First set both models
85+
init({
86+
defaultModel: {
87+
completion: "gpt-4-turbo",
88+
embedding: "text-embedding-3-large",
89+
},
90+
});
91+
92+
expect(getDefaultModel()).toBe("gpt-4-turbo");
93+
expect(getDefaultEmbeddingModel()).toBe("text-embedding-3-large");
94+
95+
// Then use string form - should reset embedding to default
96+
init({
97+
defaultModel: "claude-3-5-sonnet-20241022",
98+
});
99+
100+
expect(getDefaultModel()).toBe("claude-3-5-sonnet-20241022");
101+
expect(getDefaultEmbeddingModel()).toBe("text-embedding-ada-002"); // Reset to default
102+
});
103+
});

js/oai.ts

Lines changed: 78 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ declare global {
166166
var __inherited_braintrust_wrap_openai: ((openai: any) => any) | undefined;
167167
var __client: OpenAI | undefined;
168168
var __defaultModel: string | undefined;
169+
var __defaultEmbeddingModel: string | undefined;
169170
}
170171

171172
export interface InitOptions {
@@ -176,17 +177,57 @@ export interface InitOptions {
176177
*/
177178
client?: OpenAI;
178179
/**
179-
* The default model to use for evaluations when not specified per-call.
180-
* Defaults to "gpt-4o" if not set.
180+
* The default model(s) to use for evaluations when not specified per-call.
181+
*
182+
* Can be either:
183+
* - A string (for backward compatibility): Sets the default completion model only.
184+
* Defaults to "gpt-4o" if not set.
185+
* - An object with `completion` and/or `embedding` properties: Allows setting
186+
* default models for different evaluation types. Only the specified models
187+
* are updated; others remain unchanged.
181188
*
182189
* When using non-OpenAI providers via the Braintrust proxy, set this to
183190
* the appropriate model string (e.g., "claude-3-5-sonnet-20241022").
191+
*
192+
* @example
193+
* // String form (backward compatible)
194+
* init({ defaultModel: "gpt-4-turbo" })
195+
*
196+
* @example
197+
* // Object form: set both models
198+
* init({
199+
* defaultModel: {
200+
* completion: "claude-3-5-sonnet-20241022",
201+
* embedding: "text-embedding-3-large"
202+
* }
203+
* })
204+
*
205+
* @example
206+
* // Object form: set only embedding model
207+
* init({
208+
* defaultModel: {
209+
* embedding: "text-embedding-3-large"
210+
* }
211+
* })
184212
*/
185-
defaultModel?: string;
213+
defaultModel?:
214+
| string
215+
| {
216+
/**
217+
* Default model for LLM-as-a-judge evaluations (completion).
218+
* Defaults to "gpt-4o" if not set.
219+
*/
220+
completion?: string;
221+
/**
222+
* Default model for embedding-based evaluations.
223+
* Defaults to "text-embedding-ada-002" if not set.
224+
*/
225+
embedding?: string;
226+
};
186227
}
187228

188229
/**
189-
* Initialize autoevals with a custom client and/or default model.
230+
* Initialize autoevals with a custom client and/or default models.
190231
*
191232
* @example
192233
* // Using with OpenAI (default)
@@ -205,21 +246,51 @@ export interface InitOptions {
205246
* apiKey: process.env.BRAINTRUST_API_KEY,
206247
* baseURL: "https://api.braintrust.dev/v1/proxy",
207248
* }),
208-
* defaultModel: "claude-3-5-sonnet-20241022",
249+
* defaultModel: {
250+
* completion: "claude-3-5-sonnet-20241022",
251+
* embedding: "text-embedding-3-large",
252+
* },
209253
* });
254+
*
255+
* @example
256+
* // String form (backward compatible)
257+
* init({ defaultModel: "gpt-4-turbo" });
210258
*/
211259
export const init = ({ client, defaultModel }: InitOptions = {}) => {
212260
globalThis.__client = client;
213-
globalThis.__defaultModel = defaultModel;
261+
if (typeof defaultModel === "string") {
262+
// String form: sets completion model only, resets embedding to default
263+
globalThis.__defaultModel = defaultModel;
264+
globalThis.__defaultEmbeddingModel = undefined;
265+
} else if (defaultModel) {
266+
// Object form: only update models that are explicitly provided
267+
if ("completion" in defaultModel) {
268+
globalThis.__defaultModel = defaultModel.completion;
269+
}
270+
if ("embedding" in defaultModel) {
271+
globalThis.__defaultEmbeddingModel = defaultModel.embedding;
272+
}
273+
} else {
274+
// No defaultModel: reset both to defaults
275+
globalThis.__defaultModel = undefined;
276+
globalThis.__defaultEmbeddingModel = undefined;
277+
}
214278
};
215279

216280
/**
217-
* Get the configured default model, or "gpt-4o" if not set.
281+
* Get the configured default completion model, or "gpt-4o" if not set.
218282
*/
219283
export const getDefaultModel = (): string => {
220284
return globalThis.__defaultModel ?? "gpt-4o";
221285
};
222286

287+
/**
288+
* Get the configured default embedding model, or "text-embedding-ada-002" if not set.
289+
*/
290+
export const getDefaultEmbeddingModel = (): string => {
291+
return globalThis.__defaultEmbeddingModel ?? "text-embedding-ada-002";
292+
};
293+
223294
export async function cachedChatCompletion(
224295
params: CachedLLMParams,
225296
options: { cache?: ChatCache } & OpenAIAuth,

js/ragas.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ import mustache from "mustache";
103103

104104
import { Scorer, ScorerArgs } from "./score";
105105
import { LLMArgs } from "./llm";
106-
import { getDefaultModel } from "./oai";
106+
import { getDefaultModel, getDefaultEmbeddingModel } from "./oai";
107107
import { buildOpenAIClient, extractOpenAIArgs } from "./oai";
108108
import OpenAI from "openai";
109109
import { ListContains } from "./list";
@@ -767,7 +767,7 @@ export const AnswerRelevancy: ScorerWithPartial<
767767
...extractOpenAIArgs(args),
768768
output: question,
769769
expected: input,
770-
model: args.embeddingModel,
770+
model: args.embeddingModel ?? getDefaultEmbeddingModel(),
771771
});
772772
return { question, score };
773773
}),

js/string.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Scorer, ScorerArgs } from "./score";
22
import levenshtein from "js-levenshtein";
3-
import { OpenAIAuth, buildOpenAIClient } from "./oai";
3+
import { OpenAIAuth, buildOpenAIClient, getDefaultEmbeddingModel } from "./oai";
44
import cossim from "compute-cosine-similarity";
55
import { makePartial, ScorerWithPartial } from "./partial";
66

@@ -69,7 +69,7 @@ export const EmbeddingSimilarity: ScorerWithPartial<
6969
[output, expected].map((input) =>
7070
openai.embeddings.create({
7171
input,
72-
model: args.model ?? "text-embedding-ada-002",
72+
model: args.model ?? getDefaultEmbeddingModel(),
7373
}),
7474
),
7575
);

0 commit comments

Comments
 (0)