dev-strender's picture
Replace v24-era demo with v34 pipeline demo (engine-vendored bundle)
9c84f9d verified
Raw History Blame Contribute Delete
4.77 kB
"""EvalSample โ€” ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰ ํ•œ ๊ฑด์„ ๋‹ด๋Š” ๋ ˆ์ฝ”๋“œ.
RAGAS ์˜ `EvalSample` ๊ฐœ๋…์„ ์ด ๋ ˆํฌ ํ•„๋“œ๋ช…์œผ๋กœ ์˜ฎ๊ธด ๊ฒƒ์ด๋‹ค. ๊ต์—ด ๋ฌธ๋งฅ์—์„œ
`user_input`/`response` ๊ฐ™์€ RAGAS ์ด๋ฆ„์€ ์–ด์ƒ‰ํ•ด์„œ ์šฐ๋ฆฌ์‹(`input`/`output`)์œผ๋กœ
๋ฐ”๊ฟจ๋‹ค (2026-08-09 ๊ฒฐ์ •, `.agents/01-plans/harness/2026-08-09-chosun-proofread-evalsample-migration.md` ยง9).
์ด ํŒŒ์ผ์€ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋‹จ๊ณ„ A ์‚ฐ์ถœ๋ฌผ์ด๋‹ค. ๋‹จ๊ณ„ C ์—์„œ `pipelines/*` ๊ฐ€, ๋‹จ๊ณ„ D/E ์—์„œ
`core/runner.py`ยท`evaluators/*` ๊ฐ€ ์ด ํด๋ž˜์Šค๋ฅผ ์‹ค์ œ๋กœ ์†Œ๋น„ํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ๋‹ค โ€” `input`/
`output`/`artifacts["step_outputs"]` ๋Š” ํŒŒ์ดํ”„๋ผ์ธ์ด ์ฑ„์šฐ๊ณ , ๋Ÿฌ๋„ˆ๊ฐ€ ์ €์žฅ ์ง์ „์—
๋ ˆ๊ฑฐ์‹œ 8+trace ํ‚ค dict ๋กœ ํŽผ์นœ๋‹ค(`to_record()` ์™€๋Š” ํ‚ค ์ด๋ฆ„์ด ๋‹ค๋ฅด๋‹ค โ€” ์ €์žฅ ์Šคํ‚ค๋งˆ
ํ•˜์œ„ ํ˜ธํ™˜ ๋•Œ๋ฌธ, `core/runner.py:build_eval_sample_from_result` ์ฐธ๊ณ ), ์ฑ„์ ๊ธฐ๋Š”
`required_fields` ๋กœ ์„ ์–ธํ•œ ํ•„๋“œ๊ฐ€ ์ฑ„์›Œ์กŒ๋Š”์ง€ ํ™•์ธํ•œ ๋’ค ์ด ์ƒ˜ํ”Œ์„ ๊ทธ๋Œ€๋กœ ๋ฐ›๋Š”๋‹ค.
`from_row`/`resolve_field_map` ์€ ์•„์ง ๋Ÿฌ๋„ˆ๊ฐ€ ๋ฐฐ์„ ํ•˜์ง€ ์•Š์•˜๋‹ค (์•Œ๋ ค์ง„ ํ•œ๊ณ„ โ€”
`input_fields` ๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ์ธ ํƒœ์Šคํฌ์—์„œ ์œ ๋„๋œ field_map ์ด ์ฒซ ํ•„๋“œ๋งŒ ๋‹ด๊ธฐ ๋•Œ๋ฌธ,
ยง5-C ๋‹จ๊ณ„ ๋‹ด๋‹น์ž ๋ฉ”๋ชจ ์ฐธ๊ณ ).
"""
from dataclasses import dataclass, field
from typing import Any
# field_map ์˜ value ๋กœ ์˜ฌ ์ˆ˜ ์žˆ๋Š” ๋‘ ํ˜•ํƒœ:
# - str: row ์˜ ์ปฌ๋Ÿผ๋ช… ํ•˜๋‚˜๋ฅผ ๊ทธ๋Œ€๋กœ ๊ฐ€๋ฆฌํ‚จ๋‹ค.
# - dict[str, str]: ์—ฌ๋Ÿฌ ์ปฌ๋Ÿผ์„ {์„œ๋ธŒํ‚ค: ์ปฌ๋Ÿผ๋ช…} ์œผ๋กœ ๋ฌถ์–ด ํ•ฉ์„ฑ ์ •๋‹ต(golden_fields)์„
# ๋งŒ๋“ ๋‹ค. `runner.py` ์˜ `golden_fields` ์ฒ˜๋ฆฌ์™€ ๋™์ผํ•œ ๊ทœ์น™์ด๋‹ค.
FieldMapValue = str | dict[str, str]
@dataclass
class EvalSample:
"""ํ‰๊ฐ€ ํŒŒ์ดํ”„๋ผ์ธ ํ•œ ์ƒ˜ํ”Œ์˜ ์ž…๋ ฅยท์ค‘๊ฐ„ ์‚ฐ์ถœ๋ฌผยท์ถœ๋ ฅ์„ ๋‹ด๋Š” ๋ ˆ์ฝ”๋“œ.
Attributes:
input: ๊ต์—ด์ด๋ฉด ์›๋ฌธ, RAG ๋ฉด ์งˆ๋ฌธ, MCQ ๋ฉด ๋ฌธํ•ญ+๋ณด๊ธฐ ๋“ฑ ํƒœ์Šคํฌ๋งˆ๋‹ค shape ์ด ๋‹ค๋ฅด๋‹ค.
contexts: RAG ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ๋ฆฌ์ŠคํŠธ. ๊ต์—ด/MCQ ๋Š” ์“ฐ์ง€ ์•Š์•„ None.
output: ํŒŒ์ดํ”„๋ผ์ธ์ด ์ฑ„์šด๋‹ค. **์Šคํ…๋งˆ๋‹ค ๋ฎ์–ด์“ด๋‹ค** โ€” ์ตœ์ข… ์Šคํ…์˜ ๊ฒฐ๊ณผ๋งŒ ๋‚จ๋Š”๋‹ค.
์Šคํ…๋ณ„ ์Šค๋ƒ…์ˆ์ด ํ•„์š”ํ•˜๋ฉด `artifacts["step_outputs"]` ๋ฅผ ๋ณธ๋‹ค.
reference: ์ •๋‹ต(golden). ๋‹จ์ผ ๊ฐ’์ด๊ฑฐ๋‚˜(golden_field), ์—ฌ๋Ÿฌ ์ปฌ๋Ÿผ์„ ๋ฌถ์€
dict(golden_fields) ์ผ ์ˆ˜ ์žˆ๋‹ค.
artifacts: ์ค‘๊ฐ„ ์‚ฐ์ถœ๋ฌผ ์ €์žฅ์†Œ. ๊ด€๋ก€์ƒ `artifacts["step_outputs"]` ๋Š”
{์Šคํ… ์ด๋ฆ„: ๊ทธ ์Šคํ… ์งํ›„์˜ output} ๋กœ ๋ˆ„์ ๋œ๋‹ค.
"""
input: Any = None
contexts: list[Any] | None = None
output: Any = None
reference: Any = None
artifacts: dict[str, Any] = field(default_factory=dict)
@classmethod
def from_row(cls, row: dict[str, Any], field_map: dict[str, FieldMapValue]) -> "EvalSample":
"""๋ฐ์ดํ„ฐ์…‹ ํ–‰ + field_map ์œผ๋กœ ์ƒ˜ํ”Œ์„ ๋งŒ๋“ ๋‹ค.
Args:
row: ๋ฐ์ดํ„ฐ์…‹ ํ•œ ํ–‰ (jsonl ํ•œ ์ค„์„ ํŒŒ์‹ฑํ•œ dict).
field_map: EvalSample ํ•„๋“œ๋ช…(`input`/`reference`/`contexts`) -> ๋ฐ์ดํ„ฐ์…‹
์ปฌ๋Ÿผ๋ช…(str) ๋˜๋Š” {์„œ๋ธŒํ‚ค: ์ปฌ๋Ÿผ๋ช…} dict. `core.project_loader.resolve_field_map`
์ด task ์„ค์ •์—์„œ ์ด ๊ฐ’์„ ์œ ๋„ํ•œ๋‹ค.
Returns:
field_map ์— ์žˆ๋Š” ํ‚ค๋งŒ ์ฑ„์›Œ์ง„ EvalSample (์—†๋Š” ํ‚ค๋Š” dataclass ๊ธฐ๋ณธ๊ฐ’ ์œ ์ง€).
Raises:
TypeError: field_map ์˜ value ๊ฐ€ str/dict ๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ (์กฐ์šฉํžˆ ๋ฌด์‹œํ•˜์ง€ ์•Š๋Š”๋‹ค).
"""
kwargs: dict[str, Any] = {}
for sample_field in ("input", "reference", "contexts"):
if sample_field not in field_map:
continue
resolved = _resolve_field_value(field_map[sample_field], row)
if sample_field == "contexts" and not isinstance(resolved, list):
resolved = [resolved]
kwargs[sample_field] = resolved
return cls(**kwargs)
def to_record(self) -> dict[str, Any]:
"""JsonlStore ์ €์žฅ์šฉ ์ง๋ ฌํ™”. artifacts ๋ฅผ ํฌํ•จํ•ด ํ‰ํ‰ํ•œ dict ๋กœ ํŽผ์นœ๋‹ค."""
return {
"input": self.input,
"contexts": self.contexts,
"output": self.output,
"reference": self.reference,
"artifacts": self.artifacts,
}
def _resolve_field_value(mapping: FieldMapValue, row: dict[str, Any]) -> Any:
"""field_map ์˜ value ํ•˜๋‚˜(str ๋˜๋Š” dict)๋ฅผ row ์—์„œ ์‹ค์ œ ๊ฐ’์œผ๋กœ ํ’€์–ด๋‚ธ๋‹ค."""
if isinstance(mapping, dict):
return {sub_key: row.get(column, "") for sub_key, column in mapping.items()}
if isinstance(mapping, str):
return row.get(mapping, "")
raise TypeError(
f"field_map value ๋Š” str ๋˜๋Š” dict[str, str] ์ด์–ด์•ผ ํ•œ๋‹ค: {mapping!r} ({type(mapping)})"
)