Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 170 additions & 0 deletions evals/_schemas/config.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "config.schema.json",
"title": "Evaluator config",
"description": "Shared contract for evals/**/config.json. One living schema, referenced by each config via its $schema field. Strict: additionalProperties is false at every level, so any new field must be added here deliberately.",
"type": "object",
"additionalProperties": false,
"required": ["$schema", "evaluator", "input_schema", "steps", "output_schema"],
"properties": {
"$schema": { "type": "string" },
"evaluator": {
"type": "object",
"additionalProperties": false,
"required": ["id", "name", "description", "supported_grades"],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P0] I don't think we should require supported_grades. We have seen evals that don't have grade as an input. input_schema is required and can enforce this.

"properties": {
"id": { "type": "string", "minLength": 1 },
"name": { "type": "string", "minLength": 1 },
"description": { "type": "string", "minLength": 1 },
Comment on lines +16 to +18

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P1?] "minLength": 1 feels like it implies a single character id, name, or description is ok. Can we go with "required": true or "allow_empty": false instead. Functionally the same, but no implicit endorsement of single character values for these fields.

"supported_grades": {
"type": "array",
"minItems": 1,
"items": {
"enum": ["K", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P1] I've been using int for grades with 0 = 'K'. I don't see a strong reason to prefer one over the other. Maybe ints are safer for mapping grade bands to grades? Either way, we should be consistent.
[P0] And from earlier comment, I think supported_grades should be an input field not an evaluator property.

}
}
}
},
"input_schema": { "type": "object" },
"output_schema": { "type": "object" },
"preprocessing": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["id", "type", "kind"],
"properties": {
"id": { "type": "string", "minLength": 1 },
"type": { "enum": ["api", "computation"] },
"kind": { "type": "string", "minLength": 1 },
"description": { "type": "string" },
"input": { "type": "string" },
"output": { "type": "string" },
"implementation": {
"type": "object",
"minProperties": 1,
"additionalProperties": {
"type": "object",
"additionalProperties": false,
"required": ["library", "function"],
"properties": {
"library": { "type": "string", "minLength": 1 },
"function": { "type": "string", "minLength": 1 },
"post_transform": {
"type": "object",
"additionalProperties": false,
"required": ["type"],
"properties": {
"type": { "enum": ["round"] },
"precision": { "type": "integer" }
}
}
}
}
},
"endpoint": { "type": "string" },
"params": { "type": "object" },
"auth": { "type": "string" },
"pagination": { "type": "string" }
},
"allOf": [
{
"if": { "properties": { "type": { "const": "api" } } },
"then": { "required": ["endpoint", "params", "auth"] }
},
{
"if": { "properties": { "type": { "const": "computation" } } },
"then": { "required": ["implementation", "input", "output"] }
}
]
}
},
"steps": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"additionalProperties": false,
"required": ["id", "type"],
"properties": {
"id": { "type": "string", "minLength": 1 },
"type": { "enum": ["llm", "api"] },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P1] Should we allow for a "function" type too? If there's a common step in a several evals that is not an llm or api call, we could still represent it as a step, e.g. Flesch-Kincaid.

