runtime.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. from __future__ import annotations
  2. import asyncio
  3. import importlib.util
  4. from dataclasses import dataclass
  5. from functools import lru_cache
  6. from typing import Any
  7. from app.agents.prompts import VENT_SYSTEM_PROMPT
  8. from app.core.config import settings
  9. from app.core.logging import setup_logging
  10. @dataclass
  11. class AgentInvocationResult:
  12. status: str
  13. output: str
  14. model: str
  15. error: str = ""
  16. class DeepAgentRuntime:
  17. def __init__(self) -> None:
  18. self._agent: Any | None = None
  19. self._lock = asyncio.Lock()
  20. @property
  21. def dependencies_available(self) -> bool:
  22. return all(
  23. importlib.util.find_spec(name) is not None
  24. for name in ("deepagents", "langchain_openai", "langgraph")
  25. )
  26. @property
  27. def enabled(self) -> bool:
  28. return self.dependencies_available and settings.model_configured
  29. def describe(self) -> dict[str, Any]:
  30. return {
  31. "dependencies_available": self.dependencies_available,
  32. "model_configured": settings.model_configured,
  33. "enabled": self.enabled,
  34. "model": settings.deepagent_model,
  35. "framework": "deepagents",
  36. }
  37. async def _build_agent(self) -> Any:
  38. if self._agent is not None:
  39. return self._agent
  40. async with self._lock:
  41. if self._agent is not None:
  42. return self._agent
  43. from deepagents import create_deep_agent
  44. from langchain_openai import ChatOpenAI
  45. model = ChatOpenAI(
  46. model=settings.deepagent_model,
  47. api_key=settings.openai_api_key,
  48. base_url=settings.openai_base_url or None,
  49. timeout=settings.openai_timeout,
  50. max_retries=2,
  51. )
  52. self._agent = create_deep_agent(
  53. model=model,
  54. tools=[],
  55. system_prompt=VENT_SYSTEM_PROMPT,
  56. name="vent-platform-agent",
  57. )
  58. return self._agent
  59. async def invoke(
  60. self,
  61. *,
  62. message: str,
  63. thread_id: str,
  64. context: dict[str, Any] | None = None,
  65. ) -> AgentInvocationResult:
  66. if not self.enabled:
  67. return AgentInvocationResult(
  68. status="disabled",
  69. output="",
  70. model=settings.deepagent_model,
  71. error="DeepAgent 依赖或模型配置未就绪",
  72. )
  73. try:
  74. agent = await self._build_agent()
  75. payload = message
  76. if context:
  77. payload = f"{message}\n\n业务上下文:\n{context}"
  78. result = await asyncio.wait_for(
  79. agent.ainvoke(
  80. {"messages": [{"role": "user", "content": payload}]},
  81. config={"configurable": {"thread_id": thread_id}},
  82. ),
  83. timeout=settings.openai_timeout,
  84. )
  85. messages = result.get("messages", []) if isinstance(result, dict) else []
  86. content = messages[-1].content if messages else str(result)
  87. if not isinstance(content, str):
  88. content = str(content)
  89. return AgentInvocationResult(
  90. status="success",
  91. output=content,
  92. model=settings.deepagent_model,
  93. )
  94. except Exception as exc: # pragma: no cover - 依赖外部模型
  95. setup_logging()
  96. return AgentInvocationResult(
  97. status="failed",
  98. output="",
  99. model=settings.deepagent_model,
  100. error=f"{type(exc).__name__}: {exc}",
  101. )
  102. @lru_cache(maxsize=1)
  103. def get_agent_runtime() -> DeepAgentRuntime:
  104. return DeepAgentRuntime()