feat: add Prompt template library, agent_call inter-agent tool, and RAG memory
- New PromptTemplatePicker component for browsing 13 preset prompt templates - AgentConfig.vue: "Load from library" button for system prompt - Agents.vue: "Create from Prompt template" entry with agent node + RAG memory - seed_prompt_templates.py: 13 preset templates (客服/研发/教育/内容/分析/创意/健康医疗) - agent_call tool: agents can delegate tasks to other agents (19th builtin tool) - Created 全能助手 (general orchestrator) and 家庭医生助手 agents - Switch template-created agents from type:llm to type:agent for full ReAct + RAG Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2144,3 +2144,174 @@ SCHEDULE_DELETE_SCHEMA = {
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
# ── agent_call ─────────────────────────────────────────────────
|
||||
|
||||
async def agent_call_tool(
|
||||
agent_name: str,
|
||||
query: str,
|
||||
max_iterations: int = 10,
|
||||
) -> str:
|
||||
"""
|
||||
调用另一个 Agent 处理任务并返回结果。
|
||||
|
||||
在数据库中按名称模糊匹配 Agent,用其 workflow_config 中 agent/llm 节点的
|
||||
配置执行一次 ReAct 推理,然后将结果返回给调用方(如全能助手)。
|
||||
|
||||
Args:
|
||||
agent_name: 目标 Agent 名称(支持模糊匹配,匹配到多个时取最接近的一个)
|
||||
query: 发给目标 Agent 的用户消息
|
||||
max_iterations: 最大推理步数(默认 10)
|
||||
"""
|
||||
import asyncio as _asyncio
|
||||
|
||||
try:
|
||||
from app.core.database import SessionLocal
|
||||
from app.models.agent import Agent
|
||||
from app.agent_runtime.core import AgentRuntime
|
||||
from app.agent_runtime.schemas import (
|
||||
AgentConfig,
|
||||
AgentLLMConfig,
|
||||
AgentToolConfig,
|
||||
)
|
||||
|
||||
# 1. 查 DB,模糊匹配 Agent
|
||||
db = SessionLocal()
|
||||
try:
|
||||
candidates = (
|
||||
db.query(Agent)
|
||||
.filter(Agent.name.like(f"%{agent_name}%"))
|
||||
.limit(5)
|
||||
.all()
|
||||
)
|
||||
if not candidates:
|
||||
return json.dumps(
|
||||
{
|
||||
"error": "agent_not_found",
|
||||
"message": (
|
||||
f"未找到匹配「{agent_name}」的 Agent。"
|
||||
"请确认 Agent 名称是否正确,或在 Agent 管理中先创建目标 Agent。"
|
||||
),
|
||||
},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
|
||||
# 精确匹配优先,否则取第一个
|
||||
target = next(
|
||||
(a for a in candidates if a.name == agent_name),
|
||||
candidates[0],
|
||||
)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
# 2. 从 workflow_config 提取 agent/llm 节点配置
|
||||
wf = target.workflow_config or {}
|
||||
nodes = wf.get("nodes", [])
|
||||
agent_node = next(
|
||||
(n for n in nodes if n.get("type") in ("agent", "llm")),
|
||||
None,
|
||||
)
|
||||
if not agent_node:
|
||||
return json.dumps(
|
||||
{
|
||||
"error": "no_agent_node",
|
||||
"message": f"Agent「{target.name}」的工作流中未找到 Agent/LLM 节点,无法执行",
|
||||
},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
|
||||
nd = agent_node.get("data", {}) or {}
|
||||
|
||||
system_prompt = nd.get("system_prompt") or nd.get("prompt") or (
|
||||
"你是一个有用的AI助手。"
|
||||
)
|
||||
model = nd.get("model", "deepseek-v4-flash")
|
||||
provider = nd.get("provider", "deepseek")
|
||||
temperature = float(nd.get("temperature", 0.7))
|
||||
node_max_iter = int(nd.get("max_iterations") or 0)
|
||||
if node_max_iter > 0:
|
||||
max_iterations = min(max_iterations, node_max_iter)
|
||||
|
||||
# 3. 构建配置并执行
|
||||
config = AgentConfig(
|
||||
name=target.name or "sub_agent",
|
||||
system_prompt=system_prompt,
|
||||
llm=AgentLLMConfig(
|
||||
provider=provider,
|
||||
model=model,
|
||||
temperature=temperature,
|
||||
max_iterations=max_iterations,
|
||||
),
|
||||
tools=AgentToolConfig(
|
||||
include_tools=nd.get("tools") or [],
|
||||
exclude_tools=nd.get("exclude_tools") or [],
|
||||
),
|
||||
memory={
|
||||
"enabled": nd.get("memory", True),
|
||||
"persist_to_db": nd.get("memory", True),
|
||||
},
|
||||
)
|
||||
|
||||
runtime = AgentRuntime(config=config)
|
||||
result = await runtime.run(query)
|
||||
|
||||
if result.success:
|
||||
out = {
|
||||
"agent": target.name,
|
||||
"status": "success",
|
||||
"iterations": result.iterations_used,
|
||||
"tool_calls": result.tool_calls_made,
|
||||
"reply": result.content,
|
||||
}
|
||||
else:
|
||||
out = {
|
||||
"agent": target.name,
|
||||
"status": "error",
|
||||
"error": result.error,
|
||||
"reply": result.content or f"Agent 执行失败: {result.error}",
|
||||
}
|
||||
|
||||
return json.dumps(out, ensure_ascii=False)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"agent_call 工具执行失败: {e}", exc_info=True)
|
||||
return json.dumps(
|
||||
{
|
||||
"error": "execution_failed",
|
||||
"message": f"调用 Agent 时出错: {e}",
|
||||
},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
|
||||
|
||||
AGENT_CALL_SCHEMA = {
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "agent_call",
|
||||
"description": (
|
||||
"调用另一个已注册的 Agent 来处理任务并返回结果。适合用来将子任务委托给"
|
||||
"具备特定专长的 Agent(如家庭医生助手、代码助手等)。会话不会被接管,"
|
||||
"结果会以文本形式返回给调用方用于整合回复。"
|
||||
),
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"agent_name": {
|
||||
"type": "string",
|
||||
"description": "目标 Agent 名称,支持模糊匹配(如「家庭医生」「代码助手」)",
|
||||
},
|
||||
"query": {
|
||||
"type": "string",
|
||||
"description": "发给目标 Agent 的查询内容,可以包含上下文信息",
|
||||
},
|
||||
"max_iterations": {
|
||||
"type": "integer",
|
||||
"description": "最大推理步数(默认 10),控制 Agent 的思考深度",
|
||||
"default": 10,
|
||||
},
|
||||
},
|
||||
"required": ["agent_name", "query"],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user