When using smaller LLMs (e.g., qwen3.5:4b) for resume evaluation, the model sometimes returns deductions.total as a negative value (e.g., -4 instead of 4). While semantically correct (deductions are subtractive), this violates the ge=0 constraint on the Deductions Pydantic model, causing a ValidationError that crashes the entire evaluation pipeline.
The Deductions model defines total with ge=0 and describes it as "stored as positive, applied as negative", but smaller LLMs don't reliably follow this convention.
Expected Behavior
The evaluation should complete successfully regardless of whether the LLM returns a positive or negative deductions value. A deduction of -4 and 4 should be treated as equivalent (4 points deducted).
Environment
| Component |
Version / Details |
| OS |
Windows 11 |
| Python |
3.11.3 |
| hiring-agent |
Commit 4db8655 (Merge PR #200) |
| pydantic |
2.11.7 |
| ollama (Python) |
0.5.1 |
| Ollama server |
Latest (with qwen3.5:4b model) |
| LLM model |
qwen3.5:4b via Ollama |
Steps to Reproduce
- Configure
.env to use Ollama with a smaller model:
LLM_PROVIDER=ollama
DEFAULT_MODEL=qwen3.5:4b
- Ensure Ollama is running with the
qwen3.5:4b model pulled:
- Run the scoring script on any resume PDF:
python score.py <path_to_resume.pdf>
- The evaluation completes the LLM calls successfully but crashes during Pydantic validation of the response.
Relevant Logs / Stack Trace
2026-06-29 18:53:45,579 - evaluator - 90 - evaluate_resume - ERROR - Error evaluating resume: 1 validation error for EvaluationData
deductions.total
Input should be greater than or equal to 0 [type=greater_than_equal, input_value=-4, input_type=int]
For further information visit https://errors.pydantic.dev/2.11/v/greater_than_equal
Traceback (most recent call last):
File "C:\Projects\hiring-agent\score.py", line 377, in <module>
main(pdf_path)
File "C:\Projects\hiring-agent\score.py", line 326, in main
score = _evaluate_resume(resume_data, github_data)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Projects\hiring-agent\score.py", line 184, in _evaluate_resume
evaluation_result = evaluator.evaluate_resume(resume_text)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Projects\hiring-agent\evaluator.py", line 85, in evaluate_resume
evaluation_data = EvaluationData(**evaluation_dict)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pydantic_core._pydantic_core.ValidationError: 1 validation error for EvaluationData
deductions.total
Input should be greater than or equal to 0 [type=greater_than_equal, input_value=-4, input_type=int]
For further information visit https://errors.pydantic.dev/2.11/v/greater_than_equal
The LLM returned valid JSON with "deductions": {"total": -4, "reasons": "..."}, but Pydantic rejected the negative value.
Root Cause
In evaluator.py, the raw LLM JSON response is parsed and passed directly to EvaluationData() without sanitizing the deductions value:
evaluation_dict = json.loads(response_text)
evaluation_data = EvaluationData(**evaluation_dict) # crashes if total < 0
When using smaller LLMs (e.g.,
qwen3.5:4b) for resume evaluation, the model sometimes returnsdeductions.totalas a negative value (e.g.,-4instead of4). While semantically correct (deductions are subtractive), this violates thege=0constraint on theDeductionsPydantic model, causing aValidationErrorthat crashes the entire evaluation pipeline.The
Deductionsmodel definestotalwithge=0and describes it as "stored as positive, applied as negative", but smaller LLMs don't reliably follow this convention.Expected Behavior
The evaluation should complete successfully regardless of whether the LLM returns a positive or negative deductions value. A deduction of
-4and4should be treated as equivalent (4 points deducted).Environment
4db8655(Merge PR #200)qwen3.5:4bmodel)qwen3.5:4bvia OllamaSteps to Reproduce
.envto use Ollama with a smaller model:qwen3.5:4bmodel pulled:Relevant Logs / Stack Trace
The LLM returned valid JSON with
"deductions": {"total": -4, "reasons": "..."}, but Pydantic rejected the negative value.Root Cause
In
evaluator.py, the raw LLM JSON response is parsed and passed directly toEvaluationData()without sanitizing the deductions value: