多智能体调试完成
This commit is contained in:
parent
3f79018373
commit
27e44f26c8
@ -1,4 +1,5 @@
|
|||||||
from src.agents.chatbot import ChatbotAgent, ChatbotConfiguration
|
from src.agents.chatbot import ChatbotAgent
|
||||||
|
from src.agents.react import ReActAgent
|
||||||
|
|
||||||
class AgentManager:
|
class AgentManager:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -17,6 +18,7 @@ class AgentManager:
|
|||||||
|
|
||||||
agent_manager = AgentManager()
|
agent_manager = AgentManager()
|
||||||
agent_manager.add_agent("chatbot", ChatbotAgent)
|
agent_manager.add_agent("chatbot", ChatbotAgent)
|
||||||
|
agent_manager.add_agent("react", ReActAgent)
|
||||||
|
|
||||||
__all__ = ["agent_manager"]
|
__all__ = ["agent_manager"]
|
||||||
|
|
||||||
|
|||||||
4
src/agents/react/__init__.py
Normal file
4
src/agents/react/__init__.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
from .graph import ReActAgent
|
||||||
|
from .configuration import ReActConfiguration
|
||||||
|
|
||||||
|
__all__ = ["ReActAgent", "ReActConfiguration"]
|
||||||
36
src/agents/react/configuration.py
Normal file
36
src/agents/react/configuration.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
from dataclasses import dataclass, field
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
|
from langchain_core.tools import tool
|
||||||
|
from langchain_openai import ChatOpenAI
|
||||||
|
|
||||||
|
from src.agents.registry import Configuration
|
||||||
|
|
||||||
|
def get_default_requirements():
|
||||||
|
return ["TAVILY_API_KEY"]
|
||||||
|
|
||||||
|
@tool
|
||||||
|
def multiply(first_int: int, second_int: int) -> int:
|
||||||
|
"""Multiply two integers together."""
|
||||||
|
return first_int * second_int
|
||||||
|
|
||||||
|
@dataclass(kw_only=True)
|
||||||
|
class ReActConfiguration(Configuration):
|
||||||
|
"""ReAct 的配置"""
|
||||||
|
|
||||||
|
system_prompt: str = field(
|
||||||
|
default=f"You are a helpful assistant. Now is {datetime.now(tz=timezone.utc).isoformat()}",
|
||||||
|
metadata={
|
||||||
|
"description": "The system prompt to use for the agent's interactions. "
|
||||||
|
"This prompt sets the context and behavior for the agent."
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
model: str = field(
|
||||||
|
default="zhipu/glm-4-plus",
|
||||||
|
metadata={
|
||||||
|
"description": "The name of the language model to use for the agent's main interactions. "
|
||||||
|
"Should be in the form: provider/model-name."
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
86
src/agents/react/graph.py
Normal file
86
src/agents/react/graph.py
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import asyncio
|
||||||
|
import uuid
|
||||||
|
from typing import Any
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from langchain_core.runnables import RunnableConfig
|
||||||
|
from langgraph.graph import StateGraph, START, END
|
||||||
|
from langgraph.prebuilt import ToolNode, tools_condition
|
||||||
|
from langgraph.checkpoint.memory import MemorySaver
|
||||||
|
from langchain_community.tools.tavily_search import TavilySearchResults
|
||||||
|
|
||||||
|
|
||||||
|
from src.agents.registry import State, BaseAgent
|
||||||
|
from src.agents.utils import load_chat_model
|
||||||
|
from src.agents.react.configuration import ReActConfiguration, multiply
|
||||||
|
|
||||||
|
class ReActAgent(BaseAgent):
|
||||||
|
name = "react"
|
||||||
|
description = "A react agent that can answer questions and help with tasks."
|
||||||
|
_graph_cache = None
|
||||||
|
config_schema = ReActConfiguration.to_dict()
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
|
def _get_tools(self, config_schema: RunnableConfig):
|
||||||
|
"""根据配置获取工具"""
|
||||||
|
tools = [multiply, TavilySearchResults(max_results=10)]
|
||||||
|
return tools
|
||||||
|
|
||||||
|
def llm_call(self, state: State, config: RunnableConfig = None) -> dict[str, Any]:
|
||||||
|
"""调用 llm 模型"""
|
||||||
|
config_schema = config or {}
|
||||||
|
conf = ReActConfiguration.from_runnable_config(config_schema)
|
||||||
|
model = load_chat_model(conf.model)
|
||||||
|
model_with_tools = model.bind_tools(self._get_tools(config_schema))
|
||||||
|
|
||||||
|
res = model_with_tools.invoke(
|
||||||
|
[{"role": "system", "content": conf.system_prompt}, *state["messages"]]
|
||||||
|
)
|
||||||
|
return {"messages": [res]}
|
||||||
|
|
||||||
|
def get_graph(self, config_schema: RunnableConfig = None):
|
||||||
|
"""构建图"""
|
||||||
|
workflow = StateGraph(State, config_schema=ReActConfiguration)
|
||||||
|
workflow.add_node("react", self.llm_call)
|
||||||
|
workflow.add_node("tools", ToolNode(tools=self._get_tools(config_schema)))
|
||||||
|
workflow.add_edge(START, "react")
|
||||||
|
workflow.add_conditional_edges(
|
||||||
|
"react",
|
||||||
|
tools_condition,
|
||||||
|
)
|
||||||
|
workflow.add_edge("tools", "react")
|
||||||
|
workflow.add_edge("react", END)
|
||||||
|
|
||||||
|
graph = workflow.compile(checkpointer=MemorySaver())
|
||||||
|
return graph
|
||||||
|
|
||||||
|
def stream_values(self, messages: list[str], config_schema: RunnableConfig = None):
|
||||||
|
graph = self.get_graph(config_schema)
|
||||||
|
for event in graph.stream({"messages": messages}, stream_mode="values", config=config_schema):
|
||||||
|
yield event["messages"]
|
||||||
|
|
||||||
|
def stream_messages(self, messages: list[str], config_schema: RunnableConfig = None):
|
||||||
|
graph = self.get_graph(config_schema)
|
||||||
|
conf = ReActConfiguration.from_runnable_config(config_schema)
|
||||||
|
for msg, metadata in graph.stream({"messages": messages}, stream_mode="messages", config=config_schema):
|
||||||
|
msg_type = msg.type
|
||||||
|
|
||||||
|
return_keys =conf.return_keys
|
||||||
|
if not return_keys or msg_type in return_keys:
|
||||||
|
yield msg, metadata
|
||||||
|
|
||||||
|
def main():
|
||||||
|
agent = ReActAgent(ReActConfiguration())
|
||||||
|
|
||||||
|
thread_id = str(uuid.uuid4())
|
||||||
|
config = {"configurable": {"thread_id": thread_id}}
|
||||||
|
|
||||||
|
from src.agents.utils import agent_cli
|
||||||
|
agent_cli(agent, config)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
# asyncio.run(main())
|
||||||
@ -3,7 +3,7 @@ from fastapi import APIRouter, Body
|
|||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from typing import List, Dict, Any, Optional
|
from typing import List, Dict, Any, Optional
|
||||||
|
|
||||||
from src.utils import logger
|
from src.agents import agent_manager
|
||||||
|
|
||||||
tool = APIRouter(prefix="/tool")
|
tool = APIRouter(prefix="/tool")
|
||||||
|
|
||||||
@ -15,6 +15,7 @@ class Tool(BaseModel):
|
|||||||
url: str
|
url: str
|
||||||
method: Optional[str] = "POST"
|
method: Optional[str] = "POST"
|
||||||
params: Optional[Dict[str, Any]] = None
|
params: Optional[Dict[str, Any]] = None
|
||||||
|
metadata: Optional[Dict[str, Any]] = None
|
||||||
|
|
||||||
@tool.get("/", response_model=List[Tool])
|
@tool.get("/", response_model=List[Tool])
|
||||||
async def route_index():
|
async def route_index():
|
||||||
@ -41,6 +42,18 @@ async def route_index():
|
|||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
for agent in agent_manager.agents.values():
|
||||||
|
tools.append(
|
||||||
|
Tool(
|
||||||
|
name=agent.name,
|
||||||
|
title=agent.name,
|
||||||
|
description=agent.description,
|
||||||
|
url=f"/agent/{agent.name}",
|
||||||
|
method="POST",
|
||||||
|
metadata=agent.config_schema,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return tools
|
return tools
|
||||||
|
|
||||||
@tool.post("/text-chunking")
|
@tool.post("/text-chunking")
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user