Setting the file. One moment.
Reward Function Source Template · AWS AI ML · aws/agent-toolkit-for-aws · Skills Docs
Issue No. 14 · AWS AI ML
↖ Back to the coverMessaging And Streaming Skills
Migration And Modernization Skills
Networking And Content Delivery Skills
Security And Identity Skills
Web And Mobile Development
120 chapters · 648 min
Reward Function Source Template ContentsBack to the top of the page 10
Setup DevOps Agent
24.7
Code Output Guide · references
RDS Oracle
references/model-evaluation/scripts/ reward_function_source_template.py
Python · 246 lines · 9 KB
# Add any other imports your use case requires
14
15 # ========================================================================================
16 # NOTE : INITIAL SUGGESTION ONLY - MUST BE CUSTOMIZED
17 #
18 # YOU MUST:
19 # 1. Review and update each section per YOUR use case
20 # 2. Customize the logic for YOUR SPECIFIC requirements
21 # 3. Replace example values (field names, thresholds, etc.) with your actual values
22 # 4. Test thoroughly before using
23 #
24 # DO NOT use this code as-is. It will not work until you uncomment and customize it.
25 # =========================================================================================
26
27
28 # =========================================================================================
29 # SECTION 1: Helper function 1
30 # =========================================================================================
31 # TODO : UPDATE or REMOVE the helper function as per YOUR use case
32 # Note the below lines of code are examples and will not work for your use case
33 # You MUST update them to match YOUR use case
34 def extract_number (text: str ) -> Optional[ float ]:
35 """
36 Extract numerical answer from text.
37 Looks for numbers after answer keywords, or returns the last number found.
38
39 Args:
40 text: Text containing a numerical answer
41
42 Returns:
43 Extracted number as float, or None if no number found
44 """
45 if not text:
46 return None
47
48 # Try to find numbers after common answer keywords
49 answer_patterns = [
50 r " (?: equals | is | answer is | result is | = )\s * ( - ? \d + \. ? \d * ) " ,
51 r " (?: answer | result | solution ) : \s * ( - ? \d + \. ? \d * ) " ,
52 ]
53
54 for pattern in answer_patterns:
55 match = re.search(pattern, text, re. IGNORECASE )
56 if match:
57 try :
58 return float (match.group( 1 ))
59 except ValueError :
60 pass
61
62 # Fallback: find all numbers and return the last one (likely the answer)
63 pattern = r "- ? \d + \. ? \d * "
64 matches = re.findall(pattern, text)
65
66 if matches:
67 try :
68 return float (matches[ - 1 ]) # Return last number instead of first
69 except ValueError :
70 return None
71
72 return None
73
74
75 # =========================================================================================
76 # SECTION 2: Helper function 2
77 # =========================================================================================
78 # TODO : UPDATE or REMOVE the helper function as per YOUR use case
79 # Note the below lines of code are examples and will not work for your use case
80 # You MUST update them to match YOUR use case
81 def compute_reasoning_quality (response: str ) -> float :
82 """
83 Compute reasoning quality score based on response characteristics.
84 This is a simple heuristic - customize based on your needs.
85
86 Args:
87 response: The model's response text
88
89 Returns:
90 Quality score between 0.0 and 1.0
91 """
92 if not response:
93 return 0.0
94
95 score = 0.0
96
97 # Check for reasoning indicators (customize these for your use case)
98 reasoning_indicators = [
99 "because" ,
100 "therefore" ,
101 "thus" ,
102 "since" ,
103 "so" ,
104 "first" ,
105 "second" ,
106 "then" ,
107 "finally" ,
108 "step" ,
109 "calculate" ,
110 "compute" ,
111 "equals" ,
112 ]
113
114 response_lower = response.lower()
115
116 # Award points for reasoning indicators (max 0.55)
117 indicator_count = sum ( 1 for indicator in reasoning_indicators if indicator in response_lower)
118 score += min (indicator_count * 0.11 , 0.55 )
119
120 # Award points for response length (indicates detailed reasoning, max 0.25)
121 if len (response) > 30 :
122 score += 0.05
123 if len (response) > 60 :
124 score += 0.1
125 if len (response) > 120 :
126 score += 0.1
127
128 # Award points for structured response (max 0.2)
129 if " \n " in response or "." in response:
130 score += 0.2
131
132 return min (score, 1.0 )
133
134
135 # =========================================================================================
136 # SECTION 3: Sample reward function
137 # =========================================================================================
138 # TODO : UPDATE or REMOVE the reward function as per YOUR use case
139 # Note the below lines of code are examples and will not work for your use case
140 # You MUST update them to match YOUR use case
141 def reward_function (sample: Dict[ str , Any], index: int ) -> Dict[ str , Any]:
142 """
143 Args:
144 sample: Dictionary containing messages and reference_answer
145 index: Sample index in batch
146
147 Returns:
148 Dictionary with reward scores and metrics
149 """
150 # ========================================================================
151 # SECTION 4: Parse input
152 # ========================================================================
153 # TODO : UPDATE logic to parse the input as per YOUR use case
154 # Note the below lines of code are examples and will not work for your use case
155 # You MUST update them to match YOUR use case
156 #
157 # The evaluation framework sends each sample with these fields:
158 # model_response: str — the model's generated text
159 # query: str — the original prompt sent to the model
160 # response: str — ground truth from the dataset
161 # reference_answer: dict {"text": str} OR str — ground truth (type varies)
162 # id: str — unique sample identifier
163 response = sample.get( "model_response" , "" )
164 question = sample.get( "query" , "" )
165
166 # reference_answer may be a dict or a plain string — handle both
167 ref_answer = sample.get( "reference_answer" , "" )
168 if isinstance (ref_answer, dict ):
169 reference_answer = ref_answer.get( "text" , "" ) or sample.get( "response" , "" )
170 else :
171 reference_answer = ref_answer or sample.get( "response" , "" )
172
173 # Extract numerical answers
174 predicted = extract_number(response)
175 expected = extract_number(reference_answer)
176
177 # Compute metrics
178 exact_match = 0.0
179 answer_present = 0.0
180 reasoning_quality = compute_reasoning_quality(response)
181
182 if predicted is not None and expected is not None :
183 exact_match = 1.0 if abs (predicted - expected) < 1e-6 else 0.0
184 answer_present = 1.0
185
186 # ========================================================================
187 # SECTION 5: Compute reward scores
188 # ========================================================================
189 # TODO : UPDATE logic to compute aggregate score
190 # Note the below lines of code are examples and will not work for your use case
191 # You MUST update them to match YOUR use case
192 # Aggregate reward computation
193 aggregate_reward = 0.7 * exact_match + 0.3 * reasoning_quality
194
195 # ========================================================================
196 # SECTION 6: Form the metrics list
197 # ========================================================================
198 # TODO : UPDATE logic to compute metrics list
199 # Note the below lines of code are examples and will not work for your use case
200 # You MUST update them to match YOUR use case
201 metrics = [
202 { "name" : "exact_match" , "value" : float (exact_match), "type" : "Reward" },
203 { "name" : "answer_present" , "value" : float (answer_present), "type" : "Metric" },
204 { "name" : "reasoning_quality" , "value" : float (reasoning_quality), "type" : "Metric" },
205 ]
206
207 # ========================================================================
208 # SECTION 7: Return output
209 # ========================================================================
210 # TODO : UPDATE the return statement to return YOUR outout
211 # UPDATE the key before creating the evaluator
212 # Note the below lines of code are examples and will not work for your use case
213 # You MUST update them to match YOUR use case
214
215 return {
216 "id" : str (
217 sample.get( "id" , f "sample- { index :03d} " )
218 ), # Use the id from the evaluation framework
219 "aggregate_reward_score" : float (aggregate_reward),
220 "metrics_list" : metrics,
221 }
222
223
224 def lambda_handler (event: Dict[ str , Any], context: Any) -> Dict[ str , Any]:
225 """
226 AWS Lambda Handler for reward function.
227 The evaluation framework invokes this once per sample.
228 Event is a list containing a single sample dict.
229 """
230 try :
231 # The framework sends a list with one sample: [{...}]
232 samples = event if isinstance (event, list ) else [event]
233 sample = samples[ 0 ]
234
235 result = reward_function(sample, 0 )
236
237 # body MUST be a JSON string (not a parsed list).
238 # The container rejects lists with:
239 # "Lambda response body must be a JSON string, got <class 'list'>"
240 return {
241 "statusCode" : 200 ,
242 "headers" : { "Content-Type" : "application/json" },
243 "body" : json.dumps([result]),
244 }
245 except Exception as e:
246 return { "statusCode" : 400 , "body" : json.dumps({ "error" : str (e)})}