Skip to content

Commit aacc01f

Browse files
committed
add deprecated and proof that the LLM will retry
1 parent 5050320 commit aacc01f

2 files changed

Lines changed: 212 additions & 5 deletions

File tree

examples/og_test.ipynb

Lines changed: 198 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"cells": [
33
{
44
"cell_type": "code",
5-
"execution_count": 1,
5+
"execution_count": 11,
66
"id": "7fad2095",
77
"metadata": {},
88
"outputs": [],
@@ -16,9 +16,10 @@
1616
"import asyncio\n",
1717
"from datetime import datetime\n",
1818
"from typing import List, Optional\n",
19-
"from pydantic import BaseModel, Field\n",
19+
"from pydantic import BaseModel, Field, field_validator\n",
2020
"import base64\n",
2121
"import os\n",
22+
"from pydantic import validator\n",
2223
"\n",
2324
"\n",
2425
"# Example models for different use cases\n",
@@ -79,9 +80,57 @@
7980
" due_date: str\n",
8081
" estimated_hours: int\n",
8182
"\n",
82-
"# Example functions demonstrating different usage patterns\n"
83+
"# Example functions demonstrating different usage patterns\n",
84+
"\n",
85+
"\n",
86+
"class Name(BaseModel):\n",
87+
" first_name: str\n",
88+
"\n",
89+
" @field_validator(\"first_name\")\n",
90+
" @classmethod\n",
91+
" def validate_first_name(cls, value: str) -> str:\n",
92+
" if not value.endswith('abc'):\n",
93+
" raise ValueError(\"You must append 'abc' to the end of my name\")\n",
94+
" return value "
95+
]
96+
},
97+
{
98+
"cell_type": "code",
99+
"execution_count": 10,
100+
"id": "ea338493",
101+
"metadata": {},
102+
"outputs": [
103+
{
104+
"data": {
105+
"text/plain": [
106+
"Name(first_name='John Doeabc')"
107+
]
108+
},
109+
"execution_count": 10,
110+
"metadata": {},
111+
"output_type": "execute_result"
112+
}
113+
],
114+
"source": [
115+
"Name(first_name=\"John Doeabc\")"
83116
]
84117
},
118+
{
119+
"cell_type": "code",
120+
"execution_count": null,
121+
"id": "4813b35f",
122+
"metadata": {},
123+
"outputs": [],
124+
"source": []
125+
},
126+
{
127+
"cell_type": "code",
128+
"execution_count": null,
129+
"id": "ec503329",
130+
"metadata": {},
131+
"outputs": [],
132+
"source": []
133+
},
85134
{
86135
"cell_type": "code",
87136
"execution_count": 2,
@@ -2074,6 +2123,152 @@
20742123
"metadata": {},
20752124
"outputs": [],
20762125
"source": []
2126+
},
2127+
{
2128+
"cell_type": "code",
2129+
"execution_count": null,
2130+
"id": "b764df06",
2131+
"metadata": {},
2132+
"outputs": [],
2133+
"source": []
2134+
},
2135+
{
2136+
"cell_type": "markdown",
2137+
"id": "74e4e938",
2138+
"metadata": {},
2139+
"source": [
2140+
"### Test the LLM calls it again if it fails on the first try (for example validation issue)"
2141+
]
2142+
},
2143+
{
2144+
"cell_type": "code",
2145+
"execution_count": 14,
2146+
"id": "ca9a8b59",
2147+
"metadata": {},
2148+
"outputs": [
2149+
{
2150+
"name": "stderr",
2151+
"output_type": "stream",
2152+
"text": [
2153+
"Structured output validation failed for Name: Validation failed for Name. Please fix the following errors:\n",
2154+
"- Field 'first_name': Value error, You must append 'abc' to the end of my name\n",
2155+
"Structured output tool Name returned error status: error\n"
2156+
]
2157+
},
2158+
{
2159+
"name": "stdout",
2160+
"output_type": "stream",
2161+
"text": [
2162+
"inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result \n",
2163+
"inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result inside _validate_structured_output_result \n"
2164+
]
2165+
}
2166+
],
2167+
"source": [
2168+
"from strands.agent import Agent\n",
2169+
"class Name(BaseModel):\n",
2170+
" first_name: str\n",
2171+
"\n",
2172+
" @field_validator(\"first_name\")\n",
2173+
" @classmethod\n",
2174+
" def validate_first_name(cls, value: str) -> str:\n",
2175+
" if not value.endswith('abc'):\n",
2176+
" raise ValueError(\"You must append 'abc' to the end of my name\")\n",
2177+
" return value \n",
2178+
"\n",
2179+
"agent = Agent(callback_handler=None) \n",
2180+
"result = agent(\"Whats Aaron's name?\", output_type=Name)"
2181+
]
2182+
},
2183+
{
2184+
"cell_type": "code",
2185+
"execution_count": 15,
2186+
"id": "0b590625",
2187+
"metadata": {},
2188+
"outputs": [
2189+
{
2190+
"data": {
2191+
"text/plain": [
2192+
"AgentResult(stop_reason='tool_use', message={'role': 'assistant', 'content': [{'text': \"I see there's a validation requirement. Let me correct that:\"}, {'toolUse': {'toolUseId': 'tooluse_IuwQTcWYQNezNb7Y-LKt_A', 'name': 'Name', 'input': {'first_name': 'Aaronabc'}}}]}, metrics=EventLoopMetrics(cycle_count=2, tool_metrics={'Name': ToolMetrics(tool={'toolUseId': 'tooluse_IuwQTcWYQNezNb7Y-LKt_A', 'name': 'Name', 'input': {'first_name': 'Aaronabc'}}, call_count=2, success_count=1, error_count=1, total_time=0.002743959426879883)}, cycle_durations=[2.4125640392303467], traces=[<strands.telemetry.metrics.Trace object at 0x10bd58190>, <strands.telemetry.metrics.Trace object at 0x10bd58220>], accumulated_usage={'inputTokens': 921, 'outputTokens': 139, 'totalTokens': 1060}, accumulated_metrics={'latencyMs': 4217}), state={}, structured_output=Name(first_name='Aaronabc'))"
2193+
]
2194+
},
2195+
"execution_count": 15,
2196+
"metadata": {},
2197+
"output_type": "execute_result"
2198+
}
2199+
],
2200+
"source": [
2201+
"result"
2202+
]
2203+
},
2204+
{
2205+
"cell_type": "code",
2206+
"execution_count": 16,
2207+
"id": "1c8e761c",
2208+
"metadata": {},
2209+
"outputs": [
2210+
{
2211+
"data": {
2212+
"text/plain": [
2213+
"Name(first_name='Aaronabc')"
2214+
]
2215+
},
2216+
"execution_count": 16,
2217+
"metadata": {},
2218+
"output_type": "execute_result"
2219+
}
2220+
],
2221+
"source": [
2222+
"result.structured_output"
2223+
]
2224+
},
2225+
{
2226+
"cell_type": "code",
2227+
"execution_count": 17,
2228+
"id": "0b084666",
2229+
"metadata": {},
2230+
"outputs": [
2231+
{
2232+
"data": {
2233+
"text/plain": [
2234+
"[{'role': 'user', 'content': [{'text': \"Whats Aaron's name?\"}]},\n",
2235+
" {'role': 'assistant',\n",
2236+
" 'content': [{'text': \"I can help you extract Aaron's name using the available tool.\"},\n",
2237+
" {'toolUse': {'toolUseId': 'tooluse_Jz272gvUQqmLQZCttasupA',\n",
2238+
" 'name': 'Name',\n",
2239+
" 'input': {'first_name': 'Aaron'}}}]},\n",
2240+
" {'role': 'user',\n",
2241+
" 'content': [{'toolResult': {'toolUseId': 'tooluse_Jz272gvUQqmLQZCttasupA',\n",
2242+
" 'status': 'error',\n",
2243+
" 'content': [{'text': \"Validation failed for Name. Please fix the following errors:\\n- Field 'first_name': Value error, You must append 'abc' to the end of my name\"}]}}]},\n",
2244+
" {'role': 'assistant',\n",
2245+
" 'content': [{'text': \"I see there's a validation requirement. Let me correct that:\"},\n",
2246+
" {'toolUse': {'toolUseId': 'tooluse_IuwQTcWYQNezNb7Y-LKt_A',\n",
2247+
" 'name': 'Name',\n",
2248+
" 'input': {'first_name': 'Aaronabc'}}}]},\n",
2249+
" {'role': 'user',\n",
2250+
" 'content': [{'toolResult': {'toolUseId': 'tooluse_IuwQTcWYQNezNb7Y-LKt_A',\n",
2251+
" 'status': 'success',\n",
2252+
" 'content': [{'text': 'Successfully validated Name structured output'}],\n",
2253+
" '_validated_object': Name(first_name='Aaronabc')}}]}]"
2254+
]
2255+
},
2256+
"execution_count": 17,
2257+
"metadata": {},
2258+
"output_type": "execute_result"
2259+
}
2260+
],
2261+
"source": [
2262+
"agent.messages"
2263+
]
2264+
},
2265+
{
2266+
"cell_type": "code",
2267+
"execution_count": null,
2268+
"id": "88437e72",
2269+
"metadata": {},
2270+
"outputs": [],
2271+
"source": []
20772272
}
20782273
],
20792274
"metadata": {

src/strands/agent/agent.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
Union,
2828
cast,
2929
)
30-
30+
from typing_extensions import deprecated
3131
from opentelemetry import trace as trace_api
3232
from pydantic import BaseModel
3333

