Spaces:
Running
Running
File size: 3,760 Bytes
9c84f9d 3dfc93b 9c84f9d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | """`llm_completion` μ€ν
-- input_fields λ‘ μ μ λ©μμ§λ₯Ό λ§λ€μ΄ ν λ² νΈμΆ.
`single_step.py`(SingleStepPipeline) μμ λ‘μ§ μ΄λ (2026-08-10, λμ λμΌ).
λ²μ/μμ½μ²λΌ "μ
λ ₯ νλλ€ β μμ±λ¬Έ νλ" ννμ νμ€ν¬κ° μ΄λ€.
`pipeline: single_step` μ μΈμ μ΄ μ€ν
νλμ§λ¦¬ νμ΄νλΌμΈμΌλ‘ ν΄μλλ€.
"""
import logging
from typing import Any
from solar_eval.models.sample import EvalSample
from solar_eval.pipelines.pipeline import BaseStep, StepContext
from solar_eval.pipelines.registry import register_step
logger = logging.getLogger(__name__)
@register_step("llm_completion")
class LLMCompletionStep(BaseStep):
"""Single LLM call step. Used for translation and summarization."""
uses_model = True
async def run(self, sample: EvalSample, ctx: StepContext) -> None:
input_data = self._input_fields_dict(sample.input)
if ctx.messages:
# Structured messages mode: substitute {{field}} placeholders
resolved = self._resolve_messages(ctx.messages, input_data)
else:
# Legacy mode: system prompt + auto-built user message
user_content = self._build_user_message(input_data)
resolved = [
{"role": "system", "content": ctx.system_prompt},
{"role": "user", "content": user_content},
]
result = await ctx.provider.chat_completion(
messages=resolved,
model=self.config.get("model", ctx.model),
temperature=self.config.get("temperature", ctx.temperature),
max_tokens=self.config.get("max_tokens", ctx.max_tokens),
reasoning_effort=self.config.get("reasoning_effort", ctx.reasoning_effort),
)
ctx.text = result["content"]
ctx.add_usage(result.get("usage", {}))
sample.artifacts["think_content"] = result.get("think_content", "")
sample.artifacts["finish_reason"] = result.get("finish_reason", "stop")
def _input_fields_dict(self, sample_input: Any) -> dict[str, Any]:
"""`sample.input` μ {νλλͺ
: κ°} dict λ‘ μ κ·ννλ€.
λ¬λλ `task_config`μ `input_fields` μ μ²΄λ‘ λ§λ dict λ₯Ό κ·Έλλ‘
`sample.input` μ λ΄μ λκΈ΄λ€(λ¨μΌ νλλ λ€μ€ νλλ ). μ¬κΈ°μλ
κ·Έ κ΄λ‘λ₯Ό κ·Έλλ‘ λ°λ, λ€λ₯Έ shape μ΄ λ€μ΄μ€λ©΄ μ‘°μ©ν 무μνμ§ μκ³
λ°λ‘ μ€ν¨μν¨λ€.
"""
if sample_input is None:
return {}
if isinstance(sample_input, dict):
return sample_input
raise TypeError(
"LLMCompletionStep expects sample.input to be a dict of "
f"{{field: value}} (runner.py convention); got {type(sample_input)}"
)
def _resolve_messages(
self, messages: list[dict[str, str]], input_data: dict[str, Any]
) -> list[dict[str, str]]:
"""Substitute {{field_name}} placeholders in message content."""
resolved = []
for msg in messages:
content = msg["content"]
for field, value in input_data.items():
content = content.replace(f"{{{{{field}}}}}", str(value))
resolved.append({"role": msg["role"], "content": content})
return resolved
def _build_user_message(self, input_data: dict[str, Any]) -> str:
input_fields = self.env.input_fields
if len(input_fields) == 1:
return str(input_data.get(input_fields[0], ""))
# Multiple fields: format as labeled sections
parts = []
for field in input_fields:
value = input_data.get(field, "")
parts.append(f"{field}:\n{value}")
return "\n\n".join(parts)
|