From 662442752882d4d52dbaf5967c8ee9e25475f093 Mon Sep 17 00:00:00 2001 From: liubiren Date: Fri, 18 Sep 2026 20:10:07 +0800 Subject: [PATCH] 1 --- .../workshop/bank_customer_service.py | 100 ++++++++++-------- agent/database.db | Bin 266240 -> 303104 bytes 2 files changed, 54 insertions(+), 46 deletions(-) diff --git a/agent/application/workshop/bank_customer_service.py b/agent/application/workshop/bank_customer_service.py index a4dc955..6ff2c04 100644 --- a/agent/application/workshop/bank_customer_service.py +++ b/agent/application/workshop/bank_customer_service.py @@ -4,6 +4,7 @@ """ from typing import Any, AsyncGenerator +from asyncpg import Pool from pydantic import BaseModel, Field from pydantic_ai import ( Agent, @@ -14,21 +15,13 @@ from pydantic_ai import ( RunUsage, UsageLimits, ) -from pydantic_ai.messages import ( - AgentStreamEvent, - PartStartEvent, - ToolCallPart, - FunctionToolResultEvent, - ToolReturnPart, -) -from pydantic_ai.run import AgentRunResultEvent, AgentRunResult +from pydantic_ai.messages import AgentStreamEvent +from pydantic_ai.run import AgentRunResultEvent from application.workshop.models import ( DEEPSEEK_V4_FLASH_MODEL, DEEPSEEK_V4_FLASH_MODEL_SETTINGS, ) -from asyncpg import Pool -from application.workshop.events import AgentRuntimeEvent class Deps(BaseModel): @@ -42,14 +35,6 @@ class Deps(BaseModel): connection_pool: Pool = Field(..., description="连接池") -class Output(BaseModel): - """ - 输出类 - """ - - response: str = Field(..., description="客服应答") - - # 账户上下文能力 account_context = Capability[Deps]( id="account-context", @@ -89,15 +74,61 @@ async def query_account_balance(ctx: RunContext[Deps]) -> str: # 智能体 -agent = Agent[Deps, Output]( +agent = Agent[Deps, str]( model=DEEPSEEK_V4_FLASH_MODEL, model_settings=DEEPSEEK_V4_FLASH_MODEL_SETTINGS, deps_type=Deps, - output_type=Output, - instructions="你是我方银行的客服智能体,为客户提供客服应答。", + output_type=str, # 若输出类型为 str,则智能体输出结果时不进行输出类型校验。若定义输出类型,需考虑处理相应事件 + instructions="你是我方银行的客服智能体,为客户提供客服应答。", # 优先使用 instructions capabilities=[account_context], ) +""" +此为设置输出类型为 Output,智能体输出结果时需校验输出类型,同工具调用: +PartStartEvent(index=0, part=ToolCallPart(tool_name='final_result', args='', tool_call_id='call_3ab0ed20b1114fa0be726723')) +FinalResultEvent(tool_name='final_result', tool_call_id='call_3ab0ed20b1114fa0be726723') +PartDeltaEvent(index=0, delta=ToolCallPartDelta(args_delta='', tool_call_id='call_3ab0ed20b1114fa0be726723')) +PartDeltaEvent(index=0, delta=ToolCallPartDelta(args_delta='{', tool_call_id='call_3ab0ed20b1114fa0be726723')) +PartDeltaEvent (index=0, delta=ToolCallPartDelta (args_delta='"response": " 您好 ', tool_call_id='call_3ab0ed20b1114fa0be726723')) +PartDeltaEvent (index=0, delta=ToolCallPartDelta (args_delta=',刘 ', tool_call_id='call_3ab0ed20b1114fa0be726723')) +PartDeltaEvent (index=0, delta=ToolCallPartDelta (args_delta=' 弼仁 ', tool_call_id='call_3ab0ed20b1114fa0be726723')) +PartDeltaEvent (index=0, delta=ToolCallPartDelta (args_delta=' 先生。', tool_call_id='call_3ab0ed20b1114fa0be726723')) +PartDeltaEvent (index=0, delta=ToolCallPartDelta (args_delta=' 您账户 ', tool_call_id='call_3ab0ed20b1114fa0be726723')) +PartDeltaEvent (index=0, delta=ToolCallPartDelta (args_delta=' 的 ', tool_call_id='call_3ab0ed20b1114fa0be726723')) +PartDeltaEvent (index=0, delta=ToolCallPartDelta (args_delta=' 当前余额 ', tool_call_id='call_3ab0ed20b1114fa0be726723')) +PartDeltaEvent (index=0, delta=ToolCallPartDelta (args_delta=' 为 **', tool_call_id='call_3ab0ed20b1114fa0be726723')) +PartDeltaEvent(index=0, delta=ToolCallPartDelta(args_delta='9.', tool_call_id='call_3ab0ed20b1114fa0be726723')) +PartDeltaEvent (index=0, delta=ToolCallPartDelta (args_delta='99 元 ', tool_call_id='call_3ab0ed20b1114fa0be726723')) +PartDeltaEvent(index=0, delta=ToolCallPartDelta(args_delta='**。', tool_call_id='call_3ab0ed20b1114fa0be726723')) +PartDeltaEvent (index=0, delta=ToolCallPartDelta (args_delta=' 请问还有什么 ', tool_call_id='call_3ab0ed20b1114fa0be726723')) +PartDeltaEvent (index=0, delta=ToolCallPartDelta (args_delta=' 可以帮 ', tool_call_id='call_3ab0ed20b1114fa0be726723')) +PartDeltaEvent (index=0, delta=ToolCallPartDelta (args_delta=' 您的 ', tool_call_id='call_3ab0ed20b1114fa0be726723')) +PartDeltaEvent (index=0, delta=ToolCallPartDelta (args_delta=' 吗?"}', tool_call_id='call_3ab0ed20b1114fa0be726723')) +PartEndEvent (index=0, part=ToolCallPart (tool_name='final_result', args='{"response": " 您好,刘弼仁先生。您账户的当前余额为 **9.99 元**。请问还有什么可以帮您的吗?"}', tool_call_id='call_3ab0ed20b1114fa0be726723')) +OutputToolCallEvent (part=ToolCallPart (tool_name='final_result', args='{"response": " 您好,刘弼仁先生。您账户的当前余额为 **9.99 元**。请问还有什么可以帮您的吗?"}', tool_call_id='call_3ab0ed20b1114fa0be726723'), args_valid=True) +OutputToolResultEvent(part=ToolReturnPart(tool_name='final_result', content='Final result processed.', tool_call_id='call_3ab0ed20b1114fa0be726723', timestamp=datetime.datetime(2026, 9, 17, 10, 34, 0, 799329, tzinfo=datetime.timezone.utc))) + +此为设置输出类型为 str,智能体输出结果时不进行输出类型校验: +PartStartEvent(index=0, part=TextPart(content='您好')) +FinalResultEvent(tool_name=None, tool_call_id=None) +PartDeltaEvent(index=0, delta=TextPartDelta(content_delta=',刘')) +PartDeltaEvent(index=0, delta=TextPartDelta(content_delta='弼仁')) +PartDeltaEvent(index=0, delta=TextPartDelta(content_delta='先生。')) +PartDeltaEvent(index=0, delta=TextPartDelta(content_delta='您账户')) +PartDeltaEvent(index=0, delta=TextPartDelta(content_delta='的')) +PartDeltaEvent(index=0, delta=TextPartDelta(content_delta='当前余额')) +PartDeltaEvent(index=0, delta=TextPartDelta(content_delta='为 **')) +PartDeltaEvent(index=0, delta=TextPartDelta(content_delta='9.')) +PartDeltaEvent(index=0, delta=TextPartDelta(content_delta='99')) +PartDeltaEvent(index=0, delta=TextPartDelta(content_delta='元**')) +PartDeltaEvent(index=0, delta=TextPartDelta(content_delta='。请问')) +PartDeltaEvent(index=0, delta=TextPartDelta(content_delta='还有什么')) +PartDeltaEvent(index=0, delta=TextPartDelta(content_delta='可以帮')) +PartDeltaEvent(index=0, delta=TextPartDelta(content_delta='您的吗')) +PartDeltaEvent(index=0, delta=TextPartDelta(content_delta='?')) +PartEndEvent(index=0, part=TextPart(content='您好,刘弼仁先生。您账户的当前余额为 **9.99元**。请问还有什么可以帮您的吗?')) +""" + async def run_stream_events( deps: Any, @@ -106,7 +137,7 @@ async def run_stream_events( usage: RunUsage, usage_limits: UsageLimits | None = None, deferred_tool_results: DeferredToolResults | None = None, -) -> AsyncGenerator[AgentStreamEvent | AgentRunResultEvent[Output] | None,]: +) -> AsyncGenerator[AgentStreamEvent | AgentRunResultEvent[str] | None,]: """ 运行并流式输出事件 """ @@ -122,28 +153,5 @@ async def run_stream_events( deferred_tool_results=deferred_tool_results, ) as events: async for event in events: - match event: - case PartStartEvent( - part=part, - ): - match part: - case ToolCallPart(tool_name=tool_name): - if tool_name.startswith("final_result"): - continue - - case FunctionToolResultEvent(part): - match part: - case ToolReturnPart( - tool_name=tool_name, - ): - if tool_name.startswith("final_result"): - continue - - case AgentRunResultEvent(result=result): - match result: - case AgentRunResult(output=output): - match output: - case Output(response=response): - yield AgentRuntimeEvent(content=response) - + print(event) yield event diff --git a/agent/database.db b/agent/database.db index c83cc2545ef143d54ef0cbd272020dde554e32d1..4df905af09e404fe246ff032bb5ecdf1657bfb4d 100644 GIT binary patch delta 7624 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 delta 1338 zcmcJNU1(fI7>4)koNeO%CTU_~W7}|=APYI`%=w>n6WtrZ*0#196%yReIde`MyY8Co z#x@CUQo1TckqrkOh(f(+3q_(Si`jrhTkyggu@bS~h>aMn1&PI=P=D}bYhy)vS%#U5 zkN0D~=X>AD^G%a)HU>{J{g`3)dk9adgHi_4SOmF zpWnr^auV#^Xy)?=ZJKeigZmE@g=B6dn{}7QI(r3+WV0FDCe+3fEIqp+*w?o;U4NXE zwn0Q7u}v&O=smh-SR%1hDq>0%tU=Sl#7&R2L`q#Zo9yE)Z0UQ@>0T{9#UlwpHuN>u z&9Xh9*^g9qb{vem?+F@UD?ieuy3~WrOMM^jECHPU-Ily zjEjfYHr^f^^(bgBFZYKy@A|9#A#mm-sP`SK*3E%G?+^2l8DFdr zor~^>%y=#L_#b=oiFlx|Z@zuq9*Ihhs4F@Z4T_Pd$VfJ!g^-HnbG{7%vLs4XWEre+74)`v<_?c$h-KwRa>a~EvLt8OjI4rfZMI`O6j9Z2 zWJ@u0#~_GO%|Pthb#TP5C^zzTVwP)Sr&{^XY5=u)m4v2Zj5SvN1C;9_POd>H?DJm% z?j*89h#^a&qj-x`EL|0etSh2nAgWVDsH!?F@f%3oX~f-Qe5&kabvvB$52Hn4K;RW^MuuWep_asImx-uUsY$t$Oi zEib&gJay)WnbLBZt(-eCAh78aXltW3H5~)%6q~kUNyNk&wRG87GwmoF+R2G-bfVd> z>FgmLeEKh*n!sM3booD?sWs0qq^hn<5Q>gw>Y`#=rie`yiW1d`rOA>54O8eAoWa~+ W;Xr2CCWU-XND9S#b>=7F2!8`R9j9sl