工具
This commit is contained in:
@@ -78,7 +78,7 @@ def generate_chat_agent(db: Session, user: User):
|
||||
"provider": "deepseek",
|
||||
"model": "deepseek-chat",
|
||||
"temperature": "0.3",
|
||||
"max_tokens": "1000",
|
||||
"max_tokens": "200",
|
||||
"prompt": """你是一个专业的对话意图分析助手。请分析用户的输入,识别用户的意图和情感。
|
||||
|
||||
用户输入:{{user_input}}
|
||||
@@ -129,7 +129,7 @@ def generate_chat_agent(db: Session, user: User):
|
||||
"provider": "deepseek",
|
||||
"model": "deepseek-chat",
|
||||
"temperature": "0.7",
|
||||
"max_tokens": "500",
|
||||
"max_tokens": "200",
|
||||
"prompt": """你是一个温暖、友好的AI助手。用户向你打招呼,请用自然、亲切的方式回应。
|
||||
|
||||
用户输入:{{user_input}}
|
||||
@@ -150,19 +150,20 @@ def generate_chat_agent(db: Session, user: User):
|
||||
"provider": "deepseek",
|
||||
"model": "deepseek-chat",
|
||||
"temperature": "0.5",
|
||||
"max_tokens": "2000",
|
||||
"prompt": """你是一个知识渊博、乐于助人的AI助手。请回答用户的问题。
|
||||
"max_tokens": "500",
|
||||
"prompt": """你是一个知识渊博、乐于助人的AI助手。请简洁、准确地回答用户的问题。
|
||||
|
||||
用户问题:{{user_input}}
|
||||
对话历史:{{memory.conversation_history}}
|
||||
意图分析:{{output}}
|
||||
|
||||
请提供:
|
||||
1. 直接、准确的答案
|
||||
2. 必要的解释和说明
|
||||
3. 如果问题不明确,友好地询问更多信息
|
||||
回答要求:
|
||||
1. 直接给出核心答案,避免冗长描述
|
||||
2. 如果是介绍类问题(如"你能做什么"),用简洁的要点列举,控制在100字以内
|
||||
3. 如果是知识性问题,提供准确答案和简要说明,控制在150字以内
|
||||
4. 如果问题不明确,友好地询问更多信息,控制在50字以内
|
||||
|
||||
请以自然、易懂的方式回答,长度控制在200字以内。直接输出回答内容。"""
|
||||
请以自然、简洁的方式回答,避免重复和冗余。直接输出回答内容,无需额外格式化。"""
|
||||
}
|
||||
}
|
||||
nodes.append(question_node)
|
||||
@@ -177,7 +178,7 @@ def generate_chat_agent(db: Session, user: User):
|
||||
"provider": "deepseek",
|
||||
"model": "deepseek-chat",
|
||||
"temperature": "0.8",
|
||||
"max_tokens": "1000",
|
||||
"max_tokens": "500",
|
||||
"prompt": """你是一个善解人意的AI助手。请根据用户的情感状态,给予适当的回应。
|
||||
|
||||
用户输入:{{user_input}}
|
||||
@@ -204,7 +205,7 @@ def generate_chat_agent(db: Session, user: User):
|
||||
"provider": "deepseek",
|
||||
"model": "deepseek-chat",
|
||||
"temperature": "0.4",
|
||||
"max_tokens": "1500",
|
||||
"max_tokens": "800",
|
||||
"prompt": """你是一个专业的AI助手。用户提出了一个请求,请分析并回应。
|
||||
|
||||
用户请求:{{user_input}}
|
||||
@@ -231,7 +232,7 @@ def generate_chat_agent(db: Session, user: User):
|
||||
"provider": "deepseek",
|
||||
"model": "deepseek-chat",
|
||||
"temperature": "0.6",
|
||||
"max_tokens": "300",
|
||||
"max_tokens": "150",
|
||||
"prompt": """你是一个友好的AI助手。用户要结束对话,请给予温暖的告别。
|
||||
|
||||
用户输入:{{user_input}}
|
||||
@@ -252,7 +253,7 @@ def generate_chat_agent(db: Session, user: User):
|
||||
"provider": "deepseek",
|
||||
"model": "deepseek-chat",
|
||||
"temperature": "0.6",
|
||||
"max_tokens": "1000",
|
||||
"max_tokens": "500",
|
||||
"prompt": """你是一个友好、专业的AI助手。请回应用户的输入。
|
||||
|
||||
用户输入:{{user_input}}
|
||||
@@ -286,31 +287,24 @@ def generate_chat_agent(db: Session, user: User):
|
||||
"label": "更新记忆",
|
||||
"operation": "set",
|
||||
"key": "user_memory_{user_id}",
|
||||
"value": '{"conversation_history": {{memory.conversation_history}} + [{"role": "user", "content": "{{user_input}}", "timestamp": "{{timestamp}}"}, {"role": "assistant", "content": "{{output}}", "timestamp": "{{timestamp}}"}], "user_profile": {{memory.user_profile}}, "context": {{memory.context}}}',
|
||||
"value": '{"conversation_history": ({{memory.conversation_history}} + [{"role": "user", "content": "{{user_input}}", "timestamp": "{{timestamp}}"}, {"role": "assistant", "content": "{{output}}", "timestamp": "{{timestamp}}"}]), "user_profile": {{memory.user_profile}}, "context": {{memory.context}}}',
|
||||
"ttl": 86400
|
||||
}
|
||||
}
|
||||
nodes.append(update_memory_node)
|
||||
|
||||
# ========== 14. 格式化最终回复 ==========
|
||||
format_response_node = {
|
||||
"id": "llm-format",
|
||||
"type": "llm",
|
||||
# ========== 14. JSON提取节点 - 提取最终回答文本 ==========
|
||||
json_extract_node = {
|
||||
"id": "json-extract",
|
||||
"type": "json",
|
||||
"position": {"x": 1650, "y": 400},
|
||||
"data": {
|
||||
"label": "格式化回复",
|
||||
"provider": "deepseek",
|
||||
"model": "deepseek-chat",
|
||||
"temperature": "0.3",
|
||||
"max_tokens": "500",
|
||||
"prompt": """请将以下回复内容格式化为最终输出。确保回复自然、流畅。
|
||||
|
||||
原始回复:{{output}}
|
||||
|
||||
请直接输出格式化后的回复内容,不要包含其他说明或标记。如果原始回复已经是合适的格式,直接输出即可。"""
|
||||
"label": "提取回答",
|
||||
"operation": "extract",
|
||||
"path": "right.right.right"
|
||||
}
|
||||
}
|
||||
nodes.append(format_response_node)
|
||||
nodes.append(json_extract_node)
|
||||
|
||||
# ========== 15. 结束节点 ==========
|
||||
end_node = {
|
||||
@@ -458,19 +452,19 @@ def generate_chat_agent(db: Session, user: User):
|
||||
"targetHandle": "left"
|
||||
})
|
||||
|
||||
# 更新记忆 -> 格式化回复
|
||||
# 更新记忆 -> JSON提取
|
||||
edges.append({
|
||||
"id": "e8",
|
||||
"source": "cache-update",
|
||||
"target": "llm-format",
|
||||
"target": "json-extract",
|
||||
"sourceHandle": "right",
|
||||
"targetHandle": "left"
|
||||
})
|
||||
|
||||
# 格式化回复 -> 结束
|
||||
# JSON提取 -> 结束
|
||||
edges.append({
|
||||
"id": "e9",
|
||||
"source": "llm-format",
|
||||
"source": "json-extract",
|
||||
"target": "end-1",
|
||||
"sourceHandle": "right",
|
||||
"targetHandle": "left"
|
||||
|
||||
334
backend/scripts/generate_knowledge_base_qa_agent.py
Normal file
334
backend/scripts/generate_knowledge_base_qa_agent.py
Normal file
@@ -0,0 +1,334 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
生成知识库问答Agent示例
|
||||
展示如何使用向量数据库和RAG技术构建知识库问答系统,包含:
|
||||
- 文本向量化(HTTP节点调用embedding API)
|
||||
- 向量数据库检索(vector_db节点)
|
||||
- 基于检索结果的答案生成(LLM节点)
|
||||
- 上下文整合和格式化
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
from app.core.database import SessionLocal
|
||||
from app.models.agent import Agent
|
||||
from app.models.user import User
|
||||
from datetime import datetime
|
||||
import uuid
|
||||
|
||||
|
||||
def generate_knowledge_base_qa_agent(db: Session, user: User):
|
||||
"""生成知识库问答Agent"""
|
||||
nodes = []
|
||||
edges = []
|
||||
|
||||
# ========== 1. 开始节点 ==========
|
||||
start_node = {
|
||||
"id": "start-1",
|
||||
"type": "start",
|
||||
"position": {"x": 50, "y": 400},
|
||||
"data": {
|
||||
"label": "开始",
|
||||
"output_format": "json"
|
||||
}
|
||||
}
|
||||
nodes.append(start_node)
|
||||
|
||||
# ========== 2. 问题预处理节点 ==========
|
||||
preprocess_node = {
|
||||
"id": "transform-preprocess",
|
||||
"type": "transform",
|
||||
"position": {"x": 250, "y": 400},
|
||||
"data": {
|
||||
"label": "问题预处理",
|
||||
"mode": "merge",
|
||||
"mapping": {
|
||||
"query": "{{query}}",
|
||||
"user_id": "{{user_id}}",
|
||||
"timestamp": "{{timestamp}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
nodes.append(preprocess_node)
|
||||
|
||||
# ========== 3. 文本向量化节点(HTTP调用embedding API)==========
|
||||
# 注意:需要在HTTP节点配置中手动设置Authorization header,使用环境变量DEEPSEEK_API_KEY
|
||||
embedding_node = {
|
||||
"id": "http-embedding",
|
||||
"type": "http",
|
||||
"position": {"x": 450, "y": 400},
|
||||
"data": {
|
||||
"label": "文本向量化",
|
||||
"method": "POST",
|
||||
"url": "https://api.deepseek.com/v1/embeddings",
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer sk-fdf7cc1c73504e628ec0119b7e11b8cc"
|
||||
},
|
||||
"body": {
|
||||
"model": "deepseek-embedding",
|
||||
"input": "{{query}}"
|
||||
},
|
||||
"response_format": "json"
|
||||
}
|
||||
}
|
||||
nodes.append(embedding_node)
|
||||
|
||||
# ========== 4. 提取embedding向量节点 ==========
|
||||
extract_embedding_node = {
|
||||
"id": "json-extract-embedding",
|
||||
"type": "json",
|
||||
"position": {"x": 650, "y": 400},
|
||||
"data": {
|
||||
"label": "提取向量",
|
||||
"operation": "extract",
|
||||
"path": "output.data.data[0].embedding"
|
||||
}
|
||||
}
|
||||
nodes.append(extract_embedding_node)
|
||||
|
||||
# ========== 5. 准备向量搜索数据节点 ==========
|
||||
prepare_search_node = {
|
||||
"id": "transform-prepare-search",
|
||||
"type": "transform",
|
||||
"position": {"x": 850, "y": 400},
|
||||
"data": {
|
||||
"label": "准备搜索数据",
|
||||
"mode": "merge",
|
||||
"mapping": {
|
||||
"embedding": "{{output}}",
|
||||
"query": "{{query}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
nodes.append(prepare_search_node)
|
||||
|
||||
# ========== 6. 向量数据库检索节点 ==========
|
||||
vector_search_node = {
|
||||
"id": "vector-search",
|
||||
"type": "vector_db",
|
||||
"position": {"x": 1050, "y": 400},
|
||||
"data": {
|
||||
"label": "知识库检索",
|
||||
"operation": "search",
|
||||
"collection": "knowledge_base",
|
||||
"query_vector": "{{embedding}}",
|
||||
"top_k": 5
|
||||
}
|
||||
}
|
||||
nodes.append(vector_search_node)
|
||||
|
||||
# ========== 7. 整理检索结果节点 ==========
|
||||
format_results_node = {
|
||||
"id": "transform-format-results",
|
||||
"type": "transform",
|
||||
"position": {"x": 1250, "y": 400},
|
||||
"data": {
|
||||
"label": "整理检索结果",
|
||||
"mode": "merge",
|
||||
"mapping": {
|
||||
"query": "{{query}}",
|
||||
"search_results": "{{output}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
nodes.append(format_results_node)
|
||||
|
||||
# ========== 8. 生成答案节点(LLM)==========
|
||||
answer_node = {
|
||||
"id": "llm-answer",
|
||||
"type": "llm",
|
||||
"position": {"x": 1650, "y": 400},
|
||||
"data": {
|
||||
"label": "生成答案",
|
||||
"provider": "deepseek",
|
||||
"model": "deepseek-chat",
|
||||
"temperature": "0.7",
|
||||
"max_tokens": "2000",
|
||||
"prompt": """你是一个专业的知识库问答助手。请基于提供的知识库内容回答用户的问题。
|
||||
|
||||
用户问题:{{query}}
|
||||
|
||||
相关知识库内容(从向量搜索中检索到的相关文档):
|
||||
{{search_results}}
|
||||
|
||||
请根据以上知识库内容回答用户的问题。要求:
|
||||
1. 答案要准确、完整,基于知识库内容
|
||||
2. 如果知识库中没有相关信息,请明确说明"根据知识库,未找到相关信息"
|
||||
3. 答案要清晰、有条理,使用Markdown格式
|
||||
4. 如果知识库内容与问题不完全匹配,可以结合常识进行补充说明,但要标注哪些是知识库内容,哪些是补充说明
|
||||
|
||||
请直接输出答案,不要包含其他格式说明。"""
|
||||
}
|
||||
}
|
||||
nodes.append(answer_node)
|
||||
|
||||
# ========== 9. 提取最终答案节点 ==========
|
||||
extract_answer_node = {
|
||||
"id": "json-extract-answer",
|
||||
"type": "json",
|
||||
"position": {"x": 1850, "y": 400},
|
||||
"data": {
|
||||
"label": "提取最终答案",
|
||||
"operation": "extract",
|
||||
"path": "output"
|
||||
}
|
||||
}
|
||||
nodes.append(extract_answer_node)
|
||||
|
||||
# ========== 10. 结束节点 ==========
|
||||
end_node = {
|
||||
"id": "end-1",
|
||||
"type": "end",
|
||||
"position": {"x": 2050, "y": 400},
|
||||
"data": {
|
||||
"label": "结束"
|
||||
}
|
||||
}
|
||||
nodes.append(end_node)
|
||||
|
||||
# ========== 连接边 ==========
|
||||
edges.append({
|
||||
"id": "e1",
|
||||
"source": "start-1",
|
||||
"target": "transform-preprocess",
|
||||
"sourceHandle": "right",
|
||||
"targetHandle": "left"
|
||||
})
|
||||
|
||||
edges.append({
|
||||
"id": "e2",
|
||||
"source": "transform-preprocess",
|
||||
"target": "http-embedding",
|
||||
"sourceHandle": "right",
|
||||
"targetHandle": "left"
|
||||
})
|
||||
|
||||
edges.append({
|
||||
"id": "e3",
|
||||
"source": "http-embedding",
|
||||
"target": "json-extract-embedding",
|
||||
"sourceHandle": "right",
|
||||
"targetHandle": "left"
|
||||
})
|
||||
|
||||
edges.append({
|
||||
"id": "e4",
|
||||
"source": "json-extract-embedding",
|
||||
"target": "transform-prepare-search",
|
||||
"sourceHandle": "right",
|
||||
"targetHandle": "left"
|
||||
})
|
||||
|
||||
edges.append({
|
||||
"id": "e5",
|
||||
"source": "transform-prepare-search",
|
||||
"target": "vector-search",
|
||||
"sourceHandle": "right",
|
||||
"targetHandle": "left"
|
||||
})
|
||||
|
||||
edges.append({
|
||||
"id": "e6",
|
||||
"source": "vector-search",
|
||||
"target": "transform-format-results",
|
||||
"sourceHandle": "right",
|
||||
"targetHandle": "left"
|
||||
})
|
||||
|
||||
edges.append({
|
||||
"id": "e7",
|
||||
"source": "transform-format-results",
|
||||
"target": "llm-answer",
|
||||
"sourceHandle": "right",
|
||||
"targetHandle": "left"
|
||||
})
|
||||
|
||||
edges.append({
|
||||
"id": "e8",
|
||||
"source": "llm-answer",
|
||||
"target": "json-extract-answer",
|
||||
"sourceHandle": "right",
|
||||
"targetHandle": "left"
|
||||
})
|
||||
|
||||
edges.append({
|
||||
"id": "e9",
|
||||
"source": "json-extract-answer",
|
||||
"target": "end-1",
|
||||
"sourceHandle": "right",
|
||||
"targetHandle": "left"
|
||||
})
|
||||
|
||||
return {
|
||||
"name": "知识库问答助手",
|
||||
"description": "基于向量数据库和RAG技术的知识库问答系统,支持语义搜索和智能回答。需要先使用向量数据库节点将知识库文档向量化并存储。",
|
||||
"workflow_config": {"nodes": nodes, "edges": edges}
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
db = SessionLocal()
|
||||
try:
|
||||
# 获取或创建测试用户
|
||||
user = db.query(User).first()
|
||||
if not user:
|
||||
print("❌ 未找到用户,请先创建用户")
|
||||
return
|
||||
|
||||
print(f"📝 使用用户: {user.username} (ID: {user.id})")
|
||||
|
||||
# 生成Agent数据
|
||||
agent_data = generate_knowledge_base_qa_agent(db, user)
|
||||
|
||||
# 检查是否已存在
|
||||
existing = db.query(Agent).filter(
|
||||
Agent.name == agent_data["name"],
|
||||
Agent.user_id == user.id
|
||||
).first()
|
||||
|
||||
if existing:
|
||||
print(f"Agent '{agent_data['name']}' 已存在,跳过创建")
|
||||
return
|
||||
|
||||
# 创建Agent
|
||||
agent = Agent(
|
||||
name=agent_data["name"],
|
||||
description=agent_data["description"],
|
||||
workflow_config=agent_data["workflow_config"],
|
||||
user_id=user.id,
|
||||
status="draft"
|
||||
)
|
||||
db.add(agent)
|
||||
db.commit()
|
||||
db.refresh(agent)
|
||||
|
||||
print(f"✅ 成功创建Agent: {agent.name} (ID: {agent.id})")
|
||||
print(f" 节点数量: {len(agent_data['workflow_config']['nodes'])}")
|
||||
print(f" 连接数量: {len(agent_data['workflow_config']['edges'])}")
|
||||
print(f"\n📝 使用说明:")
|
||||
print(f" 1. 在Agent管理页面找到 '{agent.name}'")
|
||||
print(f" 2. 点击'设计'按钮进入工作流编辑器")
|
||||
print(f" 3. 配置HTTP节点的API密钥(DeepSeek API Key)")
|
||||
print(f" 4. 使用向量数据库节点将知识库文档向量化并存储到 'knowledge_base' 集合")
|
||||
print(f" 5. 点击'发布'按钮发布Agent")
|
||||
print(f" 6. 点击'使用'按钮测试问答功能")
|
||||
print(f"\n💡 提示:")
|
||||
print(f" - 知识库文档需要先通过向量数据库节点的 'upsert' 操作存储")
|
||||
print(f" - 每个文档需要包含 'text' 和 'embedding' 字段")
|
||||
print(f" - 可以使用HTTP节点调用embedding API将文档文本转为向量")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 创建Agent失败: {str(e)}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
db.rollback()
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
79
backend/scripts/init_builtin_tools.py
Normal file
79
backend/scripts/init_builtin_tools.py
Normal file
@@ -0,0 +1,79 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
初始化内置工具脚本
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from app.core.database import SessionLocal
|
||||
from app.models.tool import Tool
|
||||
from app.services.tool_registry import tool_registry
|
||||
from app.services.builtin_tools import (
|
||||
http_request_tool,
|
||||
file_read_tool,
|
||||
HTTP_REQUEST_SCHEMA,
|
||||
FILE_READ_SCHEMA
|
||||
)
|
||||
|
||||
|
||||
def init_builtin_tools():
|
||||
"""初始化内置工具"""
|
||||
db = SessionLocal()
|
||||
|
||||
try:
|
||||
# 注册内置工具到注册表
|
||||
tool_registry.register_builtin_tool(
|
||||
"http_request",
|
||||
http_request_tool,
|
||||
HTTP_REQUEST_SCHEMA
|
||||
)
|
||||
|
||||
tool_registry.register_builtin_tool(
|
||||
"file_read",
|
||||
file_read_tool,
|
||||
FILE_READ_SCHEMA
|
||||
)
|
||||
|
||||
print("✅ 内置工具已注册到工具注册表")
|
||||
|
||||
# 保存到数据库
|
||||
tools_to_create = [
|
||||
("http_request", HTTP_REQUEST_SCHEMA, "发送HTTP请求,支持GET、POST、PUT、DELETE方法"),
|
||||
("file_read", FILE_READ_SCHEMA, "读取文件内容,只能读取项目目录下的文件")
|
||||
]
|
||||
|
||||
created_count = 0
|
||||
for tool_name, tool_schema, description in tools_to_create:
|
||||
existing = db.query(Tool).filter(Tool.name == tool_name).first()
|
||||
if not existing:
|
||||
tool = Tool(
|
||||
name=tool_name,
|
||||
description=description,
|
||||
category="builtin",
|
||||
function_schema=tool_schema,
|
||||
implementation_type="builtin",
|
||||
is_public=True
|
||||
)
|
||||
db.add(tool)
|
||||
created_count += 1
|
||||
print(f"✅ 创建工具: {tool_name}")
|
||||
else:
|
||||
# 更新工具定义
|
||||
existing.function_schema = tool_schema
|
||||
existing.description = description
|
||||
print(f"ℹ️ 更新工具: {tool_name}")
|
||||
|
||||
db.commit()
|
||||
print(f"\n✅ 内置工具初始化完成!创建了 {created_count} 个工具")
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
print(f"❌ 初始化失败: {str(e)}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
init_builtin_tools()
|
||||
Reference in New Issue
Block a user