Files
aiagent/backend/app/services/knowledge_sharing.py

238 lines
7.9 KiB
Python
Raw Normal View History

"""
Agent 间知识共享服务 Agent 经验继承 Agent 知识流通
Agent 创建时可继承父 Agent 的知识条目学习模式和全局知识
避免自主学习创建的 Agent 从零开始
"""
from __future__ import annotations
import logging
from typing import Any, Dict, List, Optional
from sqlalchemy.orm import Session
from app.core.database import SessionLocal
logger = logging.getLogger(__name__)
def inherit_knowledge_from_parent(
child_agent_id: str,
parent_agent_id: str,
db: Optional[Session] = None,
) -> Dict[str, Any]:
"""
从父 Agent 继承知识到子 Agent
拷贝内容
1. KnowledgeEntry 条目知识沉淀
2. GlobalKnowledge 条目全局知识标记为子 Agent 可见
3. AgentLearningPattern 模式工具使用经验
"""
should_close = False
if db is None:
db = SessionLocal()
should_close = True
result = {
"child_agent_id": child_agent_id,
"parent_agent_id": parent_agent_id,
"knowledge_entries_copied": 0,
"global_knowledge_shared": 0,
"learning_patterns_copied": 0,
}
try:
# 1. 拷贝 KnowledgeEntry
from app.models.knowledge_entry import KnowledgeEntry
parent_entries = (
db.query(KnowledgeEntry)
.filter(
KnowledgeEntry.is_active == True,
)
.filter(
(KnowledgeEntry.agent_id == parent_agent_id)
| (KnowledgeEntry.source_agent_name == parent_agent_id)
)
.all()
)
import uuid
for entry in parent_entries:
new_entry = KnowledgeEntry(
id=str(uuid.uuid4()),
agent_id=child_agent_id,
title=f"[继承] {entry.title}",
category=entry.category,
tags=(entry.tags or []) + ["inherited"],
situation=entry.situation,
solution=entry.solution,
caveats=entry.caveats,
source_execution_ids=entry.source_execution_ids,
source_agent_name=entry.source_agent_name,
source_model=entry.source_model,
retrieval_count=0,
success_rate=entry.success_rate,
confidence=(entry.confidence or 0.5) * 0.8, # 继承降低置信度
is_active=True,
)
db.add(new_entry)
result["knowledge_entries_copied"] += 1
# 2. 拷贝 GlobalKnowledge 标记(来源标记关联,不复制内容)
from app.models.agent import GlobalKnowledge
from datetime import datetime, timedelta
# 查找父 Agent 贡献的全局知识
parent_knowledge = (
db.query(GlobalKnowledge)
.filter(GlobalKnowledge.source_agent_id == parent_agent_id)
.all()
)
# 将父 Agent 的全局知识也关联到子 Agentscope
for gk in parent_knowledge:
# 不直接修改,而是创建新的 scope 关联scope_kind=agent, scope_id=child
# 如果已有相同内容的记录则跳过
existing = (
db.query(GlobalKnowledge)
.filter(
GlobalKnowledge.content == gk.content,
GlobalKnowledge.scope_kind == "agent",
GlobalKnowledge.scope_id == child_agent_id,
)
.first()
)
if not existing:
shared = GlobalKnowledge(
id=str(uuid.uuid4()),
content=gk.content,
embedding=gk.embedding,
source_agent_id=parent_agent_id,
source_user_id=gk.source_user_id,
tags=(gk.tags or []) + ["inherited_from_parent"],
confidence=gk.confidence or "medium",
scope_kind="agent",
scope_id=child_agent_id,
created_at=datetime.utcnow(),
)
db.add(shared)
result["global_knowledge_shared"] += 1
# 3. 拷贝 AgentLearningPattern
from app.models.agent_learning_pattern import AgentLearningPattern
parent_patterns = (
db.query(AgentLearningPattern)
.filter(
AgentLearningPattern.scope_kind == "agent",
AgentLearningPattern.scope_id == parent_agent_id,
)
.all()
)
for pattern in parent_patterns:
new_pattern = AgentLearningPattern(
id=str(uuid.uuid4()),
scope_kind="agent",
scope_id=child_agent_id,
task_category=pattern.task_category,
task_keywords=pattern.task_keywords,
suggested_tools=pattern.suggested_tools,
effectiveness_score=pattern.effectiveness_score,
total_runs=1, # 重置计数
successful_runs=0,
avg_iterations=pattern.avg_iterations,
avg_tool_calls=pattern.avg_tool_calls,
created_at=datetime.utcnow(),
updated_at=datetime.utcnow(),
)
db.add(new_pattern)
result["learning_patterns_copied"] += 1
db.commit()
logger.info(
"Agent 知识继承完成: parent=%s → child=%s, entries=%d, global=%d, patterns=%d",
parent_agent_id,
child_agent_id,
result["knowledge_entries_copied"],
result["global_knowledge_shared"],
result["learning_patterns_copied"],
)
except Exception as e:
db.rollback()
logger.error("Agent 知识继承失败: %s", e)
raise
finally:
if should_close and db:
db.close()
return result
def get_parent_knowledge_context(
agent_id: str,
max_entries: int = 5,
db: Optional[Session] = None,
) -> str:
"""
获取 Agent 的父级知识上下文用于注入 system prompt
先查直接父 Agent再查祖父 Agent最多上溯 3
"""
should_close = False
if db is None:
db = SessionLocal()
should_close = True
try:
from app.models.agent import Agent
from app.models.knowledge_entry import KnowledgeEntry
# 收集祖先 Agent ID 列表(向上追溯最多 3 层)
ancestor_ids: List[str] = []
current_id = agent_id
for _ in range(3):
agent = db.query(Agent).filter(Agent.id == current_id).first()
if not agent or not getattr(agent, "parent_agent_id", None):
break
parent_id = agent.parent_agent_id
if parent_id in ancestor_ids: # 防止循环引用
break
ancestor_ids.append(parent_id)
current_id = parent_id
if not ancestor_ids:
return ""
# 查询祖先 Agent 的高质量知识
entries = (
db.query(KnowledgeEntry)
.filter(
KnowledgeEntry.agent_id.in_(ancestor_ids),
KnowledgeEntry.is_active == True,
KnowledgeEntry.confidence >= 0.6,
)
.order_by(KnowledgeEntry.retrieval_count.desc())
.limit(max_entries)
.all()
)
if not entries:
return ""
lines = [f"## 父级 Agent 经验 ({len(entries)} 条)"]
for i, entry in enumerate(entries, 1):
tag_str = f"[{entry.category}]" if entry.category else ""
sol = (entry.solution or "")[:300]
lines.append(f"{i}. {tag_str} {entry.title}: {sol}")
return "\n".join(lines)
except Exception as e:
logger.warning("获取父级知识上下文失败: %s", e)
return ""
finally:
if should_close and db:
db.close()