"description": { "type": "string" },
"prompt": {
"type": "object",
"additionalProperties": false,
"required": ["messages", "placeholders"],
"properties": {
"messages": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"additionalProperties": false,
"required": ["role", "source_path"],
"properties": {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P1] Newer models are dropping temperature, but most of the existing evals are using older models that have temperature as an attribute of the prompts step. Should we include temperature as part of the prompt properties? How are we capturing temperature at the moment?

"role": { "enum": ["system", "user", "assistant"] },
"source_path": { "type": "string", "minLength": 1 },
"sha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" }
}
}
},
"placeholders": {
"type": "object",
"additionalProperties": {
"type": "object",
"additionalProperties": false,
"required": ["required", "source"],
"properties": {
"required": { "type": "boolean" },
"source": { "type": "string" },
"note": { "type": "string" }
}
}
}
Comment on lines +112 to +124

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P0] Can't placeholders can be inferred from the prompt templates?
Langchain's approach lets users do partial placeholder replacements for templates but ensures all placeholders have been replaced before the template can be used in the prompt. If there are any un-replaced placeholders at prompt time, an exception is thrown.
I think forcing maintainers to define an attribute that can be inferred makes the framework tedious and creates opportunities for ambiguity, e.g. a placeholder is defined in the config, but is not present in the prompt template.

}
},
"model": {
"type": "object",
"additionalProperties": false,
"required": ["provider", "name"],
"properties": {
"provider": { "enum": ["google", "openai", "anthropic"] },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P1] Should we include "custom" even if we haven't implemented support yet?

"name": { "type": "string", "minLength": 1 },
"alias": { "type": "string" }
}
},
"generation": {
"type": "object",
"additionalProperties": false,
"properties": {
"temperature": { "type": "number", "minimum": 0, "maximum": 1 }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ah! Here's where temperature lives.

}
},
"parser": {
"type": "object",
"additionalProperties": false,
"required": ["kind"],
"properties": {
"kind": { "const": "structured_output" }
}
}
},
"allOf": [
{
"if": { "properties": { "type": { "const": "llm" } } },
"then": { "required": ["prompt", "model", "parser"] }
}
]
}
},
"fixtures": {
"type": "object",
"additionalProperties": false,
"properties": {
"path": { "type": "string" },
"tolerance": { "type": "object" }
}
}
}
}
19 changes: 19 additions & 0 deletions evals/_schemas/fixtures.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "fixtures.schema.json",
"title": "Evaluator fixtures",
"description": "Shared contract for evals/**/fixtures.json. Each case carries inputs and the expected label(s); per-evaluator input/expected shapes are validated against the evaluator's own input_schema/output_schema by the eval-fixtures check, not here.",
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["id", "input", "expected"],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P1] The captures for the contract tests have: name (id), description, inputs, outputs, llm_captures. Should the fixtures replace the captures and include the additional fields?

