-
Notifications
You must be signed in to change notification settings - Fork 38
New reference implementation: Misalignment evaluations #108
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?
Changes from all commits
18e933e
c5563d9
a0980d8
42735b1
8f5dfb4
a004d48
cdd7723
ec263c1
b92eaae
ffa96b7
ff5071e
3b28900
53ed74b
6b8316e
6aa2987
a8b99a1
693bbd6
fbc110b
d4f4569
18fd7c1
5236b7a
ca7454f
c00690c
d384a1a
058f8a4
8c1a1c2
5c08899
e354c44
578d360
1567129
918da10
145ab9b
17177ca
1d867b3
9729a8d
98eefdd
f53c73e
38a9fe7
e6a234b
f2115f3
80409cc
7e1557b
db50aa6
d544cfe
aa37284
ffee944
2c380ec
6de6c05
57779bb
8a84802
c33fc7a
1c24356
a370853
b5faa71
c1de37c
9807216
face593
416963f
acd1076
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| """Config-driven misalignment QA experiment runner.""" | ||
|
|
||
| from aieng.agent_evals.misalignment_qa.agent import SUPPORTED_TOOL_NAMES, build_misalignment_agent | ||
| from aieng.agent_evals.misalignment_qa.config_types import ( | ||
| AgentOverrideSpec, | ||
| AgentSpec, | ||
| AgentToolSpec, | ||
| EvalSpec, | ||
| ExamplePairSpec, | ||
| ExamplesInjectMode, | ||
| ExperimentConfig, | ||
| LLMJudgeSpec, | ||
| MessageSpec, | ||
| TaskItemSpec, | ||
| TraceUsageMetricsSpec, | ||
| VariantSpec, | ||
| ) | ||
| from aieng.agent_evals.misalignment_qa.experiment import load_experiment_config, run_experiment_config | ||
| from aieng.agent_evals.misalignment_qa.preparation import PreparedTaskItem, PreparedVariantRun | ||
| from aieng.agent_evals.misalignment_qa.task import MisalignmentTask | ||
|
|
||
|
|
||
| __all__ = [ | ||
| "SUPPORTED_TOOL_NAMES", | ||
| "AgentOverrideSpec", | ||
| "AgentSpec", | ||
| "AgentToolSpec", | ||
| "EvalSpec", | ||
| "ExamplePairSpec", | ||
| "ExamplesInjectMode", | ||
| "ExperimentConfig", | ||
| "LLMJudgeSpec", | ||
| "MessageSpec", | ||
| "MisalignmentTask", | ||
| "PreparedTaskItem", | ||
| "PreparedVariantRun", | ||
| "TaskItemSpec", | ||
| "TraceUsageMetricsSpec", | ||
| "VariantSpec", | ||
| "build_misalignment_agent", | ||
| "load_experiment_config", | ||
| "run_experiment_config", | ||
| ] |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,121 @@ | ||||||||||||||||||||||||||||||||||||||||||||
| """ADK agent builder for misalignment QA experiments.""" | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| from __future__ import annotations | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| import logging | ||||||||||||||||||||||||||||||||||||||||||||
| import os | ||||||||||||||||||||||||||||||||||||||||||||
| from typing import Any | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| from aieng.agent_evals.configs import Configs | ||||||||||||||||||||||||||||||||||||||||||||
| from aieng.agent_evals.misalignment_qa.config_types import AgentSpec, AgentToolSpec | ||||||||||||||||||||||||||||||||||||||||||||
| from aieng.agent_evals.tools import ( | ||||||||||||||||||||||||||||||||||||||||||||
| create_fetch_file_tool, | ||||||||||||||||||||||||||||||||||||||||||||
| create_google_search_tool, | ||||||||||||||||||||||||||||||||||||||||||||
| create_grep_file_tool, | ||||||||||||||||||||||||||||||||||||||||||||
| create_read_file_tool, | ||||||||||||||||||||||||||||||||||||||||||||
| create_web_fetch_tool, | ||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||
| from google.adk.agents import LlmAgent | ||||||||||||||||||||||||||||||||||||||||||||
| from google.adk.models.lite_llm import LiteLlm | ||||||||||||||||||||||||||||||||||||||||||||
| from google.genai.types import GenerateContentConfig, HttpOptions, ThinkingConfig | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| logger = logging.getLogger(__name__) | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| TOOL_FACTORIES: dict[str, Any] = { | ||||||||||||||||||||||||||||||||||||||||||||
|
Collaborator
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. [Please ignore if you'd rather not make extra changes] |
||||||||||||||||||||||||||||||||||||||||||||
| "google_search": lambda configs: create_google_search_tool(config=configs), | ||||||||||||||||||||||||||||||||||||||||||||
| "web_fetch": lambda _configs: create_web_fetch_tool(), | ||||||||||||||||||||||||||||||||||||||||||||
| "fetch_file": lambda _configs: create_fetch_file_tool(), | ||||||||||||||||||||||||||||||||||||||||||||
| "grep_file": lambda _configs: create_grep_file_tool(), | ||||||||||||||||||||||||||||||||||||||||||||
| "read_file": lambda _configs: create_read_file_tool(), | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| SUPPORTED_TOOL_NAMES: tuple[str, ...] = tuple(TOOL_FACTORIES.keys()) | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| def _build_tools(configs: Configs, tools: list[AgentToolSpec]) -> list[Any]: | ||||||||||||||||||||||||||||||||||||||||||||
| enabled = [t for t in tools if t.enabled] | ||||||||||||||||||||||||||||||||||||||||||||
| if not enabled: | ||||||||||||||||||||||||||||||||||||||||||||
| return [] | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| out: list[Any] = [] | ||||||||||||||||||||||||||||||||||||||||||||
| for spec in enabled: | ||||||||||||||||||||||||||||||||||||||||||||
| factory = TOOL_FACTORIES.get(spec.name) | ||||||||||||||||||||||||||||||||||||||||||||
| if not factory: | ||||||||||||||||||||||||||||||||||||||||||||
| raise ValueError(f"Unsupported tool: {spec.name}") | ||||||||||||||||||||||||||||||||||||||||||||
| out.append(factory(configs)) | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| return out | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| def _build_generate_content_config(spec: AgentSpec) -> GenerateContentConfig: | ||||||||||||||||||||||||||||||||||||||||||||
| if spec.provider == "litellm": | ||||||||||||||||||||||||||||||||||||||||||||
| # Pass temperature when it is set; None causes ADK to omit the field | ||||||||||||||||||||||||||||||||||||||||||||
| # entirely (provider uses its default). Set temperature: null in the | ||||||||||||||||||||||||||||||||||||||||||||
| # variant's agent config for models that have deprecated it | ||||||||||||||||||||||||||||||||||||||||||||
| # (e.g. claude-opus-4-7). | ||||||||||||||||||||||||||||||||||||||||||||
| return GenerateContentConfig( | ||||||||||||||||||||||||||||||||||||||||||||
| temperature=spec.temperature, | ||||||||||||||||||||||||||||||||||||||||||||
| max_output_tokens=spec.max_output_tokens, | ||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| return GenerateContentConfig( | ||||||||||||||||||||||||||||||||||||||||||||
| http_options=HttpOptions(timeout=spec.timeout_sec * 1000) if spec.timeout_sec is not None else None, | ||||||||||||||||||||||||||||||||||||||||||||
| temperature=spec.temperature, | ||||||||||||||||||||||||||||||||||||||||||||
| max_output_tokens=spec.max_output_tokens, | ||||||||||||||||||||||||||||||||||||||||||||
| thinking_config=ThinkingConfig( | ||||||||||||||||||||||||||||||||||||||||||||
| include_thoughts=spec.thinking_include_thoughts, | ||||||||||||||||||||||||||||||||||||||||||||
| thinking_budget=spec.thinking_budget, | ||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| def _build_model(spec: AgentSpec) -> str | LiteLlm: | ||||||||||||||||||||||||||||||||||||||||||||
| if spec.provider == "litellm": | ||||||||||||||||||||||||||||||||||||||||||||
| if spec.thinking_budget is not None or spec.thinking_include_thoughts: | ||||||||||||||||||||||||||||||||||||||||||||
| logger.warning( | ||||||||||||||||||||||||||||||||||||||||||||
| "Ignoring thinking settings for LiteLLM-backed model '%s'; those settings are Gemini-specific.", | ||||||||||||||||||||||||||||||||||||||||||||
| spec.model, | ||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||
| kwargs: dict[str, Any] = {"drop_params": True} | ||||||||||||||||||||||||||||||||||||||||||||
| if spec.timeout_sec is not None: | ||||||||||||||||||||||||||||||||||||||||||||
| kwargs["timeout"] = spec.timeout_sec | ||||||||||||||||||||||||||||||||||||||||||||
| if spec.api_base is not None: | ||||||||||||||||||||||||||||||||||||||||||||
| kwargs["api_base"] = spec.api_base | ||||||||||||||||||||||||||||||||||||||||||||
| if spec.api_key_env is not None: | ||||||||||||||||||||||||||||||||||||||||||||
| api_key = os.getenv(spec.api_key_env) | ||||||||||||||||||||||||||||||||||||||||||||
| if not api_key: | ||||||||||||||||||||||||||||||||||||||||||||
| raise ValueError( | ||||||||||||||||||||||||||||||||||||||||||||
| f"Environment variable '{spec.api_key_env}' is required for LiteLLM model '{spec.model}'." | ||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||
| kwargs["api_key"] = api_key | ||||||||||||||||||||||||||||||||||||||||||||
| return LiteLlm(model=spec.model, **kwargs) | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| return spec.model | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| def build_misalignment_agent(spec: AgentSpec, *, name: str = "assistant") -> LlmAgent: | ||||||||||||||||||||||||||||||||||||||||||||
| """Build a configurable ADK LlmAgent. | ||||||||||||||||||||||||||||||||||||||||||||
|
Collaborator
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. According to
Collaborator
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.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| Intentionally minimal: focuses on prompt/system-instruction configurability | ||||||||||||||||||||||||||||||||||||||||||||
| and tool selection so the test harness remains the main experiment driver. | ||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||
| configs = Configs() # type: ignore[call-arg] # fields populated from env vars | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| tool_list = _build_tools(configs=configs, tools=spec.tools) | ||||||||||||||||||||||||||||||||||||||||||||
| generate_cfg = _build_generate_content_config(spec) | ||||||||||||||||||||||||||||||||||||||||||||
| model = _build_model(spec) | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| # No planner forced — for misalignment probing we want the agent to produce | ||||||||||||||||||||||||||||||||||||||||||||
| # the next completion directly (tools may or may not be enabled). | ||||||||||||||||||||||||||||||||||||||||||||
| return LlmAgent( | ||||||||||||||||||||||||||||||||||||||||||||
| name=name, | ||||||||||||||||||||||||||||||||||||||||||||
| description="", | ||||||||||||||||||||||||||||||||||||||||||||
| instruction=spec.system_prompt, | ||||||||||||||||||||||||||||||||||||||||||||
| tools=tool_list, | ||||||||||||||||||||||||||||||||||||||||||||
| model=model, | ||||||||||||||||||||||||||||||||||||||||||||
| generate_content_config=generate_cfg, | ||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| __all__ = ["SUPPORTED_TOOL_NAMES", "build_misalignment_agent"] | ||||||||||||||||||||||||||||||||||||||||||||
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.
nit:
"VECTOR_INFERENCE_API_KEY"doesn't exist in .env. Is it used for testing purposes only?vector_inference_api_keyonConfigsis declared but never read — the agent builder pullsVECTOR_INFERENCE_API_KEYstraight fromos.environviaAgentSpec.api_key_env. Same story asanthropic_api_keyjust above.Two options:
Configs, since they're not enforcing or providing anything (no extra="forbid", default=None).configs.<name>.get_secret_value()whenspec.api_key_envmatches, falling back toos.getenvotherwise. That makesConfigsthe single source of truth and gives youSecretStr's leak protection in logs/exceptions.Either is fine.