@@ -505,6 +505,12 @@ async def invoke_async(self, prompt: AgentInput = None, output_type: Optional[Ty
505505

506506
return cast(AgentResult, event["result"])
507507

508+
@deprecated(
509+
'Agent.structured_output method is deprecated.'
510+
' You should pass in `output_type` directly into the agent invocation.'
511+
' see the <LINK> for more details',
512+
category=None,
513+
)
508514
def structured_output(self, output_model: Type[T], prompt: AgentInput = None) -> T:
509515
"""This method allows you to get structured output from the agent.
510516
@@ -534,6 +540,12 @@ def execute() -> T:
534540
future = executor.submit(execute)
535541
return future.result()
536542

543+
@deprecated(
544+
'Agent.structured_output_async method is deprecated.'
545+
' You should pass in `output_type` directly into the agent invocation.'
546+
' see the <LINK> for more details',
547+
category=None,
548+
)
537549
async def structured_output_async(self, output_model: Type[T], prompt: AgentInput = None) -> T:
538550
"""This method allows you to get structured output from the agent.
539551
@@ -639,7 +651,7 @@ async def stream_async(
639651
"""
640652
callback_handler = kwargs.get("callback_handler", self.callback_handler)
641653

642-
# Resolve output schema (runtime override or agent default)
654+
# Resolve output schema (runtime override or agent default) TODO we should allow for halfway configuration. for example, the user should be able to define `output_mode` on the Agent level but `output_type` on the `output_mode`
643655
if output_schema is None:
644656
output_schema = self._resolve_output_schema(output_type, output_mode) or self.default_output_schema
645657

0 commit comments

Comments
 (0)