"properties": {
"id": { "type": "string", "minLength": 1 },
"description": { "type": "string" },
"source": { "type": "string" },
"input": { "type": "object" },
"expected": { "type": "object" }
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
{
"spec_version": "1.0",
"$schema": "../../../_schemas/config.schema.json",
"evaluator": {
"id": "feedback.productive_coaching_writing_feedback.is_acknowledges_strength",
"name": "Acknowledges Strength Feedback-Quality Evaluator",
"description": "Does the feedback identify what the student did well?"
"description": "Does the feedback identify what the student did well?",
"supported_grades": ["8", "9"]
},
"input_schema": {
"$ref": "input_schema.json"
Expand All @@ -12,9 +13,9 @@
"steps": [
{
"id": "evaluate_is_acknowledges_strength",
"type": "llm",
"description": "Single-call LLM step that produces the binary EvaluatorOutput JSON.",
"prompt": {
"type": "chat",
"messages": [
{
"role": "system",
Expand Down Expand Up @@ -46,17 +47,14 @@
"temperature": 1
},
"parser": {
"kind": "structured_output",
"output_schema_ref": "#/output_schema",
"notes": "Uses LangChain JsonOutputParser."
},
"output_binding": "formatted_output"
"kind": "structured_output"
}
}
],
"output_schema": {
"$ref": "output_schema.json"
},
"fixtures": {
"sniff_test_path": "fixtures.json"
"path": "fixtures.json"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@
"metadata": {},
"outputs": [],
"source": [
"fixtures_path = ASSETS_DIR / CONFIG[\"fixtures\"][\"sniff_test_path\"]\n",
"fixtures_path = ASSETS_DIR / CONFIG[\"fixtures\"][\"path\"]\n",
"if not fixtures_path.exists():\n",
" print(f\"(no fixtures.json yet at {fixtures_path}; skipping fixture run)\")\n",
"else:\n",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
{
"spec_version": "1.0",
"$schema": "../../../_schemas/config.schema.json",
"evaluator": {
"id": "feedback.productive_coaching_writing_feedback.is_actionable_revision",
"name": "Actionable Revision Feedback-Quality Evaluator",
"description": "If revision is needed, does the feedback give a clear next step?"
"description": "If revision is needed, does the feedback give a clear next step?",
"supported_grades": ["8", "9"]
},
"input_schema": {
"$ref": "input_schema.json"
Expand All @@ -12,9 +13,9 @@
"steps": [
{
"id": "evaluate_is_actionable_revision",
"type": "llm",
"description": "Single-call LLM step that produces the binary EvaluatorOutput JSON.",
"prompt": {
"type": "chat",
"messages": [
{
"role": "system",
Expand Down Expand Up @@ -46,17 +47,14 @@
"temperature": 1
},
"parser": {
"kind": "structured_output",
"output_schema_ref": "#/output_schema",
"notes": "Uses LangChain JsonOutputParser."
},
"output_binding": "formatted_output"
"kind": "structured_output"
}
}
],
"output_schema": {
"$ref": "output_schema.json"
},
"fixtures": {
"sniff_test_path": "fixtures.json"
"path": "fixtures.json"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@
"metadata": {},
"outputs": [],
"source": [
"fixtures_path = ASSETS_DIR / CONFIG[\"fixtures\"][\"sniff_test_path\"]\n",
"fixtures_path = ASSETS_DIR / CONFIG[\"fixtures\"][\"path\"]\n",
"if not fixtures_path.exists():\n",
" print(f\"(no fixtures.json yet at {fixtures_path}; skipping fixture run)\")\n",
"else:\n",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
{
"spec_version": "1.0",
"$schema": "../../../_schemas/config.schema.json",
"evaluator": {
"id": "feedback.productive_coaching_writing_feedback.is_anchored_in_student_response",
"name": "Anchored In Student Response Feedback-Quality Evaluator",
"description": "Is the feedback clearly based on the student's specific response? (Key features generated from rubric text; concept paper did not list explicit key feature items.)"
"description": "Is the feedback clearly based on the student's specific response? (Key features generated from rubric text; concept paper did not list explicit key feature items.)",
"supported_grades": ["8", "9"]
},
"input_schema": {
"$ref": "input_schema.json"
Expand All @@ -12,9 +13,9 @@
"steps": [
{
"id": "evaluate_is_anchored_in_student_response",
"type": "llm",
"description": "Single-call LLM step that produces the binary EvaluatorOutput JSON.",
"prompt": {
"type": "chat",
"messages": [
{
"role": "system",
Expand Down Expand Up @@ -46,17 +47,14 @@
"temperature": 1
},
"parser": {
"kind": "structured_output",
"output_schema_ref": "#/output_schema",
"notes": "Uses LangChain JsonOutputParser."
},
"output_binding": "formatted_output"
"kind": "structured_output"
}
}
],
"output_schema": {
"$ref": "output_schema.json"
},
"fixtures": {
"sniff_test_path": "fixtures.json"
"path": "fixtures.json"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@
"metadata": {},
"outputs": [],
"source": [
"fixtures_path = ASSETS_DIR / CONFIG[\"fixtures\"][\"sniff_test_path\"]\n",
"fixtures_path = ASSETS_DIR / CONFIG[\"fixtures\"][\"path\"]\n",
"if not fixtures_path.exists():\n",
" print(f\"(no fixtures.json yet at {fixtures_path}; skipping fixture run)\")\n",
"else:\n",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
{
"spec_version": "1.0",
"$schema": "../../../_schemas/config.schema.json",
"evaluator": {
"id": "feedback.productive_coaching_writing_feedback.is_appropriate_feedback",
"name": "Appropriate Feedback Feedback-Quality Evaluator",
"description": "Did the feedback correctly identify whether the student needed to revise? (Key features generated from rubric text; concept paper did not list explicit key feature items.)"
"description": "Did the feedback correctly identify whether the student needed to revise? (Key features generated from rubric text; concept paper did not list explicit key feature items.)",
"supported_grades": ["8", "9"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P1] Grade isn't an input for the feedback evals. So it looks like supported_grades makes sense as an attribute of the eval. I am wondering how grade was captured for annotations though for us to determine that the eval is only appropriate for these grades.

},
"input_schema": {
"$ref": "input_schema.json"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P2] All the evals in a suite have the same input. Should we define that input once and reference it in all the evals?

Expand All @@ -12,9 +13,9 @@
"steps": [
{
"id": "evaluate_is_appropriate_feedback",
"type": "llm",
"description": "Single-call LLM step that produces the binary EvaluatorOutput JSON.",
"prompt": {
"type": "chat",
"messages": [
{
"role": "system",
Expand Down Expand Up @@ -46,17 +47,14 @@
"temperature": 1
},
"parser": {
"kind": "structured_output",
"output_schema_ref": "#/output_schema",
"notes": "Uses LangChain JsonOutputParser."
},
"output_binding": "formatted_output"
"kind": "structured_output"
}
}
],
"output_schema": {
"$ref": "output_schema.json"
},
"fixtures": {
"sniff_test_path": "fixtures.json"
"path": "fixtures.json"
}
}
Loading
Loading