Skip to content

feat(evals): Update prompt iteration flow - #1080

Open
Ayush8923 wants to merge 2 commits into
mainfrom
feat/v2-prompt-iteration-flow
Open

feat(evals): Update prompt iteration flow#1080
Ayush8923 wants to merge 2 commits into
mainfrom
feat/v2-prompt-iteration-flow

Conversation

@Ayush8923

@Ayush8923 Ayush8923 commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Issue

Closes #1072

Summary

In this PR, adds a v2 prompt-iteration endpoint that generates prompt-improvement suggestions from the new three-metric judge results (Adherence to Ground Truth / Prompt / Knowledge Base — each a score + reasoning), instead of v1's cosine-similarity + correctness signal.

Built by reuse-and-branch on EvaluationRun.is_judge_run: the existing job / Celery / config-version-minting machinery is shared, and only the recommendation-prompt builder and callback shape differ per run type. The v1 endpoint and its behavior are left unchanged.

Checklist

Before submitting a pull request, please ensure that you mark these task.

  • Ran fastapi run --reload app/main.py or docker compose up in the repository root and test.
  • If you've fixed a bug or added code that is tested and has test cases.

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a v2 prompt-improvement endpoint for judged evaluation runs, typed recommendation callbacks, metric-aware LLM drafting, preserved v1 behavior, and route/worker tests covering validation, callbacks, redelivery, and metric handling.

Changes

V2 prompt improvement

Layer / File(s) Summary
API contract and routing
backend/app/models/evaluation.py, backend/app/api/routes/evaluations/prompt_improvement_v2.py, backend/app/api/main.py, backend/app/api/docs/..., docs/wiki/modules/evaluations.md
Adds the v2 endpoint, PromptRecommendationJobPublic, RecommendationTypeEnum.PROMPT, API registration, and corresponding documentation.
Validation and job lifecycle
backend/app/services/evaluations/prompt_improvement.py, backend/app/tests/api/routes/test_improve_prompt_v2.py
Enforces judged-run validation, selects v1/v2 payload shapes and drafting paths, and preserves callback shape during retries and failures.
Metric-aware drafting and worker verification
backend/app/services/evaluations/prompt_improvement.py, backend/app/tests/api/routes/test_improve_prompt_v2.py
Adds shared structured LLM handling and v2 drafting from metric scores and reasoning, with tests for callbacks, N/A metrics, non-judge runs, and redelivery.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested labels: enhancement

Suggested reviewers: akhileshnegi, prajna1999

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant PromptImprovementV2Route
  participant PromptImprovementService
  participant EvaluationRun
  participant LLM
  participant CallbackURL

  Client->>PromptImprovementV2Route: POST improve-prompt with callback_url
  PromptImprovementV2Route->>PromptImprovementService: enqueue with require_judge_run=true
  PromptImprovementService->>EvaluationRun: validate completed judged run and score trace
  PromptImprovementService-->>Client: 202 job handle
  PromptImprovementService->>LLM: draft prompt from metric scores and reasoning
  LLM-->>PromptImprovementService: structured prompt recommendation
  PromptImprovementService->>CallbackURL: POST APIResponse with PromptRecommendationJobPublic
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes implement the v2 prompt iteration endpoint, use judge scores and reasoning, update the prompt, and add extensible recommendation types.
Out of Scope Changes check ✅ Passed The added docs, route, models, service changes, and tests all align with the stated prompt-iteration update scope.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately reflects the main prompt-iteration changes, though it is broad.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/v2-prompt-iteration-flow

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Ayush8923 Ayush8923 self-assigned this Jul 24, 2026
@github-actions github-actions Bot changed the title feat(evals): v2 prompt iteration flow feat(evals): Update prompt iteration flow Jul 24, 2026
@github-actions

github-actions Bot commented Jul 24, 2026

Copy link
Copy Markdown

OpenAPI changes   🟢 1 non-breaking change

Tip

Safe to merge from an API-contract perspective.

Full changelog  ·  1
Method Path Change
🟢 POST /api/v2/evaluations/{evaluation_id}/improve-prompt endpoint added

main0fac46ff · generated by oasdiff

@codecov

codecov Bot commented Jul 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
backend/app/services/evaluations/prompt_improvement.py (2)

390-402: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Early failures on a v2 job emit the v1 error payload.

is_judge_run stays False until re-validation succeeds, so any failure before line 402 (re-validation raising, or a soft time limit) sends PromptImprovementJobPublic for a job the client requested via the v2 endpoint. Same root cause as the redelivery fallback: the judge flag isn't known/durable outside the happy path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/app/services/evaluations/prompt_improvement.py` around lines 390 -
402, Initialize the payload-version state from durable job/request data before
the try block, rather than defaulting is_judge_run to False. Update the early
failure and timeout callback paths around the prompt-improvement job so v2
requests consistently emit the v2 payload even when validate_improve_prompt
fails or run is not yet bound, while preserving the existing assignment from the
validated run when available.

