260602
This commit is contained in:
parent
49d3a589ee
commit
5129459d47
142
utils/agent.py
142
utils/agent.py
|
|
@ -5,8 +5,8 @@
|
||||||
|
|
||||||
# 列举导入模块
|
# 列举导入模块
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Optional
|
from sys import path
|
||||||
from typing_extensions import is_protocol
|
from typing import List, Optional, cast
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
from pydantic_ai import Agent as BaseAgent, AgentRunResult
|
from pydantic_ai import Agent as BaseAgent, AgentRunResult
|
||||||
|
|
@ -15,14 +15,15 @@ from pydantic_ai.capabilities import AgentCapability
|
||||||
from pydantic_ai.models.openai import OpenAIChatModel
|
from pydantic_ai.models.openai import OpenAIChatModel
|
||||||
from pydantic_ai.output import OutputSpec
|
from pydantic_ai.output import OutputSpec
|
||||||
from pydantic_ai.providers.openai import OpenAIProvider
|
from pydantic_ai.providers.openai import OpenAIProvider
|
||||||
|
from pydantic_ai.settings import ModelSettings
|
||||||
from pydantic_core.core_schema import is_subclass_schema
|
from pydantic_core.core_schema import is_subclass_schema
|
||||||
from starlette.applications import Starlette
|
from starlette.applications import Starlette
|
||||||
from starlette.routing import Mount, Route
|
from starlette.routing import Mount, Route
|
||||||
|
from typing_extensions import is_protocol
|
||||||
|
|
||||||
from sys import path
|
from memory import Memory
|
||||||
|
|
||||||
path.append(Path(__file__).resolve().parent.as_posix())
|
path.append(Path(__file__).resolve().parent.as_posix())
|
||||||
from memory import Memory
|
|
||||||
|
|
||||||
|
|
||||||
class Agent:
|
class Agent:
|
||||||
|
|
@ -105,19 +106,144 @@ class Agent:
|
||||||
)
|
)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def create_starlette_application(
|
def create_web_application(
|
||||||
self,
|
self,
|
||||||
builtin_tools: Optional[List[AbstractBuiltinTool]] = None,
|
builtin_tools: Optional[List[AbstractBuiltinTool]] = None,
|
||||||
) -> Starlette:
|
) -> Starlette:
|
||||||
"""
|
"""
|
||||||
创建 Starlette 应用,为智能体提供交互式对话界面
|
创建 Starlette 应用,为智能体提供交互式对话界面
|
||||||
:param models: ModelsParam = None,
|
:param builtin_tools: 前端可选工具列表
|
||||||
:param builtin_tools: Sequence[AbstractBuiltinTool] | None = None,
|
|
||||||
:return: Starlette 实例
|
:return: Starlette 实例
|
||||||
"""
|
"""
|
||||||
|
from starlette.requests import Request
|
||||||
|
from starlette.responses import JSONResponse, HTMLResponse, Response
|
||||||
|
|
||||||
|
def api(
|
||||||
|
self,
|
||||||
|
builtin_tools: Optional[List[AbstractBuiltinTool]] = None,
|
||||||
|
) -> Starlette:
|
||||||
|
"""
|
||||||
|
创建 API 应用
|
||||||
|
:param builtin_tools: 前端可选工具列表
|
||||||
|
:return: Starlette 实例
|
||||||
|
"""
|
||||||
|
from pydantic_ai.models import Model
|
||||||
|
from pydantic_ai.ui._web.api import ModelInfo
|
||||||
|
from pydantic_ai.ui._web.api import (
|
||||||
|
ConfigureFrontend,
|
||||||
|
BuiltinToolInfo,
|
||||||
|
ChatRequestExtra,
|
||||||
|
validate_request_options,
|
||||||
|
)
|
||||||
|
from pydantic_ai.ui.vercel_ai import VercelAIAdapter
|
||||||
|
from typing import TypeVar
|
||||||
|
|
||||||
|
agent_model = cast(Model, self.agent.model)
|
||||||
|
|
||||||
|
# 前端可选工具列表
|
||||||
|
frontend_builtin_tools = [
|
||||||
|
t
|
||||||
|
for t in (builtin_tools or [])
|
||||||
|
if t.unique_id
|
||||||
|
not in {
|
||||||
|
t.unique_id
|
||||||
|
for t in self.agent._cap_builtin_tools
|
||||||
|
if isinstance(t, AbstractBuiltinTool)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
async def options_chat(request: Request) -> Response:
|
||||||
|
"""处理跨域预检请求"""
|
||||||
|
return Response()
|
||||||
|
|
||||||
|
async def configurations(request: Request) -> Response:
|
||||||
|
"""处理前端模型与工具配置请求"""
|
||||||
|
configurations = ConfigureFrontend(
|
||||||
|
models=[
|
||||||
|
ModelInfo(
|
||||||
|
id=agent_model.model_id,
|
||||||
|
name=agent_model.label,
|
||||||
|
builtin_tools=[
|
||||||
|
t.unique_id
|
||||||
|
for t in frontend_builtin_tools
|
||||||
|
if type(t) in agent_model.supported_builtin_tools()
|
||||||
|
],
|
||||||
|
)
|
||||||
|
], # 前端仅可选择智能体配置的模型
|
||||||
|
builtin_tools=[
|
||||||
|
BuiltinToolInfo(id=t.unique_id, name=t.label)
|
||||||
|
for t in frontend_builtin_tools
|
||||||
|
],
|
||||||
|
)
|
||||||
|
return JSONResponse(content=configurations.model_dump(by_alias=True))
|
||||||
|
|
||||||
|
async def chat(request: Request) -> Response:
|
||||||
|
"""处理对话请求"""
|
||||||
|
# 实例 Vercel AI 适配器
|
||||||
|
adapter = await VercelAIAdapter[
|
||||||
|
TypeVar("AgentDepsT"), TypeVar("OutputDataT")
|
||||||
|
].from_request(request=request, agent=self.agent)
|
||||||
|
|
||||||
|
# 解析请求中额外数据,包括前端选择的模型标识、工具标识和其它配置等
|
||||||
|
extra_data = ChatRequestExtra.model_validate(
|
||||||
|
adapter.run_input.__pydantic_extra__
|
||||||
|
)
|
||||||
|
if error := validate_request_options(
|
||||||
|
extra_data=extra_data,
|
||||||
|
model_ids={agent_model.model_id}, # 前端仅可选择智能体配置的模型
|
||||||
|
builtin_tool_ids={t.unique_id for t in frontend_builtin_tools},
|
||||||
|
):
|
||||||
|
return JSONResponse(content={"error": error}, status_code=400)
|
||||||
|
|
||||||
|
streaming_response = await VercelAIAdapter[
|
||||||
|
TypeVar("AgentDepsT"), TypeVar("OutputDataT")
|
||||||
|
].dispatch_request(
|
||||||
|
request=request,
|
||||||
|
agent=self.agent,
|
||||||
|
builtin_tools=[
|
||||||
|
t
|
||||||
|
for t in frontend_builtin_tools
|
||||||
|
if t.unique_id in extra_data.builtin_tools
|
||||||
|
],
|
||||||
|
)
|
||||||
|
return streaming_response
|
||||||
|
|
||||||
|
async def health(request: Request) -> Response:
|
||||||
|
"""处理健康检查请求"""
|
||||||
|
return JSONResponse(content={"ok": True})
|
||||||
|
|
||||||
|
return Starlette(
|
||||||
|
routes=[
|
||||||
|
Route("/configure", configurations, methods=["GET"]),
|
||||||
|
Route("/chat", options_chat, methods=["OPTIONS"]),
|
||||||
|
Route("/chat", chat, methods=["POST"]),
|
||||||
|
Route("/health", health, methods=["GET"]),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
async def ui(request: Request) -> Response:
|
||||||
|
"""Serve the chat UI from filesystem cache or CDN."""
|
||||||
|
content = await _get_ui_html(html_source)
|
||||||
|
|
||||||
|
return HTMLResponse(
|
||||||
|
content=content,
|
||||||
|
headers={
|
||||||
|
"Cache-Control": "public, max-age=3600",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
application = Starlette(
|
||||||
|
routes=[
|
||||||
|
Mount(
|
||||||
|
"/api",
|
||||||
|
app=api(self, builtin_tools=builtin_tools),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
app.router.add_route("/", ui, methods=["GET"])
|
||||||
|
app.router.add_route("/{id}", ui, methods=["GET"])
|
||||||
|
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
exit()
|
|
||||||
return application
|
return application
|
||||||
|
|
|
||||||
|
|
@ -225,18 +225,18 @@ if __name__ == "__main__":
|
||||||
# 实例请求客户端
|
# 实例请求客户端
|
||||||
request = Request() # 不使用缓存
|
request = Request() # 不使用缓存
|
||||||
response = request.post(
|
response = request.post(
|
||||||
url="http://192.168.3.103:30380/api/v1/riskgateway/product/invokeSync.json",
|
url="https://risk-gw.pangjukeji.com/api/v1/riskgateway/product/invokeSync.json",
|
||||||
headers={
|
headers={
|
||||||
"Authorization": "Bearer C52FB4D10BC424D9F",
|
"Authorization": "Bearer 337162980141699072",
|
||||||
"Content-Type": "application/json;charset=utf-8",
|
"Content-Type": "application/json;charset=utf-8",
|
||||||
},
|
},
|
||||||
json=encryptor.encrypt(
|
json=encryptor.encrypt(
|
||||||
payload={
|
payload={
|
||||||
"productId": "BANK_CARD_4",
|
"productId": "BANK_CARD_4",
|
||||||
"name": "刘弼仁",
|
"name": "刘弼仁",
|
||||||
"idNumber": "131002198705020000",
|
"certNo": "131002198705024619",
|
||||||
"bankCard": "1234567890123456",
|
"mobilephone": "18058798752",
|
||||||
"phone": "18058798752",
|
"bankCardNo": "6214835712066453",
|
||||||
},
|
},
|
||||||
fields_mapping={
|
fields_mapping={
|
||||||
"aes_key_encoded": "encryptedAesKey",
|
"aes_key_encoded": "encryptedAesKey",
|
||||||
|
|
@ -259,3 +259,16 @@ if __name__ == "__main__":
|
||||||
tag_encoded=response.get("data").get("tag"),
|
tag_encoded=response.get("data").get("tag"),
|
||||||
)
|
)
|
||||||
print(data)
|
print(data)
|
||||||
|
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"productId": "CREDIT_RISK_PRE_SCREEN",
|
||||||
|
"mobilephone": "13833652839",
|
||||||
|
"certNo": "131002196212124620"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,9 @@
|
||||||
-----BEGIN PUBLIC KEY-----
|
-----BEGIN PUBLIC KEY-----
|
||||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApafHKXu1IwGJ1iQVT0susJ20MRl/6unJ+YMX6Lx9l43/+THA4VAJ8YQaZMH9+1eFeaFjwM9pT0ee+okBpKRuDWVkH8NxiKza4ohNHEtSUU37N3h8BEUBJHx74/6pDK8DwPsp4LzGhnUPof5/ZMqW2phqTrEYRwYOKGLYNnScNKkOWkQMSrUxGBkcMs1VsePChe0cJqrC03CTHJ/NRSyc62HqDZLp6G+DaR3VgWkhvhT4sN/3j/n9Ml5io/8I5ooPfBrYPNCfOaVqFWtqHqoG0uMLeROa8edqk6ZBBv2mERPllOG43f91FNmg/kF8XHij1LBNcf1WbO7rHg0Vo71j+wIDAQAB
|
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqj/EwmmABQLKD7fh1ydL
|
||||||
|
RDUqJjI+amaWPvX+urI9GFSl2cCJ6MlmtKgd0z/qDdJT+o5BjU0oU9wwnZSqu9HK
|
||||||
|
rvrzdEjX+74sWxRDi8GuHjGfdWmJO7tF1lHApZw9rnZt1JTp1zBUBeVOLmWP2Ub0
|
||||||
|
wjDOdYz2zKKZH6GShb1BUUqSi2hOD0S9iYMR4cz1smtMUTKzrJU8yIo6k26qXt5U
|
||||||
|
RlhalT+vChYEh7QhCHbbJKdlbmtMvwE2alRKnqeXFRpDOR1JPQDUN+n3C2FEuM0a
|
||||||
|
Hf2jmB93F4btqOFxZKSB+ZmXP0UMGeSGyuTOLn0QWWqkNBn1aYwO1rtPURR1y/mo
|
||||||
|
QQIDAQAB
|
||||||
-----END PUBLIC KEY-----
|
-----END PUBLIC KEY-----
|
||||||
|
|
@ -30,5 +30,5 @@ if __name__ == "__main__":
|
||||||
"严禁幻觉,保持专业严谨。"
|
"严禁幻觉,保持专业严谨。"
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
a = agent.create_starlette_application()
|
a = agent.create_web_application()
|
||||||
uvicorn.run(app=a, host="127.0.0.1", port=7932)
|
uvicorn.run(app=a, host="127.0.0.1", port=7932)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue