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:
renjianbo
2026-05-03 21:57:30 +08:00
parent 1c83b6284f
commit de415ca310
8 changed files with 1280 additions and 7 deletions

View File

@@ -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"],
},
},
}