644-654: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Re-raise Celery/timeouts before the catch-all in the LLM path.

SoftTimeLimitExceeded is defined as an Exception subclass, so the broad handler here masks the task’s soft-time_limit control flow and converts it into prompt_generation_failed instead of reaching the worker’s timeout branch. Re-raise SoftTimeLimitExceeded and Timeout before except Exception.

🛡️ Proposed fix
+    except (Timeout, SoftTimeLimitExceeded):
+        # Let the worker's timeout branch own these; they are not LLM faults.
+        raise
+
     except Exception as exc:
         logger.error(
             f"[_call_prompt_drafting_llm] [KAAPI] Unexpected error during LLM call "
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/app/services/evaluations/prompt_improvement.py` around lines 644 -
654, Update the exception handling around the LLM call to add dedicated handlers
before the catch-all `except Exception` in the prompt-generation path. Re-raise
both Celery `SoftTimeLimitExceeded` and the relevant `Timeout` exception
unchanged so the worker timeout branch receives them; preserve the existing
logging and `RuntimeError` conversion for other unexpected exceptions.
🧹 Nitpick comments (6)
backend/app/tests/api/routes/test_improve_prompt_v2.py (2)

26-26: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Nit: import Iterator from collections.abc.

Ruff UP035; typing.Iterator is deprecated.

♻️ Proposed tweak
-from typing import Any, Iterator
+from collections.abc import Iterator
+from typing import Any
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/app/tests/api/routes/test_improve_prompt_v2.py` at line 26, Update
the import in test_improve_prompt_v2.py to import Iterator from collections.abc
instead of typing, while retaining Any from typing.

Source: Linters/SAST tools


509-518: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Missing coverage: the v2 failure-path callback shape.

Every worker test exercises the success path. A test where drafting raises on a judge run would pin down which payload model the error callback emits — the gap flagged at prompt_improvement.py lines 390-402. Want me to draft it?

Also applies to: 589-627

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/app/tests/api/routes/test_improve_prompt_v2.py` around lines 509 -
518, Add a TestV2Worker test covering a judge-run failure in
execute_prompt_improvement: make the drafting step raise, execute the worker
with a pending PROMPT_IMPROVEMENT job, and assert the failure callback uses the
expected v2 payload model and error details. Follow the existing success-path
test setup and assertions.
backend/app/api/routes/evaluations/prompt_improvement_v2.py (1)

37-40: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Nit: chain the original exception.

raise HTTPException(...) from exc preserves the cause for tracebacks; the detail string already carries the message, so this is purely for debuggability.

♻️ Proposed tweak
     except ValueError as exc:
-        raise HTTPException(status_code=422, detail=f"invalid_callback_url: {exc}")
+        raise HTTPException(
+            status_code=422, detail=f"invalid_callback_url: {exc}"
+        ) from exc
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/app/api/routes/evaluations/prompt_improvement_v2.py` around lines 37
- 40, Update the exception handling around validate_callback_url in the request
flow to raise HTTPException from the caught ValueError using explicit exception
chaining, while preserving the existing 422 status and detail message.
backend/app/services/evaluations/prompt_improvement.py (3)

246-276: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Optional: narrow the return annotation.

-> dict[str, Any] is more precise than bare dict (same applies to execute_prompt_improvement). Branch logic itself is correct and the v1 shape is preserved.

As per coding guidelines: "provide narrow type hints for every function parameter and return value".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/app/services/evaluations/prompt_improvement.py` around lines 246 -
276, Update the return annotations for the affected callback-builder function
and execute_prompt_improvement to use dict[str, Any] instead of bare dict,
importing Any if needed. Keep the existing branch behavior and response shapes
unchanged.

Source: Coding guidelines


390-402: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

v1/v2 callback shape is derived at runtime instead of being durable, so two paths can emit the wrong model. is_judge_run is only known after a successful re-read/re-validation of the evaluation run; whenever that read is unavailable, the callback silently degrades to the v1 PromptImprovementJobPublic for a job the client submitted through the v2 endpoint. Persisting the flag (or recommendation_type) on the Job row at enqueue time fixes both sites and removes a query.

  • backend/app/services/evaluations/prompt_improvement.py#L390-L402: seed is_judge_run from the persisted job record before the try, so timeout and pre-validation failures emit the v2 error payload.
  • backend/app/services/evaluations/prompt_improvement.py#L357-L379: read the persisted flag instead of bool(redelivery_run and redelivery_run.is_judge_run), so a deleted/moved run can't flip the redelivered callback back to the v1 shape.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/app/services/evaluations/prompt_improvement.py` around lines 390 -
402, Persist the v1/v2 payload decision on the Job at enqueue time and reuse it
for callbacks. In backend/app/services/evaluations/prompt_improvement.py lines
390-402, initialize is_judge_run from the persisted job record before the try
block, while retaining re-validation updates when available; in lines 357-379,
derive the redelivery callback shape from that persisted flag instead of
redelivery_run.is_judge_run, so deleted or moved runs cannot change the payload
type.

543-552: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Nit: "instructions" is a repeated literal.

The same key is written at lines 413, 438, and 549. A module constant would keep the three sites in sync.

As per coding guidelines: "Do not use magic values; extract repeated literals into constants, enums, or settings".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/app/services/evaluations/prompt_improvement.py` around lines 543 -
552, Extract the repeated "instructions" key used in the prompt-improvement
logic into a module-level constant, then replace the literals at the sites
around lines 413, 438, and in _target_config_from_params with that constant.
Keep the existing filtering and rendering behavior unchanged.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/app/api/docs/evaluation/improve_prompt_v2.md`:
- Around line 25-27: Update the improve-prompt error documentation near the
existing source_config_unavailable entry to also list the 422 variant returned
when the run has null config_id or config_version references, while preserving
the existing 409 deletion case.

In `@backend/app/services/evaluations/prompt_improvement.py`:
- Around line 704-735: Cap the evaluation traces embedded by the prompt-building
flow before constructing user_message_text, selecting only the N lowest-scoring
rows based on the prompt and ground-truth metrics while ignoring unscoreable
values. Serialize the capped collection instead of the full traces in the
`Evaluation traces` section, and preserve the existing task instructions and
scoring behavior.

---

Outside diff comments:
In `@backend/app/services/evaluations/prompt_improvement.py`:
- Around line 390-402: Initialize the payload-version state from durable
job/request data before the try block, rather than defaulting is_judge_run to
False. Update the early failure and timeout callback paths around the
prompt-improvement job so v2 requests consistently emit the v2 payload even when
validate_improve_prompt fails or run is not yet bound, while preserving the
existing assignment from the validated run when available.
- Around line 644-654: Update the exception handling around the LLM call to add
dedicated handlers before the catch-all `except Exception` in the
prompt-generation path. Re-raise both Celery `SoftTimeLimitExceeded` and the
relevant `Timeout` exception unchanged so the worker timeout branch receives
them; preserve the existing logging and `RuntimeError` conversion for other
unexpected exceptions.

---

Nitpick comments:
In `@backend/app/api/routes/evaluations/prompt_improvement_v2.py`:
- Around line 37-40: Update the exception handling around validate_callback_url
in the request flow to raise HTTPException from the caught ValueError using
explicit exception chaining, while preserving the existing 422 status and detail
message.

In `@backend/app/services/evaluations/prompt_improvement.py`:
- Around line 246-276: Update the return annotations for the affected
callback-builder function and execute_prompt_improvement to use dict[str, Any]
instead of bare dict, importing Any if needed. Keep the existing branch behavior
and response shapes unchanged.
- Around line 390-402: Persist the v1/v2 payload decision on the Job at enqueue
time and reuse it for callbacks. In
backend/app/services/evaluations/prompt_improvement.py lines 390-402, initialize
is_judge_run from the persisted job record before the try block, while retaining
re-validation updates when available; in lines 357-379, derive the redelivery
callback shape from that persisted flag instead of redelivery_run.is_judge_run,
so deleted or moved runs cannot change the payload type.
- Around line 543-552: Extract the repeated "instructions" key used in the
prompt-improvement logic into a module-level constant, then replace the literals
at the sites around lines 413, 438, and in _target_config_from_params with that
constant. Keep the existing filtering and rendering behavior unchanged.

In `@backend/app/tests/api/routes/test_improve_prompt_v2.py`:
- Line 26: Update the import in test_improve_prompt_v2.py to import Iterator
from collections.abc instead of typing, while retaining Any from typing.
- Around line 509-518: Add a TestV2Worker test covering a judge-run failure in
execute_prompt_improvement: make the drafting step raise, execute the worker
with a pending PROMPT_IMPROVEMENT job, and assert the failure callback uses the
expected v2 payload model and error details. Follow the existing success-path
test setup and assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ced558cd-352c-4f1e-b980-5b315b938a1b

📥 Commits

Reviewing files that changed from the base of the PR and between e0c64fc and dccc7a3.

📒 Files selected for processing (7)
  • backend/app/api/docs/evaluation/improve_prompt_v2.md
  • backend/app/api/main.py
  • backend/app/api/routes/evaluations/prompt_improvement_v2.py
  • backend/app/models/evaluation.py
  • backend/app/services/evaluations/prompt_improvement.py
  • backend/app/tests/api/routes/test_improve_prompt_v2.py
  • docs/wiki/modules/evaluations.md

Comment thread backend/app/api/docs/evaluation/improve_prompt_v2.md
Comment thread backend/app/services/evaluations/prompt_improvement.py
@Ayush8923
Ayush8923 requested a review from AkhileshNegi July 27, 2026 03:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Evaluation: Update prompt iteration flow

